@ai-agent-forge/plugin-workspace-files-write 0.88.4 → 0.88.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/agent-forge.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "packageFormatVersion": 1,
3
3
  "id": "agent-forge.plugin.workspace-files-write",
4
- "pluginVersion": "0.88.4",
4
+ "pluginVersion": "0.88.6",
5
5
  "apiVersion": "1",
6
6
  "minHostVersion": "0.84.4",
7
7
  "capabilityRefs": [
@@ -1 +1 @@
1
- {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAU3E,OAAO,KAAK,EACX,4BAA4B,EAI5B,MAAM,YAAY,CAAC;AA4GpB,6EAA6E;AAC7E,wBAAgB,4CAA4C,CAC3D,OAAO,GAAE,4BAAuE,GAC9E,2BAA2B,CA+C7B","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n\tcreateNodeWorkspaceFilesWriteAdapterV1,\n\tprojectWorkspaceFilesWriteV1,\n\tWORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n} from \"./node-adapter.ts\";\nimport type {\n\tWorkspaceFilesWriteAdapterV1,\n\tWorkspaceFilesWriteModeV1,\n\tWorkspaceFilesWriteRequestV1,\n\tWorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nconst refSchema = Type.String({\n\tminLength: 1,\n\tmaxLength: WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n});\nconst requestSchema = Type.Object(\n\t{\n\t\tfileRef: refSchema,\n\t\tmode: Type.Union([Type.Literal(\"replace\"), Type.Literal(\"patch\")]),\n\t\tsourceArtifactRef: refSchema,\n\t\texpectedVersion: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tminLength: 1,\n\t\t\t\tmaxLength: WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n\t\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t\t}),\n\t\t),\n\t\tcreateIfMissing: Type.Optional(Type.Boolean()),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction generatedOperationId(): string {\n\treturn `profile-runtime-tool-call-${randomUUID()}`;\n}\n\nfunction operationIdFor(first: unknown, second: unknown): string {\n\tconst explicit = second === undefined ? undefined : first;\n\treturn typeof explicit === \"string\" &&\n\t\texplicit.trim() !== \"\" &&\n\t\texplicit.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1\n\t\t? explicit\n\t\t: generatedOperationId();\n}\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Write input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction fallback(\n\toperationId: string,\n\tstatus: \"failed\" | \"cancelled\",\n\trequest?: Partial<WorkspaceFilesWriteRequestV1>,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef: request?.fileRef ?? \"invalid:file\",\n\t\tmode: (request?.mode ?? \"replace\") as WorkspaceFilesWriteModeV1,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: {\n\t\t\tversion: 1,\n\t\t\tcode: status === \"cancelled\" ? \"cancelled\" : \"adapter_failed\",\n\t\t\tmessage: status === \"cancelled\" ? \"Workspace write was cancelled\" : \"Workspace writer failed\",\n\t\t},\n\t};\n}\n\nfunction invalidInput(operationId: string): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\"),\n\t\terror: { version: 1, code: \"invalid_input\", message: \"Workspace write request was invalid\" },\n\t};\n}\n\nfunction cancelled(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn fallback(operationId, \"cancelled\", request);\n}\n\nfunction malformed(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\", request),\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Workspace writer returned an invalid result\" },\n\t};\n}\n\nasync function runWithCancellation(\n\trun: () => Promise<WorkspaceFilesWriteResultV1>,\n\tsignal: AbortSignal | undefined,\n\toperationId: string,\n\trequest: WorkspaceFilesWriteRequestV1,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tconst result = await run();\n\tif (!signal?.aborted || result.status === \"cancelled\") return result;\n\tconst replacement = cancelled(operationId, request);\n\t// An adapter that already committed the write must not lose that fact when\n\t// its result is converted to cancelled after an abort.\n\treturn result.committed === true\n\t\t? { ...replacement, committed: true, changed: result.changed, bytesWritten: result.bytesWritten }\n\t\t: replacement;\n}\n\n/** Registers opaque file writes and patches only for a full-control host. */\nexport function createWorkspaceFilesWriteCapabilityFactoryV1(\n\truntime: WorkspaceFilesWriteAdapterV1 = createNodeWorkspaceFilesWriteAdapterV1(),\n): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"workspace_write\",\n\t\t\tlabel: \"Write workspace file\",\n\t\t\tdescription: \"Atomically replace or patch a host-owned file using opaque artifact references\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tconst operationId = operationIdFor(first, second);\n\t\t\t\tlet input: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tinput = objectInput(first, second);\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId);\n\t\t\t\t}\n\t\t\t\tconst requestInput = input.request as Record<string, unknown>;\n\t\t\t\tconst request: WorkspaceFilesWriteRequestV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\toperationId,\n\t\t\t\t\tfileRef: requestInput.fileRef as string,\n\t\t\t\t\tmode: requestInput.mode as WorkspaceFilesWriteModeV1,\n\t\t\t\t\tsourceArtifactRef: requestInput.sourceArtifactRef as string,\n\t\t\t\t\t...(requestInput.expectedVersion === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { expectedVersion: requestInput.expectedVersion as string }),\n\t\t\t\t\t...(requestInput.createIfMissing === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { createIfMissing: requestInput.createIfMissing as boolean }),\n\t\t\t\t};\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId, request);\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() => runtime.write(request, signal),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toperationId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t);\n\t\t\t\t\treturn projectWorkspaceFilesWriteV1(output, request) ?? malformed(operationId, request);\n\t\t\t\t} catch {\n\t\t\t\t\treturn signal?.aborted ? cancelled(operationId, request) : malformed(operationId, request);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAU3E,OAAO,KAAK,EACX,4BAA4B,EAI5B,MAAM,YAAY,CAAC;AA+GpB,6EAA6E;AAC7E,wBAAgB,4CAA4C,CAC3D,OAAO,GAAE,4BAAuE,GAC9E,2BAA2B,CA+C7B","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n\tcreateNodeWorkspaceFilesWriteAdapterV1,\n\tprojectWorkspaceFilesWriteV1,\n\tWORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n} from \"./node-adapter.ts\";\nimport type {\n\tWorkspaceFilesWriteAdapterV1,\n\tWorkspaceFilesWriteModeV1,\n\tWorkspaceFilesWriteRequestV1,\n\tWorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nconst refSchema = Type.String({\n\tminLength: 1,\n\tmaxLength: WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n});\nconst requestSchema = Type.Object(\n\t{\n\t\tfileRef: refSchema,\n\t\tmode: Type.Union([Type.Literal(\"replace\"), Type.Literal(\"patch\")]),\n\t\tsourceArtifactRef: refSchema,\n\t\texpectedVersion: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tminLength: 1,\n\t\t\t\tmaxLength: WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n\t\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t\t}),\n\t\t),\n\t\tcreateIfMissing: Type.Optional(Type.Boolean()),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction generatedOperationId(): string {\n\treturn `profile-runtime-tool-call-${randomUUID()}`;\n}\n\nfunction operationIdFor(first: unknown, second: unknown): string {\n\tconst explicit = second === undefined ? undefined : first;\n\treturn typeof explicit === \"string\" &&\n\t\texplicit.trim() !== \"\" &&\n\t\texplicit.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1\n\t\t? explicit\n\t\t: generatedOperationId();\n}\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Write input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction fallback(\n\toperationId: string,\n\tstatus: \"failed\" | \"cancelled\",\n\trequest?: Partial<WorkspaceFilesWriteRequestV1>,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef: request?.fileRef ?? \"invalid:file\",\n\t\tmode: (request?.mode ?? \"replace\") as WorkspaceFilesWriteModeV1,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: {\n\t\t\tversion: 1,\n\t\t\tcode: status === \"cancelled\" ? \"cancelled\" : \"adapter_failed\",\n\t\t\tmessage: status === \"cancelled\" ? \"Workspace write was cancelled\" : \"Workspace writer failed\",\n\t\t},\n\t};\n}\n\nfunction invalidInput(operationId: string): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\"),\n\t\terror: { version: 1, code: \"invalid_input\", message: \"Workspace write request was invalid\" },\n\t};\n}\n\nfunction cancelled(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn fallback(operationId, \"cancelled\", request);\n}\n\nfunction malformed(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\", request),\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Workspace writer returned an invalid result\" },\n\t};\n}\n\nasync function runWithCancellation(\n\trun: () => Promise<WorkspaceFilesWriteResultV1>,\n\tsignal: AbortSignal | undefined,\n\toperationId: string,\n\trequest: WorkspaceFilesWriteRequestV1,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tconst result = await run();\n\tif (!signal?.aborted || result.status === \"cancelled\") return result;\n\tconst replacement = cancelled(operationId, request);\n\t// An adapter that already committed the write must not lose that fact when\n\t// its result is converted to cancelled after an abort; a timeout result with\n\t// an unknown commit state must not degrade into a false \"nothing changed\".\n\tif (result.committed === \"unknown\" || result.changed === \"unknown\")\n\t\treturn { ...replacement, changed: \"unknown\", committed: \"unknown\" };\n\treturn result.committed === true\n\t\t? { ...replacement, committed: true, changed: result.changed, bytesWritten: result.bytesWritten }\n\t\t: replacement;\n}\n\n/** Registers opaque file writes and patches only for a full-control host. */\nexport function createWorkspaceFilesWriteCapabilityFactoryV1(\n\truntime: WorkspaceFilesWriteAdapterV1 = createNodeWorkspaceFilesWriteAdapterV1(),\n): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"workspace_write\",\n\t\t\tlabel: \"Write workspace file\",\n\t\t\tdescription: \"Atomically replace or patch a host-owned file using opaque artifact references\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tconst operationId = operationIdFor(first, second);\n\t\t\t\tlet input: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tinput = objectInput(first, second);\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId);\n\t\t\t\t}\n\t\t\t\tconst requestInput = input.request as Record<string, unknown>;\n\t\t\t\tconst request: WorkspaceFilesWriteRequestV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\toperationId,\n\t\t\t\t\tfileRef: requestInput.fileRef as string,\n\t\t\t\t\tmode: requestInput.mode as WorkspaceFilesWriteModeV1,\n\t\t\t\t\tsourceArtifactRef: requestInput.sourceArtifactRef as string,\n\t\t\t\t\t...(requestInput.expectedVersion === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { expectedVersion: requestInput.expectedVersion as string }),\n\t\t\t\t\t...(requestInput.createIfMissing === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { createIfMissing: requestInput.createIfMissing as boolean }),\n\t\t\t\t};\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId, request);\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() => runtime.write(request, signal),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toperationId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t);\n\t\t\t\t\treturn projectWorkspaceFilesWriteV1(output, request) ?? malformed(operationId, request);\n\t\t\t\t} catch {\n\t\t\t\t\treturn signal?.aborted ? cancelled(operationId, request) : malformed(operationId, request);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
@@ -80,7 +80,10 @@ async function runWithCancellation(run, signal, operationId, request) {
80
80
  return result;
81
81
  const replacement = cancelled(operationId, request);
82
82
  // An adapter that already committed the write must not lose that fact when
83
- // its result is converted to cancelled after an abort.
83
+ // its result is converted to cancelled after an abort; a timeout result with
84
+ // an unknown commit state must not degrade into a false "nothing changed".
85
+ if (result.committed === "unknown" || result.changed === "unknown")
86
+ return { ...replacement, changed: "unknown", committed: "unknown" };
84
87
  return result.committed === true
85
88
  ? { ...replacement, committed: true, changed: result.changed, bytesWritten: result.bytesWritten }
86
89
  : replacement;
@@ -1 +1 @@
1
- {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EACN,sCAAsC,EACtC,4BAA4B,EAC5B,+CAA+C,EAC/C,sCAAsC,EACtC,0CAA0C,GAC1C,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;IAC7B,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,sCAAsC;IACjD,OAAO,EAAE,+BAA+B;CACxC,CAAC,CAAC;AACH,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAChC;IACC,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,iBAAiB,EAAE,SAAS;IAC5B,eAAe,EAAE,IAAI,CAAC,QAAQ,CAC7B,IAAI,CAAC,MAAM,CAAC;QACX,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,0CAA0C;QACrD,OAAO,EAAE,+BAA+B;KACxC,CAAC,CACF;IACD,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;CAC9C,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAC/B,CAAC;AACF,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,CAAC;AAE7F,SAAS,oBAAoB,GAAW;IACvC,OAAO,6BAA6B,UAAU,EAAE,EAAE,CAAC;AAAA,CACnD;AAED,SAAS,cAAc,CAAC,KAAc,EAAE,MAAe,EAAU;IAChE,MAAM,QAAQ,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;IAC1D,OAAO,OAAO,QAAQ,KAAK,QAAQ;QAClC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE;QACtB,QAAQ,CAAC,MAAM,IAAI,+CAA+C;QAClE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,oBAAoB,EAAE,CAAC;AAAA,CAC1B;AAED,SAAS,WAAW,CAAC,KAAc,EAAE,MAAe,EAA2B;IAC9E,yEAAyE;IACzE,iEAAiE;IACjE,yEAAyE;IACzE,oDAAoD;IACpD,MAAM,KAAK,GAAG,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACpG,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAClD,OAAO,KAAgC,CAAC;AAAA,CACxC;AAED,SAAS,UAAU,CAAC,KAAc,EAA2B;IAC5D,OAAO,KAAK,YAAY,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAAA,CACxD;AAED,SAAS,QAAQ,CAChB,WAAmB,EACnB,MAA8B,EAC9B,OAA+C,EACjB;IAC9B,OAAO;QACN,OAAO,EAAE,CAAC;QACV,WAAW;QACX,MAAM;QACN,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,cAAc;QAC3C,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,IAAI,SAAS,CAA8B;QAC/D,OAAO,EAAE,KAAK;QACd,YAAY,EAAE,CAAC;QACf,KAAK,EAAE;YACN,OAAO,EAAE,CAAC;YACV,IAAI,EAAE,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB;YAC7D,OAAO,EAAE,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,yBAAyB;SAC7F;KACD,CAAC;AAAA,CACF;AAED,SAAS,YAAY,CAAC,WAAmB,EAA+B;IACvE,OAAO;QACN,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;QAClC,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,qCAAqC,EAAE;KAC5F,CAAC;AAAA,CACF;AAED,SAAS,SAAS,CAAC,WAAmB,EAAE,OAA+C,EAA+B;IACrH,OAAO,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAAA,CACnD;AAED,SAAS,SAAS,CAAC,WAAmB,EAAE,OAA+C,EAA+B;IACrH,OAAO;QACN,GAAG,QAAQ,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC;QAC3C,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,6CAA6C,EAAE;KACrG,CAAC;AAAA,CACF;AAED,KAAK,UAAU,mBAAmB,CACjC,GAA+C,EAC/C,MAA+B,EAC/B,WAAmB,EACnB,OAAqC,EACE;IACvC,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE,OAAO,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC;IACrE,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACpD,2EAA2E;IAC3E,uDAAuD;IACvD,OAAO,MAAM,CAAC,SAAS,KAAK,IAAI;QAC/B,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE;QACjG,CAAC,CAAC,WAAW,CAAC;AAAA,CACf;AAED,6EAA6E;AAC7E,MAAM,UAAU,4CAA4C,CAC3D,OAAO,GAAiC,sCAAsC,EAAE,EAClD;IAC9B,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QACf,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO;QACzC,GAAG,CAAC,YAAY,CAAC;YAChB,IAAI,EAAE,iBAAiB;YACvB,KAAK,EAAE,sBAAsB;YAC7B,WAAW,EAAE,gFAAgF;YAC7F,UAAU,EAAE,WAAW;YACvB,OAAO,EAAE,KAAK,EAAE,KAAc,EAAE,MAAgB,EAAE,KAAe,EAAE,EAAE,CAAC;gBACrE,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBAClD,IAAI,KAA8B,CAAC;gBACnC,IAAI,CAAC;oBACJ,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;oBACnC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC;wBAAE,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC;gBACxE,CAAC;gBAAC,MAAM,CAAC;oBACR,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC;gBAClC,CAAC;gBACD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAkC,CAAC;gBAC9D,MAAM,OAAO,GAAiC;oBAC7C,OAAO,EAAE,CAAC;oBACV,WAAW;oBACX,OAAO,EAAE,YAAY,CAAC,OAAiB;oBACvC,IAAI,EAAE,YAAY,CAAC,IAAiC;oBACpD,iBAAiB,EAAE,YAAY,CAAC,iBAA2B;oBAC3D,GAAG,CAAC,YAAY,CAAC,eAAe,KAAK,SAAS;wBAC7C,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,EAAE,eAAe,EAAE,YAAY,CAAC,eAAyB,EAAE,CAAC;oBAC/D,GAAG,CAAC,YAAY,CAAC,eAAe,KAAK,SAAS;wBAC7C,CAAC,CAAC,EAAE;wBACJ,CAAC,CAAC,EAAE,eAAe,EAAE,YAAY,CAAC,eAA0B,EAAE,CAAC;iBAChE,CAAC;gBACF,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;gBACjC,IAAI,MAAM,EAAE,OAAO;oBAAE,OAAO,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAC5D,IAAI,CAAC;oBACJ,MAAM,MAAM,GAAG,MAAM,mBAAmB,CACvC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,EACpC,MAAM,EACN,WAAW,EACX,OAAO,CACP,CAAC;oBACF,OAAO,4BAA4B,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBACzF,CAAC;gBAAC,MAAM,CAAC;oBACR,OAAO,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAC5F,CAAC;YAAA,CACD;SACD,CAAC,CAAC;IAAA,CACH,CAAC;AAAA,CACF","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n\tcreateNodeWorkspaceFilesWriteAdapterV1,\n\tprojectWorkspaceFilesWriteV1,\n\tWORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n} from \"./node-adapter.ts\";\nimport type {\n\tWorkspaceFilesWriteAdapterV1,\n\tWorkspaceFilesWriteModeV1,\n\tWorkspaceFilesWriteRequestV1,\n\tWorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nconst refSchema = Type.String({\n\tminLength: 1,\n\tmaxLength: WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n});\nconst requestSchema = Type.Object(\n\t{\n\t\tfileRef: refSchema,\n\t\tmode: Type.Union([Type.Literal(\"replace\"), Type.Literal(\"patch\")]),\n\t\tsourceArtifactRef: refSchema,\n\t\texpectedVersion: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tminLength: 1,\n\t\t\t\tmaxLength: WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n\t\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t\t}),\n\t\t),\n\t\tcreateIfMissing: Type.Optional(Type.Boolean()),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction generatedOperationId(): string {\n\treturn `profile-runtime-tool-call-${randomUUID()}`;\n}\n\nfunction operationIdFor(first: unknown, second: unknown): string {\n\tconst explicit = second === undefined ? undefined : first;\n\treturn typeof explicit === \"string\" &&\n\t\texplicit.trim() !== \"\" &&\n\t\texplicit.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1\n\t\t? explicit\n\t\t: generatedOperationId();\n}\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Write input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction fallback(\n\toperationId: string,\n\tstatus: \"failed\" | \"cancelled\",\n\trequest?: Partial<WorkspaceFilesWriteRequestV1>,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef: request?.fileRef ?? \"invalid:file\",\n\t\tmode: (request?.mode ?? \"replace\") as WorkspaceFilesWriteModeV1,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: {\n\t\t\tversion: 1,\n\t\t\tcode: status === \"cancelled\" ? \"cancelled\" : \"adapter_failed\",\n\t\t\tmessage: status === \"cancelled\" ? \"Workspace write was cancelled\" : \"Workspace writer failed\",\n\t\t},\n\t};\n}\n\nfunction invalidInput(operationId: string): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\"),\n\t\terror: { version: 1, code: \"invalid_input\", message: \"Workspace write request was invalid\" },\n\t};\n}\n\nfunction cancelled(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn fallback(operationId, \"cancelled\", request);\n}\n\nfunction malformed(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\", request),\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Workspace writer returned an invalid result\" },\n\t};\n}\n\nasync function runWithCancellation(\n\trun: () => Promise<WorkspaceFilesWriteResultV1>,\n\tsignal: AbortSignal | undefined,\n\toperationId: string,\n\trequest: WorkspaceFilesWriteRequestV1,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tconst result = await run();\n\tif (!signal?.aborted || result.status === \"cancelled\") return result;\n\tconst replacement = cancelled(operationId, request);\n\t// An adapter that already committed the write must not lose that fact when\n\t// its result is converted to cancelled after an abort.\n\treturn result.committed === true\n\t\t? { ...replacement, committed: true, changed: result.changed, bytesWritten: result.bytesWritten }\n\t\t: replacement;\n}\n\n/** Registers opaque file writes and patches only for a full-control host. */\nexport function createWorkspaceFilesWriteCapabilityFactoryV1(\n\truntime: WorkspaceFilesWriteAdapterV1 = createNodeWorkspaceFilesWriteAdapterV1(),\n): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"workspace_write\",\n\t\t\tlabel: \"Write workspace file\",\n\t\t\tdescription: \"Atomically replace or patch a host-owned file using opaque artifact references\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tconst operationId = operationIdFor(first, second);\n\t\t\t\tlet input: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tinput = objectInput(first, second);\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId);\n\t\t\t\t}\n\t\t\t\tconst requestInput = input.request as Record<string, unknown>;\n\t\t\t\tconst request: WorkspaceFilesWriteRequestV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\toperationId,\n\t\t\t\t\tfileRef: requestInput.fileRef as string,\n\t\t\t\t\tmode: requestInput.mode as WorkspaceFilesWriteModeV1,\n\t\t\t\t\tsourceArtifactRef: requestInput.sourceArtifactRef as string,\n\t\t\t\t\t...(requestInput.expectedVersion === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { expectedVersion: requestInput.expectedVersion as string }),\n\t\t\t\t\t...(requestInput.createIfMissing === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { createIfMissing: requestInput.createIfMissing as boolean }),\n\t\t\t\t};\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId, request);\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() => runtime.write(request, signal),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toperationId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t);\n\t\t\t\t\treturn projectWorkspaceFilesWriteV1(output, request) ?? malformed(operationId, request);\n\t\t\t\t} catch {\n\t\t\t\t\treturn signal?.aborted ? cancelled(operationId, request) : malformed(operationId, request);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { CapabilityPluginSyncFactory } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n\tcreateNodeWorkspaceFilesWriteAdapterV1,\n\tprojectWorkspaceFilesWriteV1,\n\tWORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tWORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n} from \"./node-adapter.ts\";\nimport type {\n\tWorkspaceFilesWriteAdapterV1,\n\tWorkspaceFilesWriteModeV1,\n\tWorkspaceFilesWriteRequestV1,\n\tWorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nconst refSchema = Type.String({\n\tminLength: 1,\n\tmaxLength: WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1,\n\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n});\nconst requestSchema = Type.Object(\n\t{\n\t\tfileRef: refSchema,\n\t\tmode: Type.Union([Type.Literal(\"replace\"), Type.Literal(\"patch\")]),\n\t\tsourceArtifactRef: refSchema,\n\t\texpectedVersion: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tminLength: 1,\n\t\t\t\tmaxLength: WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1,\n\t\t\t\tpattern: \"^[A-Za-z0-9][A-Za-z0-9._:-]*$\",\n\t\t\t}),\n\t\t),\n\t\tcreateIfMissing: Type.Optional(Type.Boolean()),\n\t},\n\t{ additionalProperties: false },\n);\nconst inputSchema = Type.Object({ request: requestSchema }, { additionalProperties: false });\n\nfunction generatedOperationId(): string {\n\treturn `profile-runtime-tool-call-${randomUUID()}`;\n}\n\nfunction operationIdFor(first: unknown, second: unknown): string {\n\tconst explicit = second === undefined ? undefined : first;\n\treturn typeof explicit === \"string\" &&\n\t\texplicit.trim() !== \"\" &&\n\t\texplicit.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1\n\t\t? explicit\n\t\t: generatedOperationId();\n}\n\nfunction objectInput(first: unknown, second: unknown): Record<string, unknown> {\n\t// Shape-based dual-convention read (aligned with subagent-delegate): the\n\t// runtime invoke face passes the input object first and the host\n\t// CapabilityToolContext second; the agent tool face passes the tool call\n\t// id (a string) first and the params object second.\n\tconst value = first !== null && typeof first === \"object\" && !Array.isArray(first) ? first : second;\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(\"Write input must be an object\");\n\treturn value as Record<string, unknown>;\n}\n\nfunction signalFrom(value: unknown): AbortSignal | undefined {\n\treturn value instanceof AbortSignal ? value : undefined;\n}\n\nfunction fallback(\n\toperationId: string,\n\tstatus: \"failed\" | \"cancelled\",\n\trequest?: Partial<WorkspaceFilesWriteRequestV1>,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef: request?.fileRef ?? \"invalid:file\",\n\t\tmode: (request?.mode ?? \"replace\") as WorkspaceFilesWriteModeV1,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: {\n\t\t\tversion: 1,\n\t\t\tcode: status === \"cancelled\" ? \"cancelled\" : \"adapter_failed\",\n\t\t\tmessage: status === \"cancelled\" ? \"Workspace write was cancelled\" : \"Workspace writer failed\",\n\t\t},\n\t};\n}\n\nfunction invalidInput(operationId: string): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\"),\n\t\terror: { version: 1, code: \"invalid_input\", message: \"Workspace write request was invalid\" },\n\t};\n}\n\nfunction cancelled(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn fallback(operationId, \"cancelled\", request);\n}\n\nfunction malformed(operationId: string, request?: Partial<WorkspaceFilesWriteRequestV1>): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\t...fallback(operationId, \"failed\", request),\n\t\terror: { version: 1, code: \"adapter_failed\", message: \"Workspace writer returned an invalid result\" },\n\t};\n}\n\nasync function runWithCancellation(\n\trun: () => Promise<WorkspaceFilesWriteResultV1>,\n\tsignal: AbortSignal | undefined,\n\toperationId: string,\n\trequest: WorkspaceFilesWriteRequestV1,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tconst result = await run();\n\tif (!signal?.aborted || result.status === \"cancelled\") return result;\n\tconst replacement = cancelled(operationId, request);\n\t// An adapter that already committed the write must not lose that fact when\n\t// its result is converted to cancelled after an abort; a timeout result with\n\t// an unknown commit state must not degrade into a false \"nothing changed\".\n\tif (result.committed === \"unknown\" || result.changed === \"unknown\")\n\t\treturn { ...replacement, changed: \"unknown\", committed: \"unknown\" };\n\treturn result.committed === true\n\t\t? { ...replacement, committed: true, changed: result.changed, bytesWritten: result.bytesWritten }\n\t\t: replacement;\n}\n\n/** Registers opaque file writes and patches only for a full-control host. */\nexport function createWorkspaceFilesWriteCapabilityFactoryV1(\n\truntime: WorkspaceFilesWriteAdapterV1 = createNodeWorkspaceFilesWriteAdapterV1(),\n): CapabilityPluginSyncFactory {\n\treturn (api) => {\n\t\tif (api.host.mode === \"readonly\") return;\n\t\tapi.registerTool({\n\t\t\tname: \"workspace_write\",\n\t\t\tlabel: \"Write workspace file\",\n\t\t\tdescription: \"Atomically replace or patch a host-owned file using opaque artifact references\",\n\t\t\tparameters: inputSchema,\n\t\t\texecute: async (first: unknown, second?: unknown, third?: unknown) => {\n\t\t\t\tconst operationId = operationIdFor(first, second);\n\t\t\t\tlet input: Record<string, unknown>;\n\t\t\t\ttry {\n\t\t\t\t\tinput = objectInput(first, second);\n\t\t\t\t\tif (!Value.Check(inputSchema, input)) return invalidInput(operationId);\n\t\t\t\t} catch {\n\t\t\t\t\treturn invalidInput(operationId);\n\t\t\t\t}\n\t\t\t\tconst requestInput = input.request as Record<string, unknown>;\n\t\t\t\tconst request: WorkspaceFilesWriteRequestV1 = {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\toperationId,\n\t\t\t\t\tfileRef: requestInput.fileRef as string,\n\t\t\t\t\tmode: requestInput.mode as WorkspaceFilesWriteModeV1,\n\t\t\t\t\tsourceArtifactRef: requestInput.sourceArtifactRef as string,\n\t\t\t\t\t...(requestInput.expectedVersion === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { expectedVersion: requestInput.expectedVersion as string }),\n\t\t\t\t\t...(requestInput.createIfMissing === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { createIfMissing: requestInput.createIfMissing as boolean }),\n\t\t\t\t};\n\t\t\t\tconst signal = signalFrom(third);\n\t\t\t\tif (signal?.aborted) return cancelled(operationId, request);\n\t\t\t\ttry {\n\t\t\t\t\tconst output = await runWithCancellation(\n\t\t\t\t\t\t() => runtime.write(request, signal),\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toperationId,\n\t\t\t\t\t\trequest,\n\t\t\t\t\t);\n\t\t\t\t\treturn projectWorkspaceFilesWriteV1(output, request) ?? malformed(operationId, request);\n\t\t\t\t} catch {\n\t\t\t\t\treturn signal?.aborted ? cancelled(operationId, request) : malformed(operationId, request);\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,uCAAuC,EAG5C,KAAK,4BAA4B,EAEjC,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,+CAA+C,MAAM,CAAC;AACnE,eAAO,MAAM,sCAAsC,MAAM,CAAC;AAC1D,eAAO,MAAM,0CAA0C,MAAM,CAAC;AAC9D,eAAO,MAAM,yCAAyC,QAAY,CAAC;AACnE,eAAO,MAAM,kCAAkC,QAAyB,CAAC;AASzE,iBAAS,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhD;AAuCD,iBAAS,eAAe,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAUlF;AAsBD,0FAA0F;AAC1F,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,4BAA4B,GACnC,2BAA2B,GAAG,SAAS,CA4CzC;AA4FD,wBAAgB,sCAAsC,CACrD,OAAO,GAAE,uCAA4C,GACnD,4BAA4B,CAmB9B;AAED,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport { projectPluginContextV1 } from \"@agent-forge/plugin-sdk\";\nimport {\n\ttype NodeWorkspaceFilesWriteAdapterOptionsV1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\ttype WorkspaceFilesWriteAdapterV1,\n\ttype WorkspaceFilesWriteModeV1,\n\ttype WorkspaceFilesWriteRequestV1,\n\ttype WorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nexport const WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const WORKSPACE_FILES_WRITE_MAX_BYTES_V1 = 4 * 1024 * 1024 * 1024;\n\nconst OPAQUE_REF_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\nconst VERSION_TOKEN_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction safeRef(value: unknown): value is string {\n\treturn typeof value === \"string\" && OPAQUE_REF_V1.test(value);\n}\n\nfunction safeVersionToken(value: unknown): value is string | undefined {\n\treturn value === undefined || (typeof value === \"string\" && VERSION_TOKEN_V1.test(value));\n}\n\nfunction validOperationId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.trim() !== \"\" &&\n\t\tvalue.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value)\n\t);\n}\n\nfunction validMode(value: unknown): value is WorkspaceFilesWriteModeV1 {\n\treturn value === \"replace\" || value === \"patch\";\n}\n\nfunction error(\n\toperationId: string,\n\tfileRef: string,\n\tmode: WorkspaceFilesWriteModeV1,\n\tstatus: WorkspaceFilesWriteResultV1[\"status\"],\n\tcode: string,\n\tmessage: string,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef,\n\t\tmode,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: { version: 1, code, message },\n\t};\n}\n\nfunction validateRequest(request: WorkspaceFilesWriteRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (!validOperationId(request.operationId)) return \"operationId is invalid\";\n\tif (!safeRef(request.fileRef)) return \"fileRef must be an opaque host handle\";\n\tif (!validMode(request.mode)) return \"mode must be replace or patch\";\n\tif (!safeRef(request.sourceArtifactRef)) return \"sourceArtifactRef must be an opaque artifact handle\";\n\tif (!safeVersionToken(request.expectedVersion)) return \"expectedVersion is invalid\";\n\tif (request.createIfMissing !== undefined && typeof request.createIfMissing !== \"boolean\")\n\t\treturn \"createIfMissing is invalid\";\n\treturn undefined;\n}\n\nfunction boundedError(value: unknown): WorkspaceFilesWriteResultV1[\"error\"] | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\ttypeof value.code !== \"string\" ||\n\t\t!/^[a-z][a-z0-9_]{0,127}$/u.test(value.code) ||\n\t\ttypeof value.message !== \"string\" ||\n\t\tvalue.message.trim() === \"\" ||\n\t\tvalue.message.length > 512\n\t)\n\t\treturn undefined;\n\treturn { version: 1, code: value.code, message: value.message.slice(0, 512) };\n}\n\nfunction nonNegativeBytes(value: unknown): value is number {\n\treturn (\n\t\tNumber.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= WORKSPACE_FILES_WRITE_MAX_BYTES_V1\n\t);\n}\n\n/** Projects host output down to status and bounded metadata; it never returns content. */\nexport function projectWorkspaceFilesWriteV1(\n\tvalue: unknown,\n\trequest: WorkspaceFilesWriteRequestV1,\n): WorkspaceFilesWriteResultV1 | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\tvalue.operationId !== request.operationId ||\n\t\tvalue.fileRef !== request.fileRef ||\n\t\tvalue.mode !== request.mode ||\n\t\ttypeof value.status !== \"string\" ||\n\t\t![\"succeeded\", \"failed\", \"cancelled\", \"needs_user\", \"unsupported\"].includes(value.status) ||\n\t\ttypeof value.changed !== \"boolean\" ||\n\t\t!nonNegativeBytes(value.bytesWritten) ||\n\t\t(!safeRef(value.outputArtifactRef) && value.outputArtifactRef !== undefined) ||\n\t\t!safeVersionToken(value.versionToken) ||\n\t\t(value.committed !== undefined && typeof value.committed !== \"boolean\")\n\t)\n\t\treturn undefined;\n\tconst result: WorkspaceFilesWriteResultV1 = {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus: value.status as WorkspaceFilesWriteResultV1[\"status\"],\n\t\tfileRef: request.fileRef,\n\t\tmode: request.mode,\n\t\tchanged: value.changed,\n\t\tbytesWritten: value.bytesWritten,\n\t\t...(value.committed === true ? { committed: true } : {}),\n\t\t...(value.outputArtifactRef === undefined ? {} : { outputArtifactRef: value.outputArtifactRef }),\n\t\t...(value.versionToken === undefined ? {} : { versionToken: value.versionToken }),\n\t\t...(value.error === undefined ? {} : { error: boundedError(value.error) }),\n\t};\n\tif (result.status !== \"succeeded\" && result.error === undefined) return undefined;\n\tif (result.status === \"succeeded\" && result.error !== undefined) return undefined;\n\tif (\n\t\tprojectPluginContextV1(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\titems: [result] as unknown as JsonValue[],\n\t\t\t\ttruncated: false,\n\t\t\t},\n\t\t\t{ maxOutputBytes: WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1, maxInlineItems: 1, maxCellChars: 512 },\n\t\t).status !== \"succeeded\"\n\t)\n\t\treturn undefined;\n\treturn result;\n}\n\nfunction timeoutMs(value: number | undefined): number {\n\tif (value === undefined) return 30_000;\n\tif (!Number.isSafeInteger(value) || value < 1 || value > 120_000) throw new Error(\"defaultTimeoutMs is invalid\");\n\treturn value;\n}\n\nasync function runHost(\n\tcallback: ((signal: AbortSignal) => Promise<unknown>) | undefined,\n\ttimeout: number,\n\trequest: WorkspaceFilesWriteRequestV1,\n\tsignal: AbortSignal | undefined,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tif (callback === undefined)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"unsupported\",\n\t\t\t\"workspace_files_write_unavailable\",\n\t\t\t\"No workspace file writer is bound\",\n\t\t);\n\tif (signal?.aborted)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"cancelled\",\n\t\t\t\"cancelled\",\n\t\t\t\"Workspace write was cancelled\",\n\t\t);\n\tconst controller = new AbortController();\n\tlet stop: \"timeout\" | \"cancelled\" | undefined;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet removeAbort: (() => void) | undefined;\n\tconst stopPromise = new Promise<void>((resolve) => {\n\t\tconst cancel = () => {\n\t\t\tstop ??= \"cancelled\";\n\t\t\tcontroller.abort();\n\t\t\tresolve();\n\t\t};\n\t\tif (signal !== undefined) {\n\t\t\tsignal.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tremoveAbort = () => signal.removeEventListener(\"abort\", cancel);\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tif (stop === undefined) {\n\t\t\t\tstop = \"timeout\";\n\t\t\t\tcontroller.abort();\n\t\t\t\tresolve();\n\t\t\t}\n\t\t}, timeout);\n\t});\n\tconst callbackPromise = callback(controller.signal).then(\n\t\t(value) => ({ kind: \"value\" as const, value }),\n\t\t() => ({ kind: \"failed\" as const }),\n\t);\n\ttry {\n\t\tconst outcome = await Promise.race([callbackPromise, stopPromise.then(() => ({ kind: \"stopped\" as const }))]);\n\t\tif (outcome.kind !== \"value\" || stop !== undefined) {\n\t\t\tconst failure = outcome.kind === \"failed\" && stop === undefined;\n\t\t\treturn error(\n\t\t\t\trequest.operationId,\n\t\t\t\trequest.fileRef,\n\t\t\t\trequest.mode,\n\t\t\t\tstop === \"cancelled\" ? \"cancelled\" : \"failed\",\n\t\t\t\tfailure ? \"adapter_failed\" : stop === \"cancelled\" ? \"cancelled\" : \"timeout\",\n\t\t\t\tfailure\n\t\t\t\t\t? \"Workspace writer failed\"\n\t\t\t\t\t: stop === \"cancelled\"\n\t\t\t\t\t\t? \"Workspace write was cancelled\"\n\t\t\t\t\t\t: \"Workspace write timed out\",\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tprojectWorkspaceFilesWriteV1(outcome.value, request) ??\n\t\t\terror(\n\t\t\t\trequest.operationId,\n\t\t\t\trequest.fileRef,\n\t\t\t\trequest.mode,\n\t\t\t\t\"failed\",\n\t\t\t\t\"adapter_failed\",\n\t\t\t\t\"Workspace writer returned an invalid result\",\n\t\t\t)\n\t\t);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tremoveAbort?.();\n\t}\n}\n\nexport function createNodeWorkspaceFilesWriteAdapterV1(\n\toptions: NodeWorkspaceFilesWriteAdapterOptionsV1 = {},\n): WorkspaceFilesWriteAdapterV1 {\n\tconst timeout = timeoutMs(options.defaultTimeoutMs);\n\treturn {\n\t\tadapterId: WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\t\twrite: async (request, signal) => {\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined)\n\t\t\t\treturn error(request.operationId, request.fileRef, request.mode, \"failed\", \"invalid_input\", invalid);\n\t\t\treturn runHost(\n\t\t\t\toptions.write === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (hostSignal) => options.write?.(request, hostSignal) ?? Promise.resolve(undefined),\n\t\t\t\ttimeout,\n\t\t\t\trequest,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport { safeRef, validateRequest };\n"]}
1
+ {"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,KAAK,uCAAuC,EAG5C,KAAK,4BAA4B,EAEjC,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,+CAA+C,MAAM,CAAC;AACnE,eAAO,MAAM,sCAAsC,MAAM,CAAC;AAC1D,eAAO,MAAM,0CAA0C,MAAM,CAAC;AAC9D,eAAO,MAAM,yCAAyC,QAAY,CAAC;AACnE,eAAO,MAAM,kCAAkC,QAAyB,CAAC;AAmBzE,iBAAS,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEhD;AAuCD,iBAAS,eAAe,CAAC,OAAO,EAAE,4BAA4B,GAAG,MAAM,GAAG,SAAS,CAUlF;AAsBD,0FAA0F;AAC1F,wBAAgB,4BAA4B,CAC3C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,4BAA4B,GACnC,2BAA2B,GAAG,SAAS,CAgDzC;AAsLD,wBAAgB,sCAAsC,CACrD,OAAO,GAAE,uCAA4C,GACnD,4BAA4B,CAmB9B;AAED,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport { projectPluginContextV1 } from \"@agent-forge/plugin-sdk\";\nimport {\n\ttype NodeWorkspaceFilesWriteAdapterOptionsV1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\ttype WorkspaceFilesWriteAdapterV1,\n\ttype WorkspaceFilesWriteModeV1,\n\ttype WorkspaceFilesWriteRequestV1,\n\ttype WorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nexport const WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const WORKSPACE_FILES_WRITE_MAX_BYTES_V1 = 4 * 1024 * 1024 * 1024;\n\n/**\n * After the stop race settles on a timeout or a cancellation, the host may\n * already have renamed new bytes onto the target (its last abort checkpoint\n * sits before the commit). The adapter waits this bounded window for the host\n * result so a finished commit is reported truthfully; past the bound it must\n * return promptly with an unknown commit state instead of hanging on a\n * stalled writer.\n */\nconst HOST_RESULT_SETTLE_BOUND_MS_V1 = 100;\n\nconst OPAQUE_REF_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\nconst VERSION_TOKEN_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction safeRef(value: unknown): value is string {\n\treturn typeof value === \"string\" && OPAQUE_REF_V1.test(value);\n}\n\nfunction safeVersionToken(value: unknown): value is string | undefined {\n\treturn value === undefined || (typeof value === \"string\" && VERSION_TOKEN_V1.test(value));\n}\n\nfunction validOperationId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.trim() !== \"\" &&\n\t\tvalue.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value)\n\t);\n}\n\nfunction validMode(value: unknown): value is WorkspaceFilesWriteModeV1 {\n\treturn value === \"replace\" || value === \"patch\";\n}\n\nfunction error(\n\toperationId: string,\n\tfileRef: string,\n\tmode: WorkspaceFilesWriteModeV1,\n\tstatus: WorkspaceFilesWriteResultV1[\"status\"],\n\tcode: string,\n\tmessage: string,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef,\n\t\tmode,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: { version: 1, code, message },\n\t};\n}\n\nfunction validateRequest(request: WorkspaceFilesWriteRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (!validOperationId(request.operationId)) return \"operationId is invalid\";\n\tif (!safeRef(request.fileRef)) return \"fileRef must be an opaque host handle\";\n\tif (!validMode(request.mode)) return \"mode must be replace or patch\";\n\tif (!safeRef(request.sourceArtifactRef)) return \"sourceArtifactRef must be an opaque artifact handle\";\n\tif (!safeVersionToken(request.expectedVersion)) return \"expectedVersion is invalid\";\n\tif (request.createIfMissing !== undefined && typeof request.createIfMissing !== \"boolean\")\n\t\treturn \"createIfMissing is invalid\";\n\treturn undefined;\n}\n\nfunction boundedError(value: unknown): WorkspaceFilesWriteResultV1[\"error\"] | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\ttypeof value.code !== \"string\" ||\n\t\t!/^[a-z][a-z0-9_]{0,127}$/u.test(value.code) ||\n\t\ttypeof value.message !== \"string\" ||\n\t\tvalue.message.trim() === \"\" ||\n\t\tvalue.message.length > 512\n\t)\n\t\treturn undefined;\n\treturn { version: 1, code: value.code, message: value.message.slice(0, 512) };\n}\n\nfunction nonNegativeBytes(value: unknown): value is number {\n\treturn (\n\t\tNumber.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= WORKSPACE_FILES_WRITE_MAX_BYTES_V1\n\t);\n}\n\n/** Projects host output down to status and bounded metadata; it never returns content. */\nexport function projectWorkspaceFilesWriteV1(\n\tvalue: unknown,\n\trequest: WorkspaceFilesWriteRequestV1,\n): WorkspaceFilesWriteResultV1 | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\tvalue.operationId !== request.operationId ||\n\t\tvalue.fileRef !== request.fileRef ||\n\t\tvalue.mode !== request.mode ||\n\t\ttypeof value.status !== \"string\" ||\n\t\t![\"succeeded\", \"failed\", \"cancelled\", \"needs_user\", \"unsupported\"].includes(value.status) ||\n\t\t(value.changed !== \"unknown\" && typeof value.changed !== \"boolean\") ||\n\t\t!nonNegativeBytes(value.bytesWritten) ||\n\t\t(!safeRef(value.outputArtifactRef) && value.outputArtifactRef !== undefined) ||\n\t\t!safeVersionToken(value.versionToken) ||\n\t\t(value.committed !== undefined &&\n\t\t\tvalue.committed !== true &&\n\t\t\tvalue.committed !== false &&\n\t\t\tvalue.committed !== \"unknown\") ||\n\t\t((value.changed === \"unknown\" || value.committed === \"unknown\") && value.status === \"succeeded\")\n\t)\n\t\treturn undefined;\n\tconst result: WorkspaceFilesWriteResultV1 = {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus: value.status as WorkspaceFilesWriteResultV1[\"status\"],\n\t\tfileRef: request.fileRef,\n\t\tmode: request.mode,\n\t\tchanged: value.changed,\n\t\tbytesWritten: value.bytesWritten,\n\t\t...(value.committed === true || value.committed === \"unknown\" ? { committed: value.committed } : {}),\n\t\t...(value.outputArtifactRef === undefined ? {} : { outputArtifactRef: value.outputArtifactRef }),\n\t\t...(value.versionToken === undefined ? {} : { versionToken: value.versionToken }),\n\t\t...(value.error === undefined ? {} : { error: boundedError(value.error) }),\n\t};\n\tif (result.status !== \"succeeded\" && result.error === undefined) return undefined;\n\tif (result.status === \"succeeded\" && result.error !== undefined) return undefined;\n\tif (\n\t\tprojectPluginContextV1(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\titems: [result] as unknown as JsonValue[],\n\t\t\t\ttruncated: false,\n\t\t\t},\n\t\t\t{ maxOutputBytes: WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1, maxInlineItems: 1, maxCellChars: 512 },\n\t\t).status !== \"succeeded\"\n\t)\n\t\treturn undefined;\n\treturn result;\n}\n\nfunction timeoutMs(value: number | undefined): number {\n\tif (value === undefined) return 30_000;\n\tif (!Number.isSafeInteger(value) || value < 1 || value > 120_000) throw new Error(\"defaultTimeoutMs is invalid\");\n\treturn value;\n}\n\n/**\n * Bounded wait for the host result after the stop race settled on a timeout or\n * a cancellation. Resolves with the host outcome when it lands inside the\n * bound, otherwise with \"settle-bound\" so the caller can report an unknown\n * commit state promptly.\n */\nasync function settleHostResult(\n\tcallbackPromise: Promise<{ kind: \"value\"; value: unknown } | { kind: \"failed\" }>,\n): Promise<{ kind: \"value\"; value: unknown } | { kind: \"failed\" } | { kind: \"settle-bound\" }> {\n\tlet settleTimer: ReturnType<typeof setTimeout> | undefined;\n\tconst bound = new Promise<{ kind: \"settle-bound\" }>((resolve) => {\n\t\tsettleTimer = setTimeout(() => resolve({ kind: \"settle-bound\" }), HOST_RESULT_SETTLE_BOUND_MS_V1);\n\t});\n\ttry {\n\t\treturn await Promise.race([callbackPromise, bound]);\n\t} finally {\n\t\tif (settleTimer !== undefined) clearTimeout(settleTimer);\n\t}\n}\n\nasync function runHost(\n\tcallback: ((signal: AbortSignal) => Promise<unknown>) | undefined,\n\ttimeout: number,\n\trequest: WorkspaceFilesWriteRequestV1,\n\tsignal: AbortSignal | undefined,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tif (callback === undefined)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"unsupported\",\n\t\t\t\"workspace_files_write_unavailable\",\n\t\t\t\"No workspace file writer is bound\",\n\t\t);\n\tif (signal?.aborted)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"cancelled\",\n\t\t\t\"cancelled\",\n\t\t\t\"Workspace write was cancelled\",\n\t\t);\n\tconst controller = new AbortController();\n\tlet stop: \"timeout\" | \"cancelled\" | undefined;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet removeAbort: (() => void) | undefined;\n\tconst stopPromise = new Promise<void>((resolve) => {\n\t\tconst cancel = () => {\n\t\t\tstop ??= \"cancelled\";\n\t\t\tcontroller.abort();\n\t\t\tresolve();\n\t\t};\n\t\tif (signal !== undefined) {\n\t\t\tsignal.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tremoveAbort = () => signal.removeEventListener(\"abort\", cancel);\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tif (stop === undefined) {\n\t\t\t\tstop = \"timeout\";\n\t\t\t\tcontroller.abort();\n\t\t\t\tresolve();\n\t\t\t}\n\t\t}, timeout);\n\t});\n\tconst callbackPromise = callback(controller.signal).then(\n\t\t(value) => ({ kind: \"value\" as const, value }),\n\t\t() => ({ kind: \"failed\" as const }),\n\t);\n\ttry {\n\t\tconst outcome = await Promise.race([callbackPromise, stopPromise.then(() => ({ kind: \"stopped\" as const }))]);\n\t\tif (outcome.kind === \"value\" && stop === undefined) {\n\t\t\treturn (\n\t\t\t\tprojectWorkspaceFilesWriteV1(outcome.value, request) ??\n\t\t\t\terror(\n\t\t\t\t\trequest.operationId,\n\t\t\t\t\trequest.fileRef,\n\t\t\t\t\trequest.mode,\n\t\t\t\t\t\"failed\",\n\t\t\t\t\t\"adapter_failed\",\n\t\t\t\t\t\"Workspace writer returned an invalid result\",\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\tif (stop === \"timeout\") {\n\t\t\tconst settled = await settleHostResult(callbackPromise);\n\t\t\tif (settled.kind !== \"settle-bound\") {\n\t\t\t\tconst projected =\n\t\t\t\t\tsettled.kind === \"value\" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;\n\t\t\t\t// A host result proving the write committed outranks the timeout verdict.\n\t\t\t\tif (projected !== undefined && (projected.status === \"succeeded\" || projected.committed === true))\n\t\t\t\t\treturn projected;\n\t\t\t\tif (projected !== undefined && projected.changed === false)\n\t\t\t\t\t// The host settled and reported no change, so \"nothing changed\" is verified truth.\n\t\t\t\t\treturn error(\n\t\t\t\t\t\trequest.operationId,\n\t\t\t\t\t\trequest.fileRef,\n\t\t\t\t\t\trequest.mode,\n\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\"timeout\",\n\t\t\t\t\t\t\"Workspace write timed out\",\n\t\t\t\t\t);\n\t\t\t}\n\t\t\t// No usable host result within the bound: the commit state stays unverified.\n\t\t\treturn {\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tfileRef: request.fileRef,\n\t\t\t\tmode: request.mode,\n\t\t\t\tchanged: \"unknown\",\n\t\t\t\tbytesWritten: 0,\n\t\t\t\tcommitted: \"unknown\",\n\t\t\t\terror: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: \"timeout\",\n\t\t\t\t\tmessage: \"Workspace write timed out before the host reported whether the file was committed\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (stop === \"cancelled\") {\n\t\t\t// The abort landed at or past the host's last cooperative checkpoint,\n\t\t\t// so the host may still rename new bytes onto the target afterwards.\n\t\t\t// The adapter waits the same bounded window as the timeout path so a\n\t\t\t// finished commit is reported truthfully instead of masked by the\n\t\t\t// cancel verdict.\n\t\t\tconst settled = await settleHostResult(callbackPromise);\n\t\t\tconst projected = settled.kind === \"value\" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;\n\t\t\t// A host result proving the write committed outranks the cancel verdict.\n\t\t\tif (projected !== undefined && (projected.status === \"succeeded\" || projected.committed === true))\n\t\t\t\treturn projected;\n\t\t\tif (projected !== undefined && projected.changed === false)\n\t\t\t\t// The host settled and reported no change, so \"nothing changed\" is verified truth.\n\t\t\t\treturn error(\n\t\t\t\t\trequest.operationId,\n\t\t\t\t\trequest.fileRef,\n\t\t\t\t\trequest.mode,\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t\"Workspace write was cancelled\",\n\t\t\t\t);\n\t\t\t// No verifiable host result within the bound: the commit state stays unverified.\n\t\t\treturn {\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\tstatus: \"cancelled\",\n\t\t\t\tfileRef: request.fileRef,\n\t\t\t\tmode: request.mode,\n\t\t\t\tchanged: \"unknown\",\n\t\t\t\tbytesWritten: 0,\n\t\t\t\tcommitted: \"unknown\",\n\t\t\t\terror: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: \"cancelled\",\n\t\t\t\t\tmessage: \"Workspace write was cancelled before the host reported whether the file was committed\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// The only remaining case: the host rejected on its own before any stop.\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"failed\",\n\t\t\t\"adapter_failed\",\n\t\t\t\"Workspace writer failed\",\n\t\t);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tremoveAbort?.();\n\t}\n}\n\nexport function createNodeWorkspaceFilesWriteAdapterV1(\n\toptions: NodeWorkspaceFilesWriteAdapterOptionsV1 = {},\n): WorkspaceFilesWriteAdapterV1 {\n\tconst timeout = timeoutMs(options.defaultTimeoutMs);\n\treturn {\n\t\tadapterId: WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\t\twrite: async (request, signal) => {\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined)\n\t\t\t\treturn error(request.operationId, request.fileRef, request.mode, \"failed\", \"invalid_input\", invalid);\n\t\t\treturn runHost(\n\t\t\t\toptions.write === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (hostSignal) => options.write?.(request, hostSignal) ?? Promise.resolve(undefined),\n\t\t\t\ttimeout,\n\t\t\t\trequest,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport { safeRef, validateRequest };\n"]}
@@ -5,6 +5,15 @@ export const WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1 = 256;
5
5
  export const WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1 = 256;
6
6
  export const WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1 = 64 * 1024;
7
7
  export const WORKSPACE_FILES_WRITE_MAX_BYTES_V1 = 4 * 1024 * 1024 * 1024;
8
+ /**
9
+ * After the stop race settles on a timeout or a cancellation, the host may
10
+ * already have renamed new bytes onto the target (its last abort checkpoint
11
+ * sits before the commit). The adapter waits this bounded window for the host
12
+ * result so a finished commit is reported truthfully; past the bound it must
13
+ * return promptly with an unknown commit state instead of hanging on a
14
+ * stalled writer.
15
+ */
16
+ const HOST_RESULT_SETTLE_BOUND_MS_V1 = 100;
8
17
  const OPAQUE_REF_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
9
18
  const VERSION_TOKEN_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
10
19
  function isRecord(value) {
@@ -79,11 +88,15 @@ export function projectWorkspaceFilesWriteV1(value, request) {
79
88
  value.mode !== request.mode ||
80
89
  typeof value.status !== "string" ||
81
90
  !["succeeded", "failed", "cancelled", "needs_user", "unsupported"].includes(value.status) ||
82
- typeof value.changed !== "boolean" ||
91
+ (value.changed !== "unknown" && typeof value.changed !== "boolean") ||
83
92
  !nonNegativeBytes(value.bytesWritten) ||
84
93
  (!safeRef(value.outputArtifactRef) && value.outputArtifactRef !== undefined) ||
85
94
  !safeVersionToken(value.versionToken) ||
86
- (value.committed !== undefined && typeof value.committed !== "boolean"))
95
+ (value.committed !== undefined &&
96
+ value.committed !== true &&
97
+ value.committed !== false &&
98
+ value.committed !== "unknown") ||
99
+ ((value.changed === "unknown" || value.committed === "unknown") && value.status === "succeeded"))
87
100
  return undefined;
88
101
  const result = {
89
102
  version: 1,
@@ -93,7 +106,7 @@ export function projectWorkspaceFilesWriteV1(value, request) {
93
106
  mode: request.mode,
94
107
  changed: value.changed,
95
108
  bytesWritten: value.bytesWritten,
96
- ...(value.committed === true ? { committed: true } : {}),
109
+ ...(value.committed === true || value.committed === "unknown" ? { committed: value.committed } : {}),
97
110
  ...(value.outputArtifactRef === undefined ? {} : { outputArtifactRef: value.outputArtifactRef }),
98
111
  ...(value.versionToken === undefined ? {} : { versionToken: value.versionToken }),
99
112
  ...(value.error === undefined ? {} : { error: boundedError(value.error) }),
@@ -118,6 +131,25 @@ function timeoutMs(value) {
118
131
  throw new Error("defaultTimeoutMs is invalid");
119
132
  return value;
120
133
  }
134
+ /**
135
+ * Bounded wait for the host result after the stop race settled on a timeout or
136
+ * a cancellation. Resolves with the host outcome when it lands inside the
137
+ * bound, otherwise with "settle-bound" so the caller can report an unknown
138
+ * commit state promptly.
139
+ */
140
+ async function settleHostResult(callbackPromise) {
141
+ let settleTimer;
142
+ const bound = new Promise((resolve) => {
143
+ settleTimer = setTimeout(() => resolve({ kind: "settle-bound" }), HOST_RESULT_SETTLE_BOUND_MS_V1);
144
+ });
145
+ try {
146
+ return await Promise.race([callbackPromise, bound]);
147
+ }
148
+ finally {
149
+ if (settleTimer !== undefined)
150
+ clearTimeout(settleTimer);
151
+ }
152
+ }
121
153
  async function runHost(callback, timeout, request, signal) {
122
154
  if (callback === undefined)
123
155
  return error(request.operationId, request.fileRef, request.mode, "unsupported", "workspace_files_write_unavailable", "No workspace file writer is bound");
@@ -148,16 +180,71 @@ async function runHost(callback, timeout, request, signal) {
148
180
  const callbackPromise = callback(controller.signal).then((value) => ({ kind: "value", value }), () => ({ kind: "failed" }));
149
181
  try {
150
182
  const outcome = await Promise.race([callbackPromise, stopPromise.then(() => ({ kind: "stopped" }))]);
151
- if (outcome.kind !== "value" || stop !== undefined) {
152
- const failure = outcome.kind === "failed" && stop === undefined;
153
- return error(request.operationId, request.fileRef, request.mode, stop === "cancelled" ? "cancelled" : "failed", failure ? "adapter_failed" : stop === "cancelled" ? "cancelled" : "timeout", failure
154
- ? "Workspace writer failed"
155
- : stop === "cancelled"
156
- ? "Workspace write was cancelled"
157
- : "Workspace write timed out");
183
+ if (outcome.kind === "value" && stop === undefined) {
184
+ return (projectWorkspaceFilesWriteV1(outcome.value, request) ??
185
+ error(request.operationId, request.fileRef, request.mode, "failed", "adapter_failed", "Workspace writer returned an invalid result"));
186
+ }
187
+ if (stop === "timeout") {
188
+ const settled = await settleHostResult(callbackPromise);
189
+ if (settled.kind !== "settle-bound") {
190
+ const projected = settled.kind === "value" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;
191
+ // A host result proving the write committed outranks the timeout verdict.
192
+ if (projected !== undefined && (projected.status === "succeeded" || projected.committed === true))
193
+ return projected;
194
+ if (projected !== undefined && projected.changed === false)
195
+ // The host settled and reported no change, so "nothing changed" is verified truth.
196
+ return error(request.operationId, request.fileRef, request.mode, "failed", "timeout", "Workspace write timed out");
197
+ }
198
+ // No usable host result within the bound: the commit state stays unverified.
199
+ return {
200
+ version: 1,
201
+ operationId: request.operationId,
202
+ status: "failed",
203
+ fileRef: request.fileRef,
204
+ mode: request.mode,
205
+ changed: "unknown",
206
+ bytesWritten: 0,
207
+ committed: "unknown",
208
+ error: {
209
+ version: 1,
210
+ code: "timeout",
211
+ message: "Workspace write timed out before the host reported whether the file was committed",
212
+ },
213
+ };
214
+ }
215
+ if (stop === "cancelled") {
216
+ // The abort landed at or past the host's last cooperative checkpoint,
217
+ // so the host may still rename new bytes onto the target afterwards.
218
+ // The adapter waits the same bounded window as the timeout path so a
219
+ // finished commit is reported truthfully instead of masked by the
220
+ // cancel verdict.
221
+ const settled = await settleHostResult(callbackPromise);
222
+ const projected = settled.kind === "value" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;
223
+ // A host result proving the write committed outranks the cancel verdict.
224
+ if (projected !== undefined && (projected.status === "succeeded" || projected.committed === true))
225
+ return projected;
226
+ if (projected !== undefined && projected.changed === false)
227
+ // The host settled and reported no change, so "nothing changed" is verified truth.
228
+ return error(request.operationId, request.fileRef, request.mode, "cancelled", "cancelled", "Workspace write was cancelled");
229
+ // No verifiable host result within the bound: the commit state stays unverified.
230
+ return {
231
+ version: 1,
232
+ operationId: request.operationId,
233
+ status: "cancelled",
234
+ fileRef: request.fileRef,
235
+ mode: request.mode,
236
+ changed: "unknown",
237
+ bytesWritten: 0,
238
+ committed: "unknown",
239
+ error: {
240
+ version: 1,
241
+ code: "cancelled",
242
+ message: "Workspace write was cancelled before the host reported whether the file was committed",
243
+ },
244
+ };
158
245
  }
159
- return (projectWorkspaceFilesWriteV1(outcome.value, request) ??
160
- error(request.operationId, request.fileRef, request.mode, "failed", "adapter_failed", "Workspace writer returned an invalid result"));
246
+ // The only remaining case: the host rejected on its own before any stop.
247
+ return error(request.operationId, request.fileRef, request.mode, "failed", "adapter_failed", "Workspace writer failed");
161
248
  }
162
249
  finally {
163
250
  if (timer !== undefined)
@@ -1 +1 @@
1
- {"version":3,"file":"node-adapter.js","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport { projectPluginContextV1 } from \"@agent-forge/plugin-sdk\";\nimport {\n\ttype NodeWorkspaceFilesWriteAdapterOptionsV1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\ttype WorkspaceFilesWriteAdapterV1,\n\ttype WorkspaceFilesWriteModeV1,\n\ttype WorkspaceFilesWriteRequestV1,\n\ttype WorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nexport const WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const WORKSPACE_FILES_WRITE_MAX_BYTES_V1 = 4 * 1024 * 1024 * 1024;\n\nconst OPAQUE_REF_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\nconst VERSION_TOKEN_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction safeRef(value: unknown): value is string {\n\treturn typeof value === \"string\" && OPAQUE_REF_V1.test(value);\n}\n\nfunction safeVersionToken(value: unknown): value is string | undefined {\n\treturn value === undefined || (typeof value === \"string\" && VERSION_TOKEN_V1.test(value));\n}\n\nfunction validOperationId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.trim() !== \"\" &&\n\t\tvalue.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value)\n\t);\n}\n\nfunction validMode(value: unknown): value is WorkspaceFilesWriteModeV1 {\n\treturn value === \"replace\" || value === \"patch\";\n}\n\nfunction error(\n\toperationId: string,\n\tfileRef: string,\n\tmode: WorkspaceFilesWriteModeV1,\n\tstatus: WorkspaceFilesWriteResultV1[\"status\"],\n\tcode: string,\n\tmessage: string,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef,\n\t\tmode,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: { version: 1, code, message },\n\t};\n}\n\nfunction validateRequest(request: WorkspaceFilesWriteRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (!validOperationId(request.operationId)) return \"operationId is invalid\";\n\tif (!safeRef(request.fileRef)) return \"fileRef must be an opaque host handle\";\n\tif (!validMode(request.mode)) return \"mode must be replace or patch\";\n\tif (!safeRef(request.sourceArtifactRef)) return \"sourceArtifactRef must be an opaque artifact handle\";\n\tif (!safeVersionToken(request.expectedVersion)) return \"expectedVersion is invalid\";\n\tif (request.createIfMissing !== undefined && typeof request.createIfMissing !== \"boolean\")\n\t\treturn \"createIfMissing is invalid\";\n\treturn undefined;\n}\n\nfunction boundedError(value: unknown): WorkspaceFilesWriteResultV1[\"error\"] | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\ttypeof value.code !== \"string\" ||\n\t\t!/^[a-z][a-z0-9_]{0,127}$/u.test(value.code) ||\n\t\ttypeof value.message !== \"string\" ||\n\t\tvalue.message.trim() === \"\" ||\n\t\tvalue.message.length > 512\n\t)\n\t\treturn undefined;\n\treturn { version: 1, code: value.code, message: value.message.slice(0, 512) };\n}\n\nfunction nonNegativeBytes(value: unknown): value is number {\n\treturn (\n\t\tNumber.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= WORKSPACE_FILES_WRITE_MAX_BYTES_V1\n\t);\n}\n\n/** Projects host output down to status and bounded metadata; it never returns content. */\nexport function projectWorkspaceFilesWriteV1(\n\tvalue: unknown,\n\trequest: WorkspaceFilesWriteRequestV1,\n): WorkspaceFilesWriteResultV1 | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\tvalue.operationId !== request.operationId ||\n\t\tvalue.fileRef !== request.fileRef ||\n\t\tvalue.mode !== request.mode ||\n\t\ttypeof value.status !== \"string\" ||\n\t\t![\"succeeded\", \"failed\", \"cancelled\", \"needs_user\", \"unsupported\"].includes(value.status) ||\n\t\ttypeof value.changed !== \"boolean\" ||\n\t\t!nonNegativeBytes(value.bytesWritten) ||\n\t\t(!safeRef(value.outputArtifactRef) && value.outputArtifactRef !== undefined) ||\n\t\t!safeVersionToken(value.versionToken) ||\n\t\t(value.committed !== undefined && typeof value.committed !== \"boolean\")\n\t)\n\t\treturn undefined;\n\tconst result: WorkspaceFilesWriteResultV1 = {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus: value.status as WorkspaceFilesWriteResultV1[\"status\"],\n\t\tfileRef: request.fileRef,\n\t\tmode: request.mode,\n\t\tchanged: value.changed,\n\t\tbytesWritten: value.bytesWritten,\n\t\t...(value.committed === true ? { committed: true } : {}),\n\t\t...(value.outputArtifactRef === undefined ? {} : { outputArtifactRef: value.outputArtifactRef }),\n\t\t...(value.versionToken === undefined ? {} : { versionToken: value.versionToken }),\n\t\t...(value.error === undefined ? {} : { error: boundedError(value.error) }),\n\t};\n\tif (result.status !== \"succeeded\" && result.error === undefined) return undefined;\n\tif (result.status === \"succeeded\" && result.error !== undefined) return undefined;\n\tif (\n\t\tprojectPluginContextV1(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\titems: [result] as unknown as JsonValue[],\n\t\t\t\ttruncated: false,\n\t\t\t},\n\t\t\t{ maxOutputBytes: WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1, maxInlineItems: 1, maxCellChars: 512 },\n\t\t).status !== \"succeeded\"\n\t)\n\t\treturn undefined;\n\treturn result;\n}\n\nfunction timeoutMs(value: number | undefined): number {\n\tif (value === undefined) return 30_000;\n\tif (!Number.isSafeInteger(value) || value < 1 || value > 120_000) throw new Error(\"defaultTimeoutMs is invalid\");\n\treturn value;\n}\n\nasync function runHost(\n\tcallback: ((signal: AbortSignal) => Promise<unknown>) | undefined,\n\ttimeout: number,\n\trequest: WorkspaceFilesWriteRequestV1,\n\tsignal: AbortSignal | undefined,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tif (callback === undefined)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"unsupported\",\n\t\t\t\"workspace_files_write_unavailable\",\n\t\t\t\"No workspace file writer is bound\",\n\t\t);\n\tif (signal?.aborted)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"cancelled\",\n\t\t\t\"cancelled\",\n\t\t\t\"Workspace write was cancelled\",\n\t\t);\n\tconst controller = new AbortController();\n\tlet stop: \"timeout\" | \"cancelled\" | undefined;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet removeAbort: (() => void) | undefined;\n\tconst stopPromise = new Promise<void>((resolve) => {\n\t\tconst cancel = () => {\n\t\t\tstop ??= \"cancelled\";\n\t\t\tcontroller.abort();\n\t\t\tresolve();\n\t\t};\n\t\tif (signal !== undefined) {\n\t\t\tsignal.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tremoveAbort = () => signal.removeEventListener(\"abort\", cancel);\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tif (stop === undefined) {\n\t\t\t\tstop = \"timeout\";\n\t\t\t\tcontroller.abort();\n\t\t\t\tresolve();\n\t\t\t}\n\t\t}, timeout);\n\t});\n\tconst callbackPromise = callback(controller.signal).then(\n\t\t(value) => ({ kind: \"value\" as const, value }),\n\t\t() => ({ kind: \"failed\" as const }),\n\t);\n\ttry {\n\t\tconst outcome = await Promise.race([callbackPromise, stopPromise.then(() => ({ kind: \"stopped\" as const }))]);\n\t\tif (outcome.kind !== \"value\" || stop !== undefined) {\n\t\t\tconst failure = outcome.kind === \"failed\" && stop === undefined;\n\t\t\treturn error(\n\t\t\t\trequest.operationId,\n\t\t\t\trequest.fileRef,\n\t\t\t\trequest.mode,\n\t\t\t\tstop === \"cancelled\" ? \"cancelled\" : \"failed\",\n\t\t\t\tfailure ? \"adapter_failed\" : stop === \"cancelled\" ? \"cancelled\" : \"timeout\",\n\t\t\t\tfailure\n\t\t\t\t\t? \"Workspace writer failed\"\n\t\t\t\t\t: stop === \"cancelled\"\n\t\t\t\t\t\t? \"Workspace write was cancelled\"\n\t\t\t\t\t\t: \"Workspace write timed out\",\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tprojectWorkspaceFilesWriteV1(outcome.value, request) ??\n\t\t\terror(\n\t\t\t\trequest.operationId,\n\t\t\t\trequest.fileRef,\n\t\t\t\trequest.mode,\n\t\t\t\t\"failed\",\n\t\t\t\t\"adapter_failed\",\n\t\t\t\t\"Workspace writer returned an invalid result\",\n\t\t\t)\n\t\t);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tremoveAbort?.();\n\t}\n}\n\nexport function createNodeWorkspaceFilesWriteAdapterV1(\n\toptions: NodeWorkspaceFilesWriteAdapterOptionsV1 = {},\n): WorkspaceFilesWriteAdapterV1 {\n\tconst timeout = timeoutMs(options.defaultTimeoutMs);\n\treturn {\n\t\tadapterId: WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\t\twrite: async (request, signal) => {\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined)\n\t\t\t\treturn error(request.operationId, request.fileRef, request.mode, \"failed\", \"invalid_input\", invalid);\n\t\t\treturn runHost(\n\t\t\t\toptions.write === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (hostSignal) => options.write?.(request, hostSignal) ?? Promise.resolve(undefined),\n\t\t\t\ttimeout,\n\t\t\t\trequest,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport { safeRef, validateRequest };\n"]}
1
+ {"version":3,"file":"node-adapter.js","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport { projectPluginContextV1 } from \"@agent-forge/plugin-sdk\";\nimport {\n\ttype NodeWorkspaceFilesWriteAdapterOptionsV1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\tWORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\ttype WorkspaceFilesWriteAdapterV1,\n\ttype WorkspaceFilesWriteModeV1,\n\ttype WorkspaceFilesWriteRequestV1,\n\ttype WorkspaceFilesWriteResultV1,\n} from \"./types.ts\";\n\nexport const WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_REF_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_VERSION_CHARS_V1 = 256;\nexport const WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1 = 64 * 1024;\nexport const WORKSPACE_FILES_WRITE_MAX_BYTES_V1 = 4 * 1024 * 1024 * 1024;\n\n/**\n * After the stop race settles on a timeout or a cancellation, the host may\n * already have renamed new bytes onto the target (its last abort checkpoint\n * sits before the commit). The adapter waits this bounded window for the host\n * result so a finished commit is reported truthfully; past the bound it must\n * return promptly with an unknown commit state instead of hanging on a\n * stalled writer.\n */\nconst HOST_RESULT_SETTLE_BOUND_MS_V1 = 100;\n\nconst OPAQUE_REF_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\nconst VERSION_TOKEN_V1 = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction safeRef(value: unknown): value is string {\n\treturn typeof value === \"string\" && OPAQUE_REF_V1.test(value);\n}\n\nfunction safeVersionToken(value: unknown): value is string | undefined {\n\treturn value === undefined || (typeof value === \"string\" && VERSION_TOKEN_V1.test(value));\n}\n\nfunction validOperationId(value: unknown): value is string {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\tvalue.trim() !== \"\" &&\n\t\tvalue.length <= WORKSPACE_FILES_WRITE_MAX_OPERATION_ID_CHARS_V1 &&\n\t\t!/[\\u0000-\\u001f\\u007f]/u.test(value)\n\t);\n}\n\nfunction validMode(value: unknown): value is WorkspaceFilesWriteModeV1 {\n\treturn value === \"replace\" || value === \"patch\";\n}\n\nfunction error(\n\toperationId: string,\n\tfileRef: string,\n\tmode: WorkspaceFilesWriteModeV1,\n\tstatus: WorkspaceFilesWriteResultV1[\"status\"],\n\tcode: string,\n\tmessage: string,\n): WorkspaceFilesWriteResultV1 {\n\treturn {\n\t\tversion: 1,\n\t\toperationId,\n\t\tstatus,\n\t\tfileRef,\n\t\tmode,\n\t\tchanged: false,\n\t\tbytesWritten: 0,\n\t\terror: { version: 1, code, message },\n\t};\n}\n\nfunction validateRequest(request: WorkspaceFilesWriteRequestV1): string | undefined {\n\tif (request.version !== 1) return \"version must be 1\";\n\tif (!validOperationId(request.operationId)) return \"operationId is invalid\";\n\tif (!safeRef(request.fileRef)) return \"fileRef must be an opaque host handle\";\n\tif (!validMode(request.mode)) return \"mode must be replace or patch\";\n\tif (!safeRef(request.sourceArtifactRef)) return \"sourceArtifactRef must be an opaque artifact handle\";\n\tif (!safeVersionToken(request.expectedVersion)) return \"expectedVersion is invalid\";\n\tif (request.createIfMissing !== undefined && typeof request.createIfMissing !== \"boolean\")\n\t\treturn \"createIfMissing is invalid\";\n\treturn undefined;\n}\n\nfunction boundedError(value: unknown): WorkspaceFilesWriteResultV1[\"error\"] | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\ttypeof value.code !== \"string\" ||\n\t\t!/^[a-z][a-z0-9_]{0,127}$/u.test(value.code) ||\n\t\ttypeof value.message !== \"string\" ||\n\t\tvalue.message.trim() === \"\" ||\n\t\tvalue.message.length > 512\n\t)\n\t\treturn undefined;\n\treturn { version: 1, code: value.code, message: value.message.slice(0, 512) };\n}\n\nfunction nonNegativeBytes(value: unknown): value is number {\n\treturn (\n\t\tNumber.isSafeInteger(value) && (value as number) >= 0 && (value as number) <= WORKSPACE_FILES_WRITE_MAX_BYTES_V1\n\t);\n}\n\n/** Projects host output down to status and bounded metadata; it never returns content. */\nexport function projectWorkspaceFilesWriteV1(\n\tvalue: unknown,\n\trequest: WorkspaceFilesWriteRequestV1,\n): WorkspaceFilesWriteResultV1 | undefined {\n\tif (!isRecord(value)) return undefined;\n\tif (\n\t\tvalue.version !== 1 ||\n\t\tvalue.operationId !== request.operationId ||\n\t\tvalue.fileRef !== request.fileRef ||\n\t\tvalue.mode !== request.mode ||\n\t\ttypeof value.status !== \"string\" ||\n\t\t![\"succeeded\", \"failed\", \"cancelled\", \"needs_user\", \"unsupported\"].includes(value.status) ||\n\t\t(value.changed !== \"unknown\" && typeof value.changed !== \"boolean\") ||\n\t\t!nonNegativeBytes(value.bytesWritten) ||\n\t\t(!safeRef(value.outputArtifactRef) && value.outputArtifactRef !== undefined) ||\n\t\t!safeVersionToken(value.versionToken) ||\n\t\t(value.committed !== undefined &&\n\t\t\tvalue.committed !== true &&\n\t\t\tvalue.committed !== false &&\n\t\t\tvalue.committed !== \"unknown\") ||\n\t\t((value.changed === \"unknown\" || value.committed === \"unknown\") && value.status === \"succeeded\")\n\t)\n\t\treturn undefined;\n\tconst result: WorkspaceFilesWriteResultV1 = {\n\t\tversion: 1,\n\t\toperationId: request.operationId,\n\t\tstatus: value.status as WorkspaceFilesWriteResultV1[\"status\"],\n\t\tfileRef: request.fileRef,\n\t\tmode: request.mode,\n\t\tchanged: value.changed,\n\t\tbytesWritten: value.bytesWritten,\n\t\t...(value.committed === true || value.committed === \"unknown\" ? { committed: value.committed } : {}),\n\t\t...(value.outputArtifactRef === undefined ? {} : { outputArtifactRef: value.outputArtifactRef }),\n\t\t...(value.versionToken === undefined ? {} : { versionToken: value.versionToken }),\n\t\t...(value.error === undefined ? {} : { error: boundedError(value.error) }),\n\t};\n\tif (result.status !== \"succeeded\" && result.error === undefined) return undefined;\n\tif (result.status === \"succeeded\" && result.error !== undefined) return undefined;\n\tif (\n\t\tprojectPluginContextV1(\n\t\t\t{\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\titems: [result] as unknown as JsonValue[],\n\t\t\t\ttruncated: false,\n\t\t\t},\n\t\t\t{ maxOutputBytes: WORKSPACE_FILES_WRITE_MAX_OUTPUT_BYTES_V1, maxInlineItems: 1, maxCellChars: 512 },\n\t\t).status !== \"succeeded\"\n\t)\n\t\treturn undefined;\n\treturn result;\n}\n\nfunction timeoutMs(value: number | undefined): number {\n\tif (value === undefined) return 30_000;\n\tif (!Number.isSafeInteger(value) || value < 1 || value > 120_000) throw new Error(\"defaultTimeoutMs is invalid\");\n\treturn value;\n}\n\n/**\n * Bounded wait for the host result after the stop race settled on a timeout or\n * a cancellation. Resolves with the host outcome when it lands inside the\n * bound, otherwise with \"settle-bound\" so the caller can report an unknown\n * commit state promptly.\n */\nasync function settleHostResult(\n\tcallbackPromise: Promise<{ kind: \"value\"; value: unknown } | { kind: \"failed\" }>,\n): Promise<{ kind: \"value\"; value: unknown } | { kind: \"failed\" } | { kind: \"settle-bound\" }> {\n\tlet settleTimer: ReturnType<typeof setTimeout> | undefined;\n\tconst bound = new Promise<{ kind: \"settle-bound\" }>((resolve) => {\n\t\tsettleTimer = setTimeout(() => resolve({ kind: \"settle-bound\" }), HOST_RESULT_SETTLE_BOUND_MS_V1);\n\t});\n\ttry {\n\t\treturn await Promise.race([callbackPromise, bound]);\n\t} finally {\n\t\tif (settleTimer !== undefined) clearTimeout(settleTimer);\n\t}\n}\n\nasync function runHost(\n\tcallback: ((signal: AbortSignal) => Promise<unknown>) | undefined,\n\ttimeout: number,\n\trequest: WorkspaceFilesWriteRequestV1,\n\tsignal: AbortSignal | undefined,\n): Promise<WorkspaceFilesWriteResultV1> {\n\tif (callback === undefined)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"unsupported\",\n\t\t\t\"workspace_files_write_unavailable\",\n\t\t\t\"No workspace file writer is bound\",\n\t\t);\n\tif (signal?.aborted)\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"cancelled\",\n\t\t\t\"cancelled\",\n\t\t\t\"Workspace write was cancelled\",\n\t\t);\n\tconst controller = new AbortController();\n\tlet stop: \"timeout\" | \"cancelled\" | undefined;\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet removeAbort: (() => void) | undefined;\n\tconst stopPromise = new Promise<void>((resolve) => {\n\t\tconst cancel = () => {\n\t\t\tstop ??= \"cancelled\";\n\t\t\tcontroller.abort();\n\t\t\tresolve();\n\t\t};\n\t\tif (signal !== undefined) {\n\t\t\tsignal.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tremoveAbort = () => signal.removeEventListener(\"abort\", cancel);\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tif (stop === undefined) {\n\t\t\t\tstop = \"timeout\";\n\t\t\t\tcontroller.abort();\n\t\t\t\tresolve();\n\t\t\t}\n\t\t}, timeout);\n\t});\n\tconst callbackPromise = callback(controller.signal).then(\n\t\t(value) => ({ kind: \"value\" as const, value }),\n\t\t() => ({ kind: \"failed\" as const }),\n\t);\n\ttry {\n\t\tconst outcome = await Promise.race([callbackPromise, stopPromise.then(() => ({ kind: \"stopped\" as const }))]);\n\t\tif (outcome.kind === \"value\" && stop === undefined) {\n\t\t\treturn (\n\t\t\t\tprojectWorkspaceFilesWriteV1(outcome.value, request) ??\n\t\t\t\terror(\n\t\t\t\t\trequest.operationId,\n\t\t\t\t\trequest.fileRef,\n\t\t\t\t\trequest.mode,\n\t\t\t\t\t\"failed\",\n\t\t\t\t\t\"adapter_failed\",\n\t\t\t\t\t\"Workspace writer returned an invalid result\",\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\tif (stop === \"timeout\") {\n\t\t\tconst settled = await settleHostResult(callbackPromise);\n\t\t\tif (settled.kind !== \"settle-bound\") {\n\t\t\t\tconst projected =\n\t\t\t\t\tsettled.kind === \"value\" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;\n\t\t\t\t// A host result proving the write committed outranks the timeout verdict.\n\t\t\t\tif (projected !== undefined && (projected.status === \"succeeded\" || projected.committed === true))\n\t\t\t\t\treturn projected;\n\t\t\t\tif (projected !== undefined && projected.changed === false)\n\t\t\t\t\t// The host settled and reported no change, so \"nothing changed\" is verified truth.\n\t\t\t\t\treturn error(\n\t\t\t\t\t\trequest.operationId,\n\t\t\t\t\t\trequest.fileRef,\n\t\t\t\t\t\trequest.mode,\n\t\t\t\t\t\t\"failed\",\n\t\t\t\t\t\t\"timeout\",\n\t\t\t\t\t\t\"Workspace write timed out\",\n\t\t\t\t\t);\n\t\t\t}\n\t\t\t// No usable host result within the bound: the commit state stays unverified.\n\t\t\treturn {\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tfileRef: request.fileRef,\n\t\t\t\tmode: request.mode,\n\t\t\t\tchanged: \"unknown\",\n\t\t\t\tbytesWritten: 0,\n\t\t\t\tcommitted: \"unknown\",\n\t\t\t\terror: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: \"timeout\",\n\t\t\t\t\tmessage: \"Workspace write timed out before the host reported whether the file was committed\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (stop === \"cancelled\") {\n\t\t\t// The abort landed at or past the host's last cooperative checkpoint,\n\t\t\t// so the host may still rename new bytes onto the target afterwards.\n\t\t\t// The adapter waits the same bounded window as the timeout path so a\n\t\t\t// finished commit is reported truthfully instead of masked by the\n\t\t\t// cancel verdict.\n\t\t\tconst settled = await settleHostResult(callbackPromise);\n\t\t\tconst projected = settled.kind === \"value\" ? projectWorkspaceFilesWriteV1(settled.value, request) : undefined;\n\t\t\t// A host result proving the write committed outranks the cancel verdict.\n\t\t\tif (projected !== undefined && (projected.status === \"succeeded\" || projected.committed === true))\n\t\t\t\treturn projected;\n\t\t\tif (projected !== undefined && projected.changed === false)\n\t\t\t\t// The host settled and reported no change, so \"nothing changed\" is verified truth.\n\t\t\t\treturn error(\n\t\t\t\t\trequest.operationId,\n\t\t\t\t\trequest.fileRef,\n\t\t\t\t\trequest.mode,\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t\"cancelled\",\n\t\t\t\t\t\"Workspace write was cancelled\",\n\t\t\t\t);\n\t\t\t// No verifiable host result within the bound: the commit state stays unverified.\n\t\t\treturn {\n\t\t\t\tversion: 1,\n\t\t\t\toperationId: request.operationId,\n\t\t\t\tstatus: \"cancelled\",\n\t\t\t\tfileRef: request.fileRef,\n\t\t\t\tmode: request.mode,\n\t\t\t\tchanged: \"unknown\",\n\t\t\t\tbytesWritten: 0,\n\t\t\t\tcommitted: \"unknown\",\n\t\t\t\terror: {\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcode: \"cancelled\",\n\t\t\t\t\tmessage: \"Workspace write was cancelled before the host reported whether the file was committed\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// The only remaining case: the host rejected on its own before any stop.\n\t\treturn error(\n\t\t\trequest.operationId,\n\t\t\trequest.fileRef,\n\t\t\trequest.mode,\n\t\t\t\"failed\",\n\t\t\t\"adapter_failed\",\n\t\t\t\"Workspace writer failed\",\n\t\t);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tremoveAbort?.();\n\t}\n}\n\nexport function createNodeWorkspaceFilesWriteAdapterV1(\n\toptions: NodeWorkspaceFilesWriteAdapterOptionsV1 = {},\n): WorkspaceFilesWriteAdapterV1 {\n\tconst timeout = timeoutMs(options.defaultTimeoutMs);\n\treturn {\n\t\tadapterId: WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1,\n\t\tadapterVersion: WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1,\n\t\twrite: async (request, signal) => {\n\t\t\tconst invalid = validateRequest(request);\n\t\t\tif (invalid !== undefined)\n\t\t\t\treturn error(request.operationId, request.fileRef, request.mode, \"failed\", \"invalid_input\", invalid);\n\t\t\treturn runHost(\n\t\t\t\toptions.write === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (hostSignal) => options.write?.(request, hostSignal) ?? Promise.resolve(undefined),\n\t\t\t\ttimeout,\n\t\t\t\trequest,\n\t\t\t\tsignal,\n\t\t\t);\n\t\t},\n\t};\n}\n\nexport { safeRef, validateRequest };\n"]}
package/dist/types.d.ts CHANGED
@@ -24,14 +24,21 @@ export interface WorkspaceFilesWriteResultV1 {
24
24
  readonly status: PluginResultStatusV1;
25
25
  readonly fileRef: string;
26
26
  readonly mode: WorkspaceFilesWriteModeV1;
27
- readonly changed: boolean;
27
+ /**
28
+ * Whether the target content changed; "unknown" when the result cannot
29
+ * verify the disk state (timeout or cancellation before the host reported).
30
+ */
31
+ readonly changed: boolean | "unknown";
28
32
  readonly bytesWritten: number;
29
33
  /**
30
34
  * True only when the host already renamed the new bytes onto the target and a
31
35
  * later step (artifact record or cancellation) failed; it keeps a failed or
32
36
  * cancelled result distinguishable from a failure that never touched the disk.
37
+ * "unknown" marks the bounded settle path (timeout or cancellation) where the
38
+ * adapter stopped waiting before the host reported whether the rename landed;
39
+ * the disk state is then unverified and `changed` is "unknown" too.
33
40
  */
34
- readonly committed?: boolean;
41
+ readonly committed?: boolean | "unknown";
35
42
  readonly outputArtifactRef?: string;
36
43
  readonly versionToken?: string;
37
44
  readonly error?: PluginErrorV1;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEnF,eAAO,MAAM,kCAAkC,4CAAsD,CAAC;AACtG,eAAO,MAAM,2CAA2C,GAAa,CAAC;AACtE,eAAO,MAAM,wCAAwC,8BAAwC,CAAC;AAC9F,eAAO,MAAM,6CAA6C,SAAmB,CAAC;AAE9E,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5D;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,CACf,OAAO,EAAE,4BAA4B,EACrC,MAAM,CAAC,EAAE,WAAW,KAChB,OAAO,CAAC,2BAA2B,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,uCAAuC;IACvD,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,4BAA4B,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAClG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,SAAS,8BAA8B,EAAE,CAAC;CAC/D;AAED,qGAAqG;AACrG,MAAM,WAAW,oCAAoC;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAC5F,sFAAsF;IACtF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACxF,QAAQ,CAAC,YAAY,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACzF,QAAQ,CAAC,aAAa,CAAC,EAAE,CACxB,KAAK,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;KAAE,EAC7F,MAAM,EAAE,WAAW,KACf,OAAO,CAAC;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACnC","sourcesContent":["import type { PluginErrorV1, PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\nexport const WORKSPACE_FILES_WRITE_PLUGIN_ID_V1 = \"agent-forge.plugin.workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_CAPABILITY_VERSION_V1 = 1 as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1 = \"node-workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1 = \"1.0.0\" as const;\n\nexport type WorkspaceFilesWriteModeV1 = \"replace\" | \"patch\";\n\n/**\n * A write request carries only opaque references. The host resolves the source\n * artifact and file handle; bytes and local paths never cross the capability\n * boundary or enter the model context.\n */\nexport interface WorkspaceFilesWriteRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly sourceArtifactRef: string;\n\treadonly expectedVersion?: string;\n\treadonly createIfMissing?: boolean;\n}\n\nexport interface WorkspaceFilesWriteResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly changed: boolean;\n\treadonly bytesWritten: number;\n\t/**\n\t * True only when the host already renamed the new bytes onto the target and a\n\t * later step (artifact record or cancellation) failed; it keeps a failed or\n\t * cancelled result distinguishable from a failure that never touched the disk.\n\t */\n\treadonly committed?: boolean;\n\treadonly outputArtifactRef?: string;\n\treadonly versionToken?: string;\n\treadonly error?: PluginErrorV1;\n}\n\nexport interface WorkspaceFilesWriteAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly write: (\n\t\trequest: WorkspaceFilesWriteRequestV1,\n\t\tsignal?: AbortSignal,\n\t) => Promise<WorkspaceFilesWriteResultV1>;\n}\n\nexport interface NodeWorkspaceFilesWriteAdapterOptionsV1 {\n\t/** Host-owned resolver and writer; the model never supplies a local path. */\n\treadonly write?: (request: WorkspaceFilesWriteRequestV1, signal: AbortSignal) => Promise<unknown>;\n\treadonly defaultTimeoutMs?: number;\n}\n\nexport interface WorkspaceFilesPatchOperationV1 {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly replacement: string;\n}\n\nexport interface WorkspaceFilesPatchDocumentV1 {\n\treadonly version: 1;\n\treadonly operations: readonly WorkspaceFilesPatchOperationV1[];\n}\n\n/** Host-only resolver: it may return a local path, but that path never enters a model-facing DTO. */\nexport interface NodeWorkspaceFilesWriteHostOptionsV1 {\n\treadonly root: string;\n\treadonly resolveFileRef: (fileRef: string, signal: AbortSignal) => Promise<string> | string;\n\t/** Optional host file reader seam for virtual filesystems and deterministic tests. */\n\treadonly readWorkspaceFile?: (path: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly readArtifact: (artifactRef: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly writeArtifact?: (\n\t\tinput: { readonly operationId: string; readonly fileRef: string; readonly bytes: Uint8Array },\n\t\tsignal: AbortSignal,\n\t) => Promise<{ readonly artifactRef: string }>;\n\treadonly defaultTimeoutMs?: number;\n}\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PluginErrorV1, PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\nexport const WORKSPACE_FILES_WRITE_PLUGIN_ID_V1 = \"agent-forge.plugin.workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_CAPABILITY_VERSION_V1 = 1 as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1 = \"node-workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1 = \"1.0.0\" as const;\n\nexport type WorkspaceFilesWriteModeV1 = \"replace\" | \"patch\";\n\n/**\n * A write request carries only opaque references. The host resolves the source\n * artifact and file handle; bytes and local paths never cross the capability\n * boundary or enter the model context.\n */\nexport interface WorkspaceFilesWriteRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly sourceArtifactRef: string;\n\treadonly expectedVersion?: string;\n\treadonly createIfMissing?: boolean;\n}\n\nexport interface WorkspaceFilesWriteResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\t/**\n\t * Whether the target content changed; \"unknown\" when the result cannot\n\t * verify the disk state (timeout or cancellation before the host reported).\n\t */\n\treadonly changed: boolean | \"unknown\";\n\treadonly bytesWritten: number;\n\t/**\n\t * True only when the host already renamed the new bytes onto the target and a\n\t * later step (artifact record or cancellation) failed; it keeps a failed or\n\t * cancelled result distinguishable from a failure that never touched the disk.\n\t * \"unknown\" marks the bounded settle path (timeout or cancellation) where the\n\t * adapter stopped waiting before the host reported whether the rename landed;\n\t * the disk state is then unverified and `changed` is \"unknown\" too.\n\t */\n\treadonly committed?: boolean | \"unknown\";\n\treadonly outputArtifactRef?: string;\n\treadonly versionToken?: string;\n\treadonly error?: PluginErrorV1;\n}\n\nexport interface WorkspaceFilesWriteAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly write: (\n\t\trequest: WorkspaceFilesWriteRequestV1,\n\t\tsignal?: AbortSignal,\n\t) => Promise<WorkspaceFilesWriteResultV1>;\n}\n\nexport interface NodeWorkspaceFilesWriteAdapterOptionsV1 {\n\t/** Host-owned resolver and writer; the model never supplies a local path. */\n\treadonly write?: (request: WorkspaceFilesWriteRequestV1, signal: AbortSignal) => Promise<unknown>;\n\treadonly defaultTimeoutMs?: number;\n}\n\nexport interface WorkspaceFilesPatchOperationV1 {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly replacement: string;\n}\n\nexport interface WorkspaceFilesPatchDocumentV1 {\n\treadonly version: 1;\n\treadonly operations: readonly WorkspaceFilesPatchOperationV1[];\n}\n\n/** Host-only resolver: it may return a local path, but that path never enters a model-facing DTO. */\nexport interface NodeWorkspaceFilesWriteHostOptionsV1 {\n\treadonly root: string;\n\treadonly resolveFileRef: (fileRef: string, signal: AbortSignal) => Promise<string> | string;\n\t/** Optional host file reader seam for virtual filesystems and deterministic tests. */\n\treadonly readWorkspaceFile?: (path: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly readArtifact: (artifactRef: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly writeArtifact?: (\n\t\tinput: { readonly operationId: string; readonly fileRef: string; readonly bytes: Uint8Array },\n\t\tsignal: AbortSignal,\n\t) => Promise<{ readonly artifactRef: string }>;\n\treadonly defaultTimeoutMs?: number;\n}\n"]}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kCAAkC,GAAG,0CAAmD,CAAC;AACtG,MAAM,CAAC,MAAM,2CAA2C,GAAG,CAAU,CAAC;AACtE,MAAM,CAAC,MAAM,wCAAwC,GAAG,4BAAqC,CAAC;AAC9F,MAAM,CAAC,MAAM,6CAA6C,GAAG,OAAgB,CAAC","sourcesContent":["import type { PluginErrorV1, PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\nexport const WORKSPACE_FILES_WRITE_PLUGIN_ID_V1 = \"agent-forge.plugin.workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_CAPABILITY_VERSION_V1 = 1 as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1 = \"node-workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1 = \"1.0.0\" as const;\n\nexport type WorkspaceFilesWriteModeV1 = \"replace\" | \"patch\";\n\n/**\n * A write request carries only opaque references. The host resolves the source\n * artifact and file handle; bytes and local paths never cross the capability\n * boundary or enter the model context.\n */\nexport interface WorkspaceFilesWriteRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly sourceArtifactRef: string;\n\treadonly expectedVersion?: string;\n\treadonly createIfMissing?: boolean;\n}\n\nexport interface WorkspaceFilesWriteResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly changed: boolean;\n\treadonly bytesWritten: number;\n\t/**\n\t * True only when the host already renamed the new bytes onto the target and a\n\t * later step (artifact record or cancellation) failed; it keeps a failed or\n\t * cancelled result distinguishable from a failure that never touched the disk.\n\t */\n\treadonly committed?: boolean;\n\treadonly outputArtifactRef?: string;\n\treadonly versionToken?: string;\n\treadonly error?: PluginErrorV1;\n}\n\nexport interface WorkspaceFilesWriteAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly write: (\n\t\trequest: WorkspaceFilesWriteRequestV1,\n\t\tsignal?: AbortSignal,\n\t) => Promise<WorkspaceFilesWriteResultV1>;\n}\n\nexport interface NodeWorkspaceFilesWriteAdapterOptionsV1 {\n\t/** Host-owned resolver and writer; the model never supplies a local path. */\n\treadonly write?: (request: WorkspaceFilesWriteRequestV1, signal: AbortSignal) => Promise<unknown>;\n\treadonly defaultTimeoutMs?: number;\n}\n\nexport interface WorkspaceFilesPatchOperationV1 {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly replacement: string;\n}\n\nexport interface WorkspaceFilesPatchDocumentV1 {\n\treadonly version: 1;\n\treadonly operations: readonly WorkspaceFilesPatchOperationV1[];\n}\n\n/** Host-only resolver: it may return a local path, but that path never enters a model-facing DTO. */\nexport interface NodeWorkspaceFilesWriteHostOptionsV1 {\n\treadonly root: string;\n\treadonly resolveFileRef: (fileRef: string, signal: AbortSignal) => Promise<string> | string;\n\t/** Optional host file reader seam for virtual filesystems and deterministic tests. */\n\treadonly readWorkspaceFile?: (path: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly readArtifact: (artifactRef: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly writeArtifact?: (\n\t\tinput: { readonly operationId: string; readonly fileRef: string; readonly bytes: Uint8Array },\n\t\tsignal: AbortSignal,\n\t) => Promise<{ readonly artifactRef: string }>;\n\treadonly defaultTimeoutMs?: number;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kCAAkC,GAAG,0CAAmD,CAAC;AACtG,MAAM,CAAC,MAAM,2CAA2C,GAAG,CAAU,CAAC;AACtE,MAAM,CAAC,MAAM,wCAAwC,GAAG,4BAAqC,CAAC;AAC9F,MAAM,CAAC,MAAM,6CAA6C,GAAG,OAAgB,CAAC","sourcesContent":["import type { PluginErrorV1, PluginResultStatusV1 } from \"@agent-forge/plugin-sdk\";\n\nexport const WORKSPACE_FILES_WRITE_PLUGIN_ID_V1 = \"agent-forge.plugin.workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_CAPABILITY_VERSION_V1 = 1 as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_ID_V1 = \"node-workspace-files-write\" as const;\nexport const WORKSPACE_FILES_WRITE_HOST_ADAPTER_VERSION_V1 = \"1.0.0\" as const;\n\nexport type WorkspaceFilesWriteModeV1 = \"replace\" | \"patch\";\n\n/**\n * A write request carries only opaque references. The host resolves the source\n * artifact and file handle; bytes and local paths never cross the capability\n * boundary or enter the model context.\n */\nexport interface WorkspaceFilesWriteRequestV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\treadonly sourceArtifactRef: string;\n\treadonly expectedVersion?: string;\n\treadonly createIfMissing?: boolean;\n}\n\nexport interface WorkspaceFilesWriteResultV1 {\n\treadonly version: 1;\n\treadonly operationId: string;\n\treadonly status: PluginResultStatusV1;\n\treadonly fileRef: string;\n\treadonly mode: WorkspaceFilesWriteModeV1;\n\t/**\n\t * Whether the target content changed; \"unknown\" when the result cannot\n\t * verify the disk state (timeout or cancellation before the host reported).\n\t */\n\treadonly changed: boolean | \"unknown\";\n\treadonly bytesWritten: number;\n\t/**\n\t * True only when the host already renamed the new bytes onto the target and a\n\t * later step (artifact record or cancellation) failed; it keeps a failed or\n\t * cancelled result distinguishable from a failure that never touched the disk.\n\t * \"unknown\" marks the bounded settle path (timeout or cancellation) where the\n\t * adapter stopped waiting before the host reported whether the rename landed;\n\t * the disk state is then unverified and `changed` is \"unknown\" too.\n\t */\n\treadonly committed?: boolean | \"unknown\";\n\treadonly outputArtifactRef?: string;\n\treadonly versionToken?: string;\n\treadonly error?: PluginErrorV1;\n}\n\nexport interface WorkspaceFilesWriteAdapterV1 {\n\treadonly adapterId: string;\n\treadonly adapterVersion: string;\n\treadonly write: (\n\t\trequest: WorkspaceFilesWriteRequestV1,\n\t\tsignal?: AbortSignal,\n\t) => Promise<WorkspaceFilesWriteResultV1>;\n}\n\nexport interface NodeWorkspaceFilesWriteAdapterOptionsV1 {\n\t/** Host-owned resolver and writer; the model never supplies a local path. */\n\treadonly write?: (request: WorkspaceFilesWriteRequestV1, signal: AbortSignal) => Promise<unknown>;\n\treadonly defaultTimeoutMs?: number;\n}\n\nexport interface WorkspaceFilesPatchOperationV1 {\n\treadonly start: number;\n\treadonly end: number;\n\treadonly replacement: string;\n}\n\nexport interface WorkspaceFilesPatchDocumentV1 {\n\treadonly version: 1;\n\treadonly operations: readonly WorkspaceFilesPatchOperationV1[];\n}\n\n/** Host-only resolver: it may return a local path, but that path never enters a model-facing DTO. */\nexport interface NodeWorkspaceFilesWriteHostOptionsV1 {\n\treadonly root: string;\n\treadonly resolveFileRef: (fileRef: string, signal: AbortSignal) => Promise<string> | string;\n\t/** Optional host file reader seam for virtual filesystems and deterministic tests. */\n\treadonly readWorkspaceFile?: (path: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly readArtifact: (artifactRef: string, signal: AbortSignal) => Promise<Uint8Array>;\n\treadonly writeArtifact?: (\n\t\tinput: { readonly operationId: string; readonly fileRef: string; readonly bytes: Uint8Array },\n\t\tsignal: AbortSignal,\n\t) => Promise<{ readonly artifactRef: string }>;\n\treadonly defaultTimeoutMs?: number;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-agent-forge/plugin-workspace-files-write",
3
- "version": "0.88.4",
3
+ "version": "0.88.6",
4
4
  "description": "Workspace file write capability plugin for Agent Forge (full-control workspace_write tool with atomic replace/patch)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "typebox": "1.3.27",
48
- "@ai-agent-forge/plugin-sdk": "^0.88.4"
48
+ "@ai-agent-forge/plugin-sdk": "^0.88.6"
49
49
  },
50
50
  "devDependencies": {
51
51
  "shx": "0.4.0",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "agent-forge.plugin.workspace-files-write",
3
- "version": "0.88.4",
3
+ "version": "0.88.6",
4
4
  "apiVersion": "1-draft",
5
5
  "entry": "./dist/entry.js",
6
6
  "hostVersion": ">=0.84.4",