@clanker-cleanroom/claude 0.2.8 → 0.2.9-build.45
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/lib/{binding-DRnzgDU4.mjs → binding-1hmUr1aZ.mjs} +2 -3
- package/lib/{binding-DRnzgDU4.mjs.map → binding-1hmUr1aZ.mjs.map} +1 -1
- package/lib/{binding-BZPFUSsx.cjs → binding-Df3GdqVB.cjs} +2 -3
- package/lib/binding-Df3GdqVB.cjs.map +1 -0
- package/lib/index.cjs +1 -1
- package/lib/index.mjs +1 -1
- package/lib/register.cjs +1 -1
- package/lib/register.mjs +1 -1
- package/package.json +2 -2
- package/src/binding.ts +1 -2
- package/lib/binding-BZPFUSsx.cjs.map +0 -1
|
@@ -161,7 +161,7 @@ const claudeBinding = {
|
|
|
161
161
|
trajectoryKind: "claude",
|
|
162
162
|
adaptEvents: adaptClaudeEvents,
|
|
163
163
|
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
164
|
-
command: ({
|
|
164
|
+
command: ({ model, sessionId }) => {
|
|
165
165
|
const claudeArgs = [
|
|
166
166
|
"claude",
|
|
167
167
|
"-p",
|
|
@@ -172,7 +172,6 @@ const claudeBinding = {
|
|
|
172
172
|
];
|
|
173
173
|
if (sessionId !== void 0 && sessionId !== "") claudeArgs.push("--resume", sessionId);
|
|
174
174
|
if (model !== void 0 && model !== "") claudeArgs.push("--model", model);
|
|
175
|
-
claudeArgs.push("--", prompt);
|
|
176
175
|
return claudeArgs;
|
|
177
176
|
},
|
|
178
177
|
prepare: async () => {
|
|
@@ -227,4 +226,4 @@ function describeErrorResult(result) {
|
|
|
227
226
|
//#endregion
|
|
228
227
|
export { CLAUDE_API_KEY_ENV as a, CLAUDE_IMAGE as c, resolveClaudeCredentials as i, CLAUDE_OAUTH_TOKEN_ENV as l, adaptClaudeEvents as n, CLAUDE_CONTAINER_CREDENTIALS_PATH as o, credentialsEnv as r, CLAUDE_CONTAINER_SESSION_PATH as s, claudeBinding as t, defaultClaudeHostCredentialsFile as u };
|
|
229
228
|
|
|
230
|
-
//# sourceMappingURL=binding-
|
|
229
|
+
//# sourceMappingURL=binding-1hmUr1aZ.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding-DRnzgDU4.mjs","names":["fsConstants"],"sources":["../src/constants.ts","../src/credentials.ts","../src/trajectory.ts","../src/binding.ts"],"sourcesContent":["import { CONTAINER_HOME } from \"clanker-cleanroom\";\n\nexport const CLAUDE_IMAGE = \"clanker-cleanroom/claude\";\nexport const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;\n/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */\nexport const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;\n\n/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */\nexport const CLAUDE_OAUTH_TOKEN_ENV = \"CLAUDE_CODE_OAUTH_TOKEN\";\n/** Anthropic API key (pay-as-you-go). */\nexport const CLAUDE_API_KEY_ENV = \"ANTHROPIC_API_KEY\";\n\n/** Linux hosts persist OAuth credentials here; macOS uses the Keychain instead. */\nexport const defaultClaudeHostCredentialsFile = (home: string): string =>\n `${home}/.claude/.credentials.json`;\n","import { access } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport { homedir } from \"node:os\";\n\nimport {\n CLAUDE_API_KEY_ENV,\n CLAUDE_OAUTH_TOKEN_ENV,\n defaultClaudeHostCredentialsFile,\n} from \"./constants.js\";\n\n/**\n * How Claude Code authenticates inside the container. Env-backed kinds are forwarded\n * to `docker run` by name (never on argv); the file kind is bind-mounted read-only.\n * See `constants.ts` for which host setups produce each.\n */\nexport type ClaudeCredentials =\n | { kind: \"oauth-token\"; token: string }\n | { kind: \"api-key\"; apiKey: string }\n | { kind: \"credentials-file\"; file: string };\n\n/** Env OAuth token, then env API key, then a readable host credentials file. */\nexport async function resolveClaudeCredentials(\n options: { env?: NodeJS.ProcessEnv; home?: string } = {},\n): Promise<ClaudeCredentials> {\n const env = options.env ?? process.env;\n const home = options.home ?? homedir();\n\n const token = env[CLAUDE_OAUTH_TOKEN_ENV];\n if (token !== undefined && token !== \"\") {\n return { kind: \"oauth-token\", token };\n }\n\n const apiKey = env[CLAUDE_API_KEY_ENV];\n if (apiKey !== undefined && apiKey !== \"\") {\n return { kind: \"api-key\", apiKey };\n }\n\n const file = defaultClaudeHostCredentialsFile(home);\n try {\n await access(file, fsConstants.R_OK);\n } catch {\n throw new Error(\n `Claude Code credentials not found. Set ${CLAUDE_OAUTH_TOKEN_ENV} (run \\`claude setup-token\\` on the host) ` +\n `or ${CLAUDE_API_KEY_ENV}, or provide ${file} (Linux hosts; macOS keeps credentials in the Keychain).`,\n );\n }\n\n return { kind: \"credentials-file\", file };\n}\n\n/** Secret values for the docker CLI process, keyed by env names forwarded via envPassthrough. */\nexport function credentialsEnv(credentials: ClaudeCredentials): Record<string, string> {\n switch (credentials.kind) {\n case \"oauth-token\":\n return { [CLAUDE_OAUTH_TOKEN_ENV]: credentials.token };\n case \"api-key\":\n return { [CLAUDE_API_KEY_ENV]: credentials.apiKey };\n case \"credentials-file\":\n return {};\n }\n}\n","import {\n asRecord,\n extractTextContent,\n readString,\n readTokenCount,\n type TrajectoryEvent,\n} from \"clanker-cleanroom\";\n\nexport function adaptClaudeEvents(rawEvents: readonly unknown[]): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n\n for (const raw of rawEvents) {\n const record = asRecord(raw);\n if (record === undefined) {\n events.push({ kind: \"other\", type: \"unknown\", raw });\n continue;\n }\n\n const type = readString(record.type) ?? \"unknown\";\n\n switch (type) {\n case \"system\":\n events.push({\n kind: \"system\",\n sessionId: readString(record.session_id),\n model: readString(record.model),\n raw,\n });\n break;\n case \"user\":\n events.push(...adaptClaudeUser(record, raw));\n break;\n case \"assistant\":\n events.push(...adaptClaudeAssistant(record, raw));\n break;\n case \"result\":\n events.push({\n kind: \"result\",\n text: readString(record.result) ?? \"\",\n isError: record.is_error === true,\n durationMs: readTokenCount(record.duration_ms),\n costUsd: readTokenCount(record.total_cost_usd),\n raw,\n });\n break;\n default:\n events.push({ kind: \"other\", type, raw });\n }\n }\n\n return events;\n}\n\nfunction adaptClaudeAssistant(\n record: Record<string, unknown>,\n raw: unknown,\n): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n if (text !== \"\") {\n events.push({ kind: \"assistant\", text, raw });\n }\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_use\") {\n continue;\n }\n events.push({\n kind: \"tool\",\n phase: \"started\",\n callId: readString(block.id) ?? \"\",\n name: readString(block.name) ?? \"unknown\",\n args: block.input ?? null,\n result: null,\n raw,\n });\n }\n\n if (events.length === 0) {\n events.push({ kind: \"assistant\", text: \"\", raw });\n }\n\n return events;\n}\n\nfunction adaptClaudeUser(record: Record<string, unknown>, raw: unknown): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n const toolResults: TrajectoryEvent[] = [];\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_result\") {\n continue;\n }\n toolResults.push({\n kind: \"tool\",\n phase: \"completed\",\n callId: readString(block.tool_use_id) ?? \"\",\n name: \"tool_result\",\n args: null,\n result: block.content ?? null,\n raw,\n });\n }\n\n if (text !== \"\" || toolResults.length === 0) {\n events.push({ kind: \"user\", text, raw });\n }\n events.push(...toolResults);\n return events;\n}\n\nfunction contentBlocks(message: unknown): Record<string, unknown>[] {\n const content = asRecord(message)?.content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.map((block) => asRecord(block)).filter((block) => block !== undefined);\n}\n","import {\n asRecord,\n parseAgentJsonOutput,\n readTokenCount,\n type AgentBinding,\n type AgentRunResult,\n type DockerVolumeMount,\n} from \"clanker-cleanroom\";\n\nimport { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE } from \"./constants.js\";\nimport { credentialsEnv, resolveClaudeCredentials } from \"./credentials.js\";\nimport { adaptClaudeEvents } from \"./trajectory.js\";\n\nexport const claudeBinding: AgentBinding = {\n image: CLAUDE_IMAGE,\n displayName: \"Claude\",\n trajectoryKind: \"claude\",\n adaptEvents: adaptClaudeEvents,\n sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,\n command: ({ prompt, model, sessionId }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\n ];\n if (sessionId !== undefined && sessionId !== \"\") {\n claudeArgs.push(\"--resume\", sessionId);\n }\n if (model !== undefined && model !== \"\") {\n claudeArgs.push(\"--model\", model);\n }\n claudeArgs.push(\"--\", prompt);\n return claudeArgs;\n },\n prepare: async () => {\n const credentials = await resolveClaudeCredentials();\n const volumes: DockerVolumeMount[] = [];\n if (credentials.kind === \"credentials-file\") {\n volumes.push({\n host: credentials.file,\n container: CLAUDE_CONTAINER_CREDENTIALS_PATH,\n mode: \"ro\",\n });\n }\n return {\n volumes,\n env: credentialsEnv(credentials),\n };\n },\n parseResult: parseClaudeResult,\n describeFailure: describeClaudeFailure,\n};\n\nfunction parseClaudeResult(trajectory: string): AgentRunResult {\n const parsed = parseAgentJsonOutput(trajectory);\n if (isErrorResult(parsed)) {\n throw new Error(`Claude agent reported an error: ${describeErrorResult(parsed)}`);\n }\n\n const record = asRecord(parsed);\n const usage = asRecord(record?.usage);\n\n return {\n durationMs: readTokenCount(record?.duration_ms),\n costUsd: readTokenCount(record?.total_cost_usd),\n usage: {\n inputTokens: readTokenCount(usage?.input_tokens ?? usage?.inputTokens),\n outputTokens: readTokenCount(usage?.output_tokens ?? usage?.outputTokens),\n cacheReadTokens: readTokenCount(usage?.cache_read_input_tokens ?? usage?.cacheReadTokens),\n cacheWriteTokens: readTokenCount(\n usage?.cache_creation_input_tokens ?? usage?.cacheWriteTokens,\n ),\n },\n };\n}\n\nfunction describeClaudeFailure(trajectory: string): string | undefined {\n try {\n const parsed = parseAgentJsonOutput(trajectory);\n return isErrorResult(parsed) ? describeErrorResult(parsed) : undefined;\n } catch {\n return undefined;\n }\n}\n\ntype ClaudeErrorResult = {\n is_error: true;\n result: string;\n subtype?: string;\n terminal_reason?: string;\n};\n\nfunction isErrorResult(value: unknown): value is ClaudeErrorResult {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { is_error?: unknown }).is_error === true\n );\n}\n\nfunction describeErrorResult(result: ClaudeErrorResult): string {\n const message = String(result.result);\n\n if (result.terminal_reason !== undefined && result.terminal_reason !== \"completed\") {\n return `${result.terminal_reason}: ${message}`;\n }\n\n if (result.subtype !== undefined && result.subtype !== \"success\") {\n return `${result.subtype}: ${message}`;\n }\n\n return message;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"binding-1hmUr1aZ.mjs","names":["fsConstants"],"sources":["../src/constants.ts","../src/credentials.ts","../src/trajectory.ts","../src/binding.ts"],"sourcesContent":["import { CONTAINER_HOME } from \"clanker-cleanroom\";\n\nexport const CLAUDE_IMAGE = \"clanker-cleanroom/claude\";\nexport const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;\n/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */\nexport const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;\n\n/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */\nexport const CLAUDE_OAUTH_TOKEN_ENV = \"CLAUDE_CODE_OAUTH_TOKEN\";\n/** Anthropic API key (pay-as-you-go). */\nexport const CLAUDE_API_KEY_ENV = \"ANTHROPIC_API_KEY\";\n\n/** Linux hosts persist OAuth credentials here; macOS uses the Keychain instead. */\nexport const defaultClaudeHostCredentialsFile = (home: string): string =>\n `${home}/.claude/.credentials.json`;\n","import { access } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport { homedir } from \"node:os\";\n\nimport {\n CLAUDE_API_KEY_ENV,\n CLAUDE_OAUTH_TOKEN_ENV,\n defaultClaudeHostCredentialsFile,\n} from \"./constants.js\";\n\n/**\n * How Claude Code authenticates inside the container. Env-backed kinds are forwarded\n * to `docker run` by name (never on argv); the file kind is bind-mounted read-only.\n * See `constants.ts` for which host setups produce each.\n */\nexport type ClaudeCredentials =\n | { kind: \"oauth-token\"; token: string }\n | { kind: \"api-key\"; apiKey: string }\n | { kind: \"credentials-file\"; file: string };\n\n/** Env OAuth token, then env API key, then a readable host credentials file. */\nexport async function resolveClaudeCredentials(\n options: { env?: NodeJS.ProcessEnv; home?: string } = {},\n): Promise<ClaudeCredentials> {\n const env = options.env ?? process.env;\n const home = options.home ?? homedir();\n\n const token = env[CLAUDE_OAUTH_TOKEN_ENV];\n if (token !== undefined && token !== \"\") {\n return { kind: \"oauth-token\", token };\n }\n\n const apiKey = env[CLAUDE_API_KEY_ENV];\n if (apiKey !== undefined && apiKey !== \"\") {\n return { kind: \"api-key\", apiKey };\n }\n\n const file = defaultClaudeHostCredentialsFile(home);\n try {\n await access(file, fsConstants.R_OK);\n } catch {\n throw new Error(\n `Claude Code credentials not found. Set ${CLAUDE_OAUTH_TOKEN_ENV} (run \\`claude setup-token\\` on the host) ` +\n `or ${CLAUDE_API_KEY_ENV}, or provide ${file} (Linux hosts; macOS keeps credentials in the Keychain).`,\n );\n }\n\n return { kind: \"credentials-file\", file };\n}\n\n/** Secret values for the docker CLI process, keyed by env names forwarded via envPassthrough. */\nexport function credentialsEnv(credentials: ClaudeCredentials): Record<string, string> {\n switch (credentials.kind) {\n case \"oauth-token\":\n return { [CLAUDE_OAUTH_TOKEN_ENV]: credentials.token };\n case \"api-key\":\n return { [CLAUDE_API_KEY_ENV]: credentials.apiKey };\n case \"credentials-file\":\n return {};\n }\n}\n","import {\n asRecord,\n extractTextContent,\n readString,\n readTokenCount,\n type TrajectoryEvent,\n} from \"clanker-cleanroom\";\n\nexport function adaptClaudeEvents(rawEvents: readonly unknown[]): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n\n for (const raw of rawEvents) {\n const record = asRecord(raw);\n if (record === undefined) {\n events.push({ kind: \"other\", type: \"unknown\", raw });\n continue;\n }\n\n const type = readString(record.type) ?? \"unknown\";\n\n switch (type) {\n case \"system\":\n events.push({\n kind: \"system\",\n sessionId: readString(record.session_id),\n model: readString(record.model),\n raw,\n });\n break;\n case \"user\":\n events.push(...adaptClaudeUser(record, raw));\n break;\n case \"assistant\":\n events.push(...adaptClaudeAssistant(record, raw));\n break;\n case \"result\":\n events.push({\n kind: \"result\",\n text: readString(record.result) ?? \"\",\n isError: record.is_error === true,\n durationMs: readTokenCount(record.duration_ms),\n costUsd: readTokenCount(record.total_cost_usd),\n raw,\n });\n break;\n default:\n events.push({ kind: \"other\", type, raw });\n }\n }\n\n return events;\n}\n\nfunction adaptClaudeAssistant(\n record: Record<string, unknown>,\n raw: unknown,\n): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n if (text !== \"\") {\n events.push({ kind: \"assistant\", text, raw });\n }\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_use\") {\n continue;\n }\n events.push({\n kind: \"tool\",\n phase: \"started\",\n callId: readString(block.id) ?? \"\",\n name: readString(block.name) ?? \"unknown\",\n args: block.input ?? null,\n result: null,\n raw,\n });\n }\n\n if (events.length === 0) {\n events.push({ kind: \"assistant\", text: \"\", raw });\n }\n\n return events;\n}\n\nfunction adaptClaudeUser(record: Record<string, unknown>, raw: unknown): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n const toolResults: TrajectoryEvent[] = [];\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_result\") {\n continue;\n }\n toolResults.push({\n kind: \"tool\",\n phase: \"completed\",\n callId: readString(block.tool_use_id) ?? \"\",\n name: \"tool_result\",\n args: null,\n result: block.content ?? null,\n raw,\n });\n }\n\n if (text !== \"\" || toolResults.length === 0) {\n events.push({ kind: \"user\", text, raw });\n }\n events.push(...toolResults);\n return events;\n}\n\nfunction contentBlocks(message: unknown): Record<string, unknown>[] {\n const content = asRecord(message)?.content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.map((block) => asRecord(block)).filter((block) => block !== undefined);\n}\n","import {\n asRecord,\n parseAgentJsonOutput,\n readTokenCount,\n type AgentBinding,\n type AgentRunResult,\n type DockerVolumeMount,\n} from \"clanker-cleanroom\";\n\nimport { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE } from \"./constants.js\";\nimport { credentialsEnv, resolveClaudeCredentials } from \"./credentials.js\";\nimport { adaptClaudeEvents } from \"./trajectory.js\";\n\nexport const claudeBinding: AgentBinding = {\n image: CLAUDE_IMAGE,\n displayName: \"Claude\",\n trajectoryKind: \"claude\",\n adaptEvents: adaptClaudeEvents,\n sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,\n command: ({ model, sessionId }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\n ];\n if (sessionId !== undefined && sessionId !== \"\") {\n claudeArgs.push(\"--resume\", sessionId);\n }\n if (model !== undefined && model !== \"\") {\n claudeArgs.push(\"--model\", model);\n }\n return claudeArgs;\n },\n prepare: async () => {\n const credentials = await resolveClaudeCredentials();\n const volumes: DockerVolumeMount[] = [];\n if (credentials.kind === \"credentials-file\") {\n volumes.push({\n host: credentials.file,\n container: CLAUDE_CONTAINER_CREDENTIALS_PATH,\n mode: \"ro\",\n });\n }\n return {\n volumes,\n env: credentialsEnv(credentials),\n };\n },\n parseResult: parseClaudeResult,\n describeFailure: describeClaudeFailure,\n};\n\nfunction parseClaudeResult(trajectory: string): AgentRunResult {\n const parsed = parseAgentJsonOutput(trajectory);\n if (isErrorResult(parsed)) {\n throw new Error(`Claude agent reported an error: ${describeErrorResult(parsed)}`);\n }\n\n const record = asRecord(parsed);\n const usage = asRecord(record?.usage);\n\n return {\n durationMs: readTokenCount(record?.duration_ms),\n costUsd: readTokenCount(record?.total_cost_usd),\n usage: {\n inputTokens: readTokenCount(usage?.input_tokens ?? usage?.inputTokens),\n outputTokens: readTokenCount(usage?.output_tokens ?? usage?.outputTokens),\n cacheReadTokens: readTokenCount(usage?.cache_read_input_tokens ?? usage?.cacheReadTokens),\n cacheWriteTokens: readTokenCount(\n usage?.cache_creation_input_tokens ?? usage?.cacheWriteTokens,\n ),\n },\n };\n}\n\nfunction describeClaudeFailure(trajectory: string): string | undefined {\n try {\n const parsed = parseAgentJsonOutput(trajectory);\n return isErrorResult(parsed) ? describeErrorResult(parsed) : undefined;\n } catch {\n return undefined;\n }\n}\n\ntype ClaudeErrorResult = {\n is_error: true;\n result: string;\n subtype?: string;\n terminal_reason?: string;\n};\n\nfunction isErrorResult(value: unknown): value is ClaudeErrorResult {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { is_error?: unknown }).is_error === true\n );\n}\n\nfunction describeErrorResult(result: ClaudeErrorResult): string {\n const message = String(result.result);\n\n if (result.terminal_reason !== undefined && result.terminal_reason !== \"completed\") {\n return `${result.terminal_reason}: ${message}`;\n }\n\n if (result.subtype !== undefined && result.subtype !== \"success\") {\n return `${result.subtype}: ${message}`;\n }\n\n return message;\n}\n"],"mappings":"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"}
|
|
@@ -161,7 +161,7 @@ const claudeBinding = {
|
|
|
161
161
|
trajectoryKind: "claude",
|
|
162
162
|
adaptEvents: adaptClaudeEvents,
|
|
163
163
|
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
164
|
-
command: ({
|
|
164
|
+
command: ({ model, sessionId }) => {
|
|
165
165
|
const claudeArgs = [
|
|
166
166
|
"claude",
|
|
167
167
|
"-p",
|
|
@@ -172,7 +172,6 @@ const claudeBinding = {
|
|
|
172
172
|
];
|
|
173
173
|
if (sessionId !== void 0 && sessionId !== "") claudeArgs.push("--resume", sessionId);
|
|
174
174
|
if (model !== void 0 && model !== "") claudeArgs.push("--model", model);
|
|
175
|
-
claudeArgs.push("--", prompt);
|
|
176
175
|
return claudeArgs;
|
|
177
176
|
},
|
|
178
177
|
prepare: async () => {
|
|
@@ -286,4 +285,4 @@ Object.defineProperty(exports, "resolveClaudeCredentials", {
|
|
|
286
285
|
}
|
|
287
286
|
});
|
|
288
287
|
|
|
289
|
-
//# sourceMappingURL=binding-
|
|
288
|
+
//# sourceMappingURL=binding-Df3GdqVB.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binding-Df3GdqVB.cjs","names":["CONTAINER_HOME","homedir","access","fsConstants","asRecord","readString","readTokenCount","extractTextContent","parseAgentJsonOutput","asRecord","readTokenCount"],"sources":["../src/constants.ts","../src/credentials.ts","../src/trajectory.ts","../src/binding.ts"],"sourcesContent":["import { CONTAINER_HOME } from \"clanker-cleanroom\";\n\nexport const CLAUDE_IMAGE = \"clanker-cleanroom/claude\";\nexport const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;\n/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */\nexport const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;\n\n/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */\nexport const CLAUDE_OAUTH_TOKEN_ENV = \"CLAUDE_CODE_OAUTH_TOKEN\";\n/** Anthropic API key (pay-as-you-go). */\nexport const CLAUDE_API_KEY_ENV = \"ANTHROPIC_API_KEY\";\n\n/** Linux hosts persist OAuth credentials here; macOS uses the Keychain instead. */\nexport const defaultClaudeHostCredentialsFile = (home: string): string =>\n `${home}/.claude/.credentials.json`;\n","import { access } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport { homedir } from \"node:os\";\n\nimport {\n CLAUDE_API_KEY_ENV,\n CLAUDE_OAUTH_TOKEN_ENV,\n defaultClaudeHostCredentialsFile,\n} from \"./constants.js\";\n\n/**\n * How Claude Code authenticates inside the container. Env-backed kinds are forwarded\n * to `docker run` by name (never on argv); the file kind is bind-mounted read-only.\n * See `constants.ts` for which host setups produce each.\n */\nexport type ClaudeCredentials =\n | { kind: \"oauth-token\"; token: string }\n | { kind: \"api-key\"; apiKey: string }\n | { kind: \"credentials-file\"; file: string };\n\n/** Env OAuth token, then env API key, then a readable host credentials file. */\nexport async function resolveClaudeCredentials(\n options: { env?: NodeJS.ProcessEnv; home?: string } = {},\n): Promise<ClaudeCredentials> {\n const env = options.env ?? process.env;\n const home = options.home ?? homedir();\n\n const token = env[CLAUDE_OAUTH_TOKEN_ENV];\n if (token !== undefined && token !== \"\") {\n return { kind: \"oauth-token\", token };\n }\n\n const apiKey = env[CLAUDE_API_KEY_ENV];\n if (apiKey !== undefined && apiKey !== \"\") {\n return { kind: \"api-key\", apiKey };\n }\n\n const file = defaultClaudeHostCredentialsFile(home);\n try {\n await access(file, fsConstants.R_OK);\n } catch {\n throw new Error(\n `Claude Code credentials not found. Set ${CLAUDE_OAUTH_TOKEN_ENV} (run \\`claude setup-token\\` on the host) ` +\n `or ${CLAUDE_API_KEY_ENV}, or provide ${file} (Linux hosts; macOS keeps credentials in the Keychain).`,\n );\n }\n\n return { kind: \"credentials-file\", file };\n}\n\n/** Secret values for the docker CLI process, keyed by env names forwarded via envPassthrough. */\nexport function credentialsEnv(credentials: ClaudeCredentials): Record<string, string> {\n switch (credentials.kind) {\n case \"oauth-token\":\n return { [CLAUDE_OAUTH_TOKEN_ENV]: credentials.token };\n case \"api-key\":\n return { [CLAUDE_API_KEY_ENV]: credentials.apiKey };\n case \"credentials-file\":\n return {};\n }\n}\n","import {\n asRecord,\n extractTextContent,\n readString,\n readTokenCount,\n type TrajectoryEvent,\n} from \"clanker-cleanroom\";\n\nexport function adaptClaudeEvents(rawEvents: readonly unknown[]): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n\n for (const raw of rawEvents) {\n const record = asRecord(raw);\n if (record === undefined) {\n events.push({ kind: \"other\", type: \"unknown\", raw });\n continue;\n }\n\n const type = readString(record.type) ?? \"unknown\";\n\n switch (type) {\n case \"system\":\n events.push({\n kind: \"system\",\n sessionId: readString(record.session_id),\n model: readString(record.model),\n raw,\n });\n break;\n case \"user\":\n events.push(...adaptClaudeUser(record, raw));\n break;\n case \"assistant\":\n events.push(...adaptClaudeAssistant(record, raw));\n break;\n case \"result\":\n events.push({\n kind: \"result\",\n text: readString(record.result) ?? \"\",\n isError: record.is_error === true,\n durationMs: readTokenCount(record.duration_ms),\n costUsd: readTokenCount(record.total_cost_usd),\n raw,\n });\n break;\n default:\n events.push({ kind: \"other\", type, raw });\n }\n }\n\n return events;\n}\n\nfunction adaptClaudeAssistant(\n record: Record<string, unknown>,\n raw: unknown,\n): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n if (text !== \"\") {\n events.push({ kind: \"assistant\", text, raw });\n }\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_use\") {\n continue;\n }\n events.push({\n kind: \"tool\",\n phase: \"started\",\n callId: readString(block.id) ?? \"\",\n name: readString(block.name) ?? \"unknown\",\n args: block.input ?? null,\n result: null,\n raw,\n });\n }\n\n if (events.length === 0) {\n events.push({ kind: \"assistant\", text: \"\", raw });\n }\n\n return events;\n}\n\nfunction adaptClaudeUser(record: Record<string, unknown>, raw: unknown): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n const toolResults: TrajectoryEvent[] = [];\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_result\") {\n continue;\n }\n toolResults.push({\n kind: \"tool\",\n phase: \"completed\",\n callId: readString(block.tool_use_id) ?? \"\",\n name: \"tool_result\",\n args: null,\n result: block.content ?? null,\n raw,\n });\n }\n\n if (text !== \"\" || toolResults.length === 0) {\n events.push({ kind: \"user\", text, raw });\n }\n events.push(...toolResults);\n return events;\n}\n\nfunction contentBlocks(message: unknown): Record<string, unknown>[] {\n const content = asRecord(message)?.content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.map((block) => asRecord(block)).filter((block) => block !== undefined);\n}\n","import {\n asRecord,\n parseAgentJsonOutput,\n readTokenCount,\n type AgentBinding,\n type AgentRunResult,\n type DockerVolumeMount,\n} from \"clanker-cleanroom\";\n\nimport { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE } from \"./constants.js\";\nimport { credentialsEnv, resolveClaudeCredentials } from \"./credentials.js\";\nimport { adaptClaudeEvents } from \"./trajectory.js\";\n\nexport const claudeBinding: AgentBinding = {\n image: CLAUDE_IMAGE,\n displayName: \"Claude\",\n trajectoryKind: \"claude\",\n adaptEvents: adaptClaudeEvents,\n sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,\n command: ({ model, sessionId }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\n ];\n if (sessionId !== undefined && sessionId !== \"\") {\n claudeArgs.push(\"--resume\", sessionId);\n }\n if (model !== undefined && model !== \"\") {\n claudeArgs.push(\"--model\", model);\n }\n return claudeArgs;\n },\n prepare: async () => {\n const credentials = await resolveClaudeCredentials();\n const volumes: DockerVolumeMount[] = [];\n if (credentials.kind === \"credentials-file\") {\n volumes.push({\n host: credentials.file,\n container: CLAUDE_CONTAINER_CREDENTIALS_PATH,\n mode: \"ro\",\n });\n }\n return {\n volumes,\n env: credentialsEnv(credentials),\n };\n },\n parseResult: parseClaudeResult,\n describeFailure: describeClaudeFailure,\n};\n\nfunction parseClaudeResult(trajectory: string): AgentRunResult {\n const parsed = parseAgentJsonOutput(trajectory);\n if (isErrorResult(parsed)) {\n throw new Error(`Claude agent reported an error: ${describeErrorResult(parsed)}`);\n }\n\n const record = asRecord(parsed);\n const usage = asRecord(record?.usage);\n\n return {\n durationMs: readTokenCount(record?.duration_ms),\n costUsd: readTokenCount(record?.total_cost_usd),\n usage: {\n inputTokens: readTokenCount(usage?.input_tokens ?? usage?.inputTokens),\n outputTokens: readTokenCount(usage?.output_tokens ?? usage?.outputTokens),\n cacheReadTokens: readTokenCount(usage?.cache_read_input_tokens ?? usage?.cacheReadTokens),\n cacheWriteTokens: readTokenCount(\n usage?.cache_creation_input_tokens ?? usage?.cacheWriteTokens,\n ),\n },\n };\n}\n\nfunction describeClaudeFailure(trajectory: string): string | undefined {\n try {\n const parsed = parseAgentJsonOutput(trajectory);\n return isErrorResult(parsed) ? describeErrorResult(parsed) : undefined;\n } catch {\n return undefined;\n }\n}\n\ntype ClaudeErrorResult = {\n is_error: true;\n result: string;\n subtype?: string;\n terminal_reason?: string;\n};\n\nfunction isErrorResult(value: unknown): value is ClaudeErrorResult {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { is_error?: unknown }).is_error === true\n );\n}\n\nfunction describeErrorResult(result: ClaudeErrorResult): string {\n const message = String(result.result);\n\n if (result.terminal_reason !== undefined && result.terminal_reason !== \"completed\") {\n return `${result.terminal_reason}: ${message}`;\n }\n\n if (result.subtype !== undefined && result.subtype !== \"success\") {\n return `${result.subtype}: ${message}`;\n }\n\n return message;\n}\n"],"mappings":"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"}
|
package/lib/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_binding = require("./binding-
|
|
2
|
+
const require_binding = require("./binding-Df3GdqVB.cjs");
|
|
3
3
|
let clanker_cleanroom = require("clanker-cleanroom");
|
|
4
4
|
let node_path = require("node:path");
|
|
5
5
|
let node_url = require("node:url");
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CLAUDE_API_KEY_ENV, c as CLAUDE_IMAGE, i as resolveClaudeCredentials, l as CLAUDE_OAUTH_TOKEN_ENV, n as adaptClaudeEvents, o as CLAUDE_CONTAINER_CREDENTIALS_PATH, r as credentialsEnv, s as CLAUDE_CONTAINER_SESSION_PATH, t as claudeBinding, u as defaultClaudeHostCredentialsFile } from "./binding-
|
|
1
|
+
import { a as CLAUDE_API_KEY_ENV, c as CLAUDE_IMAGE, i as resolveClaudeCredentials, l as CLAUDE_OAUTH_TOKEN_ENV, n as adaptClaudeEvents, o as CLAUDE_CONTAINER_CREDENTIALS_PATH, r as credentialsEnv, s as CLAUDE_CONTAINER_SESSION_PATH, t as claudeBinding, u as defaultClaudeHostCredentialsFile } from "./binding-1hmUr1aZ.mjs";
|
|
2
2
|
import { Agent } from "clanker-cleanroom";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
package/lib/register.cjs
CHANGED
package/lib/register.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clanker-cleanroom/claude",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9-build.45",
|
|
4
4
|
"description": "Claude Code agent binding for clanker-cleanroom",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
}
|
|
116
116
|
},
|
|
117
117
|
"dependencies": {
|
|
118
|
-
"clanker-cleanroom": "0.2.
|
|
118
|
+
"clanker-cleanroom": "0.2.9-build.45"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@types/node": "^26.2.0",
|
package/src/binding.ts
CHANGED
|
@@ -17,7 +17,7 @@ export const claudeBinding: AgentBinding = {
|
|
|
17
17
|
trajectoryKind: "claude",
|
|
18
18
|
adaptEvents: adaptClaudeEvents,
|
|
19
19
|
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
20
|
-
command: ({
|
|
20
|
+
command: ({ model, sessionId }) => {
|
|
21
21
|
const claudeArgs = [
|
|
22
22
|
"claude",
|
|
23
23
|
"-p",
|
|
@@ -32,7 +32,6 @@ export const claudeBinding: AgentBinding = {
|
|
|
32
32
|
if (model !== undefined && model !== "") {
|
|
33
33
|
claudeArgs.push("--model", model);
|
|
34
34
|
}
|
|
35
|
-
claudeArgs.push("--", prompt);
|
|
36
35
|
return claudeArgs;
|
|
37
36
|
},
|
|
38
37
|
prepare: async () => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"binding-BZPFUSsx.cjs","names":["CONTAINER_HOME","homedir","access","fsConstants","asRecord","readString","readTokenCount","extractTextContent","parseAgentJsonOutput","asRecord","readTokenCount"],"sources":["../src/constants.ts","../src/credentials.ts","../src/trajectory.ts","../src/binding.ts"],"sourcesContent":["import { CONTAINER_HOME } from \"clanker-cleanroom\";\n\nexport const CLAUDE_IMAGE = \"clanker-cleanroom/claude\";\nexport const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;\n/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */\nexport const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;\n\n/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */\nexport const CLAUDE_OAUTH_TOKEN_ENV = \"CLAUDE_CODE_OAUTH_TOKEN\";\n/** Anthropic API key (pay-as-you-go). */\nexport const CLAUDE_API_KEY_ENV = \"ANTHROPIC_API_KEY\";\n\n/** Linux hosts persist OAuth credentials here; macOS uses the Keychain instead. */\nexport const defaultClaudeHostCredentialsFile = (home: string): string =>\n `${home}/.claude/.credentials.json`;\n","import { access } from \"node:fs/promises\";\nimport { constants as fsConstants } from \"node:fs\";\nimport { homedir } from \"node:os\";\n\nimport {\n CLAUDE_API_KEY_ENV,\n CLAUDE_OAUTH_TOKEN_ENV,\n defaultClaudeHostCredentialsFile,\n} from \"./constants.js\";\n\n/**\n * How Claude Code authenticates inside the container. Env-backed kinds are forwarded\n * to `docker run` by name (never on argv); the file kind is bind-mounted read-only.\n * See `constants.ts` for which host setups produce each.\n */\nexport type ClaudeCredentials =\n | { kind: \"oauth-token\"; token: string }\n | { kind: \"api-key\"; apiKey: string }\n | { kind: \"credentials-file\"; file: string };\n\n/** Env OAuth token, then env API key, then a readable host credentials file. */\nexport async function resolveClaudeCredentials(\n options: { env?: NodeJS.ProcessEnv; home?: string } = {},\n): Promise<ClaudeCredentials> {\n const env = options.env ?? process.env;\n const home = options.home ?? homedir();\n\n const token = env[CLAUDE_OAUTH_TOKEN_ENV];\n if (token !== undefined && token !== \"\") {\n return { kind: \"oauth-token\", token };\n }\n\n const apiKey = env[CLAUDE_API_KEY_ENV];\n if (apiKey !== undefined && apiKey !== \"\") {\n return { kind: \"api-key\", apiKey };\n }\n\n const file = defaultClaudeHostCredentialsFile(home);\n try {\n await access(file, fsConstants.R_OK);\n } catch {\n throw new Error(\n `Claude Code credentials not found. Set ${CLAUDE_OAUTH_TOKEN_ENV} (run \\`claude setup-token\\` on the host) ` +\n `or ${CLAUDE_API_KEY_ENV}, or provide ${file} (Linux hosts; macOS keeps credentials in the Keychain).`,\n );\n }\n\n return { kind: \"credentials-file\", file };\n}\n\n/** Secret values for the docker CLI process, keyed by env names forwarded via envPassthrough. */\nexport function credentialsEnv(credentials: ClaudeCredentials): Record<string, string> {\n switch (credentials.kind) {\n case \"oauth-token\":\n return { [CLAUDE_OAUTH_TOKEN_ENV]: credentials.token };\n case \"api-key\":\n return { [CLAUDE_API_KEY_ENV]: credentials.apiKey };\n case \"credentials-file\":\n return {};\n }\n}\n","import {\n asRecord,\n extractTextContent,\n readString,\n readTokenCount,\n type TrajectoryEvent,\n} from \"clanker-cleanroom\";\n\nexport function adaptClaudeEvents(rawEvents: readonly unknown[]): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n\n for (const raw of rawEvents) {\n const record = asRecord(raw);\n if (record === undefined) {\n events.push({ kind: \"other\", type: \"unknown\", raw });\n continue;\n }\n\n const type = readString(record.type) ?? \"unknown\";\n\n switch (type) {\n case \"system\":\n events.push({\n kind: \"system\",\n sessionId: readString(record.session_id),\n model: readString(record.model),\n raw,\n });\n break;\n case \"user\":\n events.push(...adaptClaudeUser(record, raw));\n break;\n case \"assistant\":\n events.push(...adaptClaudeAssistant(record, raw));\n break;\n case \"result\":\n events.push({\n kind: \"result\",\n text: readString(record.result) ?? \"\",\n isError: record.is_error === true,\n durationMs: readTokenCount(record.duration_ms),\n costUsd: readTokenCount(record.total_cost_usd),\n raw,\n });\n break;\n default:\n events.push({ kind: \"other\", type, raw });\n }\n }\n\n return events;\n}\n\nfunction adaptClaudeAssistant(\n record: Record<string, unknown>,\n raw: unknown,\n): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n if (text !== \"\") {\n events.push({ kind: \"assistant\", text, raw });\n }\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_use\") {\n continue;\n }\n events.push({\n kind: \"tool\",\n phase: \"started\",\n callId: readString(block.id) ?? \"\",\n name: readString(block.name) ?? \"unknown\",\n args: block.input ?? null,\n result: null,\n raw,\n });\n }\n\n if (events.length === 0) {\n events.push({ kind: \"assistant\", text: \"\", raw });\n }\n\n return events;\n}\n\nfunction adaptClaudeUser(record: Record<string, unknown>, raw: unknown): TrajectoryEvent[] {\n const events: TrajectoryEvent[] = [];\n const text = extractTextContent(record.message);\n const toolResults: TrajectoryEvent[] = [];\n\n for (const block of contentBlocks(record.message)) {\n if (block.type !== \"tool_result\") {\n continue;\n }\n toolResults.push({\n kind: \"tool\",\n phase: \"completed\",\n callId: readString(block.tool_use_id) ?? \"\",\n name: \"tool_result\",\n args: null,\n result: block.content ?? null,\n raw,\n });\n }\n\n if (text !== \"\" || toolResults.length === 0) {\n events.push({ kind: \"user\", text, raw });\n }\n events.push(...toolResults);\n return events;\n}\n\nfunction contentBlocks(message: unknown): Record<string, unknown>[] {\n const content = asRecord(message)?.content;\n if (!Array.isArray(content)) {\n return [];\n }\n return content.map((block) => asRecord(block)).filter((block) => block !== undefined);\n}\n","import {\n asRecord,\n parseAgentJsonOutput,\n readTokenCount,\n type AgentBinding,\n type AgentRunResult,\n type DockerVolumeMount,\n} from \"clanker-cleanroom\";\n\nimport { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE } from \"./constants.js\";\nimport { credentialsEnv, resolveClaudeCredentials } from \"./credentials.js\";\nimport { adaptClaudeEvents } from \"./trajectory.js\";\n\nexport const claudeBinding: AgentBinding = {\n image: CLAUDE_IMAGE,\n displayName: \"Claude\",\n trajectoryKind: \"claude\",\n adaptEvents: adaptClaudeEvents,\n sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,\n command: ({ prompt, model, sessionId }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\n ];\n if (sessionId !== undefined && sessionId !== \"\") {\n claudeArgs.push(\"--resume\", sessionId);\n }\n if (model !== undefined && model !== \"\") {\n claudeArgs.push(\"--model\", model);\n }\n claudeArgs.push(\"--\", prompt);\n return claudeArgs;\n },\n prepare: async () => {\n const credentials = await resolveClaudeCredentials();\n const volumes: DockerVolumeMount[] = [];\n if (credentials.kind === \"credentials-file\") {\n volumes.push({\n host: credentials.file,\n container: CLAUDE_CONTAINER_CREDENTIALS_PATH,\n mode: \"ro\",\n });\n }\n return {\n volumes,\n env: credentialsEnv(credentials),\n };\n },\n parseResult: parseClaudeResult,\n describeFailure: describeClaudeFailure,\n};\n\nfunction parseClaudeResult(trajectory: string): AgentRunResult {\n const parsed = parseAgentJsonOutput(trajectory);\n if (isErrorResult(parsed)) {\n throw new Error(`Claude agent reported an error: ${describeErrorResult(parsed)}`);\n }\n\n const record = asRecord(parsed);\n const usage = asRecord(record?.usage);\n\n return {\n durationMs: readTokenCount(record?.duration_ms),\n costUsd: readTokenCount(record?.total_cost_usd),\n usage: {\n inputTokens: readTokenCount(usage?.input_tokens ?? usage?.inputTokens),\n outputTokens: readTokenCount(usage?.output_tokens ?? usage?.outputTokens),\n cacheReadTokens: readTokenCount(usage?.cache_read_input_tokens ?? usage?.cacheReadTokens),\n cacheWriteTokens: readTokenCount(\n usage?.cache_creation_input_tokens ?? usage?.cacheWriteTokens,\n ),\n },\n };\n}\n\nfunction describeClaudeFailure(trajectory: string): string | undefined {\n try {\n const parsed = parseAgentJsonOutput(trajectory);\n return isErrorResult(parsed) ? describeErrorResult(parsed) : undefined;\n } catch {\n return undefined;\n }\n}\n\ntype ClaudeErrorResult = {\n is_error: true;\n result: string;\n subtype?: string;\n terminal_reason?: string;\n};\n\nfunction isErrorResult(value: unknown): value is ClaudeErrorResult {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { is_error?: unknown }).is_error === true\n );\n}\n\nfunction describeErrorResult(result: ClaudeErrorResult): string {\n const message = String(result.result);\n\n if (result.terminal_reason !== undefined && result.terminal_reason !== \"completed\") {\n return `${result.terminal_reason}: ${message}`;\n }\n\n if (result.subtype !== undefined && result.subtype !== \"success\") {\n return `${result.subtype}: ${message}`;\n }\n\n return message;\n}\n"],"mappings":";;;;;AAEA,MAAa,eAAe;AAC5B,MAAa,oCAAoC,GAAGA,kBAAAA,eAAe;;AAEnE,MAAa,gCAAgC,GAAGA,kBAAAA,eAAe;;AAG/D,MAAa,yBAAyB;;AAEtC,MAAa,qBAAqB;;AAGlC,MAAa,oCAAoC,SAC/C,GAAG,KAAK;;;;ACOV,eAAsB,yBACpB,UAAsD,CAAC,GAC3B;CAC5B,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,OAAO,QAAQ,SAAA,GAAQC,QAAAA,QAAAA,CAAQ;CAErC,MAAM,QAAQ,IAAI;CAClB,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,OAAO;EAAE,MAAM;EAAe;CAAM;CAGtC,MAAM,SAAS,IAAI;CACnB,IAAI,WAAW,KAAA,KAAa,WAAW,IACrC,OAAO;EAAE,MAAM;EAAW;CAAO;CAGnC,MAAM,OAAO,iCAAiC,IAAI;CAClD,IAAI;EACF,OAAA,GAAMC,iBAAAA,OAAAA,CAAO,MAAMC,QAAAA,UAAY,IAAI;CACrC,QAAQ;EACN,MAAM,IAAI,MACR,0CAA0C,uBAAuB,+CACzD,mBAAmB,eAAe,KAAK,yDACjD;CACF;CAEA,OAAO;EAAE,MAAM;EAAoB;CAAK;AAC1C;;AAGA,SAAgB,eAAe,aAAwD;CACrF,QAAQ,YAAY,MAApB;EACE,KAAK,eACH,OAAO,GAAG,yBAAyB,YAAY,MAAM;EACvD,KAAK,WACH,OAAO,GAAG,qBAAqB,YAAY,OAAO;EACpD,KAAK,oBACH,OAAO,CAAC;CACZ;AACF;;;ACpDA,SAAgB,kBAAkB,WAAkD;CAClF,MAAM,SAA4B,CAAC;CAEnC,KAAK,MAAM,OAAO,WAAW;EAC3B,MAAM,UAAA,GAASC,kBAAAA,SAAAA,CAAS,GAAG;EAC3B,IAAI,WAAW,KAAA,GAAW;GACxB,OAAO,KAAK;IAAE,MAAM;IAAS,MAAM;IAAW;GAAI,CAAC;GACnD;EACF;EAEA,MAAM,QAAA,GAAOC,kBAAAA,WAAAA,CAAW,OAAO,IAAI,KAAK;EAExC,QAAQ,MAAR;GACE,KAAK;IACH,OAAO,KAAK;KACV,MAAM;KACN,YAAA,GAAWA,kBAAAA,WAAAA,CAAW,OAAO,UAAU;KACvC,QAAA,GAAOA,kBAAAA,WAAAA,CAAW,OAAO,KAAK;KAC9B;IACF,CAAC;IACD;GACF,KAAK;IACH,OAAO,KAAK,GAAG,gBAAgB,QAAQ,GAAG,CAAC;IAC3C;GACF,KAAK;IACH,OAAO,KAAK,GAAG,qBAAqB,QAAQ,GAAG,CAAC;IAChD;GACF,KAAK;IACH,OAAO,KAAK;KACV,MAAM;KACN,OAAA,GAAMA,kBAAAA,WAAAA,CAAW,OAAO,MAAM,KAAK;KACnC,SAAS,OAAO,aAAa;KAC7B,aAAA,GAAYC,kBAAAA,eAAAA,CAAe,OAAO,WAAW;KAC7C,UAAA,GAASA,kBAAAA,eAAAA,CAAe,OAAO,cAAc;KAC7C;IACF,CAAC;IACD;GACF,SACE,OAAO,KAAK;IAAE,MAAM;IAAS;IAAM;GAAI,CAAC;EAC5C;CACF;CAEA,OAAO;AACT;AAEA,SAAS,qBACP,QACA,KACmB;CACnB,MAAM,SAA4B,CAAC;CACnC,MAAM,QAAA,GAAOC,kBAAAA,mBAAAA,CAAmB,OAAO,OAAO;CAC9C,IAAI,SAAS,IACX,OAAO,KAAK;EAAE,MAAM;EAAa;EAAM;CAAI,CAAC;CAG9C,KAAK,MAAM,SAAS,cAAc,OAAO,OAAO,GAAG;EACjD,IAAI,MAAM,SAAS,YACjB;EAEF,OAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,SAAA,GAAQF,kBAAAA,WAAAA,CAAW,MAAM,EAAE,KAAK;GAChC,OAAA,GAAMA,kBAAAA,WAAAA,CAAW,MAAM,IAAI,KAAK;GAChC,MAAM,MAAM,SAAS;GACrB,QAAQ;GACR;EACF,CAAC;CACH;CAEA,IAAI,OAAO,WAAW,GACpB,OAAO,KAAK;EAAE,MAAM;EAAa,MAAM;EAAI;CAAI,CAAC;CAGlD,OAAO;AACT;AAEA,SAAS,gBAAgB,QAAiC,KAAiC;CACzF,MAAM,SAA4B,CAAC;CACnC,MAAM,QAAA,GAAOE,kBAAAA,mBAAAA,CAAmB,OAAO,OAAO;CAC9C,MAAM,cAAiC,CAAC;CAExC,KAAK,MAAM,SAAS,cAAc,OAAO,OAAO,GAAG;EACjD,IAAI,MAAM,SAAS,eACjB;EAEF,YAAY,KAAK;GACf,MAAM;GACN,OAAO;GACP,SAAA,GAAQF,kBAAAA,WAAAA,CAAW,MAAM,WAAW,KAAK;GACzC,MAAM;GACN,MAAM;GACN,QAAQ,MAAM,WAAW;GACzB;EACF,CAAC;CACH;CAEA,IAAI,SAAS,MAAM,YAAY,WAAW,GACxC,OAAO,KAAK;EAAE,MAAM;EAAQ;EAAM;CAAI,CAAC;CAEzC,OAAO,KAAK,GAAG,WAAW;CAC1B,OAAO;AACT;AAEA,SAAS,cAAc,SAA6C;CAClE,MAAM,WAAA,GAAUD,kBAAAA,SAAAA,CAAS,OAAO,CAAC,EAAE;CACnC,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO,CAAC;CAEV,OAAO,QAAQ,KAAK,WAAA,GAAUA,kBAAAA,SAAAA,CAAS,KAAK,CAAC,CAAC,CAAC,QAAQ,UAAU,UAAU,KAAA,CAAS;AACtF;;;ACzGA,MAAa,gBAA8B;CACzC,OAAO;CACP,aAAa;CACb,gBAAgB;CAChB,aAAa;CACb,iBAAiB;CACjB,UAAU,EAAE,QAAQ,OAAO,gBAAgB;EACzC,MAAM,aAAa;GACjB;GACA;GACA;GACA;GACA;GACA;EACF;EACA,IAAI,cAAc,KAAA,KAAa,cAAc,IAC3C,WAAW,KAAK,YAAY,SAAS;EAEvC,IAAI,UAAU,KAAA,KAAa,UAAU,IACnC,WAAW,KAAK,WAAW,KAAK;EAElC,WAAW,KAAK,MAAM,MAAM;EAC5B,OAAO;CACT;CACA,SAAS,YAAY;EACnB,MAAM,cAAc,MAAM,yBAAyB;EACnD,MAAM,UAA+B,CAAC;EACtC,IAAI,YAAY,SAAS,oBACvB,QAAQ,KAAK;GACX,MAAM,YAAY;GAClB,WAAW;GACX,MAAM;EACR,CAAC;EAEH,OAAO;GACL;GACA,KAAK,eAAe,WAAW;EACjC;CACF;CACA,aAAa;CACb,iBAAiB;AACnB;AAEA,SAAS,kBAAkB,YAAoC;CAC7D,MAAM,UAAA,GAASI,kBAAAA,qBAAAA,CAAqB,UAAU;CAC9C,IAAI,cAAc,MAAM,GACtB,MAAM,IAAI,MAAM,mCAAmC,oBAAoB,MAAM,GAAG;CAGlF,MAAM,UAAA,GAASC,kBAAAA,SAAAA,CAAS,MAAM;CAC9B,MAAM,SAAA,GAAQA,kBAAAA,SAAAA,CAAS,QAAQ,KAAK;CAEpC,OAAO;EACL,aAAA,GAAYC,kBAAAA,eAAAA,CAAe,QAAQ,WAAW;EAC9C,UAAA,GAASA,kBAAAA,eAAAA,CAAe,QAAQ,cAAc;EAC9C,OAAO;GACL,cAAA,GAAaA,kBAAAA,eAAAA,CAAe,OAAO,gBAAgB,OAAO,WAAW;GACrE,eAAA,GAAcA,kBAAAA,eAAAA,CAAe,OAAO,iBAAiB,OAAO,YAAY;GACxE,kBAAA,GAAiBA,kBAAAA,eAAAA,CAAe,OAAO,2BAA2B,OAAO,eAAe;GACxF,mBAAA,GAAkBA,kBAAAA,eAAAA,CAChB,OAAO,+BAA+B,OAAO,gBAC/C;EACF;CACF;AACF;AAEA,SAAS,sBAAsB,YAAwC;CACrE,IAAI;EACF,MAAM,UAAA,GAASF,kBAAAA,qBAAAA,CAAqB,UAAU;EAC9C,OAAO,cAAc,MAAM,IAAI,oBAAoB,MAAM,IAAI,KAAA;CAC/D,QAAQ;EACN;CACF;AACF;AASA,SAAS,cAAc,OAA4C;CACjE,OACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAiC,aAAa;AAEnD;AAEA,SAAS,oBAAoB,QAAmC;CAC9D,MAAM,UAAU,OAAO,OAAO,MAAM;CAEpC,IAAI,OAAO,oBAAoB,KAAA,KAAa,OAAO,oBAAoB,aACrE,OAAO,GAAG,OAAO,gBAAgB,IAAI;CAGvC,IAAI,OAAO,YAAY,KAAA,KAAa,OAAO,YAAY,WACrD,OAAO,GAAG,OAAO,QAAQ,IAAI;CAG/B,OAAO;AACT"}
|