@claudexor/harness-claude 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 joi-lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @claudexor/harness-claude
2
+
3
+ Internal package of [Claudexor](https://github.com/razzant/claudexor) — Claude Code adapter (claude -p --output-format stream-json).
4
+
5
+ Published as part of the Claudexor toolchain; it follows the monorepo's
6
+ lockstep version and has no separate semver contract. Use the `claudexor`
7
+ CLI (or `@claudexor/cli`) as the supported entry point.
@@ -0,0 +1,19 @@
1
+ import type { HarnessRunSpec } from "@claudexor/schema";
2
+ import type { HarnessAdapter } from "@claudexor/core";
3
+ /** The user's real Claude config dir (native subscription session lives here). */
4
+ export declare function defaultNativeClaudeConfigDir(): string;
5
+ /**
6
+ * Seed the user's NATIVE Claude session (`.credentials.json`, subscription OAuth)
7
+ * into an isolated CLAUDE_CONFIG_DIR so a Pro/Max subscriber with NO API key can
8
+ * run inside a Claudexor envelope. Copies only if scoped creds are absent and a
9
+ * native credentials file exists; never overwrites. Returns true when scoped
10
+ * creds are present afterwards.
11
+ *
12
+ * Caveats encoded by the caller: `ANTHROPIC_API_KEY` takes precedence over the
13
+ * OAuth session, and `--bare` disables it — so the subscription route must set
14
+ * neither.
15
+ */
16
+ export declare function ensureClaudeNativeAuth(env?: Record<string, string>, nativeDir?: string): boolean;
17
+ export declare function createClaudeAdapter(): HarnessAdapter;
18
+ export declare function claudeArgsForSpec(spec: HarnessRunSpec, interactive?: boolean, suppressBare?: boolean): string[];
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAyG,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE/J,OAAO,KAAK,EAAc,cAAc,EAAsB,MAAM,iBAAiB,CAAC;AAmFtF,kFAAkF;AAClF,wBAAgB,4BAA4B,IAAI,MAAM,CAIrD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,SAAS,GAAE,MAAuC,GACjD,OAAO,CAmBT;AAoCD,wBAAgB,mBAAmB,IAAI,cAAc,CA2HpD;AAOD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,WAAW,UAAQ,EAAE,YAAY,UAAQ,GAAG,MAAM,EAAE,CA8B3G"}
package/dist/index.js ADDED
@@ -0,0 +1,482 @@
1
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
2
+ import { homedir, tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { ConformanceReport as ConformanceReportSchema, HarnessCapabilityProfile as HarnessCapabilityProfileSchema, HarnessManifest as HarnessManifestSchema } from "@claudexor/schema";
5
+ import { HarnessUnavailableError, interactionChannelFromSpec, normalizeEffort, playwrightMcpArgs, providerScrubEnv, readonlyMechanism, resolveNpxBin, runCapture, runCliHarness, PROVIDER_SECRET_ENV } from "@claudexor/core";
6
+ import { resolveSecret } from "@claudexor/secrets";
7
+ import { CLAUDEXOR_VERSION, nowIso, redactSecrets } from "@claudexor/util";
8
+ import { createClaudeParser } from "./parse.js";
9
+ import { handleControlRequestFrame, initialSessionFrames, isControlRequestFrame, isResultFrame } from "./interactive.js";
10
+ const BIN = process.env.CLAUDEXOR_CLAUDE_BIN || "claude";
11
+ const CLAUDE_PROVIDER_ENV_DENYLIST = PROVIDER_SECRET_ENV.filter((k) => k !== "ANTHROPIC_API_KEY");
12
+ const CLAUDE_CAPABILITY_PROFILE = HarnessCapabilityProfileSchema.parse({
13
+ auth: {
14
+ supported_sources: ["native_session", "api_key_env"],
15
+ preferred_source: null,
16
+ credential_transports: [
17
+ { source: "native_session", kind: "config_file", relocatable_by: ["CONFIG_DIR"] },
18
+ { source: "api_key_env", kind: "env_var", relocatable_by: ["ENV"] },
19
+ ],
20
+ },
21
+ access_control: { readonly_mechanism: "tool_allowlist" },
22
+ isolation: { supported_containment: ["env_or_file_injection"] },
23
+ image_input: "base64_stream",
24
+ });
25
+ /**
26
+ * Ordered (weakest→strongest) reasoning-effort levels `claude --effort` accepts.
27
+ * Verified against the installed CLI (`claude --help`, v2.1.165): the full
28
+ * ladder is low|medium|high|xhigh|max. SINGLE source for the manifest's
29
+ * `effort_levels` and the run-time normalizer (which now clamps nothing away).
30
+ */
31
+ const CLAUDE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
32
+ function permissionArgs(access) {
33
+ switch (access) {
34
+ case "readonly":
35
+ return [];
36
+ case "workspace_write":
37
+ return ["--permission-mode", "acceptEdits"];
38
+ case "full":
39
+ case "external_sandbox_full":
40
+ return ["--permission-mode", "bypassPermissions"];
41
+ case "inherit_native":
42
+ return [];
43
+ }
44
+ }
45
+ async function detectVersion() {
46
+ try {
47
+ const r = await runCapture(BIN, ["--version"], { timeoutMs: 10_000 });
48
+ return r.stdout.trim() || `${BIN} (version unknown)`;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ async function authStatusOk() {
55
+ try {
56
+ const env = Object.fromEntries(CLAUDE_PROVIDER_ENV_DENYLIST.map((name) => [name, null]));
57
+ // Probe a REAL native/subscription session only: `claude auth status` reports
58
+ // loggedIn:true for a bare ANTHROPIC_API_KEY (authMethod:api_key), which would
59
+ // make the run path mistake an API key for a native session and pick the
60
+ // subscription route (scrubs the key -> "Not logged in"). Scrub it here so this
61
+ // probe reflects native-session readiness alone; the api_key route is chosen
62
+ // separately by runClaude when no native session exists.
63
+ env.ANTHROPIC_API_KEY = null;
64
+ const r = await runCapture(BIN, ["auth", "status"], { env, timeoutMs: 10_000 });
65
+ return r.code === 0;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ function anthropicApiKey() {
72
+ return process.env.CLAUDEXOR_ANTHROPIC_API_KEY || resolveSecret("anthropic") || process.env.ANTHROPIC_API_KEY || null;
73
+ }
74
+ /** A stored/long-lived Claude Code OAuth (`claude setup-token`) for headless
75
+ * subscription auth. The hermetic kill switch is honored inside resolveSecret
76
+ * (single owner), so this reads env-only under CLAUDEXOR_DISABLE_STORED_SECRETS. */
77
+ function claudeOAuthToken() {
78
+ return resolveSecret("claude_oauth") || process.env.CLAUDE_CODE_OAUTH_TOKEN || null;
79
+ }
80
+ /** The user's real Claude config dir (native subscription session lives here). */
81
+ export function defaultNativeClaudeConfigDir() {
82
+ const override = process.env.CLAUDEXOR_CLAUDE_NATIVE_DIR;
83
+ if (override && override.trim())
84
+ return override;
85
+ return join(homedir(), ".claude");
86
+ }
87
+ /**
88
+ * Seed the user's NATIVE Claude session (`.credentials.json`, subscription OAuth)
89
+ * into an isolated CLAUDE_CONFIG_DIR so a Pro/Max subscriber with NO API key can
90
+ * run inside a Claudexor envelope. Copies only if scoped creds are absent and a
91
+ * native credentials file exists; never overwrites. Returns true when scoped
92
+ * creds are present afterwards.
93
+ *
94
+ * Caveats encoded by the caller: `ANTHROPIC_API_KEY` takes precedence over the
95
+ * OAuth session, and `--bare` disables it — so the subscription route must set
96
+ * neither.
97
+ */
98
+ export function ensureClaudeNativeAuth(env, nativeDir = defaultNativeClaudeConfigDir()) {
99
+ const dir = env?.["CLAUDE_CONFIG_DIR"];
100
+ if (!dir)
101
+ return false;
102
+ const dest = join(dir, ".credentials.json");
103
+ if (existsSync(dest))
104
+ return true;
105
+ const src = join(nativeDir, ".credentials.json");
106
+ if (!existsSync(src))
107
+ return false;
108
+ try {
109
+ mkdirSync(dir, { recursive: true });
110
+ copyFileSync(src, dest);
111
+ try {
112
+ chmodSync(dest, 0o600);
113
+ }
114
+ catch {
115
+ /* best-effort perms */
116
+ }
117
+ return existsSync(dest);
118
+ }
119
+ catch {
120
+ return false;
121
+ }
122
+ }
123
+ /** True when a native Claude session exists and can be seeded into an envelope. */
124
+ function nativeClaudeSeedable() {
125
+ return existsSync(join(defaultNativeClaudeConfigDir(), ".credentials.json"));
126
+ }
127
+ async function smokeIsolatedApiKey() {
128
+ const key = anthropicApiKey();
129
+ if (!key)
130
+ return { ok: false, detail: "no API key fallback available" };
131
+ const dir = mkdtempSync(`${tmpdir()}/claudexor-claude-smoke-`);
132
+ try {
133
+ const env = Object.fromEntries(CLAUDE_PROVIDER_ENV_DENYLIST.map((name) => [name, null]));
134
+ env.HOME = dir;
135
+ env.XDG_CONFIG_HOME = `${dir}/.config`;
136
+ env.CLAUDE_CONFIG_DIR = dir;
137
+ env.ANTHROPIC_API_KEY = key;
138
+ const r = await runCapture(BIN, ["-p", "Reply exactly OK", "--output-format", "stream-json", "--verbose", "--permission-mode", "plan"], { cwd: dir, env, timeoutMs: 60_000 });
139
+ const text = `${r.stdout}\n${r.stderr}`;
140
+ if (r.code === 0 && text.includes("OK"))
141
+ return { ok: true, detail: "isolated CLAUDE_CONFIG_DIR smoke passed" };
142
+ return { ok: false, detail: redactClaudeDoctorDetail(text || `claude exited with code ${r.code}`) };
143
+ }
144
+ catch (err) {
145
+ return { ok: false, detail: redactClaudeDoctorDetail(err instanceof Error ? err.message : String(err)) };
146
+ }
147
+ finally {
148
+ rmSync(dir, { recursive: true, force: true });
149
+ }
150
+ }
151
+ function redactClaudeDoctorDetail(text) {
152
+ return redactSecrets(text).slice(0, 500);
153
+ }
154
+ export function createClaudeAdapter() {
155
+ return {
156
+ id: "claude",
157
+ async discover() {
158
+ const version = await detectVersion();
159
+ if (version === null) {
160
+ throw new HarnessUnavailableError("claude CLI not found on PATH (set CLAUDEXOR_CLAUDE_BIN to override)");
161
+ }
162
+ const apiKey = anthropicApiKey() !== null;
163
+ const authed = await authStatusOk();
164
+ const authModes = [
165
+ ...(authed ? ["local_session"] : []),
166
+ ...(apiKey ? ["api_key"] : []),
167
+ ];
168
+ return HarnessManifestSchema.parse({
169
+ id: "claude",
170
+ display_name: "Claude Code",
171
+ kind: "local_cli",
172
+ version,
173
+ adapter_version: CLAUDEXOR_VERSION,
174
+ provider_family: "anthropic",
175
+ capabilities: {
176
+ plan: true,
177
+ implement: true,
178
+ create_from_scratch: true,
179
+ review: true,
180
+ verify: true,
181
+ synthesize: true,
182
+ read_files: true,
183
+ // inline JSON (no disk write) — gated on web policy.
184
+ browser_tool: true,
185
+ // LIVE-VERIFIED (claude 2.1.165): `--json-schema <schema>` (inline JSON).
186
+ json_schema_output: true,
187
+ web_policy: "tools",
188
+ max_turns: true,
189
+ tool_lists: true,
190
+ interactive: true,
191
+ orchestrate: true,
192
+ // claude --effort accepts low|medium|high|xhigh|max (verified against
193
+ // the installed CLI's --help). Single source for the run-time normalizer.
194
+ effort_levels: [...CLAUDE_EFFORT_LEVELS],
195
+ // Manifest model truth source (strict model-truth validation: an explicit model outside
196
+ // this list is refused, never forwarded to die as a native error).
197
+ // Stable aliases plus current full ids; verified against the vendor
198
+ // model-config docs and the installed CLI recorded below.
199
+ known_models: [
200
+ "sonnet",
201
+ "opus",
202
+ "haiku",
203
+ "fable",
204
+ "best",
205
+ "claude-fable-5",
206
+ "claude-sonnet-5",
207
+ "claude-opus-4-8",
208
+ "claude-opus-4-7",
209
+ "claude-opus-4-6",
210
+ "claude-sonnet-4-6",
211
+ "claude-sonnet-4-5",
212
+ "claude-haiku-4-5",
213
+ ],
214
+ known_models_verified_against: "2.1.165",
215
+ },
216
+ capability_profile: {
217
+ ...CLAUDE_CAPABILITY_PROFILE,
218
+ auth: {
219
+ ...CLAUDE_CAPABILITY_PROFILE.auth,
220
+ preferred_source: apiKey ? "api_key_env" : authed ? "native_session" : null,
221
+ },
222
+ },
223
+ auth_modes: authModes,
224
+ access_profiles_supported: ["readonly", "workspace_write", "full", "inherit_native"],
225
+ });
226
+ },
227
+ async doctor(_spec) {
228
+ const version = await detectVersion();
229
+ if (version === null) {
230
+ return ConformanceReportSchema.parse({
231
+ harness_id: "claude",
232
+ status: "unavailable",
233
+ checks: [{ id: "installed", status: "fail", detail: "claude not found on PATH" }],
234
+ reasons: ["claude CLI not found (install Claude Code or set CLAUDEXOR_CLAUDE_BIN)"],
235
+ });
236
+ }
237
+ const apiKey = anthropicApiKey() !== null;
238
+ const authed = await authStatusOk();
239
+ // Native subscription readiness is FIRST-CLASS: a logged-in session whose
240
+ // .credentials.json we can seed into the envelope is `ok` with no paid API
241
+ // smoke. A stored OAuth token (claude setup-token) is also native-ready.
242
+ const nativeReady = (authed && nativeClaudeSeedable()) || claudeOAuthToken() !== null;
243
+ const smoke = !nativeReady && apiKey ? await smokeIsolatedApiKey() : { ok: false, detail: nativeReady ? "skipped (native session ready)" : "no API key fallback available" };
244
+ const ok = nativeReady || smoke.ok;
245
+ const allIntents = ["plan", "spec", "implement", "repair", "create_from_scratch", "review", "verify", "synthesize", "explain", "audit", "orchestrate"];
246
+ return ConformanceReportSchema.parse({
247
+ harness_id: "claude",
248
+ status: ok ? "ok" : authed || apiKey ? "degraded" : "unavailable",
249
+ checks: [
250
+ { id: "installed", status: "pass", detail: version },
251
+ { id: "native_session", status: nativeReady ? "pass" : "fail", detail: nativeReady ? "native Claude session seedable into envelope" : authed ? "logged in but ~/.claude/.credentials.json not found" : "not logged in (run `claude /login` or store a setup-token)" },
252
+ { id: "stored_key", status: apiKey ? "pass" : "fail", detail: apiKey ? "anthropic secret/env available (api-key fallback)" : "no anthropic key fallback" },
253
+ { id: "isolated_api_smoke", status: smoke.ok ? "pass" : nativeReady ? "skip" : apiKey ? "fail" : "skip", detail: smoke.detail },
254
+ ],
255
+ enabled_intents: ok ? allIntents : [],
256
+ disabled_intents: ok ? [] : allIntents,
257
+ reasons: ok
258
+ ? []
259
+ : apiKey
260
+ ? [`isolated Claude API-key smoke failed: ${smoke.detail}`]
261
+ : ["not authenticated (run `claude /login` for native/subscription use, or store an anthropic API key fallback)"],
262
+ });
263
+ },
264
+ run(spec) {
265
+ return runClaude(spec);
266
+ },
267
+ review(spec) {
268
+ return runClaude(spec);
269
+ },
270
+ };
271
+ }
272
+ /** Claude's native names for web-permissioned tools. This knowledge lives ONLY in the adapter. */
273
+ const CLAUDE_WEB_TOOLS = ["WebSearch", "WebFetch"];
274
+ const CLAUDE_READONLY_ALLOWED_TOOLS = ["Read", "Glob", "Grep", "LS"];
275
+ const CLAUDE_READONLY_DENIED_TOOLS = ["Write", "Edit", "MultiEdit", "NotebookEdit"];
276
+ export function claudeArgsForSpec(spec, interactive = false, suppressBare = false) {
277
+ // Interactive sessions deliver the prompt as a stream-json user message on
278
+ // stdin (the control protocol's transport); one-shot runs keep the prompt arg.
279
+ // `--permission-prompt-tool stdio` is the live-verified switch that routes
280
+ // permission prompts (AskUserQuestion included) onto the control channel as
281
+ // control_request frames instead of headless auto-denial.
282
+ const args = interactive
283
+ ? ["-p", "--output-format", "stream-json", "--input-format", "stream-json", "--verbose", "--permission-prompt-tool", "stdio", ...permissionArgs(spec.access)]
284
+ : ["-p", spec.prompt, "--output-format", "stream-json", "--verbose", ...permissionArgs(spec.access)];
285
+ if (spec.model_hint)
286
+ args.push("--model", spec.model_hint);
287
+ // Clamp onto claude's declared effort ladder; null = not
288
+ // requested OR not tunable -> pass no flag. Never sends an invalid level.
289
+ const eff = normalizeEffort(spec.effort_hint, CLAUDE_EFFORT_LEVELS);
290
+ if (eff)
291
+ args.push("--effort", eff);
292
+ if (spec.max_turns !== null && spec.max_turns > 0)
293
+ args.push("--max-turns", String(spec.max_turns));
294
+ // Structured output: constrain the FINAL message to the caller's JSON
295
+ // Schema. LIVE-VERIFIED (2.1.165): `--json-schema <inline JSON>` with
296
+ // --output-format stream-json. Passed only when the engine set it (the
297
+ // engine gates on the json_schema_output capability).
298
+ if (spec.output_schema !== undefined && spec.output_schema !== null) {
299
+ args.push("--json-schema", JSON.stringify(spec.output_schema));
300
+ }
301
+ // Resume a native Claude session as a follow-up turn of the same conversation.
302
+ if (spec.resume_session_id)
303
+ args.push("--resume", spec.resume_session_id);
304
+ args.push(...claudeBrowserArgs(spec));
305
+ args.push(...toolPermissionArgs(spec));
306
+ // `--bare` disables OAuth/keychain auth, so it is mutually exclusive with the
307
+ // subscription (native session) route — suppress it there or the run 401s.
308
+ if (spec.extra?.["bare"] === true && !suppressBare)
309
+ args.push("--bare");
310
+ return args;
311
+ }
312
+ /**
313
+ * Map the external-context policy plus the user's per-harness tool allow/deny
314
+ * lists to Claude flags. Uses the single comma-separated form: the repeated
315
+ * variadic form is a known-fragile area of the Claude CLI.
316
+ * Note `cached` executes as live web here (Claude has no cached web index);
317
+ * the orchestrator discloses that upgrade via `policy.web.upgraded`.
318
+ */
319
+ function toolPermissionArgs(spec) {
320
+ const { allow, deny } = toolPermissionSets(spec);
321
+ const args = [];
322
+ if (allow.size > 0)
323
+ args.push("--allowedTools", [...allow].join(","));
324
+ if (deny.size > 0)
325
+ args.push("--disallowedTools", [...deny].join(","));
326
+ return args;
327
+ }
328
+ function toolPermissionSets(spec) {
329
+ const policy = spec.external_context_policy;
330
+ const allow = new Set(spec.tool_permission_policy.allow);
331
+ const deny = new Set(spec.tool_permission_policy.deny);
332
+ if (spec.access === "readonly" && readonlyMechanism(CLAUDE_CAPABILITY_PROFILE) === "tool_allowlist") {
333
+ for (const tool of CLAUDE_READONLY_ALLOWED_TOOLS) {
334
+ if (!deny.has(tool))
335
+ allow.add(tool);
336
+ }
337
+ for (const tool of CLAUDE_READONLY_DENIED_TOOLS) {
338
+ deny.add(tool);
339
+ allow.delete(tool);
340
+ }
341
+ }
342
+ if (policy === "off") {
343
+ for (const tool of CLAUDE_WEB_TOOLS) {
344
+ deny.add(tool);
345
+ allow.delete(tool);
346
+ }
347
+ }
348
+ else {
349
+ for (const tool of CLAUDE_WEB_TOOLS) {
350
+ if (!deny.has(tool))
351
+ allow.add(tool);
352
+ }
353
+ }
354
+ // A browser-tool run allows the injected MCP server's tools (claude names them
355
+ // `mcp__browser__*`; the server prefix `mcp__browser` allows the whole set).
356
+ // Gated on policy: under `off` the MCP is never injected (claudeBrowserArgs is
357
+ // empty), so this allow has no tool to match anyway.
358
+ if (spec.browser && policy !== "off")
359
+ allow.add("mcp__browser");
360
+ return { allow, deny };
361
+ }
362
+ /**
363
+ * Inject the Playwright browser MCP via `--mcp-config` inline JSON (no disk
364
+ * write — fits the scoped HOME and works under `--bare`). Empty when no browser
365
+ * this run OR when web policy is `off` (the browser is live egress and must ride
366
+ * `external_context_policy`, mirroring web-tool gating).
367
+ */
368
+ function claudeBrowserArgs(spec) {
369
+ if (!spec.browser || spec.external_context_policy === "off")
370
+ return [];
371
+ const cfg = JSON.stringify({ mcpServers: { browser: { command: resolveNpxBin(), args: playwrightMcpArgs(spec.browser) } } });
372
+ return ["--mcp-config", cfg];
373
+ }
374
+ /** Build Claude base64 image blocks from image attachments (read at spec time). */
375
+ function claudeImageBlocks(attachments) {
376
+ const blocks = [];
377
+ for (const a of attachments ?? []) {
378
+ if (a.kind !== "image")
379
+ continue;
380
+ try {
381
+ blocks.push({ type: "image", source: { type: "base64", media_type: a.mime, data: readFileSync(a.path).toString("base64") } });
382
+ }
383
+ catch {
384
+ // A late-deleted attachment is non-fatal: proceed with the text prompt.
385
+ }
386
+ }
387
+ return blocks;
388
+ }
389
+ async function* runClaude(spec) {
390
+ const channel = interactionChannelFromSpec(spec);
391
+ const imageBlocks = claudeImageBlocks(spec.attachments);
392
+ // Images ride ONLY the stdin stream-json transport, so an attachment forces
393
+ // the interactive path even with no interaction channel (control frames then
394
+ // auto-decline). claudeArgsForSpec(interactive) selects --input-format stream-json.
395
+ const interactive = channel !== undefined || imageBlocks.length > 0;
396
+ const nativeAuthed = await authStatusOk();
397
+ const key = anthropicApiKey();
398
+ const oauthToken = claudeOAuthToken();
399
+ const preferApi = spec.auth_preference === "api_key";
400
+ const scopedConfig = Boolean(spec.env?.["CLAUDE_CONFIG_DIR"]);
401
+ // Choose the auth route (BOTH supported, auto-fallback). Subscription seeds the
402
+ // native session (credentials copy) or uses a stored OAuth token; api_key sets
403
+ // ANTHROPIC_API_KEY. ANTHROPIC_API_KEY overrides OAuth and --bare disables it,
404
+ // so the subscription route sets neither (and suppresses --bare).
405
+ let seededCreds = false;
406
+ const trySub = () => {
407
+ if (scopedConfig && nativeAuthed && ensureClaudeNativeAuth(spec.env)) {
408
+ seededCreds = true;
409
+ return true;
410
+ }
411
+ return (!scopedConfig && nativeAuthed) || oauthToken !== null;
412
+ };
413
+ const canKey = key !== null;
414
+ const route = preferApi
415
+ ? canKey
416
+ ? "api_key"
417
+ : trySub()
418
+ ? "subscription"
419
+ : null
420
+ : trySub()
421
+ ? "subscription"
422
+ : canKey
423
+ ? "api_key"
424
+ : null;
425
+ // An EXPLICIT auth preference that could not be honored is disclosed as a
426
+ // typed marker; the orchestrator lifts it into route.fallback.auth_switched.
427
+ const preferredRoute = preferApi ? "api_key" : "subscription";
428
+ if (spec.auth_preference !== "auto" && route !== null && route !== preferredRoute) {
429
+ yield {
430
+ type: "message",
431
+ session_id: spec.session_id,
432
+ ts: nowIso(),
433
+ text: `[auth] ${preferredRoute} route unavailable; fell back to ${route}`,
434
+ payload: {
435
+ auth_switched: true,
436
+ from_auth_mode: preferredRoute === "subscription" ? "local_session" : "api_key",
437
+ to_auth_mode: route === "subscription" ? "local_session" : "api_key",
438
+ },
439
+ };
440
+ }
441
+ if (route === null) {
442
+ yield {
443
+ type: "error",
444
+ session_id: spec.session_id,
445
+ ts: nowIso(),
446
+ error: "no usable claude auth for this envelope: native session not seedable (run `claude /login` or store a setup-token) and no Anthropic API key fallback available",
447
+ };
448
+ yield { type: "completed", session_id: spec.session_id, ts: nowIso() };
449
+ return;
450
+ }
451
+ const useSubscription = route === "subscription";
452
+ const args = claudeArgsForSpec(spec, interactive, useSubscription);
453
+ // Scrub EVERY provider secret (incl. OpenAI/others — the cross-provider leak
454
+ // fix) via the single core table, then re-add only the var this route needs.
455
+ const env = { ...spec.env, ...providerScrubEnv() };
456
+ if (route === "api_key" && key) {
457
+ env.ANTHROPIC_API_KEY = key;
458
+ }
459
+ else if (route === "subscription" && !seededCreds && oauthToken) {
460
+ env.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
461
+ }
462
+ yield* runCliHarness({
463
+ bin: BIN,
464
+ args,
465
+ spec,
466
+ env,
467
+ label: "claude",
468
+ redact: redactSecrets,
469
+ parseEvent: createClaudeParser({ deniedTools: toolPermissionSets(spec).deny }),
470
+ ...(interactive
471
+ ? {
472
+ session: {
473
+ initialStdin: initialSessionFrames(spec.prompt, imageBlocks),
474
+ matches: isControlRequestFrame,
475
+ handle: (obj, io) => handleControlRequestFrame(obj, io, spec.session_id, channel),
476
+ closeStdinOn: isResultFrame,
477
+ },
478
+ }
479
+ : {}),
480
+ });
481
+ }
482
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import type { ChildStdin, InteractionChannel } from "@claudexor/core";
2
+ import type { HarnessEvent, InteractionAnswerSet, InteractionRequest } from "@claudexor/schema";
3
+ type Json = any;
4
+ /**
5
+ * Claude Code bidirectional stream-json control protocol (the same channel the
6
+ * Agent SDK's `canUseTool` rides on):
7
+ *
8
+ * CLI -> client : {"type":"control_request","request_id":X,
9
+ * "request":{"subtype":"can_use_tool","tool_name":T,"input":I,...}}
10
+ * client -> CLI : {"type":"control_response","response":{"subtype":"success",
11
+ * "request_id":X,"response":{"behavior":"allow"|"deny",...}}}
12
+ *
13
+ * For AskUserQuestion the answers ride in `updatedInput.answers` as a record of
14
+ * question text -> selected label(s) (docs: "Handle approvals and user input").
15
+ * Frame shapes are LIVE-VERIFIED against Claude Code 2.1.165: the full
16
+ * bidirectional exchange (initialize -> can_use_tool -> allow -> ok
17
+ * tool_result -> result) is recorded in fixtures/protocol/control-handshake.jsonl.
18
+ * The control channel only activates with `--permission-prompt-tool stdio`;
19
+ * without it the headless CLI auto-denies interactive tools itself.
20
+ */
21
+ export declare function isControlRequestFrame(obj: Json): boolean;
22
+ export declare function isResultFrame(obj: Json): boolean;
23
+ /** A Claude stream-json image content block (base64 source). Claude carries
24
+ * images ONLY on the stdin stream-json transport — a one-shot `-p` argv run
25
+ * cannot, so a turn with attachments must use the interactive path. */
26
+ export interface ClaudeImageBlock {
27
+ type: "image";
28
+ source: {
29
+ type: "base64";
30
+ media_type: string;
31
+ data: string;
32
+ };
33
+ }
34
+ /** Initial user message frame for `--input-format stream-json` sessions. */
35
+ export declare function initialUserMessageFrame(prompt: string, images?: ClaudeImageBlock[]): string;
36
+ /**
37
+ * Initial stdin block for an interactive session: the initialize handshake
38
+ * (announces a live control-protocol client) followed by the user message.
39
+ * Live-verified against Claude Code 2.1.165: both frames may be written in
40
+ * one block without waiting for the initialize response
41
+ * (fixtures/protocol/control-handshake.jsonl).
42
+ */
43
+ export declare function initialSessionFrames(prompt: string, images?: ClaudeImageBlock[]): string;
44
+ /** Map the native AskUserQuestion input into the typed InteractionRequest. */
45
+ export declare function interactionRequestFromNative(requestId: string, input: Json): InteractionRequest;
46
+ /**
47
+ * Build the allow control_response carrying the user's answers.
48
+ * Per the documented contract, `answers` maps the QUESTION TEXT to the
49
+ * selected label, multi-select labels joined with ", ", free text passed
50
+ * through verbatim.
51
+ */
52
+ export declare function allowResponseFrame(requestId: string, nativeInput: Json, request: InteractionRequest, answers: InteractionAnswerSet): string;
53
+ /** Deny control_response: benign decline; the model continues with assumptions. */
54
+ export declare function denyResponseFrame(requestId: string, message: string): string;
55
+ /** Error control_response for request subtypes this adapter does not handle. */
56
+ export declare function errorResponseFrame(requestId: string, error: string): string;
57
+ export declare const DECLINE_MESSAGE = "No user answer is available (declined or timed out). Continue with your best assumptions and state them explicitly.";
58
+ /**
59
+ * Handle one control_request frame. AskUserQuestion is routed through the
60
+ * orchestrator's InteractionChannel (pausing only this tool); every other
61
+ * permission request is DENIED — flag-based permission modes already encode
62
+ * the run's policy, and headless print-mode behavior (no interactive approver)
63
+ * must not be silently liberalized by the control channel.
64
+ */
65
+ export declare function handleControlRequestFrame(obj: Json, io: ChildStdin, sessionId: string, channel: InteractionChannel | undefined): AsyncGenerator<HarnessEvent>;
66
+ export {};
67
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAuB,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGrH,KAAK,IAAI,GAAG,GAAG,CAAC;AAEhB;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAExD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAEhD;AAED;;wEAEwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,gBAAgB,EAAO,GAAG,MAAM,CAQ/F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,gBAAgB,EAAO,GAAG,MAAM,CAO5F;AAED,8EAA8E;AAC9E,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,GAAG,kBAAkB,CAa/F;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAuB3I;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,gFAAgF;AAChF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED,eAAO,MAAM,eAAe,wHAC2F,CAAC;AAExH;;;;;;GAMG;AACH,wBAAuB,yBAAyB,CAC9C,GAAG,EAAE,IAAI,EACT,EAAE,EAAE,UAAU,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,GAAG,SAAS,GACtC,cAAc,CAAC,YAAY,CAAC,CAqC9B"}
@@ -0,0 +1,154 @@
1
+ import { nowIso, redactSecrets } from "@claudexor/util";
2
+ /**
3
+ * Claude Code bidirectional stream-json control protocol (the same channel the
4
+ * Agent SDK's `canUseTool` rides on):
5
+ *
6
+ * CLI -> client : {"type":"control_request","request_id":X,
7
+ * "request":{"subtype":"can_use_tool","tool_name":T,"input":I,...}}
8
+ * client -> CLI : {"type":"control_response","response":{"subtype":"success",
9
+ * "request_id":X,"response":{"behavior":"allow"|"deny",...}}}
10
+ *
11
+ * For AskUserQuestion the answers ride in `updatedInput.answers` as a record of
12
+ * question text -> selected label(s) (docs: "Handle approvals and user input").
13
+ * Frame shapes are LIVE-VERIFIED against Claude Code 2.1.165: the full
14
+ * bidirectional exchange (initialize -> can_use_tool -> allow -> ok
15
+ * tool_result -> result) is recorded in fixtures/protocol/control-handshake.jsonl.
16
+ * The control channel only activates with `--permission-prompt-tool stdio`;
17
+ * without it the headless CLI auto-denies interactive tools itself.
18
+ */
19
+ export function isControlRequestFrame(obj) {
20
+ return obj?.type === "control_request";
21
+ }
22
+ export function isResultFrame(obj) {
23
+ return obj?.type === "result";
24
+ }
25
+ /** Initial user message frame for `--input-format stream-json` sessions. */
26
+ export function initialUserMessageFrame(prompt, images = []) {
27
+ const content = [{ type: "text", text: prompt }, ...images];
28
+ return (JSON.stringify({
29
+ type: "user",
30
+ message: { role: "user", content },
31
+ }) + "\n");
32
+ }
33
+ /**
34
+ * Initial stdin block for an interactive session: the initialize handshake
35
+ * (announces a live control-protocol client) followed by the user message.
36
+ * Live-verified against Claude Code 2.1.165: both frames may be written in
37
+ * one block without waiting for the initialize response
38
+ * (fixtures/protocol/control-handshake.jsonl).
39
+ */
40
+ export function initialSessionFrames(prompt, images = []) {
41
+ const initialize = JSON.stringify({
42
+ type: "control_request",
43
+ request_id: "req_claudexor_init",
44
+ request: { subtype: "initialize" },
45
+ });
46
+ return initialize + "\n" + initialUserMessageFrame(prompt, images);
47
+ }
48
+ /** Map the native AskUserQuestion input into the typed InteractionRequest. */
49
+ export function interactionRequestFromNative(requestId, input) {
50
+ const rawQuestions = Array.isArray(input?.questions) ? input.questions : [];
51
+ const questions = rawQuestions.map((q, idx) => ({
52
+ id: `q${idx + 1}`,
53
+ question: redactSecrets(String(q?.question ?? "")).slice(0, 2000),
54
+ header: typeof q?.header === "string" ? redactSecrets(q.header).slice(0, 100) : null,
55
+ options: (Array.isArray(q?.options) ? q.options : []).map((o) => ({
56
+ label: redactSecrets(String(o?.label ?? "")).slice(0, 500),
57
+ description: typeof o?.description === "string" ? redactSecrets(o.description).slice(0, 1000) : null,
58
+ })),
59
+ multi_select: q?.multiSelect === true,
60
+ }));
61
+ return { interaction_id: requestId, questions, source_tool: "AskUserQuestion" };
62
+ }
63
+ /**
64
+ * Build the allow control_response carrying the user's answers.
65
+ * Per the documented contract, `answers` maps the QUESTION TEXT to the
66
+ * selected label, multi-select labels joined with ", ", free text passed
67
+ * through verbatim.
68
+ */
69
+ export function allowResponseFrame(requestId, nativeInput, request, answers) {
70
+ const byId = new Map(answers.answers.map((a) => [a.question_id, a]));
71
+ const answerMap = {};
72
+ for (const q of request.questions) {
73
+ const a = byId.get(q.id);
74
+ if (!a)
75
+ continue;
76
+ const labels = a.selected_labels.filter((l) => l.trim().length > 0);
77
+ const value = a.free_text && a.free_text.trim().length > 0 ? a.free_text.trim() : labels.join(", ");
78
+ if (value)
79
+ answerMap[q.question] = value;
80
+ }
81
+ return (JSON.stringify({
82
+ type: "control_response",
83
+ response: {
84
+ subtype: "success",
85
+ request_id: requestId,
86
+ response: {
87
+ behavior: "allow",
88
+ updatedInput: { questions: nativeInput?.questions ?? [], answers: answerMap },
89
+ },
90
+ },
91
+ }) + "\n");
92
+ }
93
+ /** Deny control_response: benign decline; the model continues with assumptions. */
94
+ export function denyResponseFrame(requestId, message) {
95
+ return (JSON.stringify({
96
+ type: "control_response",
97
+ response: {
98
+ subtype: "success",
99
+ request_id: requestId,
100
+ response: { behavior: "deny", message, interrupt: false },
101
+ },
102
+ }) + "\n");
103
+ }
104
+ /** Error control_response for request subtypes this adapter does not handle. */
105
+ export function errorResponseFrame(requestId, error) {
106
+ return (JSON.stringify({
107
+ type: "control_response",
108
+ response: { subtype: "error", request_id: requestId, error },
109
+ }) + "\n");
110
+ }
111
+ export const DECLINE_MESSAGE = "No user answer is available (declined or timed out). Continue with your best assumptions and state them explicitly.";
112
+ /**
113
+ * Handle one control_request frame. AskUserQuestion is routed through the
114
+ * orchestrator's InteractionChannel (pausing only this tool); every other
115
+ * permission request is DENIED — flag-based permission modes already encode
116
+ * the run's policy, and headless print-mode behavior (no interactive approver)
117
+ * must not be silently liberalized by the control channel.
118
+ */
119
+ export async function* handleControlRequestFrame(obj, io, sessionId, channel) {
120
+ const requestId = String(obj?.request_id ?? "");
121
+ const request = obj?.request ?? {};
122
+ const subtype = String(request?.subtype ?? "");
123
+ if (subtype !== "can_use_tool") {
124
+ io.write(errorResponseFrame(requestId, `unsupported control request subtype: ${subtype || "(none)"}`));
125
+ return;
126
+ }
127
+ const toolName = String(request?.tool_name ?? "");
128
+ if (toolName !== "AskUserQuestion" || !channel) {
129
+ io.write(denyResponseFrame(requestId, toolName === "AskUserQuestion" ? DECLINE_MESSAGE : "Not permitted by Claudexor policy for this run."));
130
+ return;
131
+ }
132
+ const interaction = interactionRequestFromNative(requestId, request?.input ?? {});
133
+ yield {
134
+ type: "interaction_requested",
135
+ session_id: sessionId,
136
+ ts: nowIso(),
137
+ text: interaction.questions.map((q) => q.question).join(" | ").slice(0, 500),
138
+ interaction,
139
+ };
140
+ let answers = null;
141
+ try {
142
+ answers = await channel.request(interaction);
143
+ }
144
+ catch {
145
+ answers = null;
146
+ }
147
+ if (answers && answers.answers.length > 0) {
148
+ io.write(allowResponseFrame(requestId, request?.input ?? {}, interaction, answers));
149
+ }
150
+ else {
151
+ io.write(denyResponseFrame(requestId, DECLINE_MESSAGE));
152
+ }
153
+ }
154
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../src/interactive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { HarnessEvent } from "@claudexor/schema";
2
+ type Json = any;
3
+ export type ClaudeEventParser = (obj: Json, sessionId: string) => HarnessEvent[] | null;
4
+ export interface ClaudeParserOptions {
5
+ deniedTools?: Iterable<string>;
6
+ }
7
+ /**
8
+ * Create a stateful per-run parser for Claude `--output-format stream-json`.
9
+ * State is needed to resolve tool_result blocks (which only carry tool_use_id)
10
+ * back to the tool name/kind/target of the originating tool_use block, so the
11
+ * normalized `tool_result` event is self-describing.
12
+ * Returns `null` for unrecognized top-level shapes (counted as dropped by the
13
+ * run loop) and `[]` for recognized events that produce nothing.
14
+ */
15
+ export declare function createClaudeParser(opts?: ClaudeParserOptions): ClaudeEventParser;
16
+ export declare function parseClaudeEvent(obj: Json, sessionId: string): HarnessEvent[] | null;
17
+ export {};
18
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAqB,MAAM,mBAAmB,CAAC;AAGzE,KAAK,IAAI,GAAG,GAAG,CAAC;AAchB,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,YAAY,EAAE,GAAG,IAAI,CAAC;AAExF,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,mBAAwB,GAAG,iBAAiB,CAKpF;AAwDD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,EAAE,GAAG,IAAI,CAEpF"}
package/dist/parse.js ADDED
@@ -0,0 +1,347 @@
1
+ import { nowIso, redactSecrets } from "@claudexor/util";
2
+ const EDIT_TOOLS = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
3
+ const CLAUDE_TRANSIENT_RE = /overloaded|temporar(?:y|ily) unavailable|network|econnreset|etimedout|enotfound|eai_again|stream/i;
4
+ function toolKindFor(name) {
5
+ if (name === "WebSearch" || name === "WebFetch")
6
+ return "web";
7
+ if (name === "Bash" || name === "BashOutput" || name === "KillShell")
8
+ return "command";
9
+ if (name === "Glob" || name === "Grep")
10
+ return "search";
11
+ if (name === "Read" || name === "LS" || EDIT_TOOLS.has(name))
12
+ return "file";
13
+ if (name.startsWith("mcp__"))
14
+ return "mcp";
15
+ return "other";
16
+ }
17
+ /**
18
+ * Create a stateful per-run parser for Claude `--output-format stream-json`.
19
+ * State is needed to resolve tool_result blocks (which only carry tool_use_id)
20
+ * back to the tool name/kind/target of the originating tool_use block, so the
21
+ * normalized `tool_result` event is self-describing.
22
+ * Returns `null` for unrecognized top-level shapes (counted as dropped by the
23
+ * run loop) and `[]` for recognized events that produce nothing.
24
+ */
25
+ export function createClaudeParser(opts = {}) {
26
+ const pendingTools = new Map();
27
+ const deniedTools = new Set(opts.deniedTools ?? []);
28
+ return (obj, sessionId) => parseClaudeEventStateful(obj, sessionId, pendingTools, deniedTools);
29
+ }
30
+ const sessionTasks = new Map();
31
+ const SESSION_TASKS_MAX_SESSIONS = 64;
32
+ function applySessionTask(sessionId, tool, input) {
33
+ if (!sessionTasks.has(sessionId) && sessionTasks.size >= SESSION_TASKS_MAX_SESSIONS) {
34
+ const oldest = sessionTasks.keys().next().value;
35
+ if (oldest !== undefined)
36
+ sessionTasks.delete(oldest);
37
+ }
38
+ const list = sessionTasks.get(sessionId) ?? [];
39
+ if (tool === "TaskCreate") {
40
+ const title = typeof input["subject"] === "string" ? input["subject"] : null;
41
+ if (!title)
42
+ return false;
43
+ list.push({ id: String(list.length + 1), title, status: "pending" });
44
+ sessionTasks.set(sessionId, list);
45
+ return true;
46
+ }
47
+ // TaskUpdate: {taskId, status?} — ids are 1-based creation order (the CLI's
48
+ // own numbering, observed live).
49
+ const taskId = typeof input["taskId"] === "string" ? input["taskId"] : null;
50
+ if (!taskId)
51
+ return false;
52
+ let task = list.find((t) => t.id === taskId);
53
+ const status = input["status"];
54
+ if (status !== "completed" && status !== "in_progress" && status !== "pending")
55
+ return false;
56
+ if (!task) {
57
+ // RESUMED session: the CLI's numbering continues from prior turns while
58
+ // this accumulator started fresh — create-on-miss with the CLI's own id
59
+ // (subject line unknown; the status update is still honest progress).
60
+ const subject = typeof input["subject"] === "string" ? input["subject"] : `Task ${taskId}`;
61
+ task = { id: taskId, title: subject, status };
62
+ list.push(task);
63
+ sessionTasks.set(sessionId, list);
64
+ return true;
65
+ }
66
+ task.status = status;
67
+ sessionTasks.set(sessionId, list);
68
+ return true;
69
+ }
70
+ /** Session finished: release its accumulated task list (long-lived daemons
71
+ * must not hold every historical session's checklist). */
72
+ function releaseSessionTasks(sessionId) {
73
+ sessionTasks.delete(sessionId);
74
+ }
75
+ function sessionTaskItems(sessionId) {
76
+ return (sessionTasks.get(sessionId) ?? []).map((t) => ({ id: `claude-${t.id}`, title: t.title, status: t.status }));
77
+ }
78
+ export function parseClaudeEvent(obj, sessionId) {
79
+ return parseClaudeEventStateful(obj, sessionId, new Map());
80
+ }
81
+ function parseClaudeEventStateful(obj, sessionId, pendingTools, deniedTools = new Set()) {
82
+ const ts = nowIso();
83
+ const type = obj?.type;
84
+ if (type === "system" && obj.subtype === "init") {
85
+ return [
86
+ {
87
+ type: "started",
88
+ session_id: sessionId,
89
+ ts,
90
+ observed_model: typeof obj.model === "string" ? obj.model : undefined,
91
+ // The native session id (when present) lets the engine resume this thread.
92
+ payload: {
93
+ tools: obj.tools,
94
+ plugins: obj.plugins,
95
+ mcp_servers: obj.mcp_servers,
96
+ ...(typeof obj.session_id === "string" ? { native_session_id: obj.session_id } : {}),
97
+ },
98
+ },
99
+ ];
100
+ }
101
+ if (type === "system" && obj.subtype === "api_retry") {
102
+ const errText = String(obj.error ?? "");
103
+ const ev = {
104
+ type: "thinking",
105
+ session_id: sessionId,
106
+ ts,
107
+ text: `api_retry: ${redactSecrets(errText)}`,
108
+ payload: { api_retry: true, retry_delay_ms: obj.retry_delay_ms },
109
+ };
110
+ // Adapter-layer translation of claude's native retry into a TYPED rate-limit
111
+ // signal (the budget layer reads the typed field, not the prose).
112
+ if (/rate.?limit|overloaded|too many requests|quota/i.test(errText)) {
113
+ ev.rate_limit = {
114
+ resets_at: null,
115
+ retry_delay_ms: typeof obj.retry_delay_ms === "number" ? obj.retry_delay_ms : null,
116
+ };
117
+ }
118
+ if (CLAUDE_TRANSIENT_RE.test(errText)) {
119
+ ev.transient = {
120
+ kind: /overloaded|temporar(?:y|ily) unavailable/i.test(errText) ? "service_unavailable" : "network",
121
+ retry_delay_ms: typeof obj.retry_delay_ms === "number" ? obj.retry_delay_ms : null,
122
+ };
123
+ }
124
+ return [ev];
125
+ }
126
+ if (type === "assistant") {
127
+ const content = obj.message?.content ?? [];
128
+ const out = [];
129
+ for (const block of content) {
130
+ if (block?.type === "text" && block.text) {
131
+ out.push({ type: "message", session_id: sessionId, ts, text: String(block.text) });
132
+ }
133
+ else if (block?.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim()) {
134
+ out.push({ type: "thinking", session_id: sessionId, ts, text: String(block.thinking) });
135
+ }
136
+ else if (block?.type === "tool_use") {
137
+ const name = String(block.name ?? "tool");
138
+ const input = block.input ?? {};
139
+ const tool = {
140
+ name,
141
+ kind: toolKindFor(name),
142
+ use_id: typeof block.id === "string" ? block.id : undefined,
143
+ target: toolTarget(name, input),
144
+ };
145
+ if (tool.use_id)
146
+ pendingTools.set(tool.use_id, tool);
147
+ if (EDIT_TOOLS.has(name)) {
148
+ const path = input.file_path ?? input.path ?? input.notebook_path;
149
+ out.push({ type: "file_change", session_id: sessionId, ts, tool, payload: { path, tool: name, tool_use_id: block.id } });
150
+ }
151
+ else if (name === "TodoWrite" && Array.isArray(input.todos)) {
152
+ // Typed plan progress, legacy surface: older claude CLIs plan
153
+ // via TodoWrite (whole-list updates; statuses map 1:1).
154
+ const items = input.todos.map((t, i) => ({
155
+ id: `claude-${i}`,
156
+ title: String(t.content ?? ""),
157
+ status: t.status === "completed" ? "completed" : t.status === "in_progress" ? "in_progress" : "pending",
158
+ }));
159
+ out.push({ type: "tool_call", session_id: sessionId, ts, text: name, tool, plan_progress: { items } });
160
+ }
161
+ else if (name === "TaskCreate" || name === "TaskUpdate") {
162
+ // Typed plan progress, current surface (LIVE-VERIFIED 2.1.165):
163
+ // claude plans via TaskCreate/TaskUpdate. The adapter accumulates the
164
+ // session's task list and re-emits the WHOLE list on every change
165
+ // (the run-event contract is last-wins).
166
+ const taskChanged = applySessionTask(sessionId, name, input);
167
+ if (taskChanged) {
168
+ out.push({
169
+ type: "tool_call",
170
+ session_id: sessionId,
171
+ ts,
172
+ text: name,
173
+ tool,
174
+ plan_progress: { items: sessionTaskItems(sessionId) },
175
+ });
176
+ }
177
+ else {
178
+ out.push({ type: "tool_call", session_id: sessionId, ts, text: name, tool, payload: { input } });
179
+ }
180
+ }
181
+ else if (name === "ExitPlanMode" && typeof input.plan === "string" && input.plan.trim()) {
182
+ // The produced plan rides in ExitPlanMode's INPUT; surface it as the
183
+ // message it is so plan-mode runs keep their work product headless.
184
+ out.push({ type: "message", session_id: sessionId, ts, text: String(input.plan) });
185
+ out.push({ type: "tool_call", session_id: sessionId, ts, text: name, tool });
186
+ }
187
+ else {
188
+ out.push({ type: "tool_call", session_id: sessionId, ts, text: name, tool, payload: { input } });
189
+ }
190
+ }
191
+ }
192
+ return out;
193
+ }
194
+ if (type === "user") {
195
+ const content = obj.message?.content ?? [];
196
+ const out = [];
197
+ for (const block of content) {
198
+ if (block?.type === "tool_result") {
199
+ const detail = summarizeToolResultContent(block.content);
200
+ const isError = block.is_error === true;
201
+ const useId = typeof block.tool_use_id === "string" ? block.tool_use_id : undefined;
202
+ const origin = useId ? pendingTools.get(useId) : undefined;
203
+ if (useId)
204
+ pendingTools.delete(useId);
205
+ // ExitPlanMode and AskUserQuestion are Claude's interactive FLOW
206
+ // CONTROL tools, not work tools. A headless (or declined / timed-out)
207
+ // is_error result is their documented way of ending the interaction —
208
+ // translate it to a benign thinking event (detail preserved, the
209
+ // question text stays in the timeline) instead of a blocking error
210
+ // tool_result. Recovery-by-same-tool is impossible by construction for
211
+ // these tools, so the generic unrecovered-tool-error rule must never
212
+ // fail a run over them (CLAUDEXOR_BIBLE §5).
213
+ if (origin?.name === "ExitPlanMode" && isError) {
214
+ out.push({
215
+ type: "thinking",
216
+ session_id: sessionId,
217
+ ts,
218
+ text: `plan mode ended (ExitPlanMode has no headless approver${detail ? `: ${detail}` : ""})`,
219
+ payload: { tool: "ExitPlanMode", tool_use_id: useId },
220
+ });
221
+ continue;
222
+ }
223
+ if (origin?.name === "AskUserQuestion" && isError) {
224
+ out.push({
225
+ type: "thinking",
226
+ session_id: sessionId,
227
+ ts,
228
+ text: `clarifying questions declined (no user answer); the model continues with assumptions${detail ? `: ${detail}` : ""}`,
229
+ payload: { tool: "AskUserQuestion", tool_use_id: useId },
230
+ });
231
+ continue;
232
+ }
233
+ const denied = isError && origin?.name !== undefined && deniedTools.has(origin.name);
234
+ const status = denied ? "denied" : isError ? "error" : "ok";
235
+ const tool = {
236
+ name: origin?.name ?? "tool",
237
+ kind: origin?.kind ?? "other",
238
+ use_id: useId,
239
+ target: origin?.target,
240
+ status,
241
+ error_summary: status === "error" ? detail || "tool result marked error" : undefined,
242
+ content_summary: detail || undefined,
243
+ };
244
+ out.push({
245
+ type: "tool_result",
246
+ session_id: sessionId,
247
+ ts,
248
+ text: status !== "ok" ? `tool_result: ${status}${detail ? `: ${detail}` : ""}` : "tool_result",
249
+ tool,
250
+ });
251
+ }
252
+ }
253
+ return out;
254
+ }
255
+ if (type === "result") {
256
+ // The session is finishing: release its accumulated task list.
257
+ releaseSessionTasks(sessionId);
258
+ const out = [];
259
+ const u = obj.usage ?? {};
260
+ out.push({
261
+ type: "usage",
262
+ session_id: sessionId,
263
+ ts,
264
+ usage: {
265
+ input_tokens: numberOrUndef(u.input_tokens),
266
+ output_tokens: numberOrUndef(u.output_tokens),
267
+ cached_input_tokens: sumOrUndef(u.cache_read_input_tokens, u.cache_creation_input_tokens),
268
+ cost_usd: numberOrUndef(obj.total_cost_usd),
269
+ },
270
+ });
271
+ if (typeof obj.result === "string" && obj.result.trim()) {
272
+ out.push({ type: "message", session_id: sessionId, ts, text: obj.result });
273
+ }
274
+ if (obj.subtype && obj.subtype !== "success") {
275
+ // `error_max_turns` is NOT a run failure: the turn ended because it hit the
276
+ // configured --max-turns ceiling, with all partial work already streamed
277
+ // (file_change / message events). Mirror the ExitPlanMode / AskUserQuestion
278
+ // benign-event handling above — surface it as a normal timeline event so
279
+ // the run is NOT marked errored. (CLAUDEXOR_BIBLE §5: benign turn-control
280
+ // outcomes never fail a run.)
281
+ if (obj.subtype === "error_max_turns") {
282
+ out.push({
283
+ type: "thinking",
284
+ session_id: sessionId,
285
+ ts,
286
+ text: "turn ended at the configured max-turns limit (partial work preserved)",
287
+ payload: { max_turns_reached: true, num_turns: numberOrUndef(obj.num_turns) },
288
+ });
289
+ }
290
+ else {
291
+ out.push({ type: "error", session_id: sessionId, ts, error: `result subtype: ${obj.subtype}` });
292
+ }
293
+ }
294
+ return out;
295
+ }
296
+ if (type === "system")
297
+ return []; // recognized but uninteresting system subtypes
298
+ // Control-protocol plumbing frames. Incoming control_requests are consumed
299
+ // by the interactive session handler BEFORE this parser; responses to OUR
300
+ // initialize handshake (and cancel acks) are recognized plumbing, never
301
+ // counted as dropped events.
302
+ if (type === "control_response" || type === "control_cancel_request")
303
+ return [];
304
+ return null;
305
+ }
306
+ function toolTarget(name, input) {
307
+ const candidates = [
308
+ input["query"],
309
+ input["url"],
310
+ input["file_path"],
311
+ input["path"],
312
+ input["command"],
313
+ ];
314
+ const found = candidates.find((v) => typeof v === "string" && v.trim().length > 0);
315
+ return found ? redactSecrets(`${name}: ${String(found)}`).slice(0, 500) : undefined;
316
+ }
317
+ function summarizeToolResultContent(content) {
318
+ if (typeof content === "string")
319
+ return redactSecrets(content).trim().replace(/\s+/g, " ").slice(0, 1000);
320
+ if (Array.isArray(content)) {
321
+ const parts = content
322
+ .map((item) => {
323
+ if (typeof item === "string")
324
+ return item;
325
+ if (!item || typeof item !== "object" || Array.isArray(item))
326
+ return "";
327
+ const rec = item;
328
+ return typeof rec["text"] === "string" ? rec["text"] : typeof rec["content"] === "string" ? rec["content"] : "";
329
+ })
330
+ .filter(Boolean);
331
+ return redactSecrets(parts.join(" ")).trim().replace(/\s+/g, " ").slice(0, 1000);
332
+ }
333
+ if (content && typeof content === "object") {
334
+ return redactSecrets(JSON.stringify(content)).slice(0, 1000);
335
+ }
336
+ return "";
337
+ }
338
+ function numberOrUndef(v) {
339
+ return typeof v === "number" ? v : undefined;
340
+ }
341
+ function sumOrUndef(...values) {
342
+ const nums = values.filter((v) => typeof v === "number");
343
+ if (nums.length === 0)
344
+ return undefined;
345
+ return nums.reduce((a, b) => a + b, 0);
346
+ }
347
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@claudexor/harness-claude",
3
+ "version": "1.0.0",
4
+ "license": "MIT",
5
+ "description": "Claude Code adapter (claude -p --output-format stream-json).",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@claudexor/core": "1.0.0",
20
+ "@claudexor/schema": "1.0.0",
21
+ "@claudexor/util": "1.0.0",
22
+ "@claudexor/secrets": "1.0.0"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/razzant/claudexor.git",
27
+ "directory": "packages/harness-claude"
28
+ },
29
+ "homepage": "https://github.com/razzant/claudexor#readme",
30
+ "bugs": {
31
+ "url": "https://github.com/razzant/claudexor/issues"
32
+ },
33
+ "engines": {
34
+ "node": ">=20.19"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc",
41
+ "typecheck": "tsc --noEmit"
42
+ }
43
+ }