@clanker-cleanroom/claude 0.2.7-build.37 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docker/claude.Dockerfile +2 -1
- package/lib/{binding-C2kSQy-B.cjs → binding-BZPFUSsx.cjs} +12 -2
- package/lib/binding-BZPFUSsx.cjs.map +1 -0
- package/lib/{binding-DAPBfelH.mjs → binding-DRnzgDU4.mjs} +7 -3
- package/lib/binding-DRnzgDU4.mjs.map +1 -0
- package/lib/index.cjs +2 -1
- package/lib/index.d.cts +3 -1
- package/lib/index.d.mts +3 -1
- package/lib/index.mjs +2 -2
- package/lib/register.cjs +1 -1
- package/lib/register.mjs +1 -1
- package/package.json +2 -2
- package/src/binding.ts +6 -2
- package/src/constants.ts +2 -0
- package/src/index.ts +1 -0
- package/lib/binding-C2kSQy-B.cjs.map +0 -1
- package/lib/binding-DAPBfelH.mjs.map +0 -1
package/docker/claude.Dockerfile
CHANGED
|
@@ -18,7 +18,8 @@ RUN curl -fsSL https://claude.ai/install.sh | bash \
|
|
|
18
18
|
|
|
19
19
|
# Empty home for arbitrary host UIDs. ~/.claude is pre-created so a read-only
|
|
20
20
|
# .credentials.json bind mount does not leave the directory root-owned.
|
|
21
|
-
|
|
21
|
+
# Pre-create projects/-workspace for the narrow session mount (cwd=/workspace).
|
|
22
|
+
RUN mkdir -p /home/agent/.claude/projects/-workspace \
|
|
22
23
|
&& chmod -R 0777 /home/agent
|
|
23
24
|
|
|
24
25
|
ENV HOME=/home/agent
|
|
@@ -5,6 +5,8 @@ let node_os = require("node:os");
|
|
|
5
5
|
//#region src/constants.ts
|
|
6
6
|
const CLAUDE_IMAGE = "clanker-cleanroom/claude";
|
|
7
7
|
const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${clanker_cleanroom.CONTAINER_HOME}/.claude/.credentials.json`;
|
|
8
|
+
/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */
|
|
9
|
+
const CLAUDE_CONTAINER_SESSION_PATH = `${clanker_cleanroom.CONTAINER_HOME}/.claude/projects/-workspace`;
|
|
8
10
|
/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */
|
|
9
11
|
const CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
10
12
|
/** Anthropic API key (pay-as-you-go). */
|
|
@@ -158,7 +160,8 @@ const claudeBinding = {
|
|
|
158
160
|
displayName: "Claude",
|
|
159
161
|
trajectoryKind: "claude",
|
|
160
162
|
adaptEvents: adaptClaudeEvents,
|
|
161
|
-
|
|
163
|
+
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
164
|
+
command: ({ prompt, model, sessionId }) => {
|
|
162
165
|
const claudeArgs = [
|
|
163
166
|
"claude",
|
|
164
167
|
"-p",
|
|
@@ -167,6 +170,7 @@ const claudeBinding = {
|
|
|
167
170
|
"--verbose",
|
|
168
171
|
"--dangerously-skip-permissions"
|
|
169
172
|
];
|
|
173
|
+
if (sessionId !== void 0 && sessionId !== "") claudeArgs.push("--resume", sessionId);
|
|
170
174
|
if (model !== void 0 && model !== "") claudeArgs.push("--model", model);
|
|
171
175
|
claudeArgs.push("--", prompt);
|
|
172
176
|
return claudeArgs;
|
|
@@ -233,6 +237,12 @@ Object.defineProperty(exports, "CLAUDE_CONTAINER_CREDENTIALS_PATH", {
|
|
|
233
237
|
return CLAUDE_CONTAINER_CREDENTIALS_PATH;
|
|
234
238
|
}
|
|
235
239
|
});
|
|
240
|
+
Object.defineProperty(exports, "CLAUDE_CONTAINER_SESSION_PATH", {
|
|
241
|
+
enumerable: true,
|
|
242
|
+
get: function() {
|
|
243
|
+
return CLAUDE_CONTAINER_SESSION_PATH;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
236
246
|
Object.defineProperty(exports, "CLAUDE_IMAGE", {
|
|
237
247
|
enumerable: true,
|
|
238
248
|
get: function() {
|
|
@@ -276,4 +286,4 @@ Object.defineProperty(exports, "resolveClaudeCredentials", {
|
|
|
276
286
|
}
|
|
277
287
|
});
|
|
278
288
|
|
|
279
|
-
//# sourceMappingURL=binding-
|
|
289
|
+
//# sourceMappingURL=binding-BZPFUSsx.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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":"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"}
|
|
@@ -5,6 +5,8 @@ import { homedir } from "node:os";
|
|
|
5
5
|
//#region src/constants.ts
|
|
6
6
|
const CLAUDE_IMAGE = "clanker-cleanroom/claude";
|
|
7
7
|
const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;
|
|
8
|
+
/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */
|
|
9
|
+
const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;
|
|
8
10
|
/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */
|
|
9
11
|
const CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
10
12
|
/** Anthropic API key (pay-as-you-go). */
|
|
@@ -158,7 +160,8 @@ const claudeBinding = {
|
|
|
158
160
|
displayName: "Claude",
|
|
159
161
|
trajectoryKind: "claude",
|
|
160
162
|
adaptEvents: adaptClaudeEvents,
|
|
161
|
-
|
|
163
|
+
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
164
|
+
command: ({ prompt, model, sessionId }) => {
|
|
162
165
|
const claudeArgs = [
|
|
163
166
|
"claude",
|
|
164
167
|
"-p",
|
|
@@ -167,6 +170,7 @@ const claudeBinding = {
|
|
|
167
170
|
"--verbose",
|
|
168
171
|
"--dangerously-skip-permissions"
|
|
169
172
|
];
|
|
173
|
+
if (sessionId !== void 0 && sessionId !== "") claudeArgs.push("--resume", sessionId);
|
|
170
174
|
if (model !== void 0 && model !== "") claudeArgs.push("--model", model);
|
|
171
175
|
claudeArgs.push("--", prompt);
|
|
172
176
|
return claudeArgs;
|
|
@@ -221,6 +225,6 @@ function describeErrorResult(result) {
|
|
|
221
225
|
return message;
|
|
222
226
|
}
|
|
223
227
|
//#endregion
|
|
224
|
-
export { CLAUDE_API_KEY_ENV as a,
|
|
228
|
+
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 };
|
|
225
229
|
|
|
226
|
-
//# sourceMappingURL=binding-
|
|
230
|
+
//# sourceMappingURL=binding-DRnzgDU4.mjs.map
|
|
@@ -0,0 +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":";;;;;AAEA,MAAa,eAAe;AAC5B,MAAa,oCAAoC,GAAG,eAAe;;AAEnE,MAAa,gCAAgC,GAAG,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,QAAQ,QAAQ;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,MAAM,OAAO,MAAMA,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,SAAS,SAAS,GAAG;EAC3B,IAAI,WAAW,KAAA,GAAW;GACxB,OAAO,KAAK;IAAE,MAAM;IAAS,MAAM;IAAW;GAAI,CAAC;GACnD;EACF;EAEA,MAAM,OAAO,WAAW,OAAO,IAAI,KAAK;EAExC,QAAQ,MAAR;GACE,KAAK;IACH,OAAO,KAAK;KACV,MAAM;KACN,WAAW,WAAW,OAAO,UAAU;KACvC,OAAO,WAAW,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,MAAM,WAAW,OAAO,MAAM,KAAK;KACnC,SAAS,OAAO,aAAa;KAC7B,YAAY,eAAe,OAAO,WAAW;KAC7C,SAAS,eAAe,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,OAAO,mBAAmB,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,QAAQ,WAAW,MAAM,EAAE,KAAK;GAChC,MAAM,WAAW,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,OAAO,mBAAmB,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,QAAQ,WAAW,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,UAAU,SAAS,OAAO,CAAC,EAAE;CACnC,IAAI,CAAC,MAAM,QAAQ,OAAO,GACxB,OAAO,CAAC;CAEV,OAAO,QAAQ,KAAK,UAAU,SAAS,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,SAAS,qBAAqB,UAAU;CAC9C,IAAI,cAAc,MAAM,GACtB,MAAM,IAAI,MAAM,mCAAmC,oBAAoB,MAAM,GAAG;CAGlF,MAAM,SAAS,SAAS,MAAM;CAC9B,MAAM,QAAQ,SAAS,QAAQ,KAAK;CAEpC,OAAO;EACL,YAAY,eAAe,QAAQ,WAAW;EAC9C,SAAS,eAAe,QAAQ,cAAc;EAC9C,OAAO;GACL,aAAa,eAAe,OAAO,gBAAgB,OAAO,WAAW;GACrE,cAAc,eAAe,OAAO,iBAAiB,OAAO,YAAY;GACxE,iBAAiB,eAAe,OAAO,2BAA2B,OAAO,eAAe;GACxF,kBAAkB,eAChB,OAAO,+BAA+B,OAAO,gBAC/C;EACF;CACF;AACF;AAEA,SAAS,sBAAsB,YAAwC;CACrE,IAAI;EACF,MAAM,SAAS,qBAAqB,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"}
|
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-BZPFUSsx.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");
|
|
@@ -14,6 +14,7 @@ const DOCKER_DIR = (0, node_path.join)(PACKAGE_ROOT, "docker");
|
|
|
14
14
|
//#endregion
|
|
15
15
|
exports.CLAUDE_API_KEY_ENV = require_binding.CLAUDE_API_KEY_ENV;
|
|
16
16
|
exports.CLAUDE_CONTAINER_CREDENTIALS_PATH = require_binding.CLAUDE_CONTAINER_CREDENTIALS_PATH;
|
|
17
|
+
exports.CLAUDE_CONTAINER_SESSION_PATH = require_binding.CLAUDE_CONTAINER_SESSION_PATH;
|
|
17
18
|
exports.CLAUDE_IMAGE = require_binding.CLAUDE_IMAGE;
|
|
18
19
|
exports.CLAUDE_OAUTH_TOKEN_ENV = require_binding.CLAUDE_OAUTH_TOKEN_ENV;
|
|
19
20
|
exports.DOCKER_DIR = DOCKER_DIR;
|
package/lib/index.d.cts
CHANGED
|
@@ -2,6 +2,8 @@ import { Agent, AgentBinding, TrajectoryEvent } from "clanker-cleanroom";
|
|
|
2
2
|
//#region src/constants.d.ts
|
|
3
3
|
declare const CLAUDE_IMAGE = "clanker-cleanroom/claude";
|
|
4
4
|
declare const CLAUDE_CONTAINER_CREDENTIALS_PATH = "/home/agent/.claude/.credentials.json";
|
|
5
|
+
/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */
|
|
6
|
+
declare const CLAUDE_CONTAINER_SESSION_PATH = "/home/agent/.claude/projects/-workspace";
|
|
5
7
|
/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */
|
|
6
8
|
declare const CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
7
9
|
/** Anthropic API key (pay-as-you-go). */
|
|
@@ -48,5 +50,5 @@ declare const PACKAGE_ROOT: string;
|
|
|
48
50
|
/** Folder of `*.Dockerfile` files for this agent. */
|
|
49
51
|
declare const DOCKER_DIR: string;
|
|
50
52
|
//#endregion
|
|
51
|
-
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, type ClaudeCredentials, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
53
|
+
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, type ClaudeCredentials, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
52
54
|
//# sourceMappingURL=index.d.cts.map
|
package/lib/index.d.mts
CHANGED
|
@@ -2,6 +2,8 @@ import { Agent, AgentBinding, TrajectoryEvent } from "clanker-cleanroom";
|
|
|
2
2
|
//#region src/constants.d.ts
|
|
3
3
|
declare const CLAUDE_IMAGE = "clanker-cleanroom/claude";
|
|
4
4
|
declare const CLAUDE_CONTAINER_CREDENTIALS_PATH = "/home/agent/.claude/.credentials.json";
|
|
5
|
+
/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */
|
|
6
|
+
declare const CLAUDE_CONTAINER_SESSION_PATH = "/home/agent/.claude/projects/-workspace";
|
|
5
7
|
/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */
|
|
6
8
|
declare const CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
7
9
|
/** Anthropic API key (pay-as-you-go). */
|
|
@@ -48,5 +50,5 @@ declare const PACKAGE_ROOT: string;
|
|
|
48
50
|
/** Folder of `*.Dockerfile` files for this agent. */
|
|
49
51
|
declare const DOCKER_DIR: string;
|
|
50
52
|
//#endregion
|
|
51
|
-
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, type ClaudeCredentials, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
53
|
+
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, type ClaudeCredentials, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
52
54
|
//# sourceMappingURL=index.d.mts.map
|
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as CLAUDE_API_KEY_ENV, c as
|
|
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-DRnzgDU4.mjs";
|
|
2
2
|
import { Agent } from "clanker-cleanroom";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,6 +11,6 @@ const PACKAGE_ROOT = fileURLToPath(new URL("..", import.meta.url));
|
|
|
11
11
|
/** Folder of `*.Dockerfile` files for this agent. */
|
|
12
12
|
const DOCKER_DIR = join(PACKAGE_ROOT, "docker");
|
|
13
13
|
//#endregion
|
|
14
|
-
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
14
|
+
export { CLAUDE_API_KEY_ENV, CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE, CLAUDE_OAUTH_TOKEN_ENV, DOCKER_DIR, PACKAGE_ROOT, adaptClaudeEvents, claudeAgent, claudeBinding, credentialsEnv, defaultClaudeHostCredentialsFile, resolveClaudeCredentials };
|
|
15
15
|
|
|
16
16
|
//# sourceMappingURL=index.mjs.map
|
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.7
|
|
3
|
+
"version": "0.2.7",
|
|
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.7
|
|
118
|
+
"clanker-cleanroom": "0.2.7"
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@types/node": "^26.2.0",
|
package/src/binding.ts
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type DockerVolumeMount,
|
|
8
8
|
} from "clanker-cleanroom";
|
|
9
9
|
|
|
10
|
-
import { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_IMAGE } from "./constants.js";
|
|
10
|
+
import { CLAUDE_CONTAINER_CREDENTIALS_PATH, CLAUDE_CONTAINER_SESSION_PATH, CLAUDE_IMAGE } from "./constants.js";
|
|
11
11
|
import { credentialsEnv, resolveClaudeCredentials } from "./credentials.js";
|
|
12
12
|
import { adaptClaudeEvents } from "./trajectory.js";
|
|
13
13
|
|
|
@@ -16,7 +16,8 @@ export const claudeBinding: AgentBinding = {
|
|
|
16
16
|
displayName: "Claude",
|
|
17
17
|
trajectoryKind: "claude",
|
|
18
18
|
adaptEvents: adaptClaudeEvents,
|
|
19
|
-
|
|
19
|
+
sessionDataPath: CLAUDE_CONTAINER_SESSION_PATH,
|
|
20
|
+
command: ({ prompt, model, sessionId }) => {
|
|
20
21
|
const claudeArgs = [
|
|
21
22
|
"claude",
|
|
22
23
|
"-p",
|
|
@@ -25,6 +26,9 @@ export const claudeBinding: AgentBinding = {
|
|
|
25
26
|
"--verbose",
|
|
26
27
|
"--dangerously-skip-permissions",
|
|
27
28
|
];
|
|
29
|
+
if (sessionId !== undefined && sessionId !== "") {
|
|
30
|
+
claudeArgs.push("--resume", sessionId);
|
|
31
|
+
}
|
|
28
32
|
if (model !== undefined && model !== "") {
|
|
29
33
|
claudeArgs.push("--model", model);
|
|
30
34
|
}
|
package/src/constants.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { CONTAINER_HOME } from "clanker-cleanroom";
|
|
|
2
2
|
|
|
3
3
|
export const CLAUDE_IMAGE = "clanker-cleanroom/claude";
|
|
4
4
|
export const CLAUDE_CONTAINER_CREDENTIALS_PATH = `${CONTAINER_HOME}/.claude/.credentials.json`;
|
|
5
|
+
/** Session transcripts for cwd `/workspace` (Claude encodes `/` as `-`). */
|
|
6
|
+
export const CLAUDE_CONTAINER_SESSION_PATH = `${CONTAINER_HOME}/.claude/projects/-workspace`;
|
|
5
7
|
|
|
6
8
|
/** Long-lived OAuth token from `claude setup-token` (Claude subscription). */
|
|
7
9
|
export const CLAUDE_OAUTH_TOKEN_ENV = "CLAUDE_CODE_OAUTH_TOKEN";
|
package/src/index.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"binding-C2kSQy-B.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\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_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 command: ({ prompt, model }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\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 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"binding-DAPBfelH.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\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_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 command: ({ prompt, model }) => {\n const claudeArgs = [\n \"claude\",\n \"-p\",\n \"--output-format\",\n \"stream-json\",\n \"--verbose\",\n \"--dangerously-skip-permissions\",\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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"}
|