@atrvd/trigger 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +3 -10
- package/dist/index.d.ts +3 -10
- package/dist/index.js +18 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +11 -12
package/dist/index.d.mts
CHANGED
|
@@ -98,13 +98,6 @@ interface ClaudeCodeInput<T = unknown> {
|
|
|
98
98
|
* exit with a non-zero code and the promise will reject.
|
|
99
99
|
*/
|
|
100
100
|
addDir: string;
|
|
101
|
-
/**
|
|
102
|
-
* Controls CLAUDE.md auto-discovery.
|
|
103
|
-
* - "none" (default): sets CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 — disables all CLAUDE.md files
|
|
104
|
-
* - "project-local": passes --setting-sources=project,local — loads only project/local settings
|
|
105
|
-
* - "all": standard Claude behavior, no restriction
|
|
106
|
-
*/
|
|
107
|
-
claudeMds?: "none" | "project-local" | "all";
|
|
108
101
|
}
|
|
109
102
|
/**
|
|
110
103
|
* The JSON envelope that `claude --output-format json` wraps every response in.
|
|
@@ -144,10 +137,10 @@ declare class SchemaValidationError extends Error {
|
|
|
144
137
|
}
|
|
145
138
|
/**
|
|
146
139
|
* Runs the configured binary (default: ccs) with --print flag as a subprocess.
|
|
147
|
-
* Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`
|
|
140
|
+
* Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`
|
|
148
141
|
* The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).
|
|
149
|
-
*
|
|
150
|
-
*
|
|
142
|
+
* --bare suppresses global CLAUDE.md auto-discovery, hooks, LSP, auto-memory and other
|
|
143
|
+
* side effects — ensuring the agent runs only with the provided systemPrompt.
|
|
151
144
|
*
|
|
152
145
|
* When a `schema` is provided (Zod v4+):
|
|
153
146
|
* - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).
|
package/dist/index.d.ts
CHANGED
|
@@ -98,13 +98,6 @@ interface ClaudeCodeInput<T = unknown> {
|
|
|
98
98
|
* exit with a non-zero code and the promise will reject.
|
|
99
99
|
*/
|
|
100
100
|
addDir: string;
|
|
101
|
-
/**
|
|
102
|
-
* Controls CLAUDE.md auto-discovery.
|
|
103
|
-
* - "none" (default): sets CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 — disables all CLAUDE.md files
|
|
104
|
-
* - "project-local": passes --setting-sources=project,local — loads only project/local settings
|
|
105
|
-
* - "all": standard Claude behavior, no restriction
|
|
106
|
-
*/
|
|
107
|
-
claudeMds?: "none" | "project-local" | "all";
|
|
108
101
|
}
|
|
109
102
|
/**
|
|
110
103
|
* The JSON envelope that `claude --output-format json` wraps every response in.
|
|
@@ -144,10 +137,10 @@ declare class SchemaValidationError extends Error {
|
|
|
144
137
|
}
|
|
145
138
|
/**
|
|
146
139
|
* Runs the configured binary (default: ccs) with --print flag as a subprocess.
|
|
147
|
-
* Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`
|
|
140
|
+
* Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`
|
|
148
141
|
* The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).
|
|
149
|
-
*
|
|
150
|
-
*
|
|
142
|
+
* --bare suppresses global CLAUDE.md auto-discovery, hooks, LSP, auto-memory and other
|
|
143
|
+
* side effects — ensuring the agent runs only with the provided systemPrompt.
|
|
151
144
|
*
|
|
152
145
|
* When a `schema` is provided (Zod v4+):
|
|
153
146
|
* - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).
|
package/dist/index.js
CHANGED
|
@@ -42,18 +42,18 @@ function killGracefully(proc) {
|
|
|
42
42
|
proc.kill("SIGKILL");
|
|
43
43
|
}, 5e3).unref();
|
|
44
44
|
}
|
|
45
|
-
function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
45
|
+
function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
|
|
46
46
|
const toolsList = tools?.length ? tools.join(",") : "Read,Grep,Glob";
|
|
47
|
-
const args = ["--print", "--output-format", "json", "--model", model, "--tools", toolsList];
|
|
47
|
+
const args = ["--print", "--bare", "--output-format", "json", "--model", model, "--tools", toolsList];
|
|
48
48
|
if (allowedTools?.length) args.push("--allowed-tools", ...allowedTools);
|
|
49
49
|
if (mcpConfigPath) args.push("--mcp-config", mcpConfigPath);
|
|
50
50
|
args.push("--add-dir", addDir);
|
|
51
51
|
if (systemPrompt) args.push("--system-prompt", systemPrompt);
|
|
52
|
-
if (jsonSchemaStr)
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
if (jsonSchemaStr) {
|
|
53
|
+
args.push("--json-schema", jsonSchemaStr);
|
|
54
|
+
}
|
|
55
55
|
return new Promise((resolve, reject) => {
|
|
56
|
-
const proc = (0, import_node_child_process.spawn)(binary, args, { env
|
|
56
|
+
const proc = (0, import_node_child_process.spawn)(binary, args, { env, cwd: addDir });
|
|
57
57
|
if (!proc.stdout || !proc.stderr || !proc.stdin) {
|
|
58
58
|
reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));
|
|
59
59
|
return;
|
|
@@ -96,10 +96,12 @@ function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir,
|
|
|
96
96
|
const stdout = Buffer.concat(stdoutChunks).toString();
|
|
97
97
|
const stderr = Buffer.concat(stderrChunks).toString();
|
|
98
98
|
if (code !== 0) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
reject(
|
|
100
|
+
new Error(
|
|
101
|
+
`${binary} exited with code ${code}${stderr ? `
|
|
102
|
+
stderr: ${stderr}` : ""}`
|
|
103
|
+
)
|
|
104
|
+
);
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
let envelope;
|
|
@@ -145,9 +147,9 @@ var IsErrorResponse = class extends Error {
|
|
|
145
147
|
this.name = "IsErrorResponse";
|
|
146
148
|
}
|
|
147
149
|
};
|
|
148
|
-
function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
150
|
+
function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
|
|
149
151
|
if (!accounts || accounts.length === 0) {
|
|
150
|
-
return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
152
|
+
return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
151
153
|
}
|
|
152
154
|
return (async () => {
|
|
153
155
|
let lastIsError;
|
|
@@ -157,7 +159,7 @@ function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env,
|
|
|
157
159
|
CLAUDE_CONFIG_DIR: `${(0, import_node_os.homedir)()}/.ccs/instances/${account}`
|
|
158
160
|
};
|
|
159
161
|
try {
|
|
160
|
-
return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
162
|
+
return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
161
163
|
} catch (err) {
|
|
162
164
|
if (err instanceof IsErrorResponse) {
|
|
163
165
|
lastIsError = err;
|
|
@@ -205,8 +207,7 @@ async function runClaudeCode(input) {
|
|
|
205
207
|
addDir,
|
|
206
208
|
tools,
|
|
207
209
|
allowedTools,
|
|
208
|
-
systemPrompt
|
|
209
|
-
claudeMds = "none"
|
|
210
|
+
systemPrompt
|
|
210
211
|
} = input;
|
|
211
212
|
if (!prompt || prompt.trim().length === 0) {
|
|
212
213
|
throw new Error("prompt cannot be empty");
|
|
@@ -242,7 +243,7 @@ async function runClaudeCode(input) {
|
|
|
242
243
|
throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
|
-
const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
246
|
+
const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
246
247
|
if (!schema) {
|
|
247
248
|
return { text: raw.text, parsed: raw.parsed, envelope: raw.envelope, fixAttempts: 0 };
|
|
248
249
|
}
|
|
@@ -256,7 +257,7 @@ async function runClaudeCode(input) {
|
|
|
256
257
|
}
|
|
257
258
|
for (let attempt = 1; attempt <= maxFixes; attempt++) {
|
|
258
259
|
const fixPromptStr = buildFixPrompt(lastText, lastError);
|
|
259
|
-
const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
260
|
+
const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
260
261
|
try {
|
|
261
262
|
const parsed = schema.parse(fixRaw.parsed);
|
|
262
263
|
return { ...fixRaw, parsed, fixAttempts: attempt };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/runners/claude-code.ts"],"sourcesContent":["export { runClaudeCode, SchemaValidationError } from \"./runners/claude-code\";\nexport type { ClaudeCodeInput, ClaudeCodeResult, ClaudeEnvelope } from \"./runners/claude-code\";\n","import { spawn } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\n\nexport interface ClaudeCodeInput<T = unknown> {\n prompt: string;\n model?: string;\n /** Timeout in milliseconds. Default: 300_000 (5 min) */\n timeout?: number;\n /**\n * Maximum allowed stdout size in bytes. Default: 10_485_760 (10 MB).\n * If claude output exceeds this limit the process is killed and the promise rejects.\n */\n maxOutputBytes?: number;\n /**\n * Environment variables passed to the subprocess.\n * Defaults to the full process.env so that the binary can access its auth\n * tokens and config (ANTHROPIC_API_KEY, HOME, etc.).\n * Override if you need to restrict or augment the environment.\n */\n env?: NodeJS.ProcessEnv;\n /**\n * Binary to execute. Default: \"ccs\" (Claude Code Profile & Model Switcher).\n * Use \"claude\" to invoke the Claude CLI directly without profile switching.\n * Using `--print` (not `-p`) avoids the ccs delegation system while\n * preserving the standard `--output-format json` envelope output.\n */\n binary?: string;\n /**\n * Optional Zod schema (requires Zod v4+). When provided:\n * - Its JSON Schema representation is passed via `--json-schema` CLI flag\n * (CLI-level enforcement — Claude physically cannot return non-JSON).\n * - The response is validated with `schema.parse()`.\n * - On failure, an auto-fix retry is sent to `fixModel`.\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n * - Mutually exclusive with `jsonSchema`.\n */\n schema?: z.ZodType<T>;\n /**\n * Model used for auto-fix retries. Default: \"claude-haiku-4-5-20251001\"\n * (cheap and fast, good for JSON correction tasks).\n */\n fixModel?: string;\n /**\n * Maximum number of auto-fix attempts on schema validation failure. Default: 1.\n */\n maxFixes?: number;\n /**\n * Raw JSON Schema for CLI-level structured output enforcement.\n * Adds `--json-schema <schema>` to spawn args.\n * Claude returns structured_output in the envelope — guaranteed JSON.\n * No runtime validation or auto-fix. `result.parsed` is `unknown`.\n * Mutually exclusive with `schema`.\n */\n jsonSchema?: Record<string, unknown>;\n /**\n * Override the default tool list passed via `--tools`.\n * Default: `[\"Read\", \"Grep\", \"Glob\"]` (read-only by design).\n * Pass `[\"Bash\", \"Read\", \"Grep\", \"Glob\"]` to also allow Bash execution.\n */\n tools?: string[];\n /**\n * Restrict Bash commands via `--allowed-tools` flag.\n * Each entry is a pattern like `\"Bash(git log*)\"`.\n * Only meaningful when `tools` includes `\"Bash\"`.\n * When omitted, no `--allowed-tools` flag is added.\n */\n allowedTools?: string[];\n /**\n * List of CCS account names to rotate through on `is_error: true` responses.\n * Each account maps to `CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>`.\n * On `is_error`, the next account in the list is tried automatically.\n * Non-is_error failures (timeouts, non-zero exit, etc.) are thrown immediately.\n * If all accounts return `is_error`, throws with the last error message.\n */\n ccsAccounts?: string[];\n /**\n * Path to an MCP config JSON file.\n * When provided, adds `--mcp-config <path>` to the spawn args so the\n * Claude CLI can load MCP servers (filesystem, supabase, etc.).\n * The caller is responsible for writing the file before calling\n * `runClaudeCode` and deleting it afterwards.\n * If the file does not exist or is not accessible, the Claude CLI\n * will exit with a non-zero code and the promise will reject.\n */\n mcpConfigPath?: string;\n /**\n * Replaces the default system prompt entirely.\n * Adds `--system-prompt <text>` to spawn args.\n * CLAUDE.md is ignored when this is set.\n */\n systemPrompt: string;\n /**\n * Absolute path to the repository directory Claude should work in.\n * Required — without it Claude would inherit the worker CWD, exposing\n * worker source files, env vars, and credentials to the model.\n * Adds `--add-dir <path>` and sets `cwd: addDir` on the spawned process\n * so relative paths (e.g. Read(\"src/foo.ts\")) resolve inside the repo.\n * Throws if empty. If the directory does not exist, the Claude CLI will\n * exit with a non-zero code and the promise will reject.\n */\n addDir: string;\n /**\n * Controls CLAUDE.md auto-discovery.\n * - \"none\" (default): sets CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 — disables all CLAUDE.md files\n * - \"project-local\": passes --setting-sources=project,local — loads only project/local settings\n * - \"all\": standard Claude behavior, no restriction\n */\n claudeMds?: \"none\" | \"project-local\" | \"all\";\n}\n\n/**\n * The JSON envelope that `claude --output-format json` wraps every response in.\n * Only the fields we care about are typed; the rest are captured in the index signature.\n */\nexport interface ClaudeEnvelope {\n type: string;\n subtype: string;\n /** The actual text response from the model (plain text / raw JSON string) */\n result: string;\n is_error: boolean;\n /**\n * Present when `--json-schema` flag is used.\n * Contains the structured output object — use this instead of `result`.\n */\n structured_output?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ClaudeCodeResult<T = unknown> {\n /** The actual text content of claude's response (extracted from envelope.result) */\n text: string;\n /**\n * Parsed value. Typed as `T` when a schema is provided and validation passes.\n * Without schema: `unknown` (will be `null` when the response is not valid JSON).\n */\n parsed: T;\n /** The full response envelope from `claude --output-format json` */\n envelope: ClaudeEnvelope;\n /** Number of auto-fix retries used. 0 means the first response was valid. */\n fixAttempts: number;\n}\n\n/**\n * Thrown when schema validation fails after all auto-fix attempts are exhausted.\n */\nexport class SchemaValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SchemaValidationError\";\n }\n}\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Kills a process gracefully: SIGTERM first, SIGKILL after 5 seconds if still alive.\n */\nfunction killGracefully(proc: ReturnType<typeof spawn>): void {\n proc.kill(\"SIGTERM\");\n setTimeout(() => {\n proc.kill(\"SIGKILL\");\n }, 5000).unref();\n}\n\n/** Internal raw result from a single spawn cycle (before schema validation). */\ninterface RawResult {\n text: string;\n parsed: unknown | null;\n envelope: ClaudeEnvelope;\n}\n\n/**\n * Spawns the binary once and collects the JSON envelope result.\n * All validation/retry logic lives in `runClaudeCode`.\n */\nfunction spawnOnce(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string,\n claudeMds: \"none\" | \"project-local\" | \"all\" = \"none\"\n): Promise<RawResult> {\n // Use --print (not -p) so that ccs passes args through to claude without\n // triggering its delegation system. Prompt is the final positional argument.\n const toolsList = tools?.length ? tools.join(\",\") : \"Read,Grep,Glob\";\n const args = [\"--print\", \"--output-format\", \"json\", \"--model\", model, \"--tools\", toolsList];\n if (allowedTools?.length) args.push(\"--allowed-tools\", ...allowedTools);\n if (mcpConfigPath) args.push(\"--mcp-config\", mcpConfigPath);\n args.push(\"--add-dir\", addDir);\n if (systemPrompt) args.push(\"--system-prompt\", systemPrompt);\n if (jsonSchemaStr) args.push(\"--json-schema\", jsonSchemaStr);\n if (claudeMds === \"project-local\") args.push(\"--setting-sources\", \"project,local\");\n // Prompt is delivered via stdin — avoids OS ARG_MAX limits (~2MB on Linux)\n\n // Suppress CLAUDE.md auto-discovery via env var (default) or setting-sources flag.\n // CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 disables all CLAUDE.md files without touching HOME,\n // preserving credentials and avoiding the HOME-isolation overhead.\n const spawnEnv = claudeMds === \"none\"\n ? { ...env, CLAUDE_CODE_DISABLE_CLAUDE_MDS: \"1\" }\n : { ...env };\n\n return new Promise((resolve, reject) => {\n const proc = spawn(binary, args, { env: spawnEnv, cwd: addDir });\n\n if (!proc.stdout || !proc.stderr || !proc.stdin) {\n reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));\n return;\n }\n\n // Suppress all stdin errors — EPIPE is expected when the process exits before reading\n // all of stdin; other stdin errors are extremely rare and non-fatal (process already spawned).\n proc.stdin.on(\"error\", () => {});\n // If the internal buffer is full (write returns false), wait for drain before closing.\n // This handles extremely large prompts where the OS pipe buffer fills up.\n if (proc.stdin.write(prompt, \"utf8\")) {\n proc.stdin.end();\n } else {\n proc.stdin.once(\"drain\", () => proc.stdin!.end());\n }\n\n // settled prevents double-resolve/reject between timeout and close handlers\n let settled = false;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let totalStdoutSize = 0;\n\n const timer = setTimeout(() => {\n settled = true;\n killGracefully(proc);\n reject(new Error(`${binary} process timed out after ${timeout}ms`));\n }, timeout);\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n totalStdoutSize += chunk.length;\n if (totalStdoutSize > maxOutputBytes) {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n killGracefully(proc);\n reject(new Error(`${binary} output exceeded ${maxOutputBytes} bytes`));\n return;\n }\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n proc.on(\"close\", (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (code !== 0) {\n const parts = [`${binary} exited with code ${code}`];\n if (stderr) parts.push(`stderr: ${stderr}`);\n if (stdout) parts.push(`stdout: ${stdout}`);\n reject(new Error(parts.join(\"\\n\")));\n return;\n }\n\n let envelope: ClaudeEnvelope;\n try {\n envelope = JSON.parse(stdout.trim()) as ClaudeEnvelope;\n } catch {\n reject(new Error(`${binary} output is not valid JSON: ${stdout.trim().slice(0, 200)}`));\n return;\n }\n\n if (envelope.is_error) {\n reject(new IsErrorResponse(envelope.result));\n return;\n }\n\n // --json-schema mode: result comes in structured_output, not result field\n if (envelope.structured_output !== undefined) {\n const text = JSON.stringify(envelope.structured_output);\n resolve({ text, parsed: envelope.structured_output, envelope });\n return;\n }\n\n if (typeof envelope.result !== \"string\") {\n reject(new Error(\"Invalid envelope: result field is not a string\"));\n return;\n }\n\n const text = envelope.result;\n\n let parsed: unknown | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n // text is not JSON — that's fine\n }\n\n resolve({ text, parsed, envelope });\n });\n\n proc.on(\"error\", (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn ${binary}: ${err.message}`));\n });\n });\n}\n\n/**\n * Thrown internally by spawnOnce when the Claude envelope contains is_error=true.\n * Caught by spawnWithAccounts to distinguish account-level errors from other failures.\n */\nclass IsErrorResponse extends Error {\n constructor(public readonly result: string) {\n super(`returned is_error=true: ${result}`);\n this.name = \"IsErrorResponse\";\n }\n}\n\n/**\n * Calls spawnOnce with optional CCS account rotation.\n * When `accounts` is provided, tries each account in order by setting\n * CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>. Rotates only on is_error=true;\n * any other error (timeout, non-zero exit, ENOENT) is thrown immediately.\n * If all accounts return is_error, throws with the last error message.\n *\n * Implemented as a regular (non-async) function so the no-rotation path\n * returns spawnOnce's promise directly without adding an extra microtask tick.\n */\nfunction spawnWithAccounts(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n accounts: string[] | undefined,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string,\n claudeMds: \"none\" | \"project-local\" | \"all\" = \"none\"\n): Promise<RawResult> {\n // Fast path: return promise directly — no extra microtask overhead\n if (!accounts || accounts.length === 0) {\n return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n }\n\n // Rotation path: async IIFE to iterate through accounts\n return (async () => {\n let lastIsError: IsErrorResponse | undefined;\n for (const account of accounts) {\n const accountEnv: NodeJS.ProcessEnv = {\n ...env,\n CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`,\n };\n try {\n return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n } catch (err) {\n if (err instanceof IsErrorResponse) {\n lastIsError = err;\n continue;\n }\n throw err;\n }\n }\n throw new Error(lastIsError!.result);\n })();\n}\n\n/**\n * Builds the auto-fix prompt sent to the fixModel when schema validation fails.\n * Includes structured ZodError issues (when available) and the original invalid\n * response so the model can self-correct.\n */\nfunction buildFixPrompt(invalidText: string, error: unknown): string {\n let errorMessage: string;\n if (error instanceof z.ZodError) {\n errorMessage = error.issues\n .map((i) => `Path: ${i.path.length ? i.path.join(\".\") : \"(root)\"}, ${i.message}`)\n .join(\"\\n\");\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = String(error);\n }\n return (\n `The following JSON failed schema validation.\\n\\n` +\n `Errors:\\n${errorMessage}\\n\\n` +\n `Invalid response:\\n${invalidText}\\n\\n` +\n `Output ONLY corrected JSON. No explanation, no markdown.`\n );\n}\n\n/**\n * Runs the configured binary (default: ccs) with --print flag as a subprocess.\n * Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`\n * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).\n * A per-invocation isolated HOME dir is set to suppress ~/CLAUDE.md auto-discovery\n * without --bare, which would disable OAuth/keychain auth.\n *\n * When a `schema` is provided (Zod v4+):\n * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).\n * - Claude returns structured_output in the envelope — guaranteed JSON.\n * - The response is validated; on failure an auto-fix retry is sent to `fixModel`.\n * - `result.fixAttempts` indicates how many retries were used (0 = first response valid).\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n *\n * When `jsonSchema` is provided:\n * - Passed via `--json-schema` CLI flag (hard enforcement, no validation or retry).\n * - `result.parsed` is `unknown`.\n *\n * Without schema: `result.parsed` is `unknown` (may be `null` for plain-text responses).\n *\n * Designed to be used as a plain async function inside a trigger.dev task `run()`.\n */\nexport function runClaudeCode(input: ClaudeCodeInput): Promise<ClaudeCodeResult<unknown>>;\nexport function runClaudeCode<T>(\n input: ClaudeCodeInput<T> & { schema: z.ZodType<T> }\n): Promise<ClaudeCodeResult<T>>;\nexport async function runClaudeCode<T = unknown>(\n input: ClaudeCodeInput<T>\n): Promise<ClaudeCodeResult<T | null>> {\n const {\n prompt,\n model = \"claude-sonnet-4-6\",\n timeout = 300_000,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n env = process.env,\n binary = \"ccs\",\n schema,\n fixModel = \"claude-haiku-4-5-20251001\",\n maxFixes = 1,\n jsonSchema,\n ccsAccounts,\n mcpConfigPath,\n addDir,\n tools,\n allowedTools,\n systemPrompt,\n claudeMds = \"none\",\n } = input;\n\n if (!prompt || prompt.trim().length === 0) {\n throw new Error(\"prompt cannot be empty\");\n }\n\n if (!addDir || addDir.trim().length === 0) {\n throw new Error(\"addDir is required: omitting it exposes the worker CWD to the model\");\n }\n\n if (!binary || binary.trim().length === 0) {\n throw new Error(\"binary cannot be empty\");\n }\n\n if (jsonSchema && schema) {\n throw new Error(\"cannot use jsonSchema with schema\");\n }\n\n if (!systemPrompt || systemPrompt.trim().length === 0) {\n throw new Error(\"systemPrompt cannot be empty\");\n }\n\n if (allowedTools?.length && (!tools || !tools.includes(\"Bash\"))) {\n throw new Error(\"allowedTools requires 'Bash' in tools array\");\n }\n\n // Build jsonSchemaStr from Zod schema or raw jsonSchema — passed as CLI flag, not prompt text\n let jsonSchemaStr: string | undefined;\n if (schema) {\n try {\n jsonSchemaStr = JSON.stringify(z.toJSONSchema(schema));\n } catch (err) {\n throw new Error(\n `Failed to convert Zod schema to JSON Schema (requires Zod v4+): ${String(err)}`\n );\n }\n } else if (jsonSchema) {\n try {\n jsonSchemaStr = JSON.stringify(jsonSchema);\n } catch (err) {\n throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);\n }\n }\n\n const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n\n // No schema — return raw result. parsed may be null for plain-text responses.\n // Cast is safe: overload 1 constrains T = unknown, so T | null = unknown.\n if (!schema) {\n return { text: raw.text, parsed: raw.parsed as T | null, envelope: raw.envelope, fixAttempts: 0 };\n }\n\n // Try to validate the initial response.\n // Note: if raw.parsed is null (plain-text response), schema.parse(null) throws ZodError,\n // which correctly triggers the auto-fix flow.\n let lastText = raw.text;\n let lastError: unknown;\n try {\n const parsed = schema.parse(raw.parsed);\n return { ...raw, parsed, fixAttempts: 0 };\n } catch (err) {\n lastError = err;\n }\n\n // Auto-fix loop: send errors + original output back to fixModel for self-correction.\n // jsonSchemaStr is passed so the fix spawn also uses --json-schema enforcement.\n for (let attempt = 1; attempt <= maxFixes; attempt++) {\n const fixPromptStr = buildFixPrompt(lastText, lastError);\n const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n try {\n const parsed = schema.parse(fixRaw.parsed);\n return { ...fixRaw, parsed, fixAttempts: attempt };\n } catch (err) {\n lastText = fixRaw.text;\n lastError = err;\n }\n }\n\n const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);\n throw new SchemaValidationError(\n `SchemaValidationError: validation failed after ${maxFixes} fix attempt(s): ${errorMessage}`\n );\n}\n"],"mappings":"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","names":["text"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/runners/claude-code.ts"],"sourcesContent":["export { runClaudeCode, SchemaValidationError } from \"./runners/claude-code\";\nexport type { ClaudeCodeInput, ClaudeCodeResult, ClaudeEnvelope } from \"./runners/claude-code\";\n","import { spawn } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\n\nexport interface ClaudeCodeInput<T = unknown> {\n prompt: string;\n model?: string;\n /** Timeout in milliseconds. Default: 300_000 (5 min) */\n timeout?: number;\n /**\n * Maximum allowed stdout size in bytes. Default: 10_485_760 (10 MB).\n * If claude output exceeds this limit the process is killed and the promise rejects.\n */\n maxOutputBytes?: number;\n /**\n * Environment variables passed to the subprocess.\n * Defaults to the full process.env so that the binary can access its auth\n * tokens and config (ANTHROPIC_API_KEY, HOME, etc.).\n * Override if you need to restrict or augment the environment.\n */\n env?: NodeJS.ProcessEnv;\n /**\n * Binary to execute. Default: \"ccs\" (Claude Code Profile & Model Switcher).\n * Use \"claude\" to invoke the Claude CLI directly without profile switching.\n * Using `--print` (not `-p`) avoids the ccs delegation system while\n * preserving the standard `--output-format json` envelope output.\n */\n binary?: string;\n /**\n * Optional Zod schema (requires Zod v4+). When provided:\n * - Its JSON Schema representation is passed via `--json-schema` CLI flag\n * (CLI-level enforcement — Claude physically cannot return non-JSON).\n * - The response is validated with `schema.parse()`.\n * - On failure, an auto-fix retry is sent to `fixModel`.\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n * - Mutually exclusive with `jsonSchema`.\n */\n schema?: z.ZodType<T>;\n /**\n * Model used for auto-fix retries. Default: \"claude-haiku-4-5-20251001\"\n * (cheap and fast, good for JSON correction tasks).\n */\n fixModel?: string;\n /**\n * Maximum number of auto-fix attempts on schema validation failure. Default: 1.\n */\n maxFixes?: number;\n /**\n * Raw JSON Schema for CLI-level structured output enforcement.\n * Adds `--json-schema <schema>` to spawn args.\n * Claude returns structured_output in the envelope — guaranteed JSON.\n * No runtime validation or auto-fix. `result.parsed` is `unknown`.\n * Mutually exclusive with `schema`.\n */\n jsonSchema?: Record<string, unknown>;\n /**\n * Override the default tool list passed via `--tools`.\n * Default: `[\"Read\", \"Grep\", \"Glob\"]` (read-only by design).\n * Pass `[\"Bash\", \"Read\", \"Grep\", \"Glob\"]` to also allow Bash execution.\n */\n tools?: string[];\n /**\n * Restrict Bash commands via `--allowed-tools` flag.\n * Each entry is a pattern like `\"Bash(git log*)\"`.\n * Only meaningful when `tools` includes `\"Bash\"`.\n * When omitted, no `--allowed-tools` flag is added.\n */\n allowedTools?: string[];\n /**\n * List of CCS account names to rotate through on `is_error: true` responses.\n * Each account maps to `CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>`.\n * On `is_error`, the next account in the list is tried automatically.\n * Non-is_error failures (timeouts, non-zero exit, etc.) are thrown immediately.\n * If all accounts return `is_error`, throws with the last error message.\n */\n ccsAccounts?: string[];\n /**\n * Path to an MCP config JSON file.\n * When provided, adds `--mcp-config <path>` to the spawn args so the\n * Claude CLI can load MCP servers (filesystem, supabase, etc.).\n * The caller is responsible for writing the file before calling\n * `runClaudeCode` and deleting it afterwards.\n * If the file does not exist or is not accessible, the Claude CLI\n * will exit with a non-zero code and the promise will reject.\n */\n mcpConfigPath?: string;\n /**\n * Replaces the default system prompt entirely.\n * Adds `--system-prompt <text>` to spawn args.\n * CLAUDE.md is ignored when this is set.\n */\n systemPrompt: string;\n /**\n * Absolute path to the repository directory Claude should work in.\n * Required — without it Claude would inherit the worker CWD, exposing\n * worker source files, env vars, and credentials to the model.\n * Adds `--add-dir <path>` and sets `cwd: addDir` on the spawned process\n * so relative paths (e.g. Read(\"src/foo.ts\")) resolve inside the repo.\n * Throws if empty. If the directory does not exist, the Claude CLI will\n * exit with a non-zero code and the promise will reject.\n */\n addDir: string;\n}\n\n/**\n * The JSON envelope that `claude --output-format json` wraps every response in.\n * Only the fields we care about are typed; the rest are captured in the index signature.\n */\nexport interface ClaudeEnvelope {\n type: string;\n subtype: string;\n /** The actual text response from the model (plain text / raw JSON string) */\n result: string;\n is_error: boolean;\n /**\n * Present when `--json-schema` flag is used.\n * Contains the structured output object — use this instead of `result`.\n */\n structured_output?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ClaudeCodeResult<T = unknown> {\n /** The actual text content of claude's response (extracted from envelope.result) */\n text: string;\n /**\n * Parsed value. Typed as `T` when a schema is provided and validation passes.\n * Without schema: `unknown` (will be `null` when the response is not valid JSON).\n */\n parsed: T;\n /** The full response envelope from `claude --output-format json` */\n envelope: ClaudeEnvelope;\n /** Number of auto-fix retries used. 0 means the first response was valid. */\n fixAttempts: number;\n}\n\n/**\n * Thrown when schema validation fails after all auto-fix attempts are exhausted.\n */\nexport class SchemaValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SchemaValidationError\";\n }\n}\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Kills a process gracefully: SIGTERM first, SIGKILL after 5 seconds if still alive.\n */\nfunction killGracefully(proc: ReturnType<typeof spawn>): void {\n proc.kill(\"SIGTERM\");\n setTimeout(() => {\n proc.kill(\"SIGKILL\");\n }, 5000).unref();\n}\n\n/** Internal raw result from a single spawn cycle (before schema validation). */\ninterface RawResult {\n text: string;\n parsed: unknown | null;\n envelope: ClaudeEnvelope;\n}\n\n/**\n * Spawns the binary once and collects the JSON envelope result.\n * All validation/retry logic lives in `runClaudeCode`.\n */\nfunction spawnOnce(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string\n): Promise<RawResult> {\n // Use --print (not -p) so that ccs passes args through to claude without\n // triggering its delegation system. Prompt is the final positional argument.\n const toolsList = tools?.length ? tools.join(\",\") : \"Read,Grep,Glob\";\n const args = [\"--print\", \"--bare\", \"--output-format\", \"json\", \"--model\", model, \"--tools\", toolsList];\n if (allowedTools?.length) args.push(\"--allowed-tools\", ...allowedTools);\n if (mcpConfigPath) args.push(\"--mcp-config\", mcpConfigPath);\n args.push(\"--add-dir\", addDir);\n if (systemPrompt) args.push(\"--system-prompt\", systemPrompt);\n if (jsonSchemaStr) {\n args.push(\"--json-schema\", jsonSchemaStr);\n }\n // Prompt is delivered via stdin — avoids OS ARG_MAX limits (~2MB on Linux)\n\n return new Promise((resolve, reject) => {\n const proc = spawn(binary, args, { env, cwd: addDir });\n\n if (!proc.stdout || !proc.stderr || !proc.stdin) {\n reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));\n return;\n }\n\n // Suppress all stdin errors — EPIPE is expected when the process exits before reading\n // all of stdin; other stdin errors are extremely rare and non-fatal (process already spawned).\n proc.stdin.on(\"error\", () => {});\n // If the internal buffer is full (write returns false), wait for drain before closing.\n // This handles extremely large prompts where the OS pipe buffer fills up.\n if (proc.stdin.write(prompt, \"utf8\")) {\n proc.stdin.end();\n } else {\n proc.stdin.once(\"drain\", () => proc.stdin!.end());\n }\n\n // settled prevents double-resolve/reject between timeout and close handlers\n let settled = false;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let totalStdoutSize = 0;\n\n const timer = setTimeout(() => {\n settled = true;\n killGracefully(proc);\n reject(new Error(`${binary} process timed out after ${timeout}ms`));\n }, timeout);\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n totalStdoutSize += chunk.length;\n if (totalStdoutSize > maxOutputBytes) {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n killGracefully(proc);\n reject(new Error(`${binary} output exceeded ${maxOutputBytes} bytes`));\n return;\n }\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n proc.on(\"close\", (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (code !== 0) {\n reject(\n new Error(\n `${binary} exited with code ${code}${stderr ? `\\nstderr: ${stderr}` : \"\"}`\n )\n );\n return;\n }\n\n let envelope: ClaudeEnvelope;\n try {\n envelope = JSON.parse(stdout.trim()) as ClaudeEnvelope;\n } catch {\n reject(new Error(`${binary} output is not valid JSON: ${stdout.trim().slice(0, 200)}`));\n return;\n }\n\n if (envelope.is_error) {\n reject(new IsErrorResponse(envelope.result));\n return;\n }\n\n // --json-schema mode: result comes in structured_output, not result field\n if (envelope.structured_output !== undefined) {\n const text = JSON.stringify(envelope.structured_output);\n resolve({ text, parsed: envelope.structured_output, envelope });\n return;\n }\n\n if (typeof envelope.result !== \"string\") {\n reject(new Error(\"Invalid envelope: result field is not a string\"));\n return;\n }\n\n const text = envelope.result;\n\n let parsed: unknown | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n // text is not JSON — that's fine\n }\n\n resolve({ text, parsed, envelope });\n });\n\n proc.on(\"error\", (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn ${binary}: ${err.message}`));\n });\n });\n}\n\n/**\n * Thrown internally by spawnOnce when the Claude envelope contains is_error=true.\n * Caught by spawnWithAccounts to distinguish account-level errors from other failures.\n */\nclass IsErrorResponse extends Error {\n constructor(public readonly result: string) {\n super(`returned is_error=true: ${result}`);\n this.name = \"IsErrorResponse\";\n }\n}\n\n/**\n * Calls spawnOnce with optional CCS account rotation.\n * When `accounts` is provided, tries each account in order by setting\n * CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>. Rotates only on is_error=true;\n * any other error (timeout, non-zero exit, ENOENT) is thrown immediately.\n * If all accounts return is_error, throws with the last error message.\n *\n * Implemented as a regular (non-async) function so the no-rotation path\n * returns spawnOnce's promise directly without adding an extra microtask tick.\n */\nfunction spawnWithAccounts(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n accounts: string[] | undefined,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string\n): Promise<RawResult> {\n // Fast path: return promise directly — no extra microtask overhead\n if (!accounts || accounts.length === 0) {\n return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n }\n\n // Rotation path: async IIFE to iterate through accounts\n return (async () => {\n let lastIsError: IsErrorResponse | undefined;\n for (const account of accounts) {\n const accountEnv: NodeJS.ProcessEnv = {\n ...env,\n CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`,\n };\n try {\n return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n } catch (err) {\n if (err instanceof IsErrorResponse) {\n lastIsError = err;\n continue;\n }\n throw err;\n }\n }\n throw new Error(lastIsError!.result);\n })();\n}\n\n/**\n * Builds the auto-fix prompt sent to the fixModel when schema validation fails.\n * Includes structured ZodError issues (when available) and the original invalid\n * response so the model can self-correct.\n */\nfunction buildFixPrompt(invalidText: string, error: unknown): string {\n let errorMessage: string;\n if (error instanceof z.ZodError) {\n errorMessage = error.issues\n .map((i) => `Path: ${i.path.length ? i.path.join(\".\") : \"(root)\"}, ${i.message}`)\n .join(\"\\n\");\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = String(error);\n }\n return (\n `The following JSON failed schema validation.\\n\\n` +\n `Errors:\\n${errorMessage}\\n\\n` +\n `Invalid response:\\n${invalidText}\\n\\n` +\n `Output ONLY corrected JSON. No explanation, no markdown.`\n );\n}\n\n/**\n * Runs the configured binary (default: ccs) with --print flag as a subprocess.\n * Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`\n * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).\n * --bare suppresses global CLAUDE.md auto-discovery, hooks, LSP, auto-memory and other\n * side effects — ensuring the agent runs only with the provided systemPrompt.\n *\n * When a `schema` is provided (Zod v4+):\n * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).\n * - Claude returns structured_output in the envelope — guaranteed JSON.\n * - The response is validated; on failure an auto-fix retry is sent to `fixModel`.\n * - `result.fixAttempts` indicates how many retries were used (0 = first response valid).\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n *\n * When `jsonSchema` is provided:\n * - Passed via `--json-schema` CLI flag (hard enforcement, no validation or retry).\n * - `result.parsed` is `unknown`.\n *\n * Without schema: `result.parsed` is `unknown` (may be `null` for plain-text responses).\n *\n * Designed to be used as a plain async function inside a trigger.dev task `run()`.\n */\nexport function runClaudeCode(input: ClaudeCodeInput): Promise<ClaudeCodeResult<unknown>>;\nexport function runClaudeCode<T>(\n input: ClaudeCodeInput<T> & { schema: z.ZodType<T> }\n): Promise<ClaudeCodeResult<T>>;\nexport async function runClaudeCode<T = unknown>(\n input: ClaudeCodeInput<T>\n): Promise<ClaudeCodeResult<T | null>> {\n const {\n prompt,\n model = \"claude-sonnet-4-6\",\n timeout = 300_000,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n env = process.env,\n binary = \"ccs\",\n schema,\n fixModel = \"claude-haiku-4-5-20251001\",\n maxFixes = 1,\n jsonSchema,\n ccsAccounts,\n mcpConfigPath,\n addDir,\n tools,\n allowedTools,\n systemPrompt,\n } = input;\n\n if (!prompt || prompt.trim().length === 0) {\n throw new Error(\"prompt cannot be empty\");\n }\n\n if (!addDir || addDir.trim().length === 0) {\n throw new Error(\"addDir is required: omitting it exposes the worker CWD to the model\");\n }\n\n if (!binary || binary.trim().length === 0) {\n throw new Error(\"binary cannot be empty\");\n }\n\n if (jsonSchema && schema) {\n throw new Error(\"cannot use jsonSchema with schema\");\n }\n\n if (!systemPrompt || systemPrompt.trim().length === 0) {\n throw new Error(\"systemPrompt cannot be empty\");\n }\n\n if (allowedTools?.length && (!tools || !tools.includes(\"Bash\"))) {\n throw new Error(\"allowedTools requires 'Bash' in tools array\");\n }\n\n // Build jsonSchemaStr from Zod schema or raw jsonSchema — passed as CLI flag, not prompt text\n let jsonSchemaStr: string | undefined;\n if (schema) {\n try {\n jsonSchemaStr = JSON.stringify(z.toJSONSchema(schema));\n } catch (err) {\n throw new Error(\n `Failed to convert Zod schema to JSON Schema (requires Zod v4+): ${String(err)}`\n );\n }\n } else if (jsonSchema) {\n try {\n jsonSchemaStr = JSON.stringify(jsonSchema);\n } catch (err) {\n throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);\n }\n }\n\n const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n\n // No schema — return raw result. parsed may be null for plain-text responses.\n // Cast is safe: overload 1 constrains T = unknown, so T | null = unknown.\n if (!schema) {\n return { text: raw.text, parsed: raw.parsed as T | null, envelope: raw.envelope, fixAttempts: 0 };\n }\n\n // Try to validate the initial response.\n // Note: if raw.parsed is null (plain-text response), schema.parse(null) throws ZodError,\n // which correctly triggers the auto-fix flow.\n let lastText = raw.text;\n let lastError: unknown;\n try {\n const parsed = schema.parse(raw.parsed);\n return { ...raw, parsed, fixAttempts: 0 };\n } catch (err) {\n lastError = err;\n }\n\n // Auto-fix loop: send errors + original output back to fixModel for self-correction.\n // jsonSchemaStr is passed so the fix spawn also uses --json-schema enforcement.\n for (let attempt = 1; attempt <= maxFixes; attempt++) {\n const fixPromptStr = buildFixPrompt(lastText, lastError);\n const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n try {\n const parsed = schema.parse(fixRaw.parsed);\n return { ...fixRaw, parsed, fixAttempts: attempt };\n } catch (err) {\n lastText = fixRaw.text;\n lastError = err;\n }\n }\n\n const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);\n throw new SchemaValidationError(\n `SchemaValidationError: validation failed after ${maxFixes} fix attempt(s): ${errorMessage}`\n );\n}\n"],"mappings":"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","names":["text"]}
|
package/dist/index.mjs
CHANGED
|
@@ -15,18 +15,18 @@ function killGracefully(proc) {
|
|
|
15
15
|
proc.kill("SIGKILL");
|
|
16
16
|
}, 5e3).unref();
|
|
17
17
|
}
|
|
18
|
-
function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
18
|
+
function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
|
|
19
19
|
const toolsList = tools?.length ? tools.join(",") : "Read,Grep,Glob";
|
|
20
|
-
const args = ["--print", "--output-format", "json", "--model", model, "--tools", toolsList];
|
|
20
|
+
const args = ["--print", "--bare", "--output-format", "json", "--model", model, "--tools", toolsList];
|
|
21
21
|
if (allowedTools?.length) args.push("--allowed-tools", ...allowedTools);
|
|
22
22
|
if (mcpConfigPath) args.push("--mcp-config", mcpConfigPath);
|
|
23
23
|
args.push("--add-dir", addDir);
|
|
24
24
|
if (systemPrompt) args.push("--system-prompt", systemPrompt);
|
|
25
|
-
if (jsonSchemaStr)
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
if (jsonSchemaStr) {
|
|
26
|
+
args.push("--json-schema", jsonSchemaStr);
|
|
27
|
+
}
|
|
28
28
|
return new Promise((resolve, reject) => {
|
|
29
|
-
const proc = spawn(binary, args, { env
|
|
29
|
+
const proc = spawn(binary, args, { env, cwd: addDir });
|
|
30
30
|
if (!proc.stdout || !proc.stderr || !proc.stdin) {
|
|
31
31
|
reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));
|
|
32
32
|
return;
|
|
@@ -69,10 +69,12 @@ function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir,
|
|
|
69
69
|
const stdout = Buffer.concat(stdoutChunks).toString();
|
|
70
70
|
const stderr = Buffer.concat(stderrChunks).toString();
|
|
71
71
|
if (code !== 0) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
reject(
|
|
73
|
+
new Error(
|
|
74
|
+
`${binary} exited with code ${code}${stderr ? `
|
|
75
|
+
stderr: ${stderr}` : ""}`
|
|
76
|
+
)
|
|
77
|
+
);
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
let envelope;
|
|
@@ -118,9 +120,9 @@ var IsErrorResponse = class extends Error {
|
|
|
118
120
|
this.name = "IsErrorResponse";
|
|
119
121
|
}
|
|
120
122
|
};
|
|
121
|
-
function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
123
|
+
function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
|
|
122
124
|
if (!accounts || accounts.length === 0) {
|
|
123
|
-
return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
125
|
+
return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
124
126
|
}
|
|
125
127
|
return (async () => {
|
|
126
128
|
let lastIsError;
|
|
@@ -130,7 +132,7 @@ function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env,
|
|
|
130
132
|
CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`
|
|
131
133
|
};
|
|
132
134
|
try {
|
|
133
|
-
return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
135
|
+
return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
134
136
|
} catch (err) {
|
|
135
137
|
if (err instanceof IsErrorResponse) {
|
|
136
138
|
lastIsError = err;
|
|
@@ -178,8 +180,7 @@ async function runClaudeCode(input) {
|
|
|
178
180
|
addDir,
|
|
179
181
|
tools,
|
|
180
182
|
allowedTools,
|
|
181
|
-
systemPrompt
|
|
182
|
-
claudeMds = "none"
|
|
183
|
+
systemPrompt
|
|
183
184
|
} = input;
|
|
184
185
|
if (!prompt || prompt.trim().length === 0) {
|
|
185
186
|
throw new Error("prompt cannot be empty");
|
|
@@ -215,7 +216,7 @@ async function runClaudeCode(input) {
|
|
|
215
216
|
throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);
|
|
216
217
|
}
|
|
217
218
|
}
|
|
218
|
-
const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
219
|
+
const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
219
220
|
if (!schema) {
|
|
220
221
|
return { text: raw.text, parsed: raw.parsed, envelope: raw.envelope, fixAttempts: 0 };
|
|
221
222
|
}
|
|
@@ -229,7 +230,7 @@ async function runClaudeCode(input) {
|
|
|
229
230
|
}
|
|
230
231
|
for (let attempt = 1; attempt <= maxFixes; attempt++) {
|
|
231
232
|
const fixPromptStr = buildFixPrompt(lastText, lastError);
|
|
232
|
-
const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt
|
|
233
|
+
const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
|
|
233
234
|
try {
|
|
234
235
|
const parsed = schema.parse(fixRaw.parsed);
|
|
235
236
|
return { ...fixRaw, parsed, fixAttempts: attempt };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runners/claude-code.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\n\nexport interface ClaudeCodeInput<T = unknown> {\n prompt: string;\n model?: string;\n /** Timeout in milliseconds. Default: 300_000 (5 min) */\n timeout?: number;\n /**\n * Maximum allowed stdout size in bytes. Default: 10_485_760 (10 MB).\n * If claude output exceeds this limit the process is killed and the promise rejects.\n */\n maxOutputBytes?: number;\n /**\n * Environment variables passed to the subprocess.\n * Defaults to the full process.env so that the binary can access its auth\n * tokens and config (ANTHROPIC_API_KEY, HOME, etc.).\n * Override if you need to restrict or augment the environment.\n */\n env?: NodeJS.ProcessEnv;\n /**\n * Binary to execute. Default: \"ccs\" (Claude Code Profile & Model Switcher).\n * Use \"claude\" to invoke the Claude CLI directly without profile switching.\n * Using `--print` (not `-p`) avoids the ccs delegation system while\n * preserving the standard `--output-format json` envelope output.\n */\n binary?: string;\n /**\n * Optional Zod schema (requires Zod v4+). When provided:\n * - Its JSON Schema representation is passed via `--json-schema` CLI flag\n * (CLI-level enforcement — Claude physically cannot return non-JSON).\n * - The response is validated with `schema.parse()`.\n * - On failure, an auto-fix retry is sent to `fixModel`.\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n * - Mutually exclusive with `jsonSchema`.\n */\n schema?: z.ZodType<T>;\n /**\n * Model used for auto-fix retries. Default: \"claude-haiku-4-5-20251001\"\n * (cheap and fast, good for JSON correction tasks).\n */\n fixModel?: string;\n /**\n * Maximum number of auto-fix attempts on schema validation failure. Default: 1.\n */\n maxFixes?: number;\n /**\n * Raw JSON Schema for CLI-level structured output enforcement.\n * Adds `--json-schema <schema>` to spawn args.\n * Claude returns structured_output in the envelope — guaranteed JSON.\n * No runtime validation or auto-fix. `result.parsed` is `unknown`.\n * Mutually exclusive with `schema`.\n */\n jsonSchema?: Record<string, unknown>;\n /**\n * Override the default tool list passed via `--tools`.\n * Default: `[\"Read\", \"Grep\", \"Glob\"]` (read-only by design).\n * Pass `[\"Bash\", \"Read\", \"Grep\", \"Glob\"]` to also allow Bash execution.\n */\n tools?: string[];\n /**\n * Restrict Bash commands via `--allowed-tools` flag.\n * Each entry is a pattern like `\"Bash(git log*)\"`.\n * Only meaningful when `tools` includes `\"Bash\"`.\n * When omitted, no `--allowed-tools` flag is added.\n */\n allowedTools?: string[];\n /**\n * List of CCS account names to rotate through on `is_error: true` responses.\n * Each account maps to `CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>`.\n * On `is_error`, the next account in the list is tried automatically.\n * Non-is_error failures (timeouts, non-zero exit, etc.) are thrown immediately.\n * If all accounts return `is_error`, throws with the last error message.\n */\n ccsAccounts?: string[];\n /**\n * Path to an MCP config JSON file.\n * When provided, adds `--mcp-config <path>` to the spawn args so the\n * Claude CLI can load MCP servers (filesystem, supabase, etc.).\n * The caller is responsible for writing the file before calling\n * `runClaudeCode` and deleting it afterwards.\n * If the file does not exist or is not accessible, the Claude CLI\n * will exit with a non-zero code and the promise will reject.\n */\n mcpConfigPath?: string;\n /**\n * Replaces the default system prompt entirely.\n * Adds `--system-prompt <text>` to spawn args.\n * CLAUDE.md is ignored when this is set.\n */\n systemPrompt: string;\n /**\n * Absolute path to the repository directory Claude should work in.\n * Required — without it Claude would inherit the worker CWD, exposing\n * worker source files, env vars, and credentials to the model.\n * Adds `--add-dir <path>` and sets `cwd: addDir` on the spawned process\n * so relative paths (e.g. Read(\"src/foo.ts\")) resolve inside the repo.\n * Throws if empty. If the directory does not exist, the Claude CLI will\n * exit with a non-zero code and the promise will reject.\n */\n addDir: string;\n /**\n * Controls CLAUDE.md auto-discovery.\n * - \"none\" (default): sets CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 — disables all CLAUDE.md files\n * - \"project-local\": passes --setting-sources=project,local — loads only project/local settings\n * - \"all\": standard Claude behavior, no restriction\n */\n claudeMds?: \"none\" | \"project-local\" | \"all\";\n}\n\n/**\n * The JSON envelope that `claude --output-format json` wraps every response in.\n * Only the fields we care about are typed; the rest are captured in the index signature.\n */\nexport interface ClaudeEnvelope {\n type: string;\n subtype: string;\n /** The actual text response from the model (plain text / raw JSON string) */\n result: string;\n is_error: boolean;\n /**\n * Present when `--json-schema` flag is used.\n * Contains the structured output object — use this instead of `result`.\n */\n structured_output?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ClaudeCodeResult<T = unknown> {\n /** The actual text content of claude's response (extracted from envelope.result) */\n text: string;\n /**\n * Parsed value. Typed as `T` when a schema is provided and validation passes.\n * Without schema: `unknown` (will be `null` when the response is not valid JSON).\n */\n parsed: T;\n /** The full response envelope from `claude --output-format json` */\n envelope: ClaudeEnvelope;\n /** Number of auto-fix retries used. 0 means the first response was valid. */\n fixAttempts: number;\n}\n\n/**\n * Thrown when schema validation fails after all auto-fix attempts are exhausted.\n */\nexport class SchemaValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SchemaValidationError\";\n }\n}\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Kills a process gracefully: SIGTERM first, SIGKILL after 5 seconds if still alive.\n */\nfunction killGracefully(proc: ReturnType<typeof spawn>): void {\n proc.kill(\"SIGTERM\");\n setTimeout(() => {\n proc.kill(\"SIGKILL\");\n }, 5000).unref();\n}\n\n/** Internal raw result from a single spawn cycle (before schema validation). */\ninterface RawResult {\n text: string;\n parsed: unknown | null;\n envelope: ClaudeEnvelope;\n}\n\n/**\n * Spawns the binary once and collects the JSON envelope result.\n * All validation/retry logic lives in `runClaudeCode`.\n */\nfunction spawnOnce(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string,\n claudeMds: \"none\" | \"project-local\" | \"all\" = \"none\"\n): Promise<RawResult> {\n // Use --print (not -p) so that ccs passes args through to claude without\n // triggering its delegation system. Prompt is the final positional argument.\n const toolsList = tools?.length ? tools.join(\",\") : \"Read,Grep,Glob\";\n const args = [\"--print\", \"--output-format\", \"json\", \"--model\", model, \"--tools\", toolsList];\n if (allowedTools?.length) args.push(\"--allowed-tools\", ...allowedTools);\n if (mcpConfigPath) args.push(\"--mcp-config\", mcpConfigPath);\n args.push(\"--add-dir\", addDir);\n if (systemPrompt) args.push(\"--system-prompt\", systemPrompt);\n if (jsonSchemaStr) args.push(\"--json-schema\", jsonSchemaStr);\n if (claudeMds === \"project-local\") args.push(\"--setting-sources\", \"project,local\");\n // Prompt is delivered via stdin — avoids OS ARG_MAX limits (~2MB on Linux)\n\n // Suppress CLAUDE.md auto-discovery via env var (default) or setting-sources flag.\n // CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 disables all CLAUDE.md files without touching HOME,\n // preserving credentials and avoiding the HOME-isolation overhead.\n const spawnEnv = claudeMds === \"none\"\n ? { ...env, CLAUDE_CODE_DISABLE_CLAUDE_MDS: \"1\" }\n : { ...env };\n\n return new Promise((resolve, reject) => {\n const proc = spawn(binary, args, { env: spawnEnv, cwd: addDir });\n\n if (!proc.stdout || !proc.stderr || !proc.stdin) {\n reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));\n return;\n }\n\n // Suppress all stdin errors — EPIPE is expected when the process exits before reading\n // all of stdin; other stdin errors are extremely rare and non-fatal (process already spawned).\n proc.stdin.on(\"error\", () => {});\n // If the internal buffer is full (write returns false), wait for drain before closing.\n // This handles extremely large prompts where the OS pipe buffer fills up.\n if (proc.stdin.write(prompt, \"utf8\")) {\n proc.stdin.end();\n } else {\n proc.stdin.once(\"drain\", () => proc.stdin!.end());\n }\n\n // settled prevents double-resolve/reject between timeout and close handlers\n let settled = false;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let totalStdoutSize = 0;\n\n const timer = setTimeout(() => {\n settled = true;\n killGracefully(proc);\n reject(new Error(`${binary} process timed out after ${timeout}ms`));\n }, timeout);\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n totalStdoutSize += chunk.length;\n if (totalStdoutSize > maxOutputBytes) {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n killGracefully(proc);\n reject(new Error(`${binary} output exceeded ${maxOutputBytes} bytes`));\n return;\n }\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n proc.on(\"close\", (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (code !== 0) {\n const parts = [`${binary} exited with code ${code}`];\n if (stderr) parts.push(`stderr: ${stderr}`);\n if (stdout) parts.push(`stdout: ${stdout}`);\n reject(new Error(parts.join(\"\\n\")));\n return;\n }\n\n let envelope: ClaudeEnvelope;\n try {\n envelope = JSON.parse(stdout.trim()) as ClaudeEnvelope;\n } catch {\n reject(new Error(`${binary} output is not valid JSON: ${stdout.trim().slice(0, 200)}`));\n return;\n }\n\n if (envelope.is_error) {\n reject(new IsErrorResponse(envelope.result));\n return;\n }\n\n // --json-schema mode: result comes in structured_output, not result field\n if (envelope.structured_output !== undefined) {\n const text = JSON.stringify(envelope.structured_output);\n resolve({ text, parsed: envelope.structured_output, envelope });\n return;\n }\n\n if (typeof envelope.result !== \"string\") {\n reject(new Error(\"Invalid envelope: result field is not a string\"));\n return;\n }\n\n const text = envelope.result;\n\n let parsed: unknown | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n // text is not JSON — that's fine\n }\n\n resolve({ text, parsed, envelope });\n });\n\n proc.on(\"error\", (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn ${binary}: ${err.message}`));\n });\n });\n}\n\n/**\n * Thrown internally by spawnOnce when the Claude envelope contains is_error=true.\n * Caught by spawnWithAccounts to distinguish account-level errors from other failures.\n */\nclass IsErrorResponse extends Error {\n constructor(public readonly result: string) {\n super(`returned is_error=true: ${result}`);\n this.name = \"IsErrorResponse\";\n }\n}\n\n/**\n * Calls spawnOnce with optional CCS account rotation.\n * When `accounts` is provided, tries each account in order by setting\n * CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>. Rotates only on is_error=true;\n * any other error (timeout, non-zero exit, ENOENT) is thrown immediately.\n * If all accounts return is_error, throws with the last error message.\n *\n * Implemented as a regular (non-async) function so the no-rotation path\n * returns spawnOnce's promise directly without adding an extra microtask tick.\n */\nfunction spawnWithAccounts(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n accounts: string[] | undefined,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string,\n claudeMds: \"none\" | \"project-local\" | \"all\" = \"none\"\n): Promise<RawResult> {\n // Fast path: return promise directly — no extra microtask overhead\n if (!accounts || accounts.length === 0) {\n return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n }\n\n // Rotation path: async IIFE to iterate through accounts\n return (async () => {\n let lastIsError: IsErrorResponse | undefined;\n for (const account of accounts) {\n const accountEnv: NodeJS.ProcessEnv = {\n ...env,\n CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`,\n };\n try {\n return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n } catch (err) {\n if (err instanceof IsErrorResponse) {\n lastIsError = err;\n continue;\n }\n throw err;\n }\n }\n throw new Error(lastIsError!.result);\n })();\n}\n\n/**\n * Builds the auto-fix prompt sent to the fixModel when schema validation fails.\n * Includes structured ZodError issues (when available) and the original invalid\n * response so the model can self-correct.\n */\nfunction buildFixPrompt(invalidText: string, error: unknown): string {\n let errorMessage: string;\n if (error instanceof z.ZodError) {\n errorMessage = error.issues\n .map((i) => `Path: ${i.path.length ? i.path.join(\".\") : \"(root)\"}, ${i.message}`)\n .join(\"\\n\");\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = String(error);\n }\n return (\n `The following JSON failed schema validation.\\n\\n` +\n `Errors:\\n${errorMessage}\\n\\n` +\n `Invalid response:\\n${invalidText}\\n\\n` +\n `Output ONLY corrected JSON. No explanation, no markdown.`\n );\n}\n\n/**\n * Runs the configured binary (default: ccs) with --print flag as a subprocess.\n * Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`\n * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).\n * A per-invocation isolated HOME dir is set to suppress ~/CLAUDE.md auto-discovery\n * without --bare, which would disable OAuth/keychain auth.\n *\n * When a `schema` is provided (Zod v4+):\n * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).\n * - Claude returns structured_output in the envelope — guaranteed JSON.\n * - The response is validated; on failure an auto-fix retry is sent to `fixModel`.\n * - `result.fixAttempts` indicates how many retries were used (0 = first response valid).\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n *\n * When `jsonSchema` is provided:\n * - Passed via `--json-schema` CLI flag (hard enforcement, no validation or retry).\n * - `result.parsed` is `unknown`.\n *\n * Without schema: `result.parsed` is `unknown` (may be `null` for plain-text responses).\n *\n * Designed to be used as a plain async function inside a trigger.dev task `run()`.\n */\nexport function runClaudeCode(input: ClaudeCodeInput): Promise<ClaudeCodeResult<unknown>>;\nexport function runClaudeCode<T>(\n input: ClaudeCodeInput<T> & { schema: z.ZodType<T> }\n): Promise<ClaudeCodeResult<T>>;\nexport async function runClaudeCode<T = unknown>(\n input: ClaudeCodeInput<T>\n): Promise<ClaudeCodeResult<T | null>> {\n const {\n prompt,\n model = \"claude-sonnet-4-6\",\n timeout = 300_000,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n env = process.env,\n binary = \"ccs\",\n schema,\n fixModel = \"claude-haiku-4-5-20251001\",\n maxFixes = 1,\n jsonSchema,\n ccsAccounts,\n mcpConfigPath,\n addDir,\n tools,\n allowedTools,\n systemPrompt,\n claudeMds = \"none\",\n } = input;\n\n if (!prompt || prompt.trim().length === 0) {\n throw new Error(\"prompt cannot be empty\");\n }\n\n if (!addDir || addDir.trim().length === 0) {\n throw new Error(\"addDir is required: omitting it exposes the worker CWD to the model\");\n }\n\n if (!binary || binary.trim().length === 0) {\n throw new Error(\"binary cannot be empty\");\n }\n\n if (jsonSchema && schema) {\n throw new Error(\"cannot use jsonSchema with schema\");\n }\n\n if (!systemPrompt || systemPrompt.trim().length === 0) {\n throw new Error(\"systemPrompt cannot be empty\");\n }\n\n if (allowedTools?.length && (!tools || !tools.includes(\"Bash\"))) {\n throw new Error(\"allowedTools requires 'Bash' in tools array\");\n }\n\n // Build jsonSchemaStr from Zod schema or raw jsonSchema — passed as CLI flag, not prompt text\n let jsonSchemaStr: string | undefined;\n if (schema) {\n try {\n jsonSchemaStr = JSON.stringify(z.toJSONSchema(schema));\n } catch (err) {\n throw new Error(\n `Failed to convert Zod schema to JSON Schema (requires Zod v4+): ${String(err)}`\n );\n }\n } else if (jsonSchema) {\n try {\n jsonSchemaStr = JSON.stringify(jsonSchema);\n } catch (err) {\n throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);\n }\n }\n\n const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n\n // No schema — return raw result. parsed may be null for plain-text responses.\n // Cast is safe: overload 1 constrains T = unknown, so T | null = unknown.\n if (!schema) {\n return { text: raw.text, parsed: raw.parsed as T | null, envelope: raw.envelope, fixAttempts: 0 };\n }\n\n // Try to validate the initial response.\n // Note: if raw.parsed is null (plain-text response), schema.parse(null) throws ZodError,\n // which correctly triggers the auto-fix flow.\n let lastText = raw.text;\n let lastError: unknown;\n try {\n const parsed = schema.parse(raw.parsed);\n return { ...raw, parsed, fixAttempts: 0 };\n } catch (err) {\n lastError = err;\n }\n\n // Auto-fix loop: send errors + original output back to fixModel for self-correction.\n // jsonSchemaStr is passed so the fix spawn also uses --json-schema enforcement.\n for (let attempt = 1; attempt <= maxFixes; attempt++) {\n const fixPromptStr = buildFixPrompt(lastText, lastError);\n const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt, claudeMds);\n try {\n const parsed = schema.parse(fixRaw.parsed);\n return { ...fixRaw, parsed, fixAttempts: attempt };\n } catch (err) {\n lastText = fixRaw.text;\n lastError = err;\n }\n }\n\n const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);\n throw new SchemaValidationError(\n `SchemaValidationError: validation failed after ${maxFixes} fix attempt(s): ${errorMessage}`\n );\n}\n"],"mappings":";AAAA,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,SAAS;AAgJX,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC/C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEA,IAAM,2BAA2B,KAAK,OAAO;AAK7C,SAAS,eAAe,MAAsC;AAC5D,OAAK,KAAK,SAAS;AACnB,aAAW,MAAM;AACf,SAAK,KAAK,SAAS;AAAA,EACrB,GAAG,GAAI,EAAE,MAAM;AACjB;AAaA,SAAS,UACP,QACA,QACA,OACA,SACA,gBACA,KACA,QACA,eACA,eACA,OACA,cACA,cACA,YAA8C,QAC1B;AAGpB,QAAM,YAAY,OAAO,SAAS,MAAM,KAAK,GAAG,IAAI;AACpD,QAAM,OAAO,CAAC,WAAW,mBAAmB,QAAQ,WAAW,OAAO,WAAW,SAAS;AAC1F,MAAI,cAAc,OAAQ,MAAK,KAAK,mBAAmB,GAAG,YAAY;AACtE,MAAI,cAAe,MAAK,KAAK,gBAAgB,aAAa;AAC1D,OAAK,KAAK,aAAa,MAAM;AAC7B,MAAI,aAAc,MAAK,KAAK,mBAAmB,YAAY;AAC3D,MAAI,cAAe,MAAK,KAAK,iBAAiB,aAAa;AAC3D,MAAI,cAAc,gBAAiB,MAAK,KAAK,qBAAqB,eAAe;AAMjF,QAAM,WAAW,cAAc,SAC3B,EAAE,GAAG,KAAK,gCAAgC,IAAI,IAC9C,EAAE,GAAG,IAAI;AAEb,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,OAAO,MAAM,QAAQ,MAAM,EAAE,KAAK,UAAU,KAAK,OAAO,CAAC;AAE/D,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU,CAAC,KAAK,OAAO;AAC/C,aAAO,IAAI,MAAM,mBAAmB,MAAM,+BAA+B,CAAC;AAC1E;AAAA,IACF;AAIA,SAAK,MAAM,GAAG,SAAS,MAAM;AAAA,IAAC,CAAC;AAG/B,QAAI,KAAK,MAAM,MAAM,QAAQ,MAAM,GAAG;AACpC,WAAK,MAAM,IAAI;AAAA,IACjB,OAAO;AACL,WAAK,MAAM,KAAK,SAAS,MAAM,KAAK,MAAO,IAAI,CAAC;AAAA,IAClD;AAGA,QAAI,UAAU;AAEd,UAAM,eAAyB,CAAC;AAChC,UAAM,eAAyB,CAAC;AAChC,QAAI,kBAAkB;AAEtB,UAAM,QAAQ,WAAW,MAAM;AAC7B,gBAAU;AACV,qBAAe,IAAI;AACnB,aAAO,IAAI,MAAM,GAAG,MAAM,4BAA4B,OAAO,IAAI,CAAC;AAAA,IACpE,GAAG,OAAO;AAEV,SAAK,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACxC,yBAAmB,MAAM;AACzB,UAAI,kBAAkB,gBAAgB;AACpC,YAAI,QAAS;AACb,kBAAU;AACV,qBAAa,KAAK;AAClB,uBAAe,IAAI;AACnB,eAAO,IAAI,MAAM,GAAG,MAAM,oBAAoB,cAAc,QAAQ,CAAC;AACrE;AAAA,MACF;AACA,mBAAa,KAAK,KAAK;AAAA,IACzB,CAAC;AAED,SAAK,OAAO,GAAG,QAAQ,CAAC,UAAkB;AACxC,mBAAa,KAAK,KAAK;AAAA,IACzB,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,SAAS;AACzB,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,KAAK;AAElB,YAAM,SAAS,OAAO,OAAO,YAAY,EAAE,SAAS;AACpD,YAAM,SAAS,OAAO,OAAO,YAAY,EAAE,SAAS;AAEpD,UAAI,SAAS,GAAG;AACd,cAAM,QAAQ,CAAC,GAAG,MAAM,qBAAqB,IAAI,EAAE;AACnD,YAAI,OAAQ,OAAM,KAAK,WAAW,MAAM,EAAE;AAC1C,YAAI,OAAQ,OAAM,KAAK,WAAW,MAAM,EAAE;AAC1C,eAAO,IAAI,MAAM,MAAM,KAAK,IAAI,CAAC,CAAC;AAClC;AAAA,MACF;AAEA,UAAI;AACJ,UAAI;AACF,mBAAW,KAAK,MAAM,OAAO,KAAK,CAAC;AAAA,MACrC,QAAQ;AACN,eAAO,IAAI,MAAM,GAAG,MAAM,8BAA8B,OAAO,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;AACtF;AAAA,MACF;AAEA,UAAI,SAAS,UAAU;AACrB,eAAO,IAAI,gBAAgB,SAAS,MAAM,CAAC;AAC3C;AAAA,MACF;AAGA,UAAI,SAAS,sBAAsB,QAAW;AAC5C,cAAMA,QAAO,KAAK,UAAU,SAAS,iBAAiB;AACtD,gBAAQ,EAAE,MAAAA,OAAM,QAAQ,SAAS,mBAAmB,SAAS,CAAC;AAC9D;AAAA,MACF;AAEA,UAAI,OAAO,SAAS,WAAW,UAAU;AACvC,eAAO,IAAI,MAAM,gDAAgD,CAAC;AAClE;AAAA,MACF;AAEA,YAAM,OAAO,SAAS;AAEtB,UAAI,SAAyB;AAC7B,UAAI;AACF,iBAAS,KAAK,MAAM,IAAI;AAAA,MAC1B,QAAQ;AAAA,MAER;AAEA,cAAQ,EAAE,MAAM,QAAQ,SAAS,CAAC;AAAA,IACpC,CAAC;AAED,SAAK,GAAG,SAAS,CAAC,QAAQ;AACxB,UAAI,QAAS;AACb,gBAAU;AACV,mBAAa,KAAK;AAClB,aAAO,IAAI,MAAM,mBAAmB,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,IAC/D,CAAC;AAAA,EACH,CAAC;AACH;AAMA,IAAM,kBAAN,cAA8B,MAAM;AAAA,EAClC,YAA4B,QAAgB;AAC1C,UAAM,2BAA2B,MAAM,EAAE;AADf;AAE1B,SAAK,OAAO;AAAA,EACd;AACF;AAYA,SAAS,kBACP,QACA,QACA,OACA,SACA,gBACA,KACA,UACA,QACA,eACA,eACA,OACA,cACA,cACA,YAA8C,QAC1B;AAEpB,MAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACtC,WAAO,UAAU,QAAQ,QAAQ,OAAO,SAAS,gBAAgB,KAAK,QAAQ,eAAe,eAAe,OAAO,cAAc,cAAc,SAAS;AAAA,EAC1J;AAGA,UAAQ,YAAY;AAClB,QAAI;AACJ,eAAW,WAAW,UAAU;AAC9B,YAAM,aAAgC;AAAA,QACpC,GAAG;AAAA,QACH,mBAAmB,GAAG,QAAQ,CAAC,mBAAmB,OAAO;AAAA,MAC3D;AACA,UAAI;AACF,eAAO,MAAM,UAAU,QAAQ,QAAQ,OAAO,SAAS,gBAAgB,YAAY,QAAQ,eAAe,eAAe,OAAO,cAAc,cAAc,SAAS;AAAA,MACvK,SAAS,KAAK;AACZ,YAAI,eAAe,iBAAiB;AAClC,wBAAc;AACd;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,IAAI,MAAM,YAAa,MAAM;AAAA,EACrC,GAAG;AACL;AAOA,SAAS,eAAe,aAAqB,OAAwB;AACnE,MAAI;AACJ,MAAI,iBAAiB,EAAE,UAAU;AAC/B,mBAAe,MAAM,OAClB,IAAI,CAAC,MAAM,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,KAAK,GAAG,IAAI,QAAQ,KAAK,EAAE,OAAO,EAAE,EAC/E,KAAK,IAAI;AAAA,EACd,WAAW,iBAAiB,OAAO;AACjC,mBAAe,MAAM;AAAA,EACvB,OAAO;AACL,mBAAe,OAAO,KAAK;AAAA,EAC7B;AACA,SACE;AAAA;AAAA;AAAA,EACY,YAAY;AAAA;AAAA;AAAA,EACF,WAAW;AAAA;AAAA;AAGrC;AA4BA,eAAsB,cACpB,OACqC;AACrC,QAAM;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,MAAM,QAAQ;AAAA,IACd,SAAS;AAAA,IACT;AAAA,IACA,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd,IAAI;AAEJ,MAAI,CAAC,UAAU,OAAO,KAAK,EAAE,WAAW,GAAG;AACzC,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,MAAI,CAAC,UAAU,OAAO,KAAK,EAAE,WAAW,GAAG;AACzC,UAAM,IAAI,MAAM,qEAAqE;AAAA,EACvF;AAEA,MAAI,CAAC,UAAU,OAAO,KAAK,EAAE,WAAW,GAAG;AACzC,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AAEA,MAAI,cAAc,QAAQ;AACxB,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,CAAC,gBAAgB,aAAa,KAAK,EAAE,WAAW,GAAG;AACrD,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AAEA,MAAI,cAAc,WAAW,CAAC,SAAS,CAAC,MAAM,SAAS,MAAM,IAAI;AAC/D,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAGA,MAAI;AACJ,MAAI,QAAQ;AACV,QAAI;AACF,sBAAgB,KAAK,UAAU,EAAE,aAAa,MAAM,CAAC;AAAA,IACvD,SAAS,KAAK;AACZ,YAAM,IAAI;AAAA,QACR,mEAAmE,OAAO,GAAG,CAAC;AAAA,MAChF;AAAA,IACF;AAAA,EACF,WAAW,YAAY;AACrB,QAAI;AACF,sBAAgB,KAAK,UAAU,UAAU;AAAA,IAC3C,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,2CAA2C,OAAO,GAAG,CAAC,EAAE;AAAA,IAC1E;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,kBAAkB,QAAQ,QAAQ,OAAO,SAAS,gBAAgB,KAAK,aAAa,QAAQ,eAAe,eAAe,OAAO,cAAc,cAAc,SAAS;AAIxL,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,MAAM,IAAI,MAAM,QAAQ,IAAI,QAAoB,UAAU,IAAI,UAAU,aAAa,EAAE;AAAA,EAClG;AAKA,MAAI,WAAW,IAAI;AACnB,MAAI;AACJ,MAAI;AACF,UAAM,SAAS,OAAO,MAAM,IAAI,MAAM;AACtC,WAAO,EAAE,GAAG,KAAK,QAAQ,aAAa,EAAE;AAAA,EAC1C,SAAS,KAAK;AACZ,gBAAY;AAAA,EACd;AAIA,WAAS,UAAU,GAAG,WAAW,UAAU,WAAW;AACpD,UAAM,eAAe,eAAe,UAAU,SAAS;AACvD,UAAM,SAAS,MAAM,kBAAkB,QAAQ,cAAc,UAAU,SAAS,gBAAgB,KAAK,aAAa,QAAQ,eAAe,eAAe,OAAO,cAAc,cAAc,SAAS;AACpM,QAAI;AACF,YAAM,SAAS,OAAO,MAAM,OAAO,MAAM;AACzC,aAAO,EAAE,GAAG,QAAQ,QAAQ,aAAa,QAAQ;AAAA,IACnD,SAAS,KAAK;AACZ,iBAAW,OAAO;AAClB,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,eAAe,qBAAqB,QAAQ,UAAU,UAAU,OAAO,SAAS;AACtF,QAAM,IAAI;AAAA,IACR,kDAAkD,QAAQ,oBAAoB,YAAY;AAAA,EAC5F;AACF;","names":["text"]}
|
|
1
|
+
{"version":3,"sources":["../src/runners/claude-code.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { z } from \"zod\";\n\nexport interface ClaudeCodeInput<T = unknown> {\n prompt: string;\n model?: string;\n /** Timeout in milliseconds. Default: 300_000 (5 min) */\n timeout?: number;\n /**\n * Maximum allowed stdout size in bytes. Default: 10_485_760 (10 MB).\n * If claude output exceeds this limit the process is killed and the promise rejects.\n */\n maxOutputBytes?: number;\n /**\n * Environment variables passed to the subprocess.\n * Defaults to the full process.env so that the binary can access its auth\n * tokens and config (ANTHROPIC_API_KEY, HOME, etc.).\n * Override if you need to restrict or augment the environment.\n */\n env?: NodeJS.ProcessEnv;\n /**\n * Binary to execute. Default: \"ccs\" (Claude Code Profile & Model Switcher).\n * Use \"claude\" to invoke the Claude CLI directly without profile switching.\n * Using `--print` (not `-p`) avoids the ccs delegation system while\n * preserving the standard `--output-format json` envelope output.\n */\n binary?: string;\n /**\n * Optional Zod schema (requires Zod v4+). When provided:\n * - Its JSON Schema representation is passed via `--json-schema` CLI flag\n * (CLI-level enforcement — Claude physically cannot return non-JSON).\n * - The response is validated with `schema.parse()`.\n * - On failure, an auto-fix retry is sent to `fixModel`.\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n * - Mutually exclusive with `jsonSchema`.\n */\n schema?: z.ZodType<T>;\n /**\n * Model used for auto-fix retries. Default: \"claude-haiku-4-5-20251001\"\n * (cheap and fast, good for JSON correction tasks).\n */\n fixModel?: string;\n /**\n * Maximum number of auto-fix attempts on schema validation failure. Default: 1.\n */\n maxFixes?: number;\n /**\n * Raw JSON Schema for CLI-level structured output enforcement.\n * Adds `--json-schema <schema>` to spawn args.\n * Claude returns structured_output in the envelope — guaranteed JSON.\n * No runtime validation or auto-fix. `result.parsed` is `unknown`.\n * Mutually exclusive with `schema`.\n */\n jsonSchema?: Record<string, unknown>;\n /**\n * Override the default tool list passed via `--tools`.\n * Default: `[\"Read\", \"Grep\", \"Glob\"]` (read-only by design).\n * Pass `[\"Bash\", \"Read\", \"Grep\", \"Glob\"]` to also allow Bash execution.\n */\n tools?: string[];\n /**\n * Restrict Bash commands via `--allowed-tools` flag.\n * Each entry is a pattern like `\"Bash(git log*)\"`.\n * Only meaningful when `tools` includes `\"Bash\"`.\n * When omitted, no `--allowed-tools` flag is added.\n */\n allowedTools?: string[];\n /**\n * List of CCS account names to rotate through on `is_error: true` responses.\n * Each account maps to `CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>`.\n * On `is_error`, the next account in the list is tried automatically.\n * Non-is_error failures (timeouts, non-zero exit, etc.) are thrown immediately.\n * If all accounts return `is_error`, throws with the last error message.\n */\n ccsAccounts?: string[];\n /**\n * Path to an MCP config JSON file.\n * When provided, adds `--mcp-config <path>` to the spawn args so the\n * Claude CLI can load MCP servers (filesystem, supabase, etc.).\n * The caller is responsible for writing the file before calling\n * `runClaudeCode` and deleting it afterwards.\n * If the file does not exist or is not accessible, the Claude CLI\n * will exit with a non-zero code and the promise will reject.\n */\n mcpConfigPath?: string;\n /**\n * Replaces the default system prompt entirely.\n * Adds `--system-prompt <text>` to spawn args.\n * CLAUDE.md is ignored when this is set.\n */\n systemPrompt: string;\n /**\n * Absolute path to the repository directory Claude should work in.\n * Required — without it Claude would inherit the worker CWD, exposing\n * worker source files, env vars, and credentials to the model.\n * Adds `--add-dir <path>` and sets `cwd: addDir` on the spawned process\n * so relative paths (e.g. Read(\"src/foo.ts\")) resolve inside the repo.\n * Throws if empty. If the directory does not exist, the Claude CLI will\n * exit with a non-zero code and the promise will reject.\n */\n addDir: string;\n}\n\n/**\n * The JSON envelope that `claude --output-format json` wraps every response in.\n * Only the fields we care about are typed; the rest are captured in the index signature.\n */\nexport interface ClaudeEnvelope {\n type: string;\n subtype: string;\n /** The actual text response from the model (plain text / raw JSON string) */\n result: string;\n is_error: boolean;\n /**\n * Present when `--json-schema` flag is used.\n * Contains the structured output object — use this instead of `result`.\n */\n structured_output?: unknown;\n [key: string]: unknown;\n}\n\nexport interface ClaudeCodeResult<T = unknown> {\n /** The actual text content of claude's response (extracted from envelope.result) */\n text: string;\n /**\n * Parsed value. Typed as `T` when a schema is provided and validation passes.\n * Without schema: `unknown` (will be `null` when the response is not valid JSON).\n */\n parsed: T;\n /** The full response envelope from `claude --output-format json` */\n envelope: ClaudeEnvelope;\n /** Number of auto-fix retries used. 0 means the first response was valid. */\n fixAttempts: number;\n}\n\n/**\n * Thrown when schema validation fails after all auto-fix attempts are exhausted.\n */\nexport class SchemaValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SchemaValidationError\";\n }\n}\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 10 * 1024 * 1024; // 10 MB\n\n/**\n * Kills a process gracefully: SIGTERM first, SIGKILL after 5 seconds if still alive.\n */\nfunction killGracefully(proc: ReturnType<typeof spawn>): void {\n proc.kill(\"SIGTERM\");\n setTimeout(() => {\n proc.kill(\"SIGKILL\");\n }, 5000).unref();\n}\n\n/** Internal raw result from a single spawn cycle (before schema validation). */\ninterface RawResult {\n text: string;\n parsed: unknown | null;\n envelope: ClaudeEnvelope;\n}\n\n/**\n * Spawns the binary once and collects the JSON envelope result.\n * All validation/retry logic lives in `runClaudeCode`.\n */\nfunction spawnOnce(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string\n): Promise<RawResult> {\n // Use --print (not -p) so that ccs passes args through to claude without\n // triggering its delegation system. Prompt is the final positional argument.\n const toolsList = tools?.length ? tools.join(\",\") : \"Read,Grep,Glob\";\n const args = [\"--print\", \"--bare\", \"--output-format\", \"json\", \"--model\", model, \"--tools\", toolsList];\n if (allowedTools?.length) args.push(\"--allowed-tools\", ...allowedTools);\n if (mcpConfigPath) args.push(\"--mcp-config\", mcpConfigPath);\n args.push(\"--add-dir\", addDir);\n if (systemPrompt) args.push(\"--system-prompt\", systemPrompt);\n if (jsonSchemaStr) {\n args.push(\"--json-schema\", jsonSchemaStr);\n }\n // Prompt is delivered via stdin — avoids OS ARG_MAX limits (~2MB on Linux)\n\n return new Promise((resolve, reject) => {\n const proc = spawn(binary, args, { env, cwd: addDir });\n\n if (!proc.stdout || !proc.stderr || !proc.stdin) {\n reject(new Error(`Failed to spawn ${binary}: stdio streams not available`));\n return;\n }\n\n // Suppress all stdin errors — EPIPE is expected when the process exits before reading\n // all of stdin; other stdin errors are extremely rare and non-fatal (process already spawned).\n proc.stdin.on(\"error\", () => {});\n // If the internal buffer is full (write returns false), wait for drain before closing.\n // This handles extremely large prompts where the OS pipe buffer fills up.\n if (proc.stdin.write(prompt, \"utf8\")) {\n proc.stdin.end();\n } else {\n proc.stdin.once(\"drain\", () => proc.stdin!.end());\n }\n\n // settled prevents double-resolve/reject between timeout and close handlers\n let settled = false;\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let totalStdoutSize = 0;\n\n const timer = setTimeout(() => {\n settled = true;\n killGracefully(proc);\n reject(new Error(`${binary} process timed out after ${timeout}ms`));\n }, timeout);\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n totalStdoutSize += chunk.length;\n if (totalStdoutSize > maxOutputBytes) {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n killGracefully(proc);\n reject(new Error(`${binary} output exceeded ${maxOutputBytes} bytes`));\n return;\n }\n stdoutChunks.push(chunk);\n });\n\n proc.stderr.on(\"data\", (chunk: Buffer) => {\n stderrChunks.push(chunk);\n });\n\n proc.on(\"close\", (code) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n\n const stdout = Buffer.concat(stdoutChunks).toString();\n const stderr = Buffer.concat(stderrChunks).toString();\n\n if (code !== 0) {\n reject(\n new Error(\n `${binary} exited with code ${code}${stderr ? `\\nstderr: ${stderr}` : \"\"}`\n )\n );\n return;\n }\n\n let envelope: ClaudeEnvelope;\n try {\n envelope = JSON.parse(stdout.trim()) as ClaudeEnvelope;\n } catch {\n reject(new Error(`${binary} output is not valid JSON: ${stdout.trim().slice(0, 200)}`));\n return;\n }\n\n if (envelope.is_error) {\n reject(new IsErrorResponse(envelope.result));\n return;\n }\n\n // --json-schema mode: result comes in structured_output, not result field\n if (envelope.structured_output !== undefined) {\n const text = JSON.stringify(envelope.structured_output);\n resolve({ text, parsed: envelope.structured_output, envelope });\n return;\n }\n\n if (typeof envelope.result !== \"string\") {\n reject(new Error(\"Invalid envelope: result field is not a string\"));\n return;\n }\n\n const text = envelope.result;\n\n let parsed: unknown | null = null;\n try {\n parsed = JSON.parse(text);\n } catch {\n // text is not JSON — that's fine\n }\n\n resolve({ text, parsed, envelope });\n });\n\n proc.on(\"error\", (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(new Error(`Failed to spawn ${binary}: ${err.message}`));\n });\n });\n}\n\n/**\n * Thrown internally by spawnOnce when the Claude envelope contains is_error=true.\n * Caught by spawnWithAccounts to distinguish account-level errors from other failures.\n */\nclass IsErrorResponse extends Error {\n constructor(public readonly result: string) {\n super(`returned is_error=true: ${result}`);\n this.name = \"IsErrorResponse\";\n }\n}\n\n/**\n * Calls spawnOnce with optional CCS account rotation.\n * When `accounts` is provided, tries each account in order by setting\n * CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>. Rotates only on is_error=true;\n * any other error (timeout, non-zero exit, ENOENT) is thrown immediately.\n * If all accounts return is_error, throws with the last error message.\n *\n * Implemented as a regular (non-async) function so the no-rotation path\n * returns spawnOnce's promise directly without adding an extra microtask tick.\n */\nfunction spawnWithAccounts(\n binary: string,\n prompt: string,\n model: string,\n timeout: number,\n maxOutputBytes: number,\n env: NodeJS.ProcessEnv,\n accounts: string[] | undefined,\n addDir: string,\n mcpConfigPath?: string,\n jsonSchemaStr?: string,\n tools?: string[],\n allowedTools?: string[],\n systemPrompt?: string\n): Promise<RawResult> {\n // Fast path: return promise directly — no extra microtask overhead\n if (!accounts || accounts.length === 0) {\n return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n }\n\n // Rotation path: async IIFE to iterate through accounts\n return (async () => {\n let lastIsError: IsErrorResponse | undefined;\n for (const account of accounts) {\n const accountEnv: NodeJS.ProcessEnv = {\n ...env,\n CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`,\n };\n try {\n return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n } catch (err) {\n if (err instanceof IsErrorResponse) {\n lastIsError = err;\n continue;\n }\n throw err;\n }\n }\n throw new Error(lastIsError!.result);\n })();\n}\n\n/**\n * Builds the auto-fix prompt sent to the fixModel when schema validation fails.\n * Includes structured ZodError issues (when available) and the original invalid\n * response so the model can self-correct.\n */\nfunction buildFixPrompt(invalidText: string, error: unknown): string {\n let errorMessage: string;\n if (error instanceof z.ZodError) {\n errorMessage = error.issues\n .map((i) => `Path: ${i.path.length ? i.path.join(\".\") : \"(root)\"}, ${i.message}`)\n .join(\"\\n\");\n } else if (error instanceof Error) {\n errorMessage = error.message;\n } else {\n errorMessage = String(error);\n }\n return (\n `The following JSON failed schema validation.\\n\\n` +\n `Errors:\\n${errorMessage}\\n\\n` +\n `Invalid response:\\n${invalidText}\\n\\n` +\n `Output ONLY corrected JSON. No explanation, no markdown.`\n );\n}\n\n/**\n * Runs the configured binary (default: ccs) with --print flag as a subprocess.\n * Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`\n * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).\n * --bare suppresses global CLAUDE.md auto-discovery, hooks, LSP, auto-memory and other\n * side effects — ensuring the agent runs only with the provided systemPrompt.\n *\n * When a `schema` is provided (Zod v4+):\n * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).\n * - Claude returns structured_output in the envelope — guaranteed JSON.\n * - The response is validated; on failure an auto-fix retry is sent to `fixModel`.\n * - `result.fixAttempts` indicates how many retries were used (0 = first response valid).\n * - `result.parsed` is typed as `T` (the schema's inferred type).\n *\n * When `jsonSchema` is provided:\n * - Passed via `--json-schema` CLI flag (hard enforcement, no validation or retry).\n * - `result.parsed` is `unknown`.\n *\n * Without schema: `result.parsed` is `unknown` (may be `null` for plain-text responses).\n *\n * Designed to be used as a plain async function inside a trigger.dev task `run()`.\n */\nexport function runClaudeCode(input: ClaudeCodeInput): Promise<ClaudeCodeResult<unknown>>;\nexport function runClaudeCode<T>(\n input: ClaudeCodeInput<T> & { schema: z.ZodType<T> }\n): Promise<ClaudeCodeResult<T>>;\nexport async function runClaudeCode<T = unknown>(\n input: ClaudeCodeInput<T>\n): Promise<ClaudeCodeResult<T | null>> {\n const {\n prompt,\n model = \"claude-sonnet-4-6\",\n timeout = 300_000,\n maxOutputBytes = DEFAULT_MAX_OUTPUT_BYTES,\n env = process.env,\n binary = \"ccs\",\n schema,\n fixModel = \"claude-haiku-4-5-20251001\",\n maxFixes = 1,\n jsonSchema,\n ccsAccounts,\n mcpConfigPath,\n addDir,\n tools,\n allowedTools,\n systemPrompt,\n } = input;\n\n if (!prompt || prompt.trim().length === 0) {\n throw new Error(\"prompt cannot be empty\");\n }\n\n if (!addDir || addDir.trim().length === 0) {\n throw new Error(\"addDir is required: omitting it exposes the worker CWD to the model\");\n }\n\n if (!binary || binary.trim().length === 0) {\n throw new Error(\"binary cannot be empty\");\n }\n\n if (jsonSchema && schema) {\n throw new Error(\"cannot use jsonSchema with schema\");\n }\n\n if (!systemPrompt || systemPrompt.trim().length === 0) {\n throw new Error(\"systemPrompt cannot be empty\");\n }\n\n if (allowedTools?.length && (!tools || !tools.includes(\"Bash\"))) {\n throw new Error(\"allowedTools requires 'Bash' in tools array\");\n }\n\n // Build jsonSchemaStr from Zod schema or raw jsonSchema — passed as CLI flag, not prompt text\n let jsonSchemaStr: string | undefined;\n if (schema) {\n try {\n jsonSchemaStr = JSON.stringify(z.toJSONSchema(schema));\n } catch (err) {\n throw new Error(\n `Failed to convert Zod schema to JSON Schema (requires Zod v4+): ${String(err)}`\n );\n }\n } else if (jsonSchema) {\n try {\n jsonSchemaStr = JSON.stringify(jsonSchema);\n } catch (err) {\n throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);\n }\n }\n\n const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n\n // No schema — return raw result. parsed may be null for plain-text responses.\n // Cast is safe: overload 1 constrains T = unknown, so T | null = unknown.\n if (!schema) {\n return { text: raw.text, parsed: raw.parsed as T | null, envelope: raw.envelope, fixAttempts: 0 };\n }\n\n // Try to validate the initial response.\n // Note: if raw.parsed is null (plain-text response), schema.parse(null) throws ZodError,\n // which correctly triggers the auto-fix flow.\n let lastText = raw.text;\n let lastError: unknown;\n try {\n const parsed = schema.parse(raw.parsed);\n return { ...raw, parsed, fixAttempts: 0 };\n } catch (err) {\n lastError = err;\n }\n\n // Auto-fix loop: send errors + original output back to fixModel for self-correction.\n // jsonSchemaStr is passed so the fix spawn also uses --json-schema enforcement.\n for (let attempt = 1; attempt <= maxFixes; attempt++) {\n const fixPromptStr = buildFixPrompt(lastText, lastError);\n const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);\n try {\n const parsed = schema.parse(fixRaw.parsed);\n return { ...fixRaw, parsed, fixAttempts: attempt };\n } catch (err) {\n lastText = fixRaw.text;\n lastError = err;\n }\n }\n\n const errorMessage = lastError instanceof Error ? lastError.message : String(lastError);\n throw new SchemaValidationError(\n `SchemaValidationError: validation failed after ${maxFixes} fix attempt(s): ${errorMessage}`\n );\n}\n"],"mappings":"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","names":["text"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atrvd/trigger",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared run-functions for trigger.dev tasks",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ATRVD",
|
|
@@ -30,16 +30,6 @@
|
|
|
30
30
|
"types": "./dist/index.d.ts"
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "tsup",
|
|
35
|
-
"prepare": "tsup",
|
|
36
|
-
"test": "vitest run",
|
|
37
|
-
"test:unit": "vitest run src/**/*.test.ts --exclude src/**/*.{integration,e2e}.test.ts",
|
|
38
|
-
"test:integration": "vitest run src/**/*.integration.test.ts",
|
|
39
|
-
"test:e2e": "CLAUDE_E2E=1 vitest run --testTimeout=120000 src/**/*.e2e.test.ts",
|
|
40
|
-
"test:watch": "vitest",
|
|
41
|
-
"typecheck": "tsc --noEmit"
|
|
42
|
-
},
|
|
43
33
|
"engines": {
|
|
44
34
|
"node": ">=18.0.0"
|
|
45
35
|
},
|
|
@@ -52,5 +42,14 @@
|
|
|
52
42
|
},
|
|
53
43
|
"dependencies": {
|
|
54
44
|
"zod": "^4.3.6"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:unit": "vitest run src/**/*.test.ts --exclude src/**/*.{integration,e2e}.test.ts",
|
|
50
|
+
"test:integration": "vitest run src/**/*.integration.test.ts",
|
|
51
|
+
"test:e2e": "CLAUDE_E2E=1 vitest run --testTimeout=120000 src/**/*.e2e.test.ts",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"typecheck": "tsc --noEmit"
|
|
55
54
|
}
|
|
56
|
-
}
|
|
55
|
+
}
|