subharness 0.0.4 → 0.0.5
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/README.md +36 -6
- package/dist/adapters/claude-process.d.ts +3 -0
- package/dist/adapters/claude-process.js +11 -1
- package/dist/adapters/claude-process.js.map +1 -1
- package/dist/adapters/claude-result.d.ts +2 -0
- package/dist/adapters/claude-result.js +22 -0
- package/dist/adapters/claude-result.js.map +1 -0
- package/dist/adapters/claude.js +30 -11
- package/dist/adapters/claude.js.map +1 -1
- package/dist/adapters/codex.js +4 -1
- package/dist/adapters/codex.js.map +1 -1
- package/dist/adapters/copilot-permissions.d.ts +26 -0
- package/dist/adapters/copilot-permissions.js +121 -0
- package/dist/adapters/copilot-permissions.js.map +1 -0
- package/dist/adapters/copilot-tools.d.ts +12 -0
- package/dist/adapters/copilot-tools.js +61 -0
- package/dist/adapters/copilot-tools.js.map +1 -0
- package/dist/adapters/copilot.d.ts +108 -0
- package/dist/adapters/copilot.js +819 -0
- package/dist/adapters/copilot.js.map +1 -0
- package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
- package/dist/adapters/cursor-cli-approvals.js +83 -0
- package/dist/adapters/cursor-cli-approvals.js.map +1 -0
- package/dist/adapters/cursor-cli-model.d.ts +4 -0
- package/dist/adapters/cursor-cli-model.js +64 -0
- package/dist/adapters/cursor-cli-model.js.map +1 -0
- package/dist/adapters/cursor-cli-session.d.ts +32 -0
- package/dist/adapters/cursor-cli-session.js +316 -0
- package/dist/adapters/cursor-cli-session.js.map +1 -0
- package/dist/adapters/cursor-cli-tools.d.ts +20 -0
- package/dist/adapters/cursor-cli-tools.js +181 -0
- package/dist/adapters/cursor-cli-tools.js.map +1 -0
- package/dist/adapters/cursor-cli.d.ts +2 -0
- package/dist/adapters/cursor-cli.js +306 -0
- package/dist/adapters/cursor-cli.js.map +1 -0
- package/dist/adapters/cursor-model.d.ts +7 -0
- package/dist/adapters/cursor-model.js +67 -0
- package/dist/adapters/cursor-model.js.map +1 -0
- package/dist/adapters/cursor-rpc.d.ts +42 -0
- package/dist/adapters/cursor-rpc.js +271 -0
- package/dist/adapters/cursor-rpc.js.map +1 -0
- package/dist/adapters/cursor-session.d.ts +4 -0
- package/dist/adapters/cursor-session.js +327 -0
- package/dist/adapters/cursor-session.js.map +1 -0
- package/dist/adapters/cursor-startup.d.ts +16 -0
- package/dist/adapters/cursor-startup.js +74 -0
- package/dist/adapters/cursor-startup.js.map +1 -0
- package/dist/adapters/cursor-tools.d.ts +11 -0
- package/dist/adapters/cursor-tools.js +49 -0
- package/dist/adapters/cursor-tools.js.map +1 -0
- package/dist/adapters/cursor.d.ts +6 -0
- package/dist/adapters/cursor.js +17 -0
- package/dist/adapters/cursor.js.map +1 -0
- package/dist/adapters/fx-auth.d.ts +12 -2
- package/dist/adapters/fx-auth.js +51 -61
- package/dist/adapters/fx-auth.js.map +1 -1
- package/dist/adapters/fx-profile.d.ts +8 -0
- package/dist/adapters/fx-profile.js +101 -0
- package/dist/adapters/fx-profile.js.map +1 -0
- package/dist/adapters/fx-rpc.d.ts +2 -0
- package/dist/adapters/fx-rpc.js +30 -4
- package/dist/adapters/fx-rpc.js.map +1 -1
- package/dist/adapters/fx-status.d.ts +2 -0
- package/dist/adapters/fx-status.js +96 -0
- package/dist/adapters/fx-status.js.map +1 -0
- package/dist/adapters/fx.js +28 -12
- package/dist/adapters/fx.js.map +1 -1
- package/dist/adapters/opencode-access.d.ts +13 -0
- package/dist/adapters/opencode-access.js +76 -0
- package/dist/adapters/opencode-access.js.map +1 -0
- package/dist/adapters/opencode-config.d.ts +11 -0
- package/dist/adapters/opencode-config.js +238 -0
- package/dist/adapters/opencode-config.js.map +1 -0
- package/dist/adapters/opencode-http.d.ts +28 -0
- package/dist/adapters/opencode-http.js +297 -0
- package/dist/adapters/opencode-http.js.map +1 -0
- package/dist/adapters/opencode-tools.d.ts +19 -0
- package/dist/adapters/opencode-tools.js +127 -0
- package/dist/adapters/opencode-tools.js.map +1 -0
- package/dist/adapters/opencode.d.ts +2 -0
- package/dist/adapters/opencode.js +569 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/rpc.d.ts +3 -0
- package/dist/adapters/rpc.js +45 -4
- package/dist/adapters/rpc.js.map +1 -1
- package/dist/adapters/types.d.ts +5 -0
- package/dist/adapters/types.js.map +1 -1
- package/dist/approvals/types.d.ts +1 -1
- package/dist/approvals/types.js.map +1 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.js +4 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/dashboard-client.js +1 -1
- package/dist/cli/dashboard-client.js.map +1 -1
- package/dist/cli/dashboard-controller.d.ts +7 -0
- package/dist/cli/dashboard-controller.js +27 -0
- package/dist/cli/dashboard-controller.js.map +1 -0
- package/dist/cli/dashboard-detail-view.d.ts +1 -1
- package/dist/cli/dashboard-detail-view.js +3 -4
- package/dist/cli/dashboard-detail-view.js.map +1 -1
- package/dist/cli/dashboard-history-view.js.map +1 -1
- package/dist/cli/dashboard-input.d.ts +1 -1
- package/dist/cli/dashboard-input.js +11 -1
- package/dist/cli/dashboard-input.js.map +1 -1
- package/dist/cli/dashboard-layout.js +3 -3
- package/dist/cli/dashboard-layout.js.map +1 -1
- package/dist/cli/dashboard-renderer.js.map +1 -1
- package/dist/cli/dashboard-style.js +2 -2
- package/dist/cli/dashboard-style.js.map +1 -1
- package/dist/cli/dashboard.d.ts +2 -2
- package/dist/cli/dashboard.js +7 -32
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +30 -12
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +5 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/config/access-provenance.d.ts +10 -0
- package/dist/config/access-provenance.js +31 -0
- package/dist/config/access-provenance.js.map +1 -0
- package/dist/config/access.d.ts +12 -2
- package/dist/config/access.js +125 -27
- package/dist/config/access.js.map +1 -1
- package/dist/config/loader.js +1 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/oidc.js +4 -2
- package/dist/config/oidc.js.map +1 -1
- package/dist/config/project.js +2 -1
- package/dist/config/project.js.map +1 -1
- package/dist/config/resolve-access.js +24 -10
- package/dist/config/resolve-access.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/process-diagnostics.d.ts +2 -0
- package/dist/process-diagnostics.js +11 -0
- package/dist/process-diagnostics.js.map +1 -0
- package/dist/runtime/access-errors.d.ts +4 -0
- package/dist/runtime/access-errors.js +25 -0
- package/dist/runtime/access-errors.js.map +1 -0
- package/dist/runtime/approval-registry.js +1 -1
- package/dist/runtime/approval-registry.js.map +1 -1
- package/dist/runtime/client.js +54 -14
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/dashboard-sanitize.d.ts +2 -0
- package/dist/runtime/dashboard-sanitize.js +7 -0
- package/dist/runtime/dashboard-sanitize.js.map +1 -0
- package/dist/runtime/dashboard.d.ts +1 -1
- package/dist/runtime/dashboard.js +2 -3
- package/dist/runtime/dashboard.js.map +1 -1
- package/dist/runtime/definition.js +11 -1
- package/dist/runtime/definition.js.map +1 -1
- package/dist/runtime/select-native.js +26 -8
- package/dist/runtime/select-native.js.map +1 -1
- package/dist/runtime/worker-client.js +38 -13
- package/dist/runtime/worker-client.js.map +1 -1
- package/dist/sdk/definitions.d.ts +4 -1
- package/dist/sdk/definitions.js +16 -2
- package/dist/sdk/definitions.js.map +1 -1
- package/dist/sdk/permission-validation.js +10 -1
- package/dist/sdk/permission-validation.js.map +1 -1
- package/dist/sdk/types.d.ts +29 -1
- package/dist/sdk/types.js.map +1 -1
- package/package.json +4 -1
- package/sdk/access-config.md +58 -4
- package/sdk/adapter-contract.md +5 -3
- package/sdk/additional-harnesses.md +43 -0
- package/sdk/agent-skill.md +2 -2
- package/sdk/agent.md +5 -3
- package/sdk/approvals.md +3 -1
- package/sdk/authentication.md +1 -1
- package/sdk/cli/dashboard-design.md +6 -0
- package/sdk/cli/index.md +9 -6
- package/sdk/cli/output.md +3 -1
- package/sdk/config.md +1 -1
- package/sdk/copilot.md +53 -0
- package/sdk/cursor.md +68 -0
- package/sdk/diagnostics.md +29 -0
- package/sdk/distribution.md +1 -1
- package/sdk/evals.md +1 -1
- package/sdk/fx.md +50 -5
- package/sdk/harnesses.md +13 -13
- package/sdk/index.md +3 -2
- package/sdk/opencode.md +57 -0
- package/sdk/permissions.md +4 -2
- package/sdk/project-team.md +2 -0
- package/sdk/tools.md +1 -1
- package/sdk/v1-runtime.md +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-errors.js","sourceRoot":"","sources":["../../src/runtime/access-errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,UAAU,iBAAiB,CAAC,KAAiB,EAAE,OAAe;IAClE,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC,CAAC;AACpE,CAAC;AAED,KAAK,UAAU,WAAW,CAAI,SAA2B,EAAE,OAAe;IACxE,IAAI,CAAC;QAAC,OAAO,MAAM,SAAS,EAAE,CAAC;IAAC,CAAC;IACjC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,UAAU,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACnE,MAAM,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAqB,EAAE,OAAe;IAC7E,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAC/D,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QACjE,SAAS,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC;QAC/D,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,OAAO,CAAC;QACzD,KAAK,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC;KACxD,CAAC;AACJ,CAAC","sourcesContent":["import type { NativeSession } from \"../adapters/types.js\";\nimport { AgentError } from \"../errors.js\";\n\nexport function withAccessContext(error: AgentError, context: string): AgentError {\n return new AgentError(error.code, `${error.message}\\n${context}`);\n}\n\nasync function sessionCall<T>(operation: () => Promise<T>, context: string): Promise<T> {\n try { return await operation(); }\n catch (error) {\n if (error instanceof AgentError && error.code === \"INVALID_CONFIG\") {\n throw withAccessContext(error, context);\n }\n throw error;\n }\n}\n\nexport function withSessionAccessContext(native: NativeSession, context: string): NativeSession {\n return {\n turn: prompt => sessionCall(() => native.turn(prompt), context),\n steer: prompt => sessionCall(() => native.steer(prompt), context),\n interrupt: () => sessionCall(() => native.interrupt(), context),\n resume: () => sessionCall(() => native.resume(), context),\n close: () => sessionCall(() => native.close(), context),\n };\n}\n"]}
|
|
@@ -31,7 +31,7 @@ export class ApprovalRegistry {
|
|
|
31
31
|
catch {
|
|
32
32
|
throw new AgentError('INPUT_REQUIRED', 'The native permission request cannot be represented within 64 KiB.');
|
|
33
33
|
}
|
|
34
|
-
if (copy.kind !== 'permission' || !['codex', 'claudeCode', 'fx'].includes(copy.harness) || typeof copy.message !== 'string')
|
|
34
|
+
if (copy.kind !== 'permission' || !['codex', 'claudeCode', 'fx', 'opencode', 'copilot', 'cursor'].includes(copy.harness) || typeof copy.message !== 'string')
|
|
35
35
|
throw new AgentError('INPUT_REQUIRED', 'The native permission request cannot be represented.');
|
|
36
36
|
validateApprovalSchema(copy.requestedSchema);
|
|
37
37
|
const requestId = `req_${randomUUID()}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-registry.js","sourceRoot":"","sources":["../../src/runtime/approval-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { isDeepStrictEqual } from 'node:util';\nimport { AgentError } from '../errors.js';\nimport { validateApprovalContent, validateApprovalSchema } from '../approvals/schema.js';\nimport type { ApprovalContent, NativeApprovalRequest } from '../approvals/types.js';\nimport type { ApprovalRequest } from './types.js';\n\ntype RequestIdentity = Pick<ApprovalRequest,'requestId'|'taskId'|'sessionId'>;\ninterface Continuation {\n resolve(content: ApprovalContent): void;\n reject(error: AgentError): void;\n cleanup(): void;\n}\ninterface PendingEntry {\n outcome: 'pending';\n request: ApprovalRequest;\n continuation: Continuation;\n}\ninterface AnsweredEntry { outcome: 'answered'; identity: RequestIdentity; answer: ApprovalContent }\ninterface WithdrawnEntry { outcome: 'withdrawn'; identity: RequestIdentity }\ntype SettledEntry = AnsweredEntry | WithdrawnEntry;\n\nconst MAX_SETTLED_REQUESTS = 1_024;\nconst expired = () => new AgentError('REQUEST_EXPIRED','The native permission request is no longer pending.');\nconst unknown = () => new AgentError('UNKNOWN_REQUEST','Permission request is unavailable in this coordinator.');\nconst identity = (request: ApprovalRequest): RequestIdentity => ({\n requestId:request.requestId,taskId:request.taskId,sessionId:request.sessionId,\n});\n\n/** Retains pending requests and a bounded settlement-ordered outcome history. */\nexport class ApprovalRegistry {\n private pending = new Map<string,PendingEntry>();\n private settled = new Map<string,SettledEntry>();\n constructor(private readonly changed: (taskId: string) => void) {}\n\n async register(taskId: string, sessionId: string, request: NativeApprovalRequest, signal: AbortSignal): Promise<ApprovalContent> {\n if (signal.aborted) throw expired();\n if (this.pendingFor(taskId).length >= 32)\n throw new AgentError('INPUT_REQUIRED','A task cannot wait on more than 32 permission requests.');\n let copy: NativeApprovalRequest;\n try {\n const serialized = JSON.stringify(request);\n if (Buffer.byteLength(serialized) > 64 * 1024) throw new Error();\n copy = JSON.parse(serialized) as NativeApprovalRequest;\n } catch { throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented within 64 KiB.'); }\n if (copy.kind !== 'permission' || !['codex','claudeCode','fx'].includes(copy.harness) || typeof copy.message !== 'string')\n throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented.');\n validateApprovalSchema(copy.requestedSchema);\n const requestId = `req_${randomUUID()}`;\n const snapshot: ApprovalRequest = {...copy,requestId,taskId,sessionId};\n if (Buffer.byteLength(JSON.stringify(snapshot)) > 64 * 1024)\n throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented within 64 KiB.');\n const answer = new Promise<ApprovalContent>((resolve,reject) => {\n const abort = () => this.retire(requestId);\n this.pending.set(requestId,{outcome:'pending',request:snapshot,\n continuation:{resolve,reject,cleanup:() => signal.removeEventListener('abort',abort)}});\n signal.addEventListener('abort',abort,{once:true});\n });\n this.changed(taskId);\n return answer;\n }\n\n request(id: string): RequestIdentity {\n const pending = this.pending.get(id);\n if (pending) return identity(pending.request);\n const settled = this.settled.get(id);\n if (!settled) throw unknown();\n return {...settled.identity};\n }\n\n respond(id: string, content: unknown) {\n const pending = this.pending.get(id);\n if (!pending) {\n const settled = this.settled.get(id);\n if (!settled) throw unknown();\n if (settled.outcome === 'withdrawn') throw expired();\n this.validateBoundedContent(content);\n if (!isDeepStrictEqual(settled.answer,content))\n throw new AgentError('INVALID_APPROVAL_RESPONSE','This permission request already has a different answer.');\n return this.receipt(settled.identity);\n }\n this.validateBoundedContent(content);\n const answer = validateApprovalContent(pending.request.requestedSchema,content);\n const requestIdentity = identity(pending.request);\n this.pending.delete(id);\n pending.continuation.cleanup();\n this.retain({outcome:'answered',identity:requestIdentity,answer:structuredClone(answer)});\n pending.continuation.resolve(answer);\n this.changed(requestIdentity.taskId);\n return this.receipt(requestIdentity);\n }\n\n pendingFor(taskId: string): ApprovalRequest[] {\n return [...this.pending.values()].filter(entry => entry.request.taskId === taskId)\n .map(entry => structuredClone(entry.request));\n }\n\n retireTask(taskId: string) {\n for (const [id,entry] of this.pending) if (entry.request.taskId === taskId) this.retire(id);\n }\n\n close() { for (const id of [...this.pending.keys()]) this.retire(id); }\n\n private retire(id: string) {\n const entry = this.pending.get(id);\n if (!entry) return;\n const requestIdentity = identity(entry.request);\n this.pending.delete(id);\n entry.continuation.cleanup();\n this.retain({outcome:'withdrawn',identity:requestIdentity});\n entry.continuation.reject(expired());\n this.changed(requestIdentity.taskId);\n }\n\n private retain(entry: SettledEntry) {\n this.settled.set(entry.identity.requestId,entry);\n while (this.settled.size > MAX_SETTLED_REQUESTS) {\n const oldest = this.settled.keys().next().value;\n if (oldest !== undefined) this.settled.delete(oldest);\n }\n }\n\n private validateBoundedContent(content: unknown) {\n let serialized: string | undefined;\n try { serialized = JSON.stringify(content); } catch { /* Report no submitted data. */ }\n if (!serialized || Buffer.byteLength(serialized) > 16 * 1024)\n throw new AgentError('INVALID_APPROVAL_RESPONSE','Approval content must be a JSON object within 16 KiB.');\n }\n\n private receipt(request: RequestIdentity) {\n return {version:1 as const,type:'approval_answered' as const,requestId:request.requestId,\n taskId:request.taskId,sessionId:request.sessionId};\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"approval-registry.js","sourceRoot":"","sources":["../../src/runtime/approval-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAmBzF,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,iBAAiB,EAAC,qDAAqD,CAAC,CAAC;AAC9G,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,iBAAiB,EAAC,wDAAwD,CAAC,CAAC;AACjH,MAAM,QAAQ,GAAG,CAAC,OAAwB,EAAmB,EAAE,CAAC,CAAC;IAC/D,SAAS,EAAC,OAAO,CAAC,SAAS,EAAC,MAAM,EAAC,OAAO,CAAC,MAAM,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS;CAC9E,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,OAAO,gBAAgB;IAGE,OAAO;IAF5B,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IACzC,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IACjD,YAA6B,OAAiC;uBAAjC,OAAO;IAA6B,CAAC;IAElE,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,SAAiB,EAAE,OAA8B,EAAE,MAAmB;QACnG,IAAI,MAAM,CAAC,OAAO;YAAE,MAAM,OAAO,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,EAAE;YACtC,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,yDAAyD,CAAC,CAAC;QACnG,IAAI,IAA2B,CAAC;QAChC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI;gBAAE,MAAM,IAAI,KAAK,EAAE,CAAC;YACjE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAA0B,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YAAC,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,oEAAoE,CAAC,CAAC;QAAC,CAAC;QACxH,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,OAAO,EAAC,YAAY,EAAC,IAAI,EAAC,UAAU,EAAC,SAAS,EAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;YACrJ,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,sDAAsD,CAAC,CAAC;QAChG,sBAAsB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,OAAO,UAAU,EAAE,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAoB,EAAC,GAAG,IAAI,EAAC,SAAS,EAAC,MAAM,EAAC,SAAS,EAAC,CAAC;QACvE,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI;YACzD,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAC,oEAAoE,CAAC,CAAC;QAC9G,MAAM,MAAM,GAAG,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAC,MAAM,EAAE,EAAE;YAC7D,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAC,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAC,QAAQ;gBAC5D,YAAY,EAAC,EAAC,OAAO,EAAC,MAAM,EAAC,OAAO,EAAC,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAC,KAAK,CAAC,EAAC,EAAC,CAAC,CAAC;YAC1F,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAC,KAAK,EAAC,EAAC,IAAI,EAAC,IAAI,EAAC,CAAC,CAAC;QACrD,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,CAAC,EAAU;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,OAAO;YAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,MAAM,OAAO,EAAE,CAAC;QAC9B,OAAO,EAAC,GAAG,OAAO,CAAC,QAAQ,EAAC,CAAC;IAC/B,CAAC;IAED,OAAO,CAAC,EAAU,EAAE,OAAgB;QAClC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC,OAAO;gBAAE,MAAM,OAAO,EAAE,CAAC;YAC9B,IAAI,OAAO,CAAC,OAAO,KAAK,WAAW;gBAAE,MAAM,OAAO,EAAE,CAAC;YACrD,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;YACrC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAC,OAAO,CAAC;gBAC5C,MAAM,IAAI,UAAU,CAAC,2BAA2B,EAAC,yDAAyD,CAAC,CAAC;YAC9G,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAC,OAAO,CAAC,CAAC;QAChF,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAC,OAAO,EAAC,UAAU,EAAC,QAAQ,EAAC,eAAe,EAAC,MAAM,EAAC,eAAe,CAAC,MAAM,CAAC,EAAC,CAAC,CAAC;QAC1F,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACrC,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACvC,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC;aAC/E,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,UAAU,CAAC,MAAc;QACvB,KAAK,MAAM,CAAC,EAAE,EAAC,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,KAAK,KAAK,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAE/D,MAAM,CAAC,EAAU;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACxB,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,EAAC,OAAO,EAAC,WAAW,EAAC,QAAQ,EAAC,eAAe,EAAC,CAAC,CAAC;QAC5D,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IAEO,MAAM,CAAC,KAAmB;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAC,KAAK,CAAC,CAAC;QACjD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,oBAAoB,EAAE,CAAC;YAChD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAChD,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAEO,sBAAsB,CAAC,OAAgB;QAC7C,IAAI,UAA8B,CAAC;QACnC,IAAI,CAAC;YAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,+BAA+B,CAAC,CAAC;QACvF,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI;YAC1D,MAAM,IAAI,UAAU,CAAC,2BAA2B,EAAC,uDAAuD,CAAC,CAAC;IAC9G,CAAC;IAEO,OAAO,CAAC,OAAwB;QACtC,OAAO,EAAC,OAAO,EAAC,CAAU,EAAC,IAAI,EAAC,mBAA4B,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS;YACtF,MAAM,EAAC,OAAO,CAAC,MAAM,EAAC,SAAS,EAAC,OAAO,CAAC,SAAS,EAAC,CAAC;IACvD,CAAC;CACF","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { isDeepStrictEqual } from 'node:util';\nimport { AgentError } from '../errors.js';\nimport { validateApprovalContent, validateApprovalSchema } from '../approvals/schema.js';\nimport type { ApprovalContent, NativeApprovalRequest } from '../approvals/types.js';\nimport type { ApprovalRequest } from './types.js';\n\ntype RequestIdentity = Pick<ApprovalRequest,'requestId'|'taskId'|'sessionId'>;\ninterface Continuation {\n resolve(content: ApprovalContent): void;\n reject(error: AgentError): void;\n cleanup(): void;\n}\ninterface PendingEntry {\n outcome: 'pending';\n request: ApprovalRequest;\n continuation: Continuation;\n}\ninterface AnsweredEntry { outcome: 'answered'; identity: RequestIdentity; answer: ApprovalContent }\ninterface WithdrawnEntry { outcome: 'withdrawn'; identity: RequestIdentity }\ntype SettledEntry = AnsweredEntry | WithdrawnEntry;\n\nconst MAX_SETTLED_REQUESTS = 1_024;\nconst expired = () => new AgentError('REQUEST_EXPIRED','The native permission request is no longer pending.');\nconst unknown = () => new AgentError('UNKNOWN_REQUEST','Permission request is unavailable in this coordinator.');\nconst identity = (request: ApprovalRequest): RequestIdentity => ({\n requestId:request.requestId,taskId:request.taskId,sessionId:request.sessionId,\n});\n\n/** Retains pending requests and a bounded settlement-ordered outcome history. */\nexport class ApprovalRegistry {\n private pending = new Map<string,PendingEntry>();\n private settled = new Map<string,SettledEntry>();\n constructor(private readonly changed: (taskId: string) => void) {}\n\n async register(taskId: string, sessionId: string, request: NativeApprovalRequest, signal: AbortSignal): Promise<ApprovalContent> {\n if (signal.aborted) throw expired();\n if (this.pendingFor(taskId).length >= 32)\n throw new AgentError('INPUT_REQUIRED','A task cannot wait on more than 32 permission requests.');\n let copy: NativeApprovalRequest;\n try {\n const serialized = JSON.stringify(request);\n if (Buffer.byteLength(serialized) > 64 * 1024) throw new Error();\n copy = JSON.parse(serialized) as NativeApprovalRequest;\n } catch { throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented within 64 KiB.'); }\n if (copy.kind !== 'permission' || !['codex','claudeCode','fx','opencode','copilot','cursor'].includes(copy.harness) || typeof copy.message !== 'string')\n throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented.');\n validateApprovalSchema(copy.requestedSchema);\n const requestId = `req_${randomUUID()}`;\n const snapshot: ApprovalRequest = {...copy,requestId,taskId,sessionId};\n if (Buffer.byteLength(JSON.stringify(snapshot)) > 64 * 1024)\n throw new AgentError('INPUT_REQUIRED','The native permission request cannot be represented within 64 KiB.');\n const answer = new Promise<ApprovalContent>((resolve,reject) => {\n const abort = () => this.retire(requestId);\n this.pending.set(requestId,{outcome:'pending',request:snapshot,\n continuation:{resolve,reject,cleanup:() => signal.removeEventListener('abort',abort)}});\n signal.addEventListener('abort',abort,{once:true});\n });\n this.changed(taskId);\n return answer;\n }\n\n request(id: string): RequestIdentity {\n const pending = this.pending.get(id);\n if (pending) return identity(pending.request);\n const settled = this.settled.get(id);\n if (!settled) throw unknown();\n return {...settled.identity};\n }\n\n respond(id: string, content: unknown) {\n const pending = this.pending.get(id);\n if (!pending) {\n const settled = this.settled.get(id);\n if (!settled) throw unknown();\n if (settled.outcome === 'withdrawn') throw expired();\n this.validateBoundedContent(content);\n if (!isDeepStrictEqual(settled.answer,content))\n throw new AgentError('INVALID_APPROVAL_RESPONSE','This permission request already has a different answer.');\n return this.receipt(settled.identity);\n }\n this.validateBoundedContent(content);\n const answer = validateApprovalContent(pending.request.requestedSchema,content);\n const requestIdentity = identity(pending.request);\n this.pending.delete(id);\n pending.continuation.cleanup();\n this.retain({outcome:'answered',identity:requestIdentity,answer:structuredClone(answer)});\n pending.continuation.resolve(answer);\n this.changed(requestIdentity.taskId);\n return this.receipt(requestIdentity);\n }\n\n pendingFor(taskId: string): ApprovalRequest[] {\n return [...this.pending.values()].filter(entry => entry.request.taskId === taskId)\n .map(entry => structuredClone(entry.request));\n }\n\n retireTask(taskId: string) {\n for (const [id,entry] of this.pending) if (entry.request.taskId === taskId) this.retire(id);\n }\n\n close() { for (const id of [...this.pending.keys()]) this.retire(id); }\n\n private retire(id: string) {\n const entry = this.pending.get(id);\n if (!entry) return;\n const requestIdentity = identity(entry.request);\n this.pending.delete(id);\n entry.continuation.cleanup();\n this.retain({outcome:'withdrawn',identity:requestIdentity});\n entry.continuation.reject(expired());\n this.changed(requestIdentity.taskId);\n }\n\n private retain(entry: SettledEntry) {\n this.settled.set(entry.identity.requestId,entry);\n while (this.settled.size > MAX_SETTLED_REQUESTS) {\n const oldest = this.settled.keys().next().value;\n if (oldest !== undefined) this.settled.delete(oldest);\n }\n }\n\n private validateBoundedContent(content: unknown) {\n let serialized: string | undefined;\n try { serialized = JSON.stringify(content); } catch { /* Report no submitted data. */ }\n if (!serialized || Buffer.byteLength(serialized) > 16 * 1024)\n throw new AgentError('INVALID_APPROVAL_RESPONSE','Approval content must be a JSON object within 16 KiB.');\n }\n\n private receipt(request: RequestIdentity) {\n return {version:1 as const,type:'approval_answered' as const,requestId:request.requestId,\n taskId:request.taskId,sessionId:request.sessionId};\n }\n}\n"]}
|
package/dist/runtime/client.js
CHANGED
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
3
|
import { AgentError } from '../errors.js';
|
|
4
|
+
import { processExitDescription } from '../process-diagnostics.js';
|
|
4
5
|
import { localProgram, privateDirectory, readEndpoint, stateDirectory } from './state.js';
|
|
5
6
|
import { startupOutcome, startupRetirementRequest } from './startup-protocol.js';
|
|
6
7
|
const retirementConfirmationMs = 1_000;
|
|
8
|
+
const coordinatorOperations = new Set([
|
|
9
|
+
'dashboard', 'dashboard-session', 'dashboard-detail', 'parent', 'run', 'send', 'resume', 'wait',
|
|
10
|
+
'status', 'queue', 'cancel', 'respond',
|
|
11
|
+
]);
|
|
12
|
+
function coordinatorOperation(body) {
|
|
13
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
14
|
+
return;
|
|
15
|
+
const command = body.command;
|
|
16
|
+
return typeof command === 'string' && coordinatorOperations.has(command) ? command : undefined;
|
|
17
|
+
}
|
|
7
18
|
export async function connect(start, options = {}) {
|
|
8
19
|
const directory = options.directory ?? stateDirectory();
|
|
9
20
|
const available = await readEndpoint(directory);
|
|
@@ -19,9 +30,14 @@ export async function connect(start, options = {}) {
|
|
|
19
30
|
if (Date.now() >= deadline)
|
|
20
31
|
throw new AgentError('STARTUP_FAILED', 'Another command did not finish coordinator startup.');
|
|
21
32
|
const program = options.program ?? localProgram('daemon');
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
try {
|
|
34
|
+
child = spawn(process.execPath, [...program.execArgv, program.file, String(Math.max(1, deadline - Date.now()))], {
|
|
35
|
+
detached: true, stdio: ['ignore', 'ignore', 'ignore', 'ipc'], env: { ...process.env, AGENT_STATE_DIR: directory },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new AgentError('STARTUP_FAILED', 'The local coordinator could not be spawned.');
|
|
40
|
+
}
|
|
25
41
|
candidate = observeCandidate(child);
|
|
26
42
|
options.afterSpawn?.(child);
|
|
27
43
|
child.unref();
|
|
@@ -44,7 +60,15 @@ export async function connect(start, options = {}) {
|
|
|
44
60
|
const replacement = await readEndpoint(directory);
|
|
45
61
|
if (replacement)
|
|
46
62
|
return replacement;
|
|
47
|
-
if (
|
|
63
|
+
if (!observed && outcome)
|
|
64
|
+
throw new AgentError('STARTUP_FAILED', 'The local coordinator timed out before publishing an endpoint.');
|
|
65
|
+
if (observed?.state === 'spawn-failed')
|
|
66
|
+
throw new AgentError('STARTUP_FAILED', 'The local coordinator could not be spawned.');
|
|
67
|
+
if (observed?.state === 'exited')
|
|
68
|
+
throw new AgentError('STARTUP_FAILED', `The local coordinator exited before startup completed${processExitDescription(observed.code, observed.signal)}.`);
|
|
69
|
+
if (observed?.state === 'retired')
|
|
70
|
+
throw new AgentError('STARTUP_FAILED', 'The local coordinator retired before startup completed.');
|
|
71
|
+
if (outcome?.state === 'retired' || outcome?.state === 'exited' || outcome?.state === 'spawn-failed')
|
|
48
72
|
throw new AgentError('STARTUP_FAILED', 'The local coordinator could not start.');
|
|
49
73
|
throw new AgentError('STARTUP_FAILED', 'The local coordinator timed out, and its retirement could not be confirmed. It was left untouched because it may have published.');
|
|
50
74
|
}
|
|
@@ -73,16 +97,17 @@ function observeCandidate(child) {
|
|
|
73
97
|
if (value)
|
|
74
98
|
finish(value);
|
|
75
99
|
};
|
|
76
|
-
const
|
|
100
|
+
const onError = () => finish({ state: 'spawn-failed' });
|
|
101
|
+
const onExit = (code, signal) => finish({ state: 'exited', code, signal });
|
|
77
102
|
child.on('message', onMessage);
|
|
78
|
-
child.once('error',
|
|
103
|
+
child.once('error', onError);
|
|
79
104
|
child.once('exit', onExit);
|
|
80
105
|
return {
|
|
81
106
|
outcome,
|
|
82
107
|
current: () => current,
|
|
83
108
|
close() {
|
|
84
109
|
child.off('message', onMessage);
|
|
85
|
-
child.off('error',
|
|
110
|
+
child.off('error', onError);
|
|
86
111
|
child.off('exit', onExit);
|
|
87
112
|
},
|
|
88
113
|
};
|
|
@@ -109,6 +134,7 @@ async function within(promise, timeoutMs) {
|
|
|
109
134
|
}
|
|
110
135
|
}
|
|
111
136
|
export async function* request(endpoint, body) {
|
|
137
|
+
const operation = coordinatorOperation(body);
|
|
112
138
|
let response;
|
|
113
139
|
try {
|
|
114
140
|
response = await fetch(endpoint.url, { method: 'POST', headers: { authorization: `Bearer ${endpoint.token}`, 'content-type': 'application/json' }, body: JSON.stringify(body) });
|
|
@@ -116,8 +142,12 @@ export async function* request(endpoint, body) {
|
|
|
116
142
|
catch {
|
|
117
143
|
throw new AgentError('COORDINATOR_UNAVAILABLE', 'Connection to the local coordinator failed. The task was not automatically retried.');
|
|
118
144
|
}
|
|
119
|
-
if (!response.ok
|
|
120
|
-
|
|
145
|
+
if (!response.ok) {
|
|
146
|
+
void response.body?.cancel().catch(() => { });
|
|
147
|
+
throw new AgentError('COORDINATOR_UNAVAILABLE', `The coordinator rejected ${operation ? `the ${operation} operation` : 'the request'} with HTTP status ${response.status}.`);
|
|
148
|
+
}
|
|
149
|
+
if (!response.body)
|
|
150
|
+
throw new AgentError('COORDINATOR_UNAVAILABLE', `The coordinator returned a successful response with no body${operation ? ` for the ${operation} operation` : ''}.`);
|
|
121
151
|
let buffer = '';
|
|
122
152
|
const decoder = new TextDecoder();
|
|
123
153
|
try {
|
|
@@ -127,16 +157,26 @@ export async function* request(endpoint, body) {
|
|
|
127
157
|
while ((newline = buffer.indexOf('\n')) >= 0) {
|
|
128
158
|
const line = buffer.slice(0, newline);
|
|
129
159
|
buffer = buffer.slice(newline + 1);
|
|
130
|
-
if (line)
|
|
131
|
-
|
|
160
|
+
if (line) {
|
|
161
|
+
let record;
|
|
162
|
+
try {
|
|
163
|
+
record = JSON.parse(line);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
throw new AgentError('COORDINATOR_UNAVAILABLE', `The coordinator returned a malformed JSON record${operation ? ` for the ${operation} operation` : ''}. The task was not automatically retried.`);
|
|
167
|
+
}
|
|
168
|
+
yield record;
|
|
169
|
+
}
|
|
132
170
|
}
|
|
133
171
|
}
|
|
134
172
|
buffer += decoder.decode();
|
|
135
173
|
if (buffer.trim())
|
|
136
|
-
throw new
|
|
174
|
+
throw new AgentError('COORDINATOR_UNAVAILABLE', `The coordinator response ended with an incomplete final record${operation ? ` for the ${operation} operation` : ''}. The task was not automatically retried.`);
|
|
137
175
|
}
|
|
138
|
-
catch {
|
|
139
|
-
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (error instanceof AgentError)
|
|
178
|
+
throw error;
|
|
179
|
+
throw new AgentError('COORDINATOR_UNAVAILABLE', 'The coordinator response stream was interrupted. The task was not automatically retried.');
|
|
140
180
|
}
|
|
141
181
|
}
|
|
142
182
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { AgentError } from '../errors.js';\nimport type { OutputRecord } from '../cli/output.js';\nimport { type Endpoint, localProgram, privateDirectory, readEndpoint, stateDirectory } from './state.js';\nimport { startupOutcome, startupRetirementRequest, type StartupOutcome } from './startup-protocol.js';\n\ninterface ConnectionOptions {\n directory?: string;\n timeoutMs?: number;\n afterSpawn?: (child: ChildProcess) => void;\n beforeRetirement?: (child: ChildProcess) => void | Promise<void>;\n program?: ReturnType<typeof localProgram>;\n}\n\ntype CandidateOutcome = StartupOutcome | {state:'exited'};\nconst retirementConfirmationMs = 1_000;\n\nexport async function connect(start: boolean, options: ConnectionOptions = {}): Promise<Endpoint> {\n const directory = options.directory ?? stateDirectory();\n const available = await readEndpoint(directory);\n if (available) return available;\n if (!start) throw new AgentError('UNKNOWN_SESSION','No coordinator is reachable from this environment. Its sessions may have ended, or native permissions may block access to its local endpoint.');\n await privateDirectory(directory);\n const deadline = Date.now() + (options.timeoutMs ?? 15_000);\n let child: ChildProcess | undefined;\n let candidate: ReturnType<typeof observeCandidate> | undefined;\n try {\n if (Date.now() >= deadline) throw new AgentError('STARTUP_FAILED','Another command did not finish coordinator startup.');\n const program = options.program ?? localProgram('daemon');\n child = spawn(process.execPath,[...program.execArgv,program.file,String(Math.max(1,deadline-Date.now()))],{\n detached:true,stdio:['ignore','ignore','ignore','ipc'],env:{...process.env,AGENT_STATE_DIR:directory},\n });\n candidate = observeCandidate(child);\n options.afterSpawn?.(child);\n child.unref();\n while (Date.now() < deadline && !candidate.current()) {\n await delay(50);\n const endpoint = await readEndpoint(directory);\n if (endpoint) return endpoint;\n }\n const observed = candidate.current();\n if (observed?.state === 'published') return observed.endpoint;\n if (!observed) {\n await options.beforeRetirement?.(child);\n requestRetirement(child);\n }\n const outcome = observed ?? await within(candidate.outcome,retirementConfirmationMs);\n if (outcome?.state === 'published') return outcome.endpoint;\n const replacement = await readEndpoint(directory);\n if (replacement) return replacement;\n if (outcome?.state === 'retired' || outcome?.state === 'exited')\n throw new AgentError('STARTUP_FAILED','The local coordinator could not start.');\n throw new AgentError('STARTUP_FAILED','The local coordinator timed out, and its retirement could not be confirmed. It was left untouched because it may have published.');\n } finally {\n candidate?.close();\n if (child?.connected) {\n try { child.disconnect(); } catch { /* The candidate may have disconnected after retirement. */ }\n }\n }\n}\n\nfunction observeCandidate(child: ChildProcess) {\n let current: CandidateOutcome | undefined;\n let settle!: (outcome: CandidateOutcome) => void;\n const outcome = new Promise<CandidateOutcome>(resolve => { settle = resolve; });\n const finish = (value: CandidateOutcome) => {\n if (current) return;\n current = value;\n settle(value);\n };\n const onMessage = (message: unknown) => {\n const value = startupOutcome(message);\n if (value) finish(value);\n };\n const onExit = () => finish({state:'exited'});\n child.on('message',onMessage);\n child.once('error',onExit);\n child.once('exit',onExit);\n return {\n outcome,\n current:() => current,\n close() {\n child.off('message',onMessage);\n child.off('error',onExit);\n child.off('exit',onExit);\n },\n };\n}\n\nfunction requestRetirement(child: ChildProcess) {\n if (!child.connected) return;\n try { child.send(startupRetirementRequest,()=>{}); }\n catch { /* The bounded outcome wait reports an unconfirmed retirement. */ }\n}\n\nasync function within<T>(promise: Promise<T>, timeoutMs: number): Promise<T | undefined> {\n let timer: number | NodeJS.Timeout | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<undefined>(resolve => { timer = setTimeout(resolve,timeoutMs); }),\n ]);\n } finally { if (timer) clearTimeout(timer); }\n}\n\nexport async function* request(endpoint: Endpoint, body: unknown): AsyncGenerator<OutputRecord> {\n let response: globalThis.Response;\n try {\n response = await fetch(endpoint.url,{method:'POST',headers:{authorization:`Bearer ${endpoint.token}`,'content-type':'application/json'},body:JSON.stringify(body)});\n } catch { throw new AgentError('COORDINATOR_UNAVAILABLE','Connection to the local coordinator failed. The task was not automatically retried.'); }\n if (!response.ok || !response.body) throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator rejected the request.');\n let buffer = '';\n const decoder = new TextDecoder();\n try {\n for await (const chunk of response.body) {\n buffer += decoder.decode(chunk,{stream:true});\n let newline;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0,newline); buffer = buffer.slice(newline + 1);\n if (line) yield JSON.parse(line) as OutputRecord;\n }\n }\n buffer += decoder.decode();\n if (buffer.trim()) throw new Error('Incomplete response record');\n } catch {\n throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator response was interrupted or invalid. The task was not automatically retried.');\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { AgentError } from '../errors.js';\nimport { processExitDescription } from '../process-diagnostics.js';\nimport type { OutputRecord } from '../cli/output.js';\nimport { type Endpoint, localProgram, privateDirectory, readEndpoint, stateDirectory } from './state.js';\nimport { startupOutcome, startupRetirementRequest, type StartupOutcome } from './startup-protocol.js';\n\ninterface ConnectionOptions {\n directory?: string;\n timeoutMs?: number;\n afterSpawn?: (child: ChildProcess) => void;\n beforeRetirement?: (child: ChildProcess) => void | Promise<void>;\n program?: ReturnType<typeof localProgram>;\n}\n\ntype CandidateOutcome = StartupOutcome\n | {state:'spawn-failed'}\n | {state:'exited';code:unknown;signal:unknown};\nconst retirementConfirmationMs = 1_000;\nconst coordinatorOperations = new Set([\n 'dashboard', 'dashboard-session', 'dashboard-detail', 'parent', 'run', 'send', 'resume', 'wait',\n 'status', 'queue', 'cancel', 'respond',\n]);\n\nfunction coordinatorOperation(body: unknown): string | undefined {\n if (!body || typeof body !== 'object' || Array.isArray(body)) return;\n const command = (body as {command?:unknown}).command;\n return typeof command === 'string' && coordinatorOperations.has(command) ? command : undefined;\n}\n\nexport async function connect(start: boolean, options: ConnectionOptions = {}): Promise<Endpoint> {\n const directory = options.directory ?? stateDirectory();\n const available = await readEndpoint(directory);\n if (available) return available;\n if (!start) throw new AgentError('UNKNOWN_SESSION','No coordinator is reachable from this environment. Its sessions may have ended, or native permissions may block access to its local endpoint.');\n await privateDirectory(directory);\n const deadline = Date.now() + (options.timeoutMs ?? 15_000);\n let child: ChildProcess | undefined;\n let candidate: ReturnType<typeof observeCandidate> | undefined;\n try {\n if (Date.now() >= deadline) throw new AgentError('STARTUP_FAILED','Another command did not finish coordinator startup.');\n const program = options.program ?? localProgram('daemon');\n try {\n child = spawn(process.execPath,[...program.execArgv,program.file,String(Math.max(1,deadline-Date.now()))],{\n detached:true,stdio:['ignore','ignore','ignore','ipc'],env:{...process.env,AGENT_STATE_DIR:directory},\n });\n } catch {\n throw new AgentError('STARTUP_FAILED','The local coordinator could not be spawned.');\n }\n candidate = observeCandidate(child);\n options.afterSpawn?.(child);\n child.unref();\n while (Date.now() < deadline && !candidate.current()) {\n await delay(50);\n const endpoint = await readEndpoint(directory);\n if (endpoint) return endpoint;\n }\n const observed = candidate.current();\n if (observed?.state === 'published') return observed.endpoint;\n if (!observed) {\n await options.beforeRetirement?.(child);\n requestRetirement(child);\n }\n const outcome = observed ?? await within(candidate.outcome,retirementConfirmationMs);\n if (outcome?.state === 'published') return outcome.endpoint;\n const replacement = await readEndpoint(directory);\n if (replacement) return replacement;\n if (!observed && outcome)\n throw new AgentError('STARTUP_FAILED','The local coordinator timed out before publishing an endpoint.');\n if (observed?.state === 'spawn-failed')\n throw new AgentError('STARTUP_FAILED','The local coordinator could not be spawned.');\n if (observed?.state === 'exited')\n throw new AgentError('STARTUP_FAILED',\n `The local coordinator exited before startup completed${processExitDescription(observed.code, observed.signal)}.`);\n if (observed?.state === 'retired')\n throw new AgentError('STARTUP_FAILED','The local coordinator retired before startup completed.');\n if (outcome?.state === 'retired' || outcome?.state === 'exited' || outcome?.state === 'spawn-failed')\n throw new AgentError('STARTUP_FAILED','The local coordinator could not start.');\n throw new AgentError('STARTUP_FAILED','The local coordinator timed out, and its retirement could not be confirmed. It was left untouched because it may have published.');\n } finally {\n candidate?.close();\n if (child?.connected) {\n try { child.disconnect(); } catch { /* The candidate may have disconnected after retirement. */ }\n }\n }\n}\n\nfunction observeCandidate(child: ChildProcess) {\n let current: CandidateOutcome | undefined;\n let settle!: (outcome: CandidateOutcome) => void;\n const outcome = new Promise<CandidateOutcome>(resolve => { settle = resolve; });\n const finish = (value: CandidateOutcome) => {\n if (current) return;\n current = value;\n settle(value);\n };\n const onMessage = (message: unknown) => {\n const value = startupOutcome(message);\n if (value) finish(value);\n };\n const onError = () => finish({state:'spawn-failed'});\n const onExit = (code: unknown, signal: unknown) => finish({state:'exited',code,signal});\n child.on('message',onMessage);\n child.once('error',onError);\n child.once('exit',onExit);\n return {\n outcome,\n current:() => current,\n close() {\n child.off('message',onMessage);\n child.off('error',onError);\n child.off('exit',onExit);\n },\n };\n}\n\nfunction requestRetirement(child: ChildProcess) {\n if (!child.connected) return;\n try { child.send(startupRetirementRequest,()=>{}); }\n catch { /* The bounded outcome wait reports an unconfirmed retirement. */ }\n}\n\nasync function within<T>(promise: Promise<T>, timeoutMs: number): Promise<T | undefined> {\n let timer: number | NodeJS.Timeout | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<undefined>(resolve => { timer = setTimeout(resolve,timeoutMs); }),\n ]);\n } finally { if (timer) clearTimeout(timer); }\n}\n\nexport async function* request(endpoint: Endpoint, body: unknown): AsyncGenerator<OutputRecord> {\n const operation = coordinatorOperation(body);\n let response: globalThis.Response;\n try {\n response = await fetch(endpoint.url,{method:'POST',headers:{authorization:`Bearer ${endpoint.token}`,'content-type':'application/json'},body:JSON.stringify(body)});\n } catch { throw new AgentError('COORDINATOR_UNAVAILABLE','Connection to the local coordinator failed. The task was not automatically retried.'); }\n if (!response.ok) {\n void response.body?.cancel().catch(() => {});\n throw new AgentError('COORDINATOR_UNAVAILABLE',\n `The coordinator rejected ${operation ? `the ${operation} operation` : 'the request'} with HTTP status ${response.status}.`);\n }\n if (!response.body) throw new AgentError('COORDINATOR_UNAVAILABLE',\n `The coordinator returned a successful response with no body${operation ? ` for the ${operation} operation` : ''}.`);\n let buffer = '';\n const decoder = new TextDecoder();\n try {\n for await (const chunk of response.body) {\n buffer += decoder.decode(chunk,{stream:true});\n let newline;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0,newline); buffer = buffer.slice(newline + 1);\n if (line) {\n let record: OutputRecord;\n try { record = JSON.parse(line) as OutputRecord; }\n catch {\n throw new AgentError('COORDINATOR_UNAVAILABLE',\n `The coordinator returned a malformed JSON record${operation ? ` for the ${operation} operation` : ''}. The task was not automatically retried.`);\n }\n yield record;\n }\n }\n }\n buffer += decoder.decode();\n if (buffer.trim()) throw new AgentError('COORDINATOR_UNAVAILABLE',\n `The coordinator response ended with an incomplete final record${operation ? ` for the ${operation} operation` : ''}. The task was not automatically retried.`);\n } catch (error) {\n if (error instanceof AgentError) throw error;\n throw new AgentError('COORDINATOR_UNAVAILABLE','The coordinator response stream was interrupted. The task was not automatically retried.');\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import stripAnsi from 'strip-ansi';
|
|
2
|
+
const unsafeControls = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/gu;
|
|
3
|
+
/** Removes terminal instructions while retaining whitespace for the caller to normalize. */
|
|
4
|
+
export function sanitizeDashboardTerminalText(text) {
|
|
5
|
+
return stripAnsi(text).replace(unsafeControls, '');
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=dashboard-sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-sanitize.js","sourceRoot":"","sources":["../../src/runtime/dashboard-sanitize.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AAEnC,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAEjF,4FAA4F;AAC5F,MAAM,UAAU,6BAA6B,CAAC,IAAY;IACxD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACrD,CAAC","sourcesContent":["import stripAnsi from 'strip-ansi';\n\nconst unsafeControls = /[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f]/gu;\n\n/** Removes terminal instructions while retaining whitespace for the caller to normalize. */\nexport function sanitizeDashboardTerminalText(text: string): string {\n return stripAnsi(text).replace(unsafeControls, '');\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ErrorInfo } from '../errors.js';
|
|
2
2
|
import type { HarnessKind } from '../sdk/types.js';
|
|
3
3
|
import type { TaskState } from './types.js';
|
|
4
|
-
export type DashboardHarness = 'codex' | 'claude' | 'fx' | 'pending';
|
|
4
|
+
export type DashboardHarness = 'codex' | 'claude' | 'fx' | 'opencode' | 'copilot' | 'cursor' | 'pending';
|
|
5
5
|
export interface DashboardWorkspace {
|
|
6
6
|
directory: string;
|
|
7
7
|
repository?: string;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sanitizeDashboardTerminalText } from './dashboard-sanitize.js';
|
|
2
2
|
export function dashboardHarness(kind) {
|
|
3
3
|
if (kind === 'claudeCode')
|
|
4
4
|
return 'claude';
|
|
5
5
|
return kind ?? 'pending';
|
|
6
6
|
}
|
|
7
7
|
export function dashboardTitle(prompt) {
|
|
8
|
-
const plain =
|
|
8
|
+
const plain = sanitizeDashboardTerminalText(prompt);
|
|
9
9
|
for (const line of plain.split(/\r\n?|\n/u)) {
|
|
10
10
|
const normalized = line
|
|
11
|
-
.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/gu, '')
|
|
12
11
|
.replace(/\s+/gu, ' ')
|
|
13
12
|
.trim();
|
|
14
13
|
if (normalized)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/runtime/dashboard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/runtime/dashboard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,6BAA6B,EAAC,MAAM,yBAAyB,CAAC;AAsEtE,MAAM,UAAU,gBAAgB,CAAC,IAAkB;IACjD,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,QAAQ,CAAC;IAC3C,OAAO,IAAI,IAAI,SAAS,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,MAAM,KAAK,GAAG,6BAA6B,CAAC,MAAM,CAAC,CAAC;IACpD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI;aACpB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;aACrB,IAAI,EAAE,CAAC;QACV,IAAI,UAAU;YAAE,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import type { ErrorInfo } from '../errors.js';\nimport type { HarnessKind } from '../sdk/types.js';\nimport {sanitizeDashboardTerminalText} from './dashboard-sanitize.ts';\nimport type { TaskState } from './types.js';\n\nexport type DashboardHarness = 'codex' | 'claude' | 'fx' | 'opencode' | 'copilot' | 'cursor' | 'pending';\n\nexport interface DashboardWorkspace {\n directory: string;\n repository?: string;\n}\n\nexport interface DashboardRow {\n sessionId: string;\n taskId: string;\n harness: DashboardHarness;\n title: string;\n state: TaskState;\n workspace: DashboardWorkspace;\n updatedAt: number;\n dispatchedAt?: number;\n failedAt?: number;\n finishedAt?: number;\n}\n\nexport interface DashboardSnapshot {\n version: 1;\n type: 'dashboard';\n history: true;\n grouping: true;\n sessions: DashboardRow[];\n}\n\nexport interface DashboardRelatedTask {\n taskId: string;\n sessionId: string;\n harness: DashboardHarness;\n title: string;\n state: TaskState;\n}\n\nexport interface DashboardRequest extends DashboardRow {\n ordinal: number;\n stopUnconfirmed: boolean;\n}\n\nexport interface DashboardSession {\n version: 1;\n type: 'dashboard-session';\n taskId: string;\n sessionId: string;\n title: string;\n harness: DashboardHarness;\n state: TaskState;\n workspace: DashboardWorkspace;\n requests: DashboardRequest[];\n subagents: DashboardRelatedTask[];\n queuePaused: boolean;\n}\n\nexport interface DashboardDetail {\n version: 1;\n type: 'dashboard-detail';\n task: DashboardRow;\n prompt?: string;\n response?: {responseId: string; text?: string};\n error?: ErrorInfo;\n children: DashboardRelatedTask[];\n queue: {paused: boolean; tasks: DashboardRelatedTask[]};\n stopUnconfirmed: boolean;\n}\n\nexport function dashboardHarness(kind?: HarnessKind): DashboardHarness {\n if (kind === 'claudeCode') return 'claude';\n return kind ?? 'pending';\n}\n\nexport function dashboardTitle(prompt: string): string {\n const plain = sanitizeDashboardTerminalText(prompt);\n for (const line of plain.split(/\\r\\n?|\\n/u)) {\n const normalized = line\n .replace(/\\s+/gu, ' ')\n .trim();\n if (normalized) return [...normalized].slice(0, 120).join('');\n }\n return '(untitled)';\n}\n"]}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
import { loadDefinition } from '../config/loader.js';
|
|
2
2
|
import { AgentError } from '../errors.js';
|
|
3
3
|
export function harnessReference(kind, model, effort) {
|
|
4
|
+
if ((kind === 'opencode' || kind === 'copilot' || kind === 'cursor') && !model?.trim()) {
|
|
5
|
+
throw new AgentError('INVALID_CONFIG', `${kind} requires --model with an explicit nonempty model identifier.`);
|
|
6
|
+
}
|
|
7
|
+
if ((kind === 'opencode' || kind === 'copilot' || kind === 'cursor') && effort !== undefined) {
|
|
8
|
+
throw new AgentError('INVALID_ARGUMENT', `${kind} does not support --effort.`);
|
|
9
|
+
}
|
|
4
10
|
if (kind === 'claudeCode') {
|
|
5
11
|
if (effort !== undefined && effort !== 'low' && effort !== 'medium' && effort !== 'high' && effort !== 'xhigh' && effort !== 'max') {
|
|
6
12
|
throw new AgentError('INVALID_ARGUMENT', 'Claude effort must be low, medium, high, xhigh, or max.');
|
|
7
13
|
}
|
|
8
14
|
return { kind: 'harness', harness: { kind, model, effort, fast: false } };
|
|
9
15
|
}
|
|
10
|
-
|
|
16
|
+
if (kind === 'fx')
|
|
17
|
+
return { kind: 'harness', harness: { kind, model, effort } };
|
|
18
|
+
if (kind === 'codex')
|
|
19
|
+
return { kind: 'harness', harness: { kind, model, effort, fast: false } };
|
|
20
|
+
return { kind: 'harness', harness: { kind, model: model } };
|
|
11
21
|
}
|
|
12
22
|
/** Generic sessions do not import user definitions or add a specialist role. */
|
|
13
23
|
export async function loadExecutionDefinition(reference) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/runtime/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,MAAM,UAAU,gBAAgB,CAAC,IAAiB,EAAE,KAAc,EAAE,MAAe;IACjF,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACnI,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,yDAAyD,CAAC,CAAC;QACtG,CAAC;QACD,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAC,EAAC,CAAC;IACxE,CAAC;IACD,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/runtime/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK1C,MAAM,UAAU,gBAAgB,CAAC,IAAiB,EAAE,KAAc,EAAE,MAAe;IACjF,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC;QACvF,MAAM,IAAI,UAAU,CAAC,gBAAgB,EAAE,GAAG,IAAI,+DAA+D,CAAC,CAAC;IACjH,CAAC;IACD,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,CAAC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7F,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,GAAG,IAAI,6BAA6B,CAAC,CAAC;IACjF,CAAC;IACD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACnI,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,yDAAyD,CAAC,CAAC;QACtG,CAAC;QACD,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAC,EAAC,CAAC;IACxE,CAAC;IACD,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAC,EAAC,CAAC;IAC5E,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAC,EAAC,CAAC;IAC5F,OAAO,EAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAC,IAAI,EAAE,KAAK,EAAE,KAAM,EAAC,EAAC,CAAC;AAC3D,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,SAA6B;IACzE,IAAI,MAAM,IAAI,SAAS;QAAE,OAAO,cAAc,CAAC,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACpF,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;IACzF,OAAO,EAAC,IAAI,EAAE,WAAW,EAAE,kBAAkB,IAAI,WAAW,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,OAAO,EAAC,CAAC;AAC9G,CAAC","sourcesContent":["import { loadDefinition } from '../config/loader.js';\nimport { AgentError } from '../errors.js';\nimport type { ExecutionDefinition } from '../adapters/types.js';\nimport type { HarnessKind } from '../sdk/types.js';\nimport type { ExecutionReference, HarnessReference } from './types.js';\n\nexport function harnessReference(kind: HarnessKind, model?: string, effort?: string): HarnessReference {\n if ((kind === 'opencode' || kind === 'copilot' || kind === 'cursor') && !model?.trim()) {\n throw new AgentError('INVALID_CONFIG', `${kind} requires --model with an explicit nonempty model identifier.`);\n }\n if ((kind === 'opencode' || kind === 'copilot' || kind === 'cursor') && effort !== undefined) {\n throw new AgentError('INVALID_ARGUMENT', `${kind} does not support --effort.`);\n }\n if (kind === 'claudeCode') {\n if (effort !== undefined && effort !== 'low' && effort !== 'medium' && effort !== 'high' && effort !== 'xhigh' && effort !== 'max') {\n throw new AgentError('INVALID_ARGUMENT', 'Claude effort must be low, medium, high, xhigh, or max.');\n }\n return {kind: 'harness', harness: {kind, model, effort, fast: false}};\n }\n if (kind === 'fx') return {kind: 'harness', harness: {kind, model, effort}};\n if (kind === 'codex') return {kind: 'harness', harness: {kind, model, effort, fast: false}};\n return {kind: 'harness', harness: {kind, model: model!}};\n}\n\n/** Generic sessions do not import user definitions or add a specialist role. */\nexport async function loadExecutionDefinition(reference: ExecutionReference): Promise<ExecutionDefinition> {\n if ('file' in reference) return loadDefinition(reference.file, reference.subagents);\n const name = reference.harness.kind === 'claudeCode' ? 'claude' : reference.harness.kind;\n return {name, description: `Run the native ${name} harness.`, instructions: '', harness: reference.harness};\n}\n"]}
|
|
@@ -1,33 +1,51 @@
|
|
|
1
1
|
import { openCodex } from '../adapters/codex.js';
|
|
2
2
|
import { openClaude } from '../adapters/claude.js';
|
|
3
3
|
import { openFx } from '../adapters/fx.js';
|
|
4
|
+
import { openOpencode } from '../adapters/opencode.js';
|
|
5
|
+
import { openCopilot } from '../adapters/copilot.js';
|
|
6
|
+
import { openCursor } from '../adapters/cursor.js';
|
|
4
7
|
import { resolveAccess } from '../config/access.js';
|
|
8
|
+
import { accessAttemptContext } from '../config/access-provenance.js';
|
|
5
9
|
import { AgentError } from '../errors.js';
|
|
6
|
-
|
|
10
|
+
import { withAccessContext, withSessionAccessContext } from './access-errors.js';
|
|
11
|
+
const openers = {
|
|
12
|
+
codex: openCodex,
|
|
13
|
+
claudeCode: openClaude,
|
|
14
|
+
fx: openFx,
|
|
15
|
+
opencode: openOpencode,
|
|
16
|
+
copilot: openCopilot,
|
|
17
|
+
cursor: openCursor,
|
|
18
|
+
};
|
|
7
19
|
export async function selectNative(agent, cwd, env, settings, open = (options) => openers[options.harness.kind](options), selected = () => { }, onApproval) {
|
|
8
20
|
const alternatives = Array.isArray(agent.harness) ? agent.harness : [agent.harness];
|
|
9
21
|
const unavailable = [];
|
|
10
22
|
for (const harness of alternatives) {
|
|
11
23
|
const configuredConnections = settings.access?.[harness.kind];
|
|
24
|
+
const explicitAccessRequired = ['fx', 'opencode', 'copilot', 'cursor'].includes(harness.kind);
|
|
12
25
|
const connections = configuredConnections ??
|
|
13
|
-
(
|
|
26
|
+
(explicitAccessRequired ? [] : [{ type: 'subscription' }]);
|
|
14
27
|
if (configuredConnections?.length === 0) {
|
|
15
28
|
unavailable.push(`${harness.kind}: Access is disabled in the main checkout's .subharness/agents.local.json.`);
|
|
16
29
|
}
|
|
17
|
-
else if (
|
|
18
|
-
unavailable.push(
|
|
30
|
+
else if (!connections.length && explicitAccessRequired) {
|
|
31
|
+
unavailable.push(harness.kind === 'cursor'
|
|
32
|
+
? 'cursor: Enable an explicit Cursor subscription or API-key connection in personal access settings.'
|
|
33
|
+
: `${harness.kind}: Enable an explicit native login, API-key, or Gateway connection in personal access settings.`);
|
|
19
34
|
}
|
|
20
|
-
for (const connection of connections) {
|
|
35
|
+
for (const [index, connection] of connections.entries()) {
|
|
36
|
+
const context = accessAttemptContext(settings, harness.kind, connection, index, connections.length);
|
|
21
37
|
try {
|
|
22
38
|
const access = await resolveAccess(connection, harness.kind, cwd, env);
|
|
23
39
|
const native = await open({ agent, harness, cwd, env, access, ...(onApproval ? { onApproval } : {}) });
|
|
24
40
|
selected(harness.kind);
|
|
25
|
-
return native;
|
|
41
|
+
return withSessionAccessContext(native, context);
|
|
26
42
|
}
|
|
27
43
|
catch (error) {
|
|
28
|
-
if (!(error instanceof AgentError)
|
|
44
|
+
if (!(error instanceof AgentError))
|
|
29
45
|
throw error;
|
|
30
|
-
|
|
46
|
+
if (!['HARNESS_UNAVAILABLE', 'ACCESS_UNAVAILABLE'].includes(error.code))
|
|
47
|
+
throw withAccessContext(error, context);
|
|
48
|
+
unavailable.push(`${harness.kind}: ${withAccessContext(error, context).message}`);
|
|
31
49
|
}
|
|
32
50
|
}
|
|
33
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-native.js","sourceRoot":"","sources":["../../src/runtime/select-native.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAqB,MAAM,qBAAqB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"select-native.js","sourceRoot":"","sources":["../../src/runtime/select-native.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HarnessKind } from '../sdk/types.js';\nimport type { AdapterOptions, ExecutionDefinition, NativeSession } from '../adapters/types.js';\nimport { openCodex } from '../adapters/codex.js';\nimport { openClaude } from '../adapters/claude.js';\nimport { openFx } from '../adapters/fx.js';\nimport { openOpencode } from '../adapters/opencode.js';\nimport { openCopilot } from '../adapters/copilot.js';\nimport { openCursor } from '../adapters/cursor.js';\nimport { resolveAccess, type AccessConfig } from '../config/access.js';\nimport { accessAttemptContext } from '../config/access-provenance.js';\nimport { AgentError } from '../errors.js';\nimport type { ApprovalHandler } from '../approvals/types.js';\nimport { withAccessContext, withSessionAccessContext } from './access-errors.js';\n\nconst openers = {\n codex:openCodex,\n claudeCode:openClaude,\n fx:openFx,\n opencode:openOpencode,\n copilot:openCopilot,\n cursor:openCursor,\n} satisfies Record<HarnessKind, (options: AdapterOptions) => Promise<NativeSession>>;\n\nexport async function selectNative(\n agent: ExecutionDefinition, cwd: string, env: NodeJS.ProcessEnv, settings: AccessConfig,\n open = (options: AdapterOptions): Promise<NativeSession> => openers[options.harness.kind](options),\n selected: (kind: HarnessKind) => void = () => {},\n onApproval?: ApprovalHandler,\n): Promise<NativeSession> {\n const alternatives = Array.isArray(agent.harness) ? agent.harness : [agent.harness];\n const unavailable: string[] = [];\n for (const harness of alternatives) {\n const configuredConnections = settings.access?.[harness.kind as HarnessKind];\n const explicitAccessRequired = ['fx','opencode','copilot','cursor'].includes(harness.kind);\n const connections = configuredConnections ??\n (explicitAccessRequired ? [] : [{type:'subscription' as const}]);\n if (configuredConnections?.length === 0) {\n unavailable.push(`${harness.kind}: Access is disabled in the main checkout's .subharness/agents.local.json.`);\n } else if (!connections.length && explicitAccessRequired) {\n unavailable.push(harness.kind === 'cursor'\n ? 'cursor: Enable an explicit Cursor subscription or API-key connection in personal access settings.'\n : `${harness.kind}: Enable an explicit native login, API-key, or Gateway connection in personal access settings.`);\n }\n for (const [index, connection] of connections.entries()) {\n const context = accessAttemptContext(settings, harness.kind, connection, index, connections.length);\n try {\n const access = await resolveAccess(connection, harness.kind, cwd, env);\n const native = await open({agent,harness,cwd,env,access,...(onApproval ? {onApproval} : {})});\n selected(harness.kind);\n return withSessionAccessContext(native, context);\n } catch (error) {\n if (!(error instanceof AgentError)) throw error;\n if (!['HARNESS_UNAVAILABLE','ACCESS_UNAVAILABLE'].includes(error.code)) throw withAccessContext(error, context);\n unavailable.push(`${harness.kind}: ${withAccessContext(error, context).message}`);\n }\n }\n }\n throw new AgentError('ACCESS_UNAVAILABLE', unavailable.length ? unavailable.join('\\n') : 'No declared harness has enabled access.');\n}\n"]}
|
|
@@ -3,8 +3,18 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
import { delimiter } from 'node:path';
|
|
4
4
|
import { AgentError, errorInfo } from '../errors.js';
|
|
5
5
|
import { createSessionLauncher } from './session-launcher.js';
|
|
6
|
+
import { processExitDescription } from '../process-diagnostics.js';
|
|
6
7
|
const closeResponseTimeoutMs = 15_000;
|
|
7
8
|
const shutdownTimeoutMs = 1_000;
|
|
9
|
+
const workerOperationLabels = {
|
|
10
|
+
open: 'startup',
|
|
11
|
+
turn: 'turn submission',
|
|
12
|
+
steer: 'steering',
|
|
13
|
+
interrupt: 'interruption',
|
|
14
|
+
resume: 'recovery',
|
|
15
|
+
close: 'closing',
|
|
16
|
+
'approval.respond': 'approval response',
|
|
17
|
+
};
|
|
8
18
|
function waitWithin(promise, timeout) {
|
|
9
19
|
return new Promise(resolve => {
|
|
10
20
|
const timer = setTimeout(() => resolve(false), timeout);
|
|
@@ -30,9 +40,9 @@ export async function createWorker(input, options = {}) {
|
|
|
30
40
|
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
|
|
31
41
|
});
|
|
32
42
|
}
|
|
33
|
-
catch
|
|
43
|
+
catch {
|
|
34
44
|
await launcher.close();
|
|
35
|
-
throw
|
|
45
|
+
throw new AgentError('HARNESS_FAILED', 'The session worker could not be spawned during startup.');
|
|
36
46
|
}
|
|
37
47
|
let nextId = 1;
|
|
38
48
|
const pending = new Map();
|
|
@@ -40,22 +50,28 @@ export async function createWorker(input, options = {}) {
|
|
|
40
50
|
const withdrawApprovals = () => { for (const controller of approvals.values())
|
|
41
51
|
controller.abort(); approvals.clear(); };
|
|
42
52
|
let exited = false;
|
|
53
|
+
let closing = false;
|
|
54
|
+
let observedExit = '';
|
|
43
55
|
let markExited;
|
|
44
56
|
const processExit = new Promise(resolve => { markExited = resolve; });
|
|
45
|
-
const exit = () => {
|
|
57
|
+
const exit = (code, signal, spawnFailure = false) => {
|
|
46
58
|
if (exited)
|
|
47
59
|
return;
|
|
48
60
|
exited = true;
|
|
61
|
+
observedExit = spawnFailure || closing ? '' : processExitDescription(code, signal);
|
|
49
62
|
withdrawApprovals();
|
|
50
63
|
markExited();
|
|
51
64
|
void launcher.close().catch(() => { }).finally(() => {
|
|
52
|
-
for (const waiting of pending.values())
|
|
53
|
-
waiting.reject(new AgentError('HARNESS_FAILED',
|
|
65
|
+
for (const waiting of pending.values()) {
|
|
66
|
+
waiting.reject(new AgentError('HARNESS_FAILED', spawnFailure
|
|
67
|
+
? `The session worker process failed while ${waiting.operation} was pending.`
|
|
68
|
+
: `The session worker exited while ${waiting.operation} was pending${observedExit}.`));
|
|
69
|
+
}
|
|
54
70
|
pending.clear();
|
|
55
71
|
});
|
|
56
72
|
};
|
|
57
|
-
child.once('error', exit);
|
|
58
|
-
child.once('exit', exit);
|
|
73
|
+
child.once('error', () => exit(undefined, undefined, true));
|
|
74
|
+
child.once('exit', (code, signal) => exit(code, signal));
|
|
59
75
|
child.on('message', (message) => {
|
|
60
76
|
if ('event' in message) {
|
|
61
77
|
if (message.event === 'approval.withdraw') {
|
|
@@ -89,16 +105,24 @@ export async function createWorker(input, options = {}) {
|
|
|
89
105
|
waiting.resolve(message.result);
|
|
90
106
|
});
|
|
91
107
|
const request = (method, extra = {}) => new Promise((resolve, reject) => {
|
|
108
|
+
const operation = workerOperationLabels[method] ?? 'native operation';
|
|
92
109
|
if (exited) {
|
|
93
|
-
reject(new AgentError('HARNESS_FAILED',
|
|
110
|
+
reject(new AgentError('HARNESS_FAILED', `The session worker is unavailable while ${operation} was pending${observedExit}.`));
|
|
94
111
|
return;
|
|
95
112
|
}
|
|
96
113
|
const id = nextId++;
|
|
97
|
-
pending.set(id, { resolve, reject });
|
|
98
|
-
child.send({ id, method, ...extra }, error => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
114
|
+
pending.set(id, { operation, resolve, reject });
|
|
115
|
+
child.send({ id, method, ...extra }, error => {
|
|
116
|
+
if (!error)
|
|
117
|
+
return;
|
|
118
|
+
setImmediate(() => {
|
|
119
|
+
const waiting = pending.get(id);
|
|
120
|
+
if (!waiting || exited)
|
|
121
|
+
return;
|
|
122
|
+
pending.delete(id);
|
|
123
|
+
waiting.reject(new AgentError('HARNESS_FAILED', `Cannot reach the session worker while ${operation} was pending.`));
|
|
124
|
+
});
|
|
125
|
+
});
|
|
102
126
|
});
|
|
103
127
|
let selectedHarness;
|
|
104
128
|
const { onApproval, ...serializedInput } = input;
|
|
@@ -136,6 +160,7 @@ export async function createWorker(input, options = {}) {
|
|
|
136
160
|
interrupt: async () => { withdrawApprovals(); await request('interrupt'); },
|
|
137
161
|
resume: () => request('resume'),
|
|
138
162
|
close: async () => {
|
|
163
|
+
closing = true;
|
|
139
164
|
withdrawApprovals();
|
|
140
165
|
let failure;
|
|
141
166
|
if (!exited) {
|