subharness 0.0.4 → 0.0.7
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 +95 -9
- package/dist/adapters/claude-process.d.ts +3 -0
- package/dist/adapters/claude-process.js +19 -2
- 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-tools.d.ts +6 -2
- package/dist/adapters/claude-tools.js +14 -12
- package/dist/adapters/claude-tools.js.map +1 -1
- package/dist/adapters/claude-worker-client.d.ts +49 -0
- package/dist/adapters/claude-worker-client.js +359 -0
- package/dist/adapters/claude-worker-client.js.map +1 -0
- package/dist/adapters/claude-worker-process.d.ts +20 -0
- package/dist/adapters/claude-worker-process.js +76 -0
- package/dist/adapters/claude-worker-process.js.map +1 -0
- package/dist/adapters/claude-worker-protocol.d.ts +38 -0
- package/dist/adapters/claude-worker-protocol.js +2 -0
- package/dist/adapters/claude-worker-protocol.js.map +1 -0
- package/dist/adapters/claude-worker.d.ts +1 -0
- package/dist/adapters/claude-worker.js +126 -0
- package/dist/adapters/claude-worker.js.map +1 -0
- package/dist/adapters/claude.d.ts +16 -6
- package/dist/adapters/claude.js +164 -75
- 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/catalog-worker.js.map +1 -1
- package/dist/cli/dashboard-client.js +20 -31
- 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 +55 -43
- 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/errors.d.ts +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +8 -2
- package/dist/index.js +4 -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.d.ts +9 -0
- package/dist/runtime/approval-registry.js +144 -5
- package/dist/runtime/approval-registry.js.map +1 -1
- package/dist/runtime/capture.d.ts +22 -0
- package/dist/runtime/capture.js +320 -0
- package/dist/runtime/capture.js.map +1 -0
- package/dist/runtime/catalog.d.ts +39 -0
- package/dist/runtime/catalog.js +84 -0
- package/dist/runtime/catalog.js.map +1 -0
- package/dist/runtime/client.d.ts +2 -1
- package/dist/runtime/client.js +74 -47
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/coordinator.d.ts +44 -7
- package/dist/runtime/coordinator.js +265 -31
- package/dist/runtime/coordinator.js.map +1 -1
- package/dist/runtime/daemon.js +12 -6
- package/dist/runtime/daemon.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-workspace.js +5 -1
- package/dist/runtime/dashboard-workspace.js.map +1 -1
- 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.d.ts +6 -1
- package/dist/runtime/definition.js +42 -2
- package/dist/runtime/definition.js.map +1 -1
- package/dist/runtime/native-owner.js +7 -1
- package/dist/runtime/native-owner.js.map +1 -1
- package/dist/runtime/pagination.d.ts +9 -0
- package/dist/runtime/pagination.js +36 -0
- package/dist/runtime/pagination.js.map +1 -0
- package/dist/runtime/sdk-observation.d.ts +8 -0
- package/dist/runtime/sdk-observation.js +75 -0
- package/dist/runtime/sdk-observation.js.map +1 -0
- package/dist/runtime/sdk-projection.d.ts +8 -0
- package/dist/runtime/sdk-projection.js +19 -0
- package/dist/runtime/sdk-projection.js.map +1 -0
- package/dist/runtime/sdk-service.d.ts +11 -0
- package/dist/runtime/sdk-service.js +109 -0
- package/dist/runtime/sdk-service.js.map +1 -0
- package/dist/runtime/select-native.d.ts +4 -1
- package/dist/runtime/select-native.js +28 -13
- package/dist/runtime/select-native.js.map +1 -1
- package/dist/runtime/service.d.ts +11 -1
- package/dist/runtime/service.js +178 -3
- package/dist/runtime/service.js.map +1 -1
- package/dist/runtime/session-launcher.js +1 -1
- package/dist/runtime/session-launcher.js.map +1 -1
- package/dist/runtime/snapshots.d.ts +103 -0
- package/dist/runtime/snapshots.js +124 -0
- package/dist/runtime/snapshots.js.map +1 -0
- package/dist/runtime/state.d.ts +26 -0
- package/dist/runtime/state.js +86 -17
- package/dist/runtime/state.js.map +1 -1
- package/dist/runtime/task-data.d.ts +38 -0
- package/dist/runtime/task-data.js +2 -0
- package/dist/runtime/task-data.js.map +1 -0
- package/dist/runtime/transport.d.ts +13 -0
- package/dist/runtime/transport.js +166 -0
- package/dist/runtime/transport.js.map +1 -0
- package/dist/runtime/types.d.ts +28 -9
- package/dist/runtime/types.js.map +1 -1
- package/dist/runtime/worker-client.js +40 -13
- package/dist/runtime/worker-client.js.map +1 -1
- package/dist/runtime/worker-server.js +105 -24
- package/dist/runtime/worker-server.js.map +1 -1
- package/dist/sdk/connected-types.d.ts +42 -0
- package/dist/sdk/connected-types.js +2 -0
- package/dist/sdk/connected-types.js.map +1 -0
- package/dist/sdk/connected.d.ts +3 -0
- package/dist/sdk/connected.js +232 -0
- package/dist/sdk/connected.js.map +1 -0
- 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/execution-definition.d.ts +3 -0
- package/dist/sdk/execution-definition.js +59 -0
- package/dist/sdk/execution-definition.js.map +1 -0
- package/dist/sdk/execution-driver.d.ts +6 -0
- package/dist/sdk/execution-driver.js +86 -0
- package/dist/sdk/execution-driver.js.map +1 -0
- package/dist/sdk/execution-observation.d.ts +3 -0
- package/dist/sdk/execution-observation.js +35 -0
- package/dist/sdk/execution-observation.js.map +1 -0
- package/dist/sdk/execution-options.d.ts +17 -0
- package/dist/sdk/execution-options.js +115 -0
- package/dist/sdk/execution-options.js.map +1 -0
- package/dist/sdk/execution-types.d.ts +72 -0
- package/dist/sdk/execution-types.js +2 -0
- package/dist/sdk/execution-types.js.map +1 -0
- package/dist/sdk/execution.d.ts +3 -0
- package/dist/sdk/execution.js +3 -0
- package/dist/sdk/execution.js.map +1 -0
- package/dist/sdk/hosted-error.d.ts +3 -0
- package/dist/sdk/hosted-error.js +14 -0
- package/dist/sdk/hosted-error.js.map +1 -0
- package/dist/sdk/hosted.d.ts +23 -0
- package/dist/sdk/hosted.js +204 -0
- package/dist/sdk/hosted.js.map +1 -0
- package/dist/sdk/permission-validation.js +10 -1
- package/dist/sdk/permission-validation.js.map +1 -1
- package/dist/sdk/runner.d.ts +5 -0
- package/dist/sdk/runner.js +107 -0
- package/dist/sdk/runner.js.map +1 -0
- package/dist/sdk/tools.js +4 -1
- package/dist/sdk/tools.js.map +1 -1
- package/dist/sdk/types.d.ts +29 -1
- package/dist/sdk/types.js.map +1 -1
- package/package.json +6 -3
- package/sdk/access-config.md +60 -4
- package/sdk/adapter-contract.md +13 -3
- package/sdk/additional-harnesses.md +43 -0
- package/sdk/agent-skill.md +2 -2
- package/sdk/agent.md +6 -4
- package/sdk/approvals.md +5 -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/completion-notifications.md +2 -0
- 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 +5 -3
- package/sdk/evals.md +1 -1
- package/sdk/examples/chat-tool.ts +126 -0
- package/sdk/execution.md +743 -0
- package/sdk/fx.md +50 -5
- package/sdk/harnesses.md +13 -13
- package/sdk/index.md +45 -20
- package/sdk/message-delivery.md +2 -0
- package/sdk/opencode.md +57 -0
- package/sdk/permissions.md +6 -2
- package/sdk/plugins/sub-agents.md +4 -2
- package/sdk/project-team.md +25 -1
- package/sdk/sessions.md +2 -0
- package/sdk/tools.md +4 -2
- package/sdk/v1-runtime.md +8 -6
- package/dist/cli/catalog.d.ts +0 -26
- package/dist/cli/catalog.js +0 -41
- package/dist/cli/catalog.js.map +0 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parentPort } from "node:worker_threads";
|
|
2
|
+
import { createSdkMcpServer, query, resolveSettings, } from "@anthropic-ai/claude-agent-sdk";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { ClaudeInput } from "./claude-input.js";
|
|
5
|
+
import { ClaudeRemoteProcess } from "./claude-worker-process.js";
|
|
6
|
+
if (!parentPort)
|
|
7
|
+
throw new Error("Claude worker requires a parent port.");
|
|
8
|
+
const port = parentPort;
|
|
9
|
+
let nextId = 1;
|
|
10
|
+
const pending = new Map();
|
|
11
|
+
const input = new ClaudeInput();
|
|
12
|
+
let native;
|
|
13
|
+
let processProxy;
|
|
14
|
+
function hostRequest(operation, value) {
|
|
15
|
+
const id = nextId++;
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
pending.set(id, { resolve, reject });
|
|
18
|
+
port.postMessage({ type: "host-request", id, operation, value });
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function serializableMetadata(value) {
|
|
22
|
+
const { signal: _signal, ...metadata } = value;
|
|
23
|
+
return metadata;
|
|
24
|
+
}
|
|
25
|
+
function abortableHostRequest(operation, value, signal) {
|
|
26
|
+
const id = nextId++;
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
pending.set(id, { resolve, reject });
|
|
29
|
+
port.postMessage({ type: "host-request", id, operation, value });
|
|
30
|
+
const abort = () => port.postMessage({ type: "event", event: "hostRequestAbort", value: id });
|
|
31
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
32
|
+
if (signal.aborted)
|
|
33
|
+
abort();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function mcpServer(namespace, tools) {
|
|
37
|
+
if (!tools.length)
|
|
38
|
+
return undefined;
|
|
39
|
+
// An explicit empty list enables the MCP tool capability before the worker
|
|
40
|
+
// installs descriptor-driven low-level handlers.
|
|
41
|
+
const server = createSdkMcpServer({ name: namespace, version: "1.0.0", tools: [] });
|
|
42
|
+
server.instance.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
43
|
+
server.instance.server.setRequestHandler(CallToolRequestSchema, async (request) => await hostRequest("toolCall", { name: request.params.name, input: request.params.arguments }));
|
|
44
|
+
return server;
|
|
45
|
+
}
|
|
46
|
+
async function start(value) {
|
|
47
|
+
const server = mcpServer(value.namespace, value.tools);
|
|
48
|
+
const options = value.options;
|
|
49
|
+
const canUseTool = async (toolName, toolInput, metadata) => await abortableHostRequest("approval", { toolName, toolInput, metadata: serializableMetadata(metadata) }, metadata.signal);
|
|
50
|
+
native = query({ prompt: input, options: {
|
|
51
|
+
...options,
|
|
52
|
+
...(server ? { mcpServers: { [value.namespace]: server } } : {}),
|
|
53
|
+
spawnClaudeCodeProcess(spawnOptions) {
|
|
54
|
+
processProxy = new ClaudeRemoteProcess(hostRequest, spawnOptions);
|
|
55
|
+
return processProxy;
|
|
56
|
+
},
|
|
57
|
+
canUseTool,
|
|
58
|
+
onElicitation: async (request, metadata) => await abortableHostRequest("elicitation", { request, metadata: serializableMetadata(metadata) }, metadata.signal),
|
|
59
|
+
stderr: () => { },
|
|
60
|
+
} });
|
|
61
|
+
void (async () => {
|
|
62
|
+
try {
|
|
63
|
+
for await (const message of native)
|
|
64
|
+
port.postMessage({ type: "event", event: "message", value: message });
|
|
65
|
+
port.postMessage({ type: "event", event: "end" });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
port.postMessage({ type: "event", event: "failure", value: "native stream" });
|
|
69
|
+
}
|
|
70
|
+
})();
|
|
71
|
+
}
|
|
72
|
+
async function perform(message) {
|
|
73
|
+
switch (message.operation) {
|
|
74
|
+
case "managedSettings": {
|
|
75
|
+
const settings = await resolveSettings({ cwd: String(message.value), settingSources: ["user", "project", "local"] });
|
|
76
|
+
return settings.sources.filter(source => source.source === "managed").map(source => source.settings);
|
|
77
|
+
}
|
|
78
|
+
case "start":
|
|
79
|
+
await start(message.value);
|
|
80
|
+
return undefined;
|
|
81
|
+
case "accountInfo": return await native.accountInfo();
|
|
82
|
+
case "supportedModels": return await native.supportedModels();
|
|
83
|
+
case "getSettings": return await native.getSettings?.();
|
|
84
|
+
case "setModel": return await native.setModel?.(message.value);
|
|
85
|
+
case "interrupt": return await native.interrupt();
|
|
86
|
+
default: throw new Error("Unknown Claude worker operation.");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
port.on("message", (message) => {
|
|
90
|
+
if (message.type === "host-response") {
|
|
91
|
+
const current = pending.get(message.id);
|
|
92
|
+
if (!current)
|
|
93
|
+
return;
|
|
94
|
+
pending.delete(message.id);
|
|
95
|
+
if (message.ok)
|
|
96
|
+
current.resolve(message.value);
|
|
97
|
+
else
|
|
98
|
+
current.reject(new Error("Claude host bridge failed."));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (message.type === "event") {
|
|
102
|
+
if (message.event === "input")
|
|
103
|
+
input.push(message.value);
|
|
104
|
+
else if (message.event === "inputEnd")
|
|
105
|
+
input.close();
|
|
106
|
+
else if (message.event === "close") {
|
|
107
|
+
input.close();
|
|
108
|
+
native?.close();
|
|
109
|
+
}
|
|
110
|
+
else if (message.event === "processExit") {
|
|
111
|
+
const value = message.value;
|
|
112
|
+
processProxy?.exited(value.code, value.signal);
|
|
113
|
+
}
|
|
114
|
+
else if (message.event === "processError")
|
|
115
|
+
processProxy?.failed();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (message.type !== "request")
|
|
119
|
+
return;
|
|
120
|
+
void perform(message).then(value => port.postMessage({ type: "response", id: message.id, ok: true, value }), error => {
|
|
121
|
+
const settingsUnavailable = message.operation === "getSettings" && error instanceof Error
|
|
122
|
+
&& /^(?:unknown|unsupported) control request(?: subtype)?:\s*get_settings\.?$/iu.test(error.message.trim());
|
|
123
|
+
port.postMessage({ type: "response", id: message.id, ok: false, ...(settingsUnavailable ? { failure: "settings-unavailable" } : {}) });
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=claude-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-worker.js","sourceRoot":"","sources":["../../src/adapters/claude-worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { parentPort } from \"node:worker_threads\";\nimport {\n createSdkMcpServer,\n query,\n resolveSettings,\n type CanUseTool,\n type Options,\n type SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport type { ClaudeQuery } from \"./claude.ts\";\nimport { CallToolRequestSchema, ListToolsRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport { ClaudeInput } from \"./claude-input.ts\";\nimport { ClaudeRemoteProcess } from \"./claude-worker-process.ts\";\nimport type {\n ClaudeBridgeMessage,\n ClaudeToolDescriptor,\n ClaudeWorkerRequest,\n} from \"./claude-worker-protocol.ts\";\n\nif (!parentPort) throw new Error(\"Claude worker requires a parent port.\");\nconst port = parentPort;\nlet nextId = 1;\nconst pending = new Map<number, {resolve(value: unknown): void; reject(error: Error): void}>();\nconst input = new ClaudeInput<SDKUserMessage>();\nlet native: ClaudeQuery | undefined;\nlet processProxy: ClaudeRemoteProcess | undefined;\n\nfunction hostRequest(operation: string, value?: unknown): Promise<unknown> {\n const id = nextId++;\n return new Promise((resolve, reject) => {\n pending.set(id, {resolve, reject});\n port.postMessage({type:\"host-request\", id, operation, value} satisfies ClaudeBridgeMessage);\n });\n}\n\nfunction serializableMetadata(value: Record<string, unknown>): Record<string, unknown> {\n const {signal: _signal, ...metadata} = value;\n return metadata;\n}\n\nfunction abortableHostRequest(operation: string, value: unknown, signal: AbortSignal): Promise<unknown> {\n const id = nextId++;\n return new Promise((resolve, reject) => {\n pending.set(id, {resolve, reject});\n port.postMessage({type:\"host-request\", id, operation, value} satisfies ClaudeBridgeMessage);\n const abort = () => port.postMessage({type:\"event\", event:\"hostRequestAbort\", value:id} satisfies ClaudeBridgeMessage);\n signal.addEventListener(\"abort\", abort, {once:true});\n if (signal.aborted) abort();\n });\n}\n\nfunction mcpServer(namespace: string, tools: readonly ClaudeToolDescriptor[]) {\n if (!tools.length) return undefined;\n // An explicit empty list enables the MCP tool capability before the worker\n // installs descriptor-driven low-level handlers.\n const server = createSdkMcpServer({name:namespace, version:\"1.0.0\", tools:[]});\n server.instance.server.setRequestHandler(ListToolsRequestSchema, async () => ({tools}));\n server.instance.server.setRequestHandler(CallToolRequestSchema, async request =>\n await hostRequest(\"toolCall\", {name:request.params.name, input:request.params.arguments}) as any);\n return server;\n}\n\nasync function start(value: any): Promise<void> {\n const server = mcpServer(value.namespace, value.tools);\n const options = value.options as Options;\n const canUseTool: CanUseTool = async (toolName, toolInput, metadata) => await abortableHostRequest(\n \"approval\", {toolName, toolInput, metadata:serializableMetadata(metadata as unknown as Record<string, unknown>)}, metadata.signal,\n ) as Awaited<ReturnType<CanUseTool>>;\n native = query({prompt:input, options:{\n ...options,\n ...(server ? {mcpServers:{[value.namespace]:server}} : {}),\n spawnClaudeCodeProcess(spawnOptions) {\n processProxy = new ClaudeRemoteProcess(hostRequest, spawnOptions);\n return processProxy;\n },\n canUseTool,\n onElicitation: async (request, metadata) => await abortableHostRequest(\n \"elicitation\", {request, metadata:serializableMetadata(metadata as unknown as Record<string, unknown>)}, metadata.signal,\n ) as any,\n stderr: () => {},\n }}) as ClaudeQuery;\n void (async () => {\n try {\n for await (const message of native!) port.postMessage({type:\"event\",event:\"message\",value:message} satisfies ClaudeBridgeMessage);\n port.postMessage({type:\"event\",event:\"end\"} satisfies ClaudeBridgeMessage);\n } catch {\n port.postMessage({type:\"event\",event:\"failure\",value:\"native stream\"} satisfies ClaudeBridgeMessage);\n }\n })();\n}\n\nasync function perform(message: ClaudeWorkerRequest): Promise<unknown> {\n switch (message.operation) {\n case \"managedSettings\": {\n const settings = await resolveSettings({cwd:String(message.value), settingSources:[\"user\",\"project\",\"local\"]});\n return settings.sources.filter(source => source.source === \"managed\").map(source => source.settings);\n }\n case \"start\": await start(message.value); return undefined;\n case \"accountInfo\": return await native!.accountInfo();\n case \"supportedModels\": return await native!.supportedModels();\n case \"getSettings\": return await native!.getSettings?.();\n case \"setModel\": return await native!.setModel?.(message.value as string | undefined);\n case \"interrupt\": return await native!.interrupt();\n default: throw new Error(\"Unknown Claude worker operation.\");\n }\n}\n\nport.on(\"message\", (message: ClaudeBridgeMessage) => {\n if (message.type === \"host-response\") {\n const current = pending.get(message.id);\n if (!current) return;\n pending.delete(message.id);\n if (message.ok) current.resolve(message.value); else current.reject(new Error(\"Claude host bridge failed.\"));\n return;\n }\n if (message.type === \"event\") {\n if (message.event === \"input\") input.push(message.value as SDKUserMessage);\n else if (message.event === \"inputEnd\") input.close();\n else if (message.event === \"close\") { input.close(); native?.close(); }\n else if (message.event === \"processExit\") {\n const value = message.value as {code:number|null; signal:NodeJS.Signals|null};\n processProxy?.exited(value.code, value.signal);\n } else if (message.event === \"processError\") processProxy?.failed();\n return;\n }\n if (message.type !== \"request\") return;\n void perform(message).then(\n value => port.postMessage({type:\"response\",id:message.id,ok:true,value} satisfies ClaudeBridgeMessage),\n error => {\n const settingsUnavailable = message.operation === \"getSettings\" && error instanceof Error\n && /^(?:unknown|unsupported) control request(?: subtype)?:\\s*get_settings\\.?$/iu.test(error.message.trim());\n port.postMessage({type:\"response\",id:message.id,ok:false,...(settingsUnavailable ? {failure:\"settings-unavailable\" as const} : {})} satisfies ClaudeBridgeMessage);\n },\n );\n});\n"]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AccountInfo, Options, SDKMessage, SDKUserMessage, Settings, ModelInfo } from "@anthropic-ai/claude-agent-sdk";
|
|
2
2
|
import type { AdapterOptions, NativeSession } from "./types.js";
|
|
3
|
-
|
|
3
|
+
import { claudeTools } from "./claude-tools.js";
|
|
4
|
+
import { ClaudeProcessOwner } from "./claude-process.js";
|
|
5
|
+
import type { ClaudeWorkerFactory } from "./claude-worker-protocol.js";
|
|
6
|
+
export interface ClaudeQuery extends AsyncIterable<SDKMessage> {
|
|
4
7
|
accountInfo(): Promise<AccountInfo>;
|
|
5
8
|
supportedModels(): Promise<ModelInfo[]>;
|
|
6
9
|
interrupt(): Promise<unknown>;
|
|
@@ -8,15 +11,22 @@ interface ClaudeQuery extends AsyncIterable<SDKMessage> {
|
|
|
8
11
|
getSettings?(): Promise<unknown>;
|
|
9
12
|
setModel?(model?: string): Promise<void>;
|
|
10
13
|
}
|
|
14
|
+
export interface ClaudeQueryBridge {
|
|
15
|
+
readonly tools: ReturnType<typeof claudeTools>;
|
|
16
|
+
readonly processOwner: ClaudeProcessOwner;
|
|
17
|
+
}
|
|
11
18
|
export interface ClaudeDependencies {
|
|
12
19
|
query(args: {
|
|
13
20
|
prompt: AsyncIterable<SDKUserMessage>;
|
|
14
21
|
options: Options;
|
|
15
|
-
}): ClaudeQuery
|
|
22
|
+
}, bridge: ClaudeQueryBridge): ClaudeQuery | Promise<ClaudeQuery>;
|
|
16
23
|
executable(env: NodeJS.ProcessEnv): Promise<string>;
|
|
17
24
|
managedSettings(cwd: string): Promise<Settings[]>;
|
|
25
|
+
dispose?(): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export interface ClaudeOpenerOptions {
|
|
28
|
+
readonly createWorker?: ClaudeWorkerFactory;
|
|
18
29
|
}
|
|
19
30
|
export declare const openClaude: (options: AdapterOptions) => Promise<NativeSession>;
|
|
20
|
-
/** Dependency injection is internal and replaces only
|
|
21
|
-
export declare function createClaudeOpener(
|
|
22
|
-
export {};
|
|
31
|
+
/** Dependency injection is internal and replaces only private process boundaries in tests. */
|
|
32
|
+
export declare function createClaudeOpener(configuration?: ClaudeDependencies | ClaudeOpenerOptions): (options: AdapterOptions) => Promise<NativeSession>;
|
package/dist/adapters/claude.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
2
|
-
import { constants } from "node:fs";
|
|
3
|
-
import { delimiter, join } from "node:path";
|
|
4
1
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { query, resolveSettings } from "@anthropic-ai/claude-agent-sdk";
|
|
6
2
|
import { AgentError } from "../errors.js";
|
|
7
3
|
import { privateClaudeConfig } from "./claude-config.js";
|
|
8
4
|
import { claudeTools } from "./claude-tools.js";
|
|
@@ -13,24 +9,8 @@ import { ClaudeSettingsUnavailable, claudeDefaultUnavailable, readClaudeAppliedS
|
|
|
13
9
|
import { NativeApprovals } from "./approval-lifetime.js";
|
|
14
10
|
import { claudeApproval } from "./claude-approvals.js";
|
|
15
11
|
import { ClaudeProcessOwner } from "./claude-process.js";
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async managedSettings(cwd) {
|
|
19
|
-
const settings = await resolveSettings({ cwd, settingSources: ["user", "project", "local"] });
|
|
20
|
-
return settings.sources.filter(source => source.source === "managed").map(source => source.settings);
|
|
21
|
-
},
|
|
22
|
-
async executable(env) {
|
|
23
|
-
for (const directory of (env.PATH ?? "").split(delimiter)) {
|
|
24
|
-
const file = join(directory, "claude");
|
|
25
|
-
try {
|
|
26
|
-
await access(file, constants.X_OK);
|
|
27
|
-
return file;
|
|
28
|
-
}
|
|
29
|
-
catch { /* Try the next PATH entry. */ }
|
|
30
|
-
}
|
|
31
|
-
throw new AgentError("HARNESS_UNAVAILABLE", "Install Claude Code and make claude available on PATH.");
|
|
32
|
-
},
|
|
33
|
-
};
|
|
12
|
+
import { claudeResultFailure } from "./claude-result.js";
|
|
13
|
+
import { ClaudeWorkerClient } from "./claude-worker-client.js";
|
|
34
14
|
function addCatalogEquivalentModels(expected, models, selected) {
|
|
35
15
|
expected.add(selected);
|
|
36
16
|
for (const model of models) {
|
|
@@ -41,9 +21,33 @@ function addCatalogEquivalentModels(expected, models, selected) {
|
|
|
41
21
|
expected.add(model.resolvedModel);
|
|
42
22
|
}
|
|
43
23
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
24
|
+
function injectedDependencies(value) {
|
|
25
|
+
return "query" in value;
|
|
26
|
+
}
|
|
27
|
+
export const openClaude = createClaudeOpener();
|
|
28
|
+
/** Dependency injection is internal and replaces only private process boundaries in tests. */
|
|
29
|
+
export function createClaudeOpener(configuration = {}) {
|
|
30
|
+
if (injectedDependencies(configuration))
|
|
31
|
+
return openClaudeWithDependencies(configuration);
|
|
32
|
+
return async (options) => {
|
|
33
|
+
const client = new ClaudeWorkerClient(options.env, configuration);
|
|
34
|
+
try {
|
|
35
|
+
return await openClaudeWithDependencies(client.dependencies)(options);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
try {
|
|
39
|
+
await client.dispose();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
const startup = error instanceof AgentError || error instanceof AggregateError
|
|
43
|
+
? error : new AgentError("HARNESS_FAILED", "Claude Code startup failed.");
|
|
44
|
+
throw new AggregateError([startup, new AgentError("HARNESS_FAILED", "Claude Code worker cleanup failed.")], "Claude Code startup and cleanup failed.");
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function openClaudeWithDependencies(deps) {
|
|
47
51
|
return async (options) => {
|
|
48
52
|
if (options.harness.kind !== "claudeCode")
|
|
49
53
|
throw new AgentError("INVALID_CONFIG", "Claude Code received configuration for a different harness.");
|
|
@@ -54,12 +58,50 @@ export function createClaudeOpener(deps) {
|
|
|
54
58
|
const tools = claudeTools(options.agent);
|
|
55
59
|
const allowedTools = [
|
|
56
60
|
...(options.harness.allowedTools ?? []),
|
|
57
|
-
...
|
|
61
|
+
...tools.allowedTools,
|
|
58
62
|
...claudeDelegationPermissions(options),
|
|
59
63
|
];
|
|
60
64
|
const config = await privateClaudeConfig(settings.settings);
|
|
61
65
|
const input = new ClaudeInput();
|
|
62
66
|
const processOwner = new ClaudeProcessOwner();
|
|
67
|
+
let cleanupComplete = false;
|
|
68
|
+
let cleanupAttempt;
|
|
69
|
+
const cleanupResources = () => {
|
|
70
|
+
if (cleanupComplete)
|
|
71
|
+
return Promise.resolve();
|
|
72
|
+
if (cleanupAttempt)
|
|
73
|
+
return cleanupAttempt;
|
|
74
|
+
cleanupAttempt = (async () => {
|
|
75
|
+
const failures = [];
|
|
76
|
+
try {
|
|
77
|
+
await processOwner.close();
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
failures.push(error instanceof AgentError ? error : new AgentError("HARNESS_FAILED", "Claude Code process cleanup failed."));
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
await config.cleanup();
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
failures.push(new AgentError("HARNESS_FAILED", "Claude Code private configuration cleanup failed."));
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await deps.dispose?.();
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
failures.push(error instanceof AgentError ? error : new AgentError("HARNESS_FAILED", "Claude Code worker cleanup failed."));
|
|
93
|
+
}
|
|
94
|
+
if (failures.length === 1)
|
|
95
|
+
throw failures[0];
|
|
96
|
+
if (failures.length > 1)
|
|
97
|
+
throw new AggregateError(failures, "Claude Code cleanup failed.");
|
|
98
|
+
cleanupComplete = true;
|
|
99
|
+
})().catch(error => {
|
|
100
|
+
cleanupAttempt = undefined;
|
|
101
|
+
throw error;
|
|
102
|
+
});
|
|
103
|
+
return cleanupAttempt;
|
|
104
|
+
};
|
|
63
105
|
let inputFailure;
|
|
64
106
|
const approvals = new NativeApprovals();
|
|
65
107
|
let acceptingApprovals = false;
|
|
@@ -74,12 +116,11 @@ export function createClaudeOpener(deps) {
|
|
|
74
116
|
};
|
|
75
117
|
let native;
|
|
76
118
|
try {
|
|
77
|
-
native = deps.query({ prompt: input, options: {
|
|
119
|
+
native = await deps.query({ prompt: input, options: {
|
|
78
120
|
pathToClaudeCodeExecutable: executable,
|
|
79
121
|
spawnClaudeCodeProcess: processOwner.spawn,
|
|
80
122
|
cwd: options.cwd,
|
|
81
123
|
...settings,
|
|
82
|
-
...tools.config,
|
|
83
124
|
...(allowedTools.length ? { allowedTools } : {}),
|
|
84
125
|
...(options.harness.disallowedTools !== undefined ? { disallowedTools: [...options.harness.disallowedTools] } : {}),
|
|
85
126
|
...(permissionMode !== undefined ? { permissionMode } : {}),
|
|
@@ -119,30 +160,37 @@ export function createClaudeOpener(deps) {
|
|
|
119
160
|
}
|
|
120
161
|
return { action: "decline" };
|
|
121
162
|
},
|
|
122
|
-
} });
|
|
163
|
+
} }, { tools, processOwner });
|
|
123
164
|
}
|
|
124
|
-
catch {
|
|
165
|
+
catch (error) {
|
|
166
|
+
const exit = processOwner.exitDescription();
|
|
125
167
|
input.close();
|
|
168
|
+
const failure = error instanceof AgentError && error.code === "HARNESS_FAILED"
|
|
169
|
+
? error : new AgentError("HARNESS_UNAVAILABLE", `Claude Code could not start${exit}.`);
|
|
126
170
|
try {
|
|
127
|
-
await
|
|
171
|
+
await cleanupResources();
|
|
128
172
|
}
|
|
129
|
-
|
|
130
|
-
|
|
173
|
+
catch (cleanupError) {
|
|
174
|
+
throw new AggregateError([failure, cleanupError], "Claude Code startup and cleanup failed.");
|
|
131
175
|
}
|
|
132
|
-
throw
|
|
176
|
+
throw failure;
|
|
133
177
|
}
|
|
134
178
|
const expectedModels = new Set();
|
|
135
179
|
let retainedModel;
|
|
180
|
+
let startupPhase = "account inspection";
|
|
136
181
|
try {
|
|
137
|
-
|
|
182
|
+
const account = await native.accountInfo();
|
|
183
|
+
verifyClaudeAccess(account, options.access);
|
|
184
|
+
startupPhase = "model catalog retrieval";
|
|
138
185
|
const models = await native.supportedModels();
|
|
139
186
|
if (options.harness.model) {
|
|
140
187
|
addCatalogEquivalentModels(expectedModels, models, options.harness.model);
|
|
141
188
|
verifyClaudeOptions(models, options);
|
|
189
|
+
startupPhase = "model settings validation";
|
|
142
190
|
try {
|
|
143
191
|
const applied = await readClaudeAppliedSettings(native);
|
|
144
192
|
if (!expectedModels.has(applied.model))
|
|
145
|
-
throw new AgentError("INVALID_CONFIG", "Claude Code selected a different model than requested.");
|
|
193
|
+
throw new AgentError("INVALID_CONFIG", "Claude Code selected a different model than requested during startup settings validation.");
|
|
146
194
|
verifyAppliedClaudeEffort(applied.effort, options.harness.effort);
|
|
147
195
|
retainedModel = applied.model;
|
|
148
196
|
expectedModels.add(applied.model);
|
|
@@ -153,6 +201,7 @@ export function createClaudeOpener(deps) {
|
|
|
153
201
|
}
|
|
154
202
|
}
|
|
155
203
|
else {
|
|
204
|
+
startupPhase = "model settings validation";
|
|
156
205
|
if (!native.getSettings || !native.setModel)
|
|
157
206
|
throw claudeDefaultUnavailable();
|
|
158
207
|
let selected;
|
|
@@ -164,9 +213,13 @@ export function createClaudeOpener(deps) {
|
|
|
164
213
|
throw claudeDefaultUnavailable();
|
|
165
214
|
throw error;
|
|
166
215
|
}
|
|
216
|
+
startupPhase = "model catalog retrieval";
|
|
167
217
|
verifyClaudeOptions(models, options, selected.model);
|
|
218
|
+
startupPhase = "model settings validation";
|
|
168
219
|
verifyAppliedClaudeEffort(selected.effort, options.harness.effort);
|
|
220
|
+
startupPhase = "model catalog retrieval";
|
|
169
221
|
addCatalogEquivalentModels(expectedModels, models, selected.model);
|
|
222
|
+
startupPhase = "model settings validation";
|
|
170
223
|
try {
|
|
171
224
|
await native.setModel(selected.model);
|
|
172
225
|
}
|
|
@@ -182,38 +235,43 @@ export function createClaudeOpener(deps) {
|
|
|
182
235
|
throw claudeDefaultUnavailable();
|
|
183
236
|
throw error;
|
|
184
237
|
}
|
|
185
|
-
if (!expectedModels.has(pinned.model))
|
|
186
|
-
throw
|
|
238
|
+
if (!expectedModels.has(pinned.model)) {
|
|
239
|
+
throw new AgentError("INVALID_CONFIG", "Claude Code changed the selected native default during startup settings validation. Supply --model <model>.");
|
|
240
|
+
}
|
|
187
241
|
verifyAppliedClaudeEffort(pinned.effort, options.harness.effort);
|
|
188
242
|
retainedModel = pinned.model;
|
|
243
|
+
startupPhase = "model catalog retrieval";
|
|
189
244
|
addCatalogEquivalentModels(expectedModels, models, pinned.model);
|
|
245
|
+
startupPhase = "model settings validation";
|
|
190
246
|
}
|
|
191
247
|
if (inputFailure)
|
|
192
248
|
throw inputFailure;
|
|
193
249
|
}
|
|
194
250
|
catch (error) {
|
|
251
|
+
const exit = processOwner.exitDescription();
|
|
195
252
|
input.close();
|
|
196
253
|
native.close();
|
|
254
|
+
const failure = error instanceof AgentError ? error
|
|
255
|
+
: new AgentError("HARNESS_FAILED", `Claude Code ${startupPhase} failed${exit}.`);
|
|
197
256
|
try {
|
|
198
|
-
await
|
|
257
|
+
await cleanupResources();
|
|
199
258
|
}
|
|
200
|
-
|
|
201
|
-
|
|
259
|
+
catch (cleanupError) {
|
|
260
|
+
throw new AggregateError([failure, cleanupError], "Claude Code startup and cleanup failed.");
|
|
202
261
|
}
|
|
203
|
-
|
|
204
|
-
throw error;
|
|
205
|
-
throw new AgentError("ACCESS_UNAVAILABLE", "Claude Code authentication could not be verified.");
|
|
262
|
+
throw failure;
|
|
206
263
|
}
|
|
207
264
|
let closed = false;
|
|
208
265
|
let preflight;
|
|
209
266
|
let sessionFailure;
|
|
267
|
+
let exitObservedBeforeClose;
|
|
210
268
|
let active;
|
|
211
269
|
const reading = (async () => {
|
|
212
270
|
try {
|
|
213
271
|
for await (const message of native) {
|
|
214
272
|
if (message.type === "system" && message.subtype === "init") {
|
|
215
273
|
if (!expectedModels.has(message.model)) {
|
|
216
|
-
sessionFailure = new AgentError("INVALID_CONFIG", "Claude Code selected a different model than requested.");
|
|
274
|
+
sessionFailure = new AgentError("INVALID_CONFIG", "Claude Code selected a different model than requested during native initialization.");
|
|
217
275
|
}
|
|
218
276
|
else if (permissionMode !== undefined && message.permissionMode !== permissionMode) {
|
|
219
277
|
sessionFailure = new AgentError("INVALID_CONFIG", "Claude Code reported a different permission mode than requested.");
|
|
@@ -244,30 +302,78 @@ export function createClaudeOpener(deps) {
|
|
|
244
302
|
current.resolve(message.result);
|
|
245
303
|
}
|
|
246
304
|
else
|
|
247
|
-
current.reject(
|
|
305
|
+
current.reject(claudeResultFailure(message.subtype));
|
|
248
306
|
}
|
|
249
307
|
}
|
|
250
|
-
catch {
|
|
308
|
+
catch (error) {
|
|
309
|
+
if (error instanceof AgentError) {
|
|
310
|
+
sessionFailure = error;
|
|
311
|
+
}
|
|
251
312
|
// Native diagnostics may contain credentials; return a stable safe message.
|
|
252
313
|
}
|
|
253
314
|
finally {
|
|
254
315
|
acceptingApprovals = false;
|
|
255
316
|
approvals.clear();
|
|
256
|
-
const
|
|
317
|
+
const explicitClose = exitObservedBeforeClose !== undefined;
|
|
318
|
+
const code = explicitClose ? "SESSION_CLOSED" : "HARNESS_ERROR";
|
|
257
319
|
closed = true;
|
|
258
320
|
input.close();
|
|
259
321
|
await tools.drain();
|
|
260
|
-
|
|
261
|
-
active
|
|
262
|
-
|
|
322
|
+
const exit = explicitClose ? exitObservedBeforeClose : processOwner.exitDescription();
|
|
323
|
+
const ending = active;
|
|
324
|
+
ending?.reject(sessionFailure ?? inputFailure ?? new AgentError(code, `The Claude Code process stopped${exit} before completing the turn.`));
|
|
263
325
|
try {
|
|
264
|
-
await
|
|
326
|
+
await cleanupResources();
|
|
265
327
|
}
|
|
266
328
|
finally {
|
|
267
|
-
|
|
329
|
+
ending?.stop();
|
|
330
|
+
if (active === ending)
|
|
331
|
+
active = undefined;
|
|
268
332
|
}
|
|
269
333
|
}
|
|
270
334
|
})();
|
|
335
|
+
void reading.catch(() => undefined);
|
|
336
|
+
let closeAttempt;
|
|
337
|
+
let closeComplete = false;
|
|
338
|
+
let failedCloseAttempts = 0;
|
|
339
|
+
const close = () => {
|
|
340
|
+
if (closeComplete)
|
|
341
|
+
return Promise.resolve();
|
|
342
|
+
if (closeAttempt)
|
|
343
|
+
return closeAttempt;
|
|
344
|
+
closeAttempt = (async () => {
|
|
345
|
+
exitObservedBeforeClose ??= processOwner.exitDescription();
|
|
346
|
+
closed = true;
|
|
347
|
+
acceptingApprovals = false;
|
|
348
|
+
approvals.clear();
|
|
349
|
+
const pending = preflight;
|
|
350
|
+
if (pending) {
|
|
351
|
+
pending.cancel(new AgentError("SESSION_CLOSED", "The native session closed before submission."));
|
|
352
|
+
await pending.stopped;
|
|
353
|
+
}
|
|
354
|
+
tools.stopAdmission();
|
|
355
|
+
input.close();
|
|
356
|
+
native.close();
|
|
357
|
+
const stoppingFailure = processOwner.close().then(() => new Promise(() => { }));
|
|
358
|
+
let readingFailure;
|
|
359
|
+
try {
|
|
360
|
+
await Promise.race([reading, stoppingFailure]);
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
readingFailure = error;
|
|
364
|
+
}
|
|
365
|
+
if (readingFailure && failedCloseAttempts === 0)
|
|
366
|
+
throw readingFailure;
|
|
367
|
+
if (!cleanupComplete)
|
|
368
|
+
await cleanupResources();
|
|
369
|
+
closeComplete = true;
|
|
370
|
+
})().catch(error => {
|
|
371
|
+
failedCloseAttempts += 1;
|
|
372
|
+
closeAttempt = undefined;
|
|
373
|
+
throw error;
|
|
374
|
+
});
|
|
375
|
+
return closeAttempt;
|
|
376
|
+
};
|
|
271
377
|
return {
|
|
272
378
|
async turn(prompt) {
|
|
273
379
|
if (closed)
|
|
@@ -294,7 +400,7 @@ export function createClaudeOpener(deps) {
|
|
|
294
400
|
throw error;
|
|
295
401
|
}
|
|
296
402
|
if (!expectedModels.has(applied.model))
|
|
297
|
-
throw new AgentError("INVALID_CONFIG", "Claude Code changed the retained
|
|
403
|
+
throw new AgentError("INVALID_CONFIG", "Claude Code changed the model during retained-session validation before submission.");
|
|
298
404
|
verifyAppliedClaudeEffort(applied.effort, options.harness.effort);
|
|
299
405
|
}
|
|
300
406
|
if (closed)
|
|
@@ -333,33 +439,16 @@ export function createClaudeOpener(deps) {
|
|
|
333
439
|
try {
|
|
334
440
|
await native.interrupt();
|
|
335
441
|
}
|
|
336
|
-
catch {
|
|
442
|
+
catch (error) {
|
|
337
443
|
current.interrupted = false;
|
|
444
|
+
if (error instanceof AgentError && error.code === "HARNESS_FAILED")
|
|
445
|
+
throw error;
|
|
338
446
|
throw new AgentError("CANCEL_FAILED", "Claude Code did not confirm interruption.");
|
|
339
447
|
}
|
|
340
448
|
await current.stopped;
|
|
341
449
|
},
|
|
342
450
|
async resume() { throw new AgentError("RECOVERY_UNSUPPORTED", "Claude Code cannot retry failed execution without replaying input."); },
|
|
343
|
-
|
|
344
|
-
closed = true;
|
|
345
|
-
acceptingApprovals = false;
|
|
346
|
-
approvals.clear();
|
|
347
|
-
const pending = preflight;
|
|
348
|
-
if (pending) {
|
|
349
|
-
pending.cancel(new AgentError("SESSION_CLOSED", "The native session closed before submission."));
|
|
350
|
-
await pending.stopped;
|
|
351
|
-
}
|
|
352
|
-
tools.stopAdmission();
|
|
353
|
-
input.close();
|
|
354
|
-
native.close();
|
|
355
|
-
const stopping = processOwner.close();
|
|
356
|
-
try {
|
|
357
|
-
await reading;
|
|
358
|
-
}
|
|
359
|
-
finally {
|
|
360
|
-
await stopping;
|
|
361
|
-
}
|
|
362
|
-
},
|
|
451
|
+
close,
|
|
363
452
|
};
|
|
364
453
|
};
|
|
365
454
|
}
|