@atrvd/trigger 0.1.6 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # @atrvd/trigger
2
+
3
+ Shared run-functions for [trigger.dev](https://trigger.dev) tasks. Wraps the Claude Code CLI (`claude --print`) as an async function you can call from any trigger.dev task, with structured output, schema validation, auto-fix retries, and account rotation built in.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @atrvd/trigger
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ ```typescript
14
+ import { runClaudeCode } from "@atrvd/trigger";
15
+
16
+ const result = await runClaudeCode({
17
+ prompt: "Summarize the README in this repo",
18
+ systemPrompt: "You are a technical writer. Be concise.",
19
+ addDir: "/path/to/repo",
20
+ });
21
+
22
+ console.log(result.text); // Claude's plain-text response
23
+ console.log(result.parsed); // JSON-parsed value, or null for plain text
24
+ ```
25
+
26
+ ## Structured output with Zod
27
+
28
+ Pass a Zod v4+ schema to get typed, validated responses. The schema is converted to JSON Schema and enforced at the CLI level (`--json-schema`), then validated again at runtime. If validation fails, an auto-fix retry is sent to a cheap model.
29
+
30
+ ```typescript
31
+ import { z } from "zod";
32
+ import { runClaudeCode } from "@atrvd/trigger";
33
+
34
+ const ReviewSchema = z.object({
35
+ summary: z.string(),
36
+ score: z.number().min(0).max(10),
37
+ issues: z.array(z.string()),
38
+ });
39
+
40
+ const result = await runClaudeCode({
41
+ prompt: "Review this PR diff",
42
+ systemPrompt: "You are a senior code reviewer. Return structured JSON.",
43
+ addDir: "/repo",
44
+ schema: ReviewSchema,
45
+ });
46
+
47
+ // result.parsed is typed as { summary: string; score: number; issues: string[] }
48
+ console.log(result.parsed.score);
49
+ console.log(result.fixAttempts); // 0 = first response was valid
50
+ ```
51
+
52
+ ## Raw JSON Schema (no validation)
53
+
54
+ For CLI-level enforcement without runtime validation or auto-fix:
55
+
56
+ ```typescript
57
+ const result = await runClaudeCode({
58
+ prompt: "Return the config",
59
+ systemPrompt: "Return raw JSON only.",
60
+ addDir: "/repo",
61
+ jsonSchema: {
62
+ type: "object",
63
+ properties: { name: { type: "string" }, version: { type: "number" } },
64
+ },
65
+ });
66
+
67
+ // result.parsed is `unknown` — no runtime validation
68
+ ```
69
+
70
+ > `schema` and `jsonSchema` are mutually exclusive.
71
+
72
+ ## API
73
+
74
+ ### `runClaudeCode(input: ClaudeCodeInput<T>): Promise<ClaudeCodeResult<T>>`
75
+
76
+ Spawns the Claude CLI as a subprocess and returns the parsed response.
77
+
78
+ ### `ClaudeCodeInput`
79
+
80
+ | Field | Type | Default | Description |
81
+ |-------|------|---------|-------------|
82
+ | `prompt` | `string` | *required* | The prompt sent to Claude (delivered via stdin). |
83
+ | `addDir` | `string` | *required* | Absolute path to the repo directory. Sets `--add-dir` and `cwd`. |
84
+ | `model` | `string` | `"claude-sonnet-4-6"` | Model ID passed to `--model`. |
85
+ | `timeout` | `number` | `300_000` | Timeout in milliseconds. Process is killed on expiry. |
86
+ | `maxOutputBytes` | `number` | `10_485_760` | Max stdout size (10 MB). Process killed if exceeded. |
87
+ | `env` | `NodeJS.ProcessEnv` | `process.env` | Environment variables for the subprocess. |
88
+ | `binary` | `string` | `"ccs"` | Binary to execute. Use `"claude"` for direct CLI invocation. |
89
+ | `schema` | `z.ZodType<T>` | — | Zod v4+ schema. Enables CLI enforcement + runtime validation + auto-fix. Mutually exclusive with `jsonSchema`. |
90
+ | `jsonSchema` | `Record<string, unknown>` | — | Raw JSON Schema for CLI enforcement only. No runtime validation. Mutually exclusive with `schema`. |
91
+ | `fixModel` | `string` | `"claude-haiku-4-5-20251001"` | Model for auto-fix retries on schema validation failure. |
92
+ | `maxFixes` | `number` | `1` | Max auto-fix attempts. |
93
+ | `tools` | `string[]` | `["Read", "Grep", "Glob"]` | Tool list passed via `--tools`. Empty array falls back to default. Read-only by default. |
94
+ | `allowedTools` | `string[]` | — | Restrict Bash commands via `--allowed-tools`. E.g. `["Bash(git log*)"]`. Requires `"Bash"` in `tools`. |
95
+ | `mcpConfigPath` | `string` | — | Path to MCP config JSON. Adds `--mcp-config`. |
96
+ | `ccsAccounts` | `string[]` | — | CCS account names for rotation on `is_error` responses. |
97
+ | `systemPrompt` | `string` | *required* | System instructions for the agent (`--system-prompt`). Always combined with `--bare` — global CLAUDE.md and all side effects are suppressed. |
98
+
99
+ ### `ClaudeCodeResult<T>`
100
+
101
+ | Field | Type | Description |
102
+ |-------|------|-------------|
103
+ | `text` | `string` | The raw text content from Claude's response. |
104
+ | `parsed` | `T \| null` | Typed value when schema is provided; `null` for plain-text responses. |
105
+ | `envelope` | `ClaudeEnvelope` | The full JSON envelope from `claude --output-format json`. |
106
+ | `fixAttempts` | `number` | Number of auto-fix retries used. `0` = first response was valid. |
107
+
108
+ ## System prompt
109
+
110
+ `systemPrompt` is required. Every invocation runs with `--bare` which disables global CLAUDE.md auto-discovery, hooks, LSP, and auto-memory. Your `systemPrompt` is the only system instruction Claude receives — full, isolated control over agent behavior per task.
111
+
112
+ ```typescript
113
+ await runClaudeCode({
114
+ prompt: "Analyze this code for security issues",
115
+ systemPrompt: "You are a security auditor. Only report vulnerabilities. Respond in JSON.",
116
+ addDir: "/repo",
117
+ });
118
+ ```
119
+
120
+ ## Error handling
121
+
122
+ ```typescript
123
+ import { runClaudeCode, SchemaValidationError } from "@atrvd/trigger";
124
+
125
+ try {
126
+ const result = await runClaudeCode({
127
+ prompt: "Analyze code",
128
+ systemPrompt: "You are a code reviewer. Return JSON.",
129
+ addDir: "/repo",
130
+ schema: ReviewSchema,
131
+ });
132
+ console.log(result.parsed);
133
+ } catch (err) {
134
+ if (err instanceof SchemaValidationError) {
135
+ // Schema validation failed after all auto-fix attempts
136
+ console.error("Schema validation failed:", err.message);
137
+ } else {
138
+ // Process timeout, non-zero exit code, spawn failure, etc.
139
+ console.error("Execution failed:", err.message);
140
+ }
141
+ }
142
+ ```
143
+
144
+ Possible errors:
145
+ - **Validation**: empty `prompt`, `systemPrompt`, or `addDir`; `allowedTools` without `Bash` in `tools`; `schema` + `jsonSchema` together
146
+ - **Process**: timeout, non-zero exit code, output exceeds `maxOutputBytes`, spawn failure
147
+ - **Schema**: `SchemaValidationError` after exhausting `maxFixes` auto-fix attempts
148
+
149
+ ## Tool permissions
150
+
151
+ By default, Claude gets read-only access: `Read`, `Grep`, `Glob`. To allow code execution:
152
+
153
+ ```typescript
154
+ await runClaudeCode({
155
+ prompt: "Run the tests and report results",
156
+ systemPrompt: "You are a test runner. Report pass/fail counts.",
157
+ addDir: "/repo",
158
+ tools: ["Bash", "Read", "Grep", "Glob"],
159
+ allowedTools: ["Bash(npm test*)", "Bash(git log*)"],
160
+ });
161
+ ```
162
+
163
+ ## MCP servers
164
+
165
+ Pass an MCP config file to give Claude access to external tools:
166
+
167
+ ```typescript
168
+ import { writeFileSync, unlinkSync } from "node:fs";
169
+
170
+ const mcpConfig = {
171
+ mcpServers: {
172
+ filesystem: {
173
+ command: "npx",
174
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"],
175
+ },
176
+ },
177
+ };
178
+
179
+ writeFileSync("/tmp/mcp.json", JSON.stringify(mcpConfig));
180
+
181
+ const result = await runClaudeCode({
182
+ prompt: "List files in /data",
183
+ systemPrompt: "List directory contents.",
184
+ addDir: "/repo",
185
+ mcpConfigPath: "/tmp/mcp.json",
186
+ });
187
+
188
+ unlinkSync("/tmp/mcp.json");
189
+ ```
190
+
191
+ ## Account rotation
192
+
193
+ When using [CCS](https://github.com/nicobailey/ccs) (Claude Code Switcher), rotate through accounts on `is_error` responses:
194
+
195
+ ```typescript
196
+ const result = await runClaudeCode({
197
+ prompt: "Complex analysis task",
198
+ systemPrompt: "Perform deep code analysis.",
199
+ addDir: "/repo",
200
+ ccsAccounts: ["account-a", "account-b", "account-c"],
201
+ });
202
+ ```
203
+
204
+ Each account maps to `CLAUDE_CONFIG_DIR=~/.ccs/instances/<name>`. On `is_error`, the next account is tried automatically. Non-error failures (timeouts, exit codes) are thrown immediately.
205
+
206
+ ## Exports
207
+
208
+ ```typescript
209
+ import { runClaudeCode, SchemaValidationError } from "@atrvd/trigger";
210
+ import type { ClaudeCodeInput, ClaudeCodeResult, ClaudeEnvelope } from "@atrvd/trigger";
211
+ ```
212
+
213
+ ## License
214
+
215
+ MIT
package/dist/index.d.mts CHANGED
@@ -82,6 +82,12 @@ interface ClaudeCodeInput<T = unknown> {
82
82
  * will exit with a non-zero code and the promise will reject.
83
83
  */
84
84
  mcpConfigPath?: string;
85
+ /**
86
+ * Replaces the default system prompt entirely.
87
+ * Adds `--system-prompt <text>` to spawn args.
88
+ * CLAUDE.md is ignored when this is set.
89
+ */
90
+ systemPrompt: string;
85
91
  /**
86
92
  * Absolute path to the repository directory Claude should work in.
87
93
  * Required — without it Claude would inherit the worker CWD, exposing
@@ -123,10 +129,18 @@ interface ClaudeCodeResult<T = unknown> {
123
129
  /** Number of auto-fix retries used. 0 means the first response was valid. */
124
130
  fixAttempts: number;
125
131
  }
132
+ /**
133
+ * Thrown when schema validation fails after all auto-fix attempts are exhausted.
134
+ */
135
+ declare class SchemaValidationError extends Error {
136
+ constructor(message: string);
137
+ }
126
138
  /**
127
139
  * Runs the configured binary (default: ccs) with --print flag as a subprocess.
128
- * Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`
140
+ * Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`
129
141
  * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).
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.
130
144
  *
131
145
  * When a `schema` is provided (Zod v4+):
132
146
  * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).
@@ -148,4 +162,4 @@ declare function runClaudeCode<T>(input: ClaudeCodeInput<T> & {
148
162
  schema: z.ZodType<T>;
149
163
  }): Promise<ClaudeCodeResult<T>>;
150
164
 
151
- export { type ClaudeCodeInput, type ClaudeCodeResult, type ClaudeEnvelope, runClaudeCode };
165
+ export { type ClaudeCodeInput, type ClaudeCodeResult, type ClaudeEnvelope, SchemaValidationError, runClaudeCode };
package/dist/index.d.ts CHANGED
@@ -82,6 +82,12 @@ interface ClaudeCodeInput<T = unknown> {
82
82
  * will exit with a non-zero code and the promise will reject.
83
83
  */
84
84
  mcpConfigPath?: string;
85
+ /**
86
+ * Replaces the default system prompt entirely.
87
+ * Adds `--system-prompt <text>` to spawn args.
88
+ * CLAUDE.md is ignored when this is set.
89
+ */
90
+ systemPrompt: string;
85
91
  /**
86
92
  * Absolute path to the repository directory Claude should work in.
87
93
  * Required — without it Claude would inherit the worker CWD, exposing
@@ -123,10 +129,18 @@ interface ClaudeCodeResult<T = unknown> {
123
129
  /** Number of auto-fix retries used. 0 means the first response was valid. */
124
130
  fixAttempts: number;
125
131
  }
132
+ /**
133
+ * Thrown when schema validation fails after all auto-fix attempts are exhausted.
134
+ */
135
+ declare class SchemaValidationError extends Error {
136
+ constructor(message: string);
137
+ }
126
138
  /**
127
139
  * Runs the configured binary (default: ccs) with --print flag as a subprocess.
128
- * Command: `<binary> --print --output-format json --model <model> [--json-schema <schema>]`
140
+ * Command: `<binary> --print --bare --output-format json --model <model> [--json-schema <schema>]`
129
141
  * The prompt is written to the process stdin to avoid OS ARG_MAX limits (~2MB on Linux).
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.
130
144
  *
131
145
  * When a `schema` is provided (Zod v4+):
132
146
  * - Its JSON Schema is passed via `--json-schema` CLI flag (hard enforcement).
@@ -148,4 +162,4 @@ declare function runClaudeCode<T>(input: ClaudeCodeInput<T> & {
148
162
  schema: z.ZodType<T>;
149
163
  }): Promise<ClaudeCodeResult<T>>;
150
164
 
151
- export { type ClaudeCodeInput, type ClaudeCodeResult, type ClaudeEnvelope, runClaudeCode };
165
+ export { type ClaudeCodeInput, type ClaudeCodeResult, type ClaudeEnvelope, SchemaValidationError, runClaudeCode };
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ SchemaValidationError: () => SchemaValidationError,
23
24
  runClaudeCode: () => runClaudeCode
24
25
  });
25
26
  module.exports = __toCommonJS(index_exports);
@@ -41,12 +42,13 @@ function killGracefully(proc) {
41
42
  proc.kill("SIGKILL");
42
43
  }, 5e3).unref();
43
44
  }
44
- function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools) {
45
+ function spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
45
46
  const toolsList = tools?.length ? tools.join(",") : "Read,Grep,Glob";
46
- const args = ["--print", "--output-format", "json", "--model", model, "--tools", toolsList];
47
+ const args = ["--print", "--bare", "--output-format", "json", "--model", model, "--tools", toolsList];
47
48
  if (allowedTools?.length) args.push("--allowed-tools", ...allowedTools);
48
49
  if (mcpConfigPath) args.push("--mcp-config", mcpConfigPath);
49
50
  args.push("--add-dir", addDir);
51
+ if (systemPrompt) args.push("--system-prompt", systemPrompt);
50
52
  if (jsonSchemaStr) {
51
53
  args.push("--json-schema", jsonSchemaStr);
52
54
  }
@@ -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) {
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);
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);
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;
@@ -204,7 +206,8 @@ async function runClaudeCode(input) {
204
206
  mcpConfigPath,
205
207
  addDir,
206
208
  tools,
207
- allowedTools
209
+ allowedTools,
210
+ systemPrompt
208
211
  } = input;
209
212
  if (!prompt || prompt.trim().length === 0) {
210
213
  throw new Error("prompt cannot be empty");
@@ -218,6 +221,12 @@ async function runClaudeCode(input) {
218
221
  if (jsonSchema && schema) {
219
222
  throw new Error("cannot use jsonSchema with schema");
220
223
  }
224
+ if (!systemPrompt || systemPrompt.trim().length === 0) {
225
+ throw new Error("systemPrompt cannot be empty");
226
+ }
227
+ if (allowedTools?.length && (!tools || !tools.includes("Bash"))) {
228
+ throw new Error("allowedTools requires 'Bash' in tools array");
229
+ }
221
230
  let jsonSchemaStr;
222
231
  if (schema) {
223
232
  try {
@@ -234,7 +243,7 @@ async function runClaudeCode(input) {
234
243
  throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);
235
244
  }
236
245
  }
237
- const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools);
246
+ const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
238
247
  if (!schema) {
239
248
  return { text: raw.text, parsed: raw.parsed, envelope: raw.envelope, fixAttempts: 0 };
240
249
  }
@@ -248,7 +257,7 @@ async function runClaudeCode(input) {
248
257
  }
249
258
  for (let attempt = 1; attempt <= maxFixes; attempt++) {
250
259
  const fixPromptStr = buildFixPrompt(lastText, lastError);
251
- const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr);
260
+ const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
252
261
  try {
253
262
  const parsed = schema.parse(fixRaw.parsed);
254
263
  return { ...fixRaw, parsed, fixAttempts: attempt };
@@ -264,6 +273,7 @@ async function runClaudeCode(input) {
264
273
  }
265
274
  // Annotate the CommonJS export names for ESM import in node:
266
275
  0 && (module.exports = {
276
+ SchemaValidationError,
267
277
  runClaudeCode
268
278
  });
269
279
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/runners/claude-code.ts"],"sourcesContent":["export { runClaudeCode } 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 * 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): 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 (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): 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);\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);\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 *\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 } = 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 // 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);\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);\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;AAAA;AAAA;AAAA;AAAA;;;ACAA,gCAAsB;AACtB,qBAAwB;AACxB,iBAAkB;AAmIX,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,cACoB;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,eAAe;AACjB,SAAK,KAAK,iBAAiB,aAAa;AAAA,EAC1C;AAGA,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,WAAO,iCAAM,QAAQ,MAAM,EAAE,KAAK,KAAK,OAAO,CAAC;AAErD,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;AAAA,UACE,IAAI;AAAA,YACF,GAAG,MAAM,qBAAqB,IAAI,GAAG,SAAS;AAAA,UAAa,MAAM,KAAK,EAAE;AAAA,UAC1E;AAAA,QACF;AACA;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,cACoB;AAEpB,MAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACtC,WAAO,UAAU,QAAQ,QAAQ,OAAO,SAAS,gBAAgB,KAAK,QAAQ,eAAe,eAAe,OAAO,YAAY;AAAA,EACjI;AAGA,UAAQ,YAAY;AAClB,QAAI;AACJ,eAAW,WAAW,UAAU;AAC9B,YAAM,aAAgC;AAAA,QACpC,GAAG;AAAA,QACH,mBAAmB,OAAG,wBAAQ,CAAC,mBAAmB,OAAO;AAAA,MAC3D;AACA,UAAI;AACF,eAAO,MAAM,UAAU,QAAQ,QAAQ,OAAO,SAAS,gBAAgB,YAAY,QAAQ,eAAe,eAAe,OAAO,YAAY;AAAA,MAC9I,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,aAAE,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;AA0BA,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,EACF,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;AAGA,MAAI;AACJ,MAAI,QAAQ;AACV,QAAI;AACF,sBAAgB,KAAK,UAAU,aAAE,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,YAAY;AAI/J,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,aAAa;AACtJ,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/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,12 +15,13 @@ 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) {
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
+ if (systemPrompt) args.push("--system-prompt", systemPrompt);
24
25
  if (jsonSchemaStr) {
25
26
  args.push("--json-schema", jsonSchemaStr);
26
27
  }
@@ -119,9 +120,9 @@ var IsErrorResponse = class extends Error {
119
120
  this.name = "IsErrorResponse";
120
121
  }
121
122
  };
122
- function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools) {
123
+ function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, accounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt) {
123
124
  if (!accounts || accounts.length === 0) {
124
- return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools);
125
+ return spawnOnce(binary, prompt, model, timeout, maxOutputBytes, env, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
125
126
  }
126
127
  return (async () => {
127
128
  let lastIsError;
@@ -131,7 +132,7 @@ function spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env,
131
132
  CLAUDE_CONFIG_DIR: `${homedir()}/.ccs/instances/${account}`
132
133
  };
133
134
  try {
134
- return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools);
135
+ return await spawnOnce(binary, prompt, model, timeout, maxOutputBytes, accountEnv, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
135
136
  } catch (err) {
136
137
  if (err instanceof IsErrorResponse) {
137
138
  lastIsError = err;
@@ -178,7 +179,8 @@ async function runClaudeCode(input) {
178
179
  mcpConfigPath,
179
180
  addDir,
180
181
  tools,
181
- allowedTools
182
+ allowedTools,
183
+ systemPrompt
182
184
  } = input;
183
185
  if (!prompt || prompt.trim().length === 0) {
184
186
  throw new Error("prompt cannot be empty");
@@ -192,6 +194,12 @@ async function runClaudeCode(input) {
192
194
  if (jsonSchema && schema) {
193
195
  throw new Error("cannot use jsonSchema with schema");
194
196
  }
197
+ if (!systemPrompt || systemPrompt.trim().length === 0) {
198
+ throw new Error("systemPrompt cannot be empty");
199
+ }
200
+ if (allowedTools?.length && (!tools || !tools.includes("Bash"))) {
201
+ throw new Error("allowedTools requires 'Bash' in tools array");
202
+ }
195
203
  let jsonSchemaStr;
196
204
  if (schema) {
197
205
  try {
@@ -208,7 +216,7 @@ async function runClaudeCode(input) {
208
216
  throw new Error(`Failed to serialize jsonSchema to JSON: ${String(err)}`);
209
217
  }
210
218
  }
211
- const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools);
219
+ const raw = await spawnWithAccounts(binary, prompt, model, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
212
220
  if (!schema) {
213
221
  return { text: raw.text, parsed: raw.parsed, envelope: raw.envelope, fixAttempts: 0 };
214
222
  }
@@ -222,7 +230,7 @@ async function runClaudeCode(input) {
222
230
  }
223
231
  for (let attempt = 1; attempt <= maxFixes; attempt++) {
224
232
  const fixPromptStr = buildFixPrompt(lastText, lastError);
225
- const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr);
233
+ const fixRaw = await spawnWithAccounts(binary, fixPromptStr, fixModel, timeout, maxOutputBytes, env, ccsAccounts, addDir, mcpConfigPath, jsonSchemaStr, tools, allowedTools, systemPrompt);
226
234
  try {
227
235
  const parsed = schema.parse(fixRaw.parsed);
228
236
  return { ...fixRaw, parsed, fixAttempts: attempt };
@@ -237,6 +245,7 @@ async function runClaudeCode(input) {
237
245
  );
238
246
  }
239
247
  export {
248
+ SchemaValidationError,
240
249
  runClaudeCode
241
250
  };
242
251
  //# sourceMappingURL=index.mjs.map
@@ -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 * 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): 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 (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): 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);\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);\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 *\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 } = 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 // 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);\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);\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/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": "0.1.6",
3
+ "version": "1.0.1",
4
4
  "description": "Shared run-functions for trigger.dev tasks",
5
5
  "license": "MIT",
6
6
  "author": "ATRVD",
@@ -25,8 +25,8 @@
25
25
  ],
26
26
  "exports": {
27
27
  ".": {
28
- "import": "./dist/index.js",
29
- "require": "./dist/index.cjs",
28
+ "import": "./dist/index.mjs",
29
+ "require": "./dist/index.js",
30
30
  "types": "./dist/index.d.ts"
31
31
  }
32
32
  },