Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459import type { ExtensionDiagnosticInput, ExtensionDiagnosticSink,} from "../shared/extension-diagnostics";import { emitExtensionDiagnostic } from "./extension-diagnostics";import { createFetchTools, type FetchResult,} from "@cloudflare/think/tools/fetch";import * as Effect from "effect/Effect";import { z } from "zod";import { bodyJson } from "../server/http";import type { SkillReview } from "../shared/skill-review";import { skillOrigin, type SkillOrigin } from "../shared/skills";import { runAgent } from "./agent-io";import { InstalledSkills, MAX_SKILL_OBJECT_BYTES } from "./installed-skills";import { OperationFailure } from "./operation-result";import { SkillPackageError, validateSkillPackage, type ValidatedSkillPackage,} from "./skill-package";import { publicWebUrl } from "./web-source";import { downloadGitHubSkill, githubSkillFolder, GitHubSkillError,} from "./github-skill";
const REVIEW_LIFETIME_MS = 5 * 60_000;const fetchPackage = createFetchTools({ allowlist: ["https://**"], maxBytes: MAX_SKILL_OBJECT_BYTES, maxModelChars: MAX_SKILL_OBJECT_BYTES, timeoutMs: 15_000, response: "text", spillToWorkspace: false, followRedirects: "none", modelHeaderAllowlist: [], defaultAccept: "application/json",}).fetch_url;
class ReviewFailure extends Error { constructor( readonly code: string, message: string, readonly status = 400, ) { super(message); }}function diagnosticFailure( error: unknown,): ExtensionDiagnosticInput["failure"] { if (error instanceof SkillPackageError) return "validation"; if (error instanceof OperationFailure) return "unavailable"; if (!(error instanceof ReviewFailure)) return "storage"; switch (error.code) { case "timeout": return "timeout"; case "download_failed": return "connection"; case "storage_unavailable": return "storage"; case "unavailable": case "review_expired": return "unavailable"; default: return "validation"; }}
const unreadable = () => new ReviewFailure( "invalid_package", "Choose a valid format-1 JSON Skill package of at most 13 MiB.", );const expired = () => new ReviewFailure( "review_expired", "This review expired or was replaced. Review the package again.", 409, );
export class SkillInstaller { private pending?: { review: SkillReview; package: ValidatedSkillPackage; timer: ReturnType<typeof setTimeout>; release: () => void; }; private generation = 0; constructor( private readonly store: InstalledSkills | undefined, private readonly reservedNames: () => ReadonlySet<string>, private readonly lifetime: { keepAlive: () => Promise<() => void>; now?: () => number; }, private readonly diagnostics?: ExtensionDiagnosticSink, ) {}
private now() { return this.lifetime.now?.() ?? Date.now(); }
private clearReview() { const pending = this.pending; this.pending = undefined; if (pending) { clearTimeout(pending.timer); pending.release(); } }
private async review( value: unknown, origin: SkillOrigin, generation: number, signal: AbortSignal, ) { if (generation !== this.generation) throw expired(); const skill = validateSkillPackage(value, origin, this.reservedNames()); const previous = this.store!.list().find( (item) => item.name === skill.name, ); const { files: _files, entry, ...metadata } = skill; const review: SkillReview = { ...metadata, reviewId: crypto.randomUUID(), expiresAt: new Date(this.now() + REVIEW_LIFETIME_MS).toISOString(), instructions: entry.body, license: entry.license, compatibility: entry.compatibility, metadata: entry.metadata, allowedTools: entry.allowedTools ?? null, resources: (entry.resources ?? []).map((resource) => ({ path: resource.path, kind: resource.kind, size: resource.size!, })), replaces: previous ? { version: previous.version, revision: previous.revision } : null, }; const release = await this.lifetime.keepAlive().catch(() => { throw new ReviewFailure( "unavailable", "Could not keep the Skill review available. Try again.", 503, ); }); try { signal.throwIfAborted(); const remaining = Date.parse(review.expiresAt) - this.now(); if (generation !== this.generation || remaining <= 0) throw expired(); // The timer prevents hibernation; native Agent alarm heartbeats prevent // idle eviction. Both end with this one bounded, memory-only review. const timer = setTimeout(() => { if (this.pending?.review.reviewId === review.reviewId) this.clearReview(); }, remaining); this.pending = { review, package: skill, timer, release }; return review; } catch (error) { release(); throw error; } }
private fromUrl(value: unknown) { return Effect.gen(function* () { const requested = yield* Effect.try({ try: () => { const { url } = z .strictObject({ url: z.url().max(2048) }) .parse(value); skillOrigin.parse({ kind: "url", url }); return publicWebUrl(url).href; }, catch: () => new ReviewFailure( "invalid_url", "Use a public GitHub folder or direct HTTPS package URL without embedded credentials.", ), }); const folder = yield* Effect.try({ try: () => githubSkillFolder(requested), catch: (error) => new ReviewFailure( "invalid_url", error instanceof GitHubSkillError ? error.message : "Use a valid public GitHub folder URL.", ), }); if (folder) return yield* downloadGitHubSkill(folder).pipe( Effect.mapError( (error) => new ReviewFailure(error.code, error.message, error.status), ), ); const result = yield* Effect.tryPromise({ try: (signal) => Promise.resolve( fetchPackage.execute!( { url: requested }, { toolCallId: "skill-package-review", messages: [], context: {}, abortSignal: signal, }, ), ) as Promise<FetchResult>, catch: () => new ReviewFailure( "download_failed", "Could not download the Skill package. Try again.", 502, ), }); if (!result.ok || result.truncated || !result.body) return yield* Effect.fail( new ReviewFailure( "download_failed", "Could not download a complete package. Use a direct HTTPS URL without redirects, at most 13 MiB.", 502, ), ); const downloaded = yield* Effect.try({ try: (): unknown => JSON.parse(result.body!), catch: unreadable, }); return { value: downloaded, origin: { kind: "url" as const, url: requested }, }; }); }
request(request: Request): Promise<Response> { const path = new URL(request.url).pathname; const startedAt = Date.now(); let provenance: Pick< ExtensionDiagnosticInput, "source" | "version" | "fingerprint" > = {}; let reported = false; const report = ( status: ExtensionDiagnosticInput["status"], failure?: ExtensionDiagnosticInput["failure"], ) => { if ( reported || request.method !== "POST" || ![ "/api/skills/install", "/api/skills/review-upload", "/api/skills/review-url", ].includes(path) ) return; reported = true; emitExtensionDiagnostic(this.diagnostics, { operation: path === "/api/skills/install" ? "skill-install" : "skill-validation", startedAt, status, ...provenance, ...(failure ? { failure } : {}), }); }; const remember = ( skill: Pick<SkillReview, "name" | "version" | "fingerprint">, ) => { provenance = { source: { kind: "skill", id: `installed:${skill.name}` }, version: skill.version, fingerprint: skill.fingerprint, }; }; const response = (value: unknown, status = 200) => Response.json(value, { status, headers: { "Cache-Control": "no-store" }, }); return runAgent( Effect.gen({ self: this }, function* () { if (!this.store) return yield* Effect.fail( new ReviewFailure( "storage_unavailable", "Skill storage is unavailable for this installation.", 503, ), ); if (request.method !== "POST") return response( { error: { code: "method_not_allowed", path: "", message: "Use POST for Skill review and installation.", }, }, 405, ); if (path === "/api/skills/install") { const input = yield* bodyJson( new Response(request.body, { headers: request.headers }), 1024, unreadable(), ); const { reviewId } = yield* Effect.try({ try: () => z.strictObject({ reviewId: z.uuid() }).parse(input), catch: unreadable, }); const pending = this.pending; if (pending?.review.reviewId === reviewId) remember(pending.review); if (pending && Date.parse(pending.review.expiresAt) <= this.now()) this.clearReview(); if ( !pending || this.pending !== pending || pending.review.reviewId !== reviewId ) return yield* Effect.fail(expired()); this.clearReview(); this.generation++; const installed = yield* this.store.install( { formatVersion: 1, files: pending.package.files }, pending.package.origin, pending.review.replaces?.revision ?? null, ); report("completed"); return response(installed, 201); } if ( path !== "/api/skills/review-upload" && path !== "/api/skills/review-url" ) return response( { error: { code: "not_found", path: "", message: "Skill route not found.", }, }, 404, ); const generation = ++this.generation; this.clearReview(); const value = yield* bodyJson( new Response(request.body, { headers: request.headers }), path.endsWith("review-url") ? 4096 : MAX_SKILL_OBJECT_BYTES, unreadable(), ); const prepared = path.endsWith("review-url") ? yield* this.fromUrl(value) : { value, origin: yield* Effect.try({ try: () => skillOrigin.parse({ kind: "upload", filename: decodeURIComponent( request.headers.get("X-Filename") ?? "package.skill.json", ), }), catch: () => new ReviewFailure( "invalid_filename", "Use an uploaded filename without directories or control characters.", ), }), }; const review = yield* Effect.tryPromise({ try: (signal) => this.review(prepared.value, prepared.origin, generation, signal), catch: (error) => error instanceof SkillPackageError || error instanceof ReviewFailure ? error : unreadable(), }); remember(review); report("completed"); return response(review); }).pipe( Effect.timeoutOrElse({ duration: 25_000, orElse: () => Effect.fail( new ReviewFailure( "timeout", "Skill operation timed out. Reload Skills before trying again.", 504, ), ), }), Effect.catch((error) => { report("error", diagnosticFailure(error)); const known = error instanceof ReviewFailure || error instanceof SkillPackageError || error instanceof OperationFailure; return Effect.succeed( response( { error: { code: known ? error.code : "storage_failed", path: error instanceof SkillPackageError ? error.path : "", message: known ? error.message : "Skill storage could not complete the operation. Reload Skills and try again.", }, }, error instanceof ReviewFailure ? error.status : error instanceof OperationFailure ? 409 : error instanceof SkillPackageError ? 400 : 502, ), ); }), Effect.catchDefect(() => { report("error", "unknown"); return Effect.succeed( response( { error: { code: "unavailable", path: "", message: "Skill operation unavailable. Try again.", }, }, 500, ), ); }), Effect.ensuring( Effect.sync(() => { if (!reported) report( request.signal.aborted ? "aborted" : "error", request.signal.aborted ? "cancelled" : "unknown", ); }), ), ), request.signal, ); }}