@nimashoghi/code-agent-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # code-agent-kit
2
+
3
+ Runtime-agnostic toolkit for running coding agents through one shared interface and one CLI.
4
+
5
+ ## Scope
6
+
7
+ This package is intentionally narrow:
8
+
9
+ - One runtime contract for Claude, Codex, Gemini, and Copilot
10
+ - One CLI command for running prompts
11
+ - Optional system prompts
12
+ - Optional text file attachments
13
+ - Optional session resume and event streaming when the selected runtime supports them
14
+
15
+ Everything related to PR automation, GitHub Actions, git workspaces, and lease-based worktrees has been removed.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @nimashoghi/code-agent-kit
21
+ npm install -g @nimashoghi/code-agent-kit
22
+ ```
23
+
24
+ Install any runtime-specific dependencies and CLIs you plan to use:
25
+
26
+ ```bash
27
+ # Claude runtime
28
+ npm install @anthropic-ai/claude-agent-sdk
29
+
30
+ # Gemini runtime expects the local `gemini` CLI on PATH
31
+ # Copilot runtime expects `github-copilot-cli` on PATH
32
+ ```
33
+
34
+ ## CLI
35
+
36
+ ```bash
37
+ code-agent-kit --runtime claude "Fix the failing tests"
38
+ code-agent-kit --runtime codex --system "Run tests before finishing." "Add validation"
39
+ code-agent-kit --runtime gemini --file src/runtime.ts "Summarize this file"
40
+ code-agent-kit --runtime claude --resume session-123 "Continue the last task"
41
+ ```
42
+
43
+ Options:
44
+
45
+ - `--runtime <name>`: `claude`, `codex`, `copilot`, or `gemini`
46
+ - `--directory <path>`: working directory for the agent
47
+ - `--system <text>`: system prompt text
48
+ - `--file <path>`: attach a text file, repeatable
49
+ - `--resume <sessionId>`: resume a previous session when supported
50
+ - `--timeout <ms>`: timeout in milliseconds
51
+
52
+ When you explicitly pass `--runtime`, the CLI propagates that choice to child processes through `CODE_AGENT_KIT_RUNTIME`. Nested invocations of `code-agent-kit` use that value as their default runtime.
53
+
54
+ ## Library Usage
55
+
56
+ ```ts
57
+ import { ClaudeRuntime } from "@nimashoghi/code-agent-kit/claude";
58
+
59
+ const runtime = new ClaudeRuntime({ model: "claude-sonnet-4-20250514" });
60
+
61
+ const result = await runtime.run({
62
+ workingDirectory: "/my/project",
63
+ prompt: "Fix the failing tests",
64
+ systemPrompt: "Run tests before finishing.",
65
+ attachments: [{ path: "src/runtime.ts" }],
66
+ });
67
+
68
+ console.log(result.output);
69
+ ```
70
+
71
+ You can also create runtimes generically:
72
+
73
+ ```ts
74
+ import { createRuntime } from "@nimashoghi/code-agent-kit";
75
+
76
+ const runtime = createRuntime({ name: "codex" });
77
+ ```
78
+
79
+ ## Runtime Contract
80
+
81
+ ```ts
82
+ interface RuntimeRunOptions {
83
+ workingDirectory: string;
84
+ prompt: string;
85
+ systemPrompt?: string;
86
+ attachments?: { path: string; content?: string }[];
87
+ env?: Record<string, string>;
88
+ session?: { mode: "new" } | { mode: "resume"; sessionId: string };
89
+ timeoutMs?: number;
90
+ signal?: AbortSignal;
91
+ onEvent?: (event: RuntimeEvent) => void;
92
+ }
93
+ ```
94
+
95
+ `attachments` are normalized into the user prompt so every runtime can consume the same shape.
96
+
97
+ ## Development
98
+
99
+ ```bash
100
+ npm install
101
+ npx vitest run
102
+ npx tsc --noEmit
103
+ npx tsup
104
+ ```
package/cli.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createCliProgram } from "./dist/cli/index.js";
4
+
5
+ createCliProgram().parseAsync().catch((error) => {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ console.error(message);
8
+ process.exit(1);
9
+ });
@@ -0,0 +1,54 @@
1
+ import {
2
+ assertRuntimeRunOptionsSupported,
3
+ buildRuntimePrompt
4
+ } from "./chunk-YAZLCEAU.js";
5
+
6
+ // src/runtimes/copilot.ts
7
+ var CopilotRuntime = class _CopilotRuntime {
8
+ static runtimeName = "copilot";
9
+ static capabilities = {
10
+ resumeSession: false,
11
+ eventStreaming: false
12
+ };
13
+ name = _CopilotRuntime.runtimeName;
14
+ config;
15
+ constructor(config) {
16
+ this.config = config ?? {};
17
+ }
18
+ async run(options) {
19
+ assertRuntimeRunOptionsSupported(_CopilotRuntime, options, "runtime.run");
20
+ const prompt = applySystemPrompt(
21
+ await buildRuntimePrompt(options),
22
+ options.systemPrompt
23
+ );
24
+ try {
25
+ const { execFile } = await import("child_process");
26
+ const { promisify } = await import("util");
27
+ const execFileAsync = promisify(execFile);
28
+ const args = ["--prompt", prompt];
29
+ if (this.config.model) args.push("--model", this.config.model);
30
+ const { stdout } = await execFileAsync("github-copilot-cli", args, {
31
+ cwd: options.workingDirectory,
32
+ env: { ...process.env, ...options.env },
33
+ timeout: options.timeoutMs,
34
+ signal: options.signal
35
+ });
36
+ return { success: true, output: stdout.trim() };
37
+ } catch (error) {
38
+ const message = error instanceof Error ? error.message : String(error);
39
+ return { success: false, output: "", error: message };
40
+ }
41
+ }
42
+ };
43
+ function applySystemPrompt(prompt, systemPrompt) {
44
+ if (!systemPrompt) {
45
+ return prompt;
46
+ }
47
+ return [`System instructions:
48
+ ${systemPrompt}`, prompt].join("\n\n");
49
+ }
50
+
51
+ export {
52
+ CopilotRuntime
53
+ };
54
+ //# sourceMappingURL=chunk-AVSJQKCD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtimes/copilot.ts"],"sourcesContent":["import {\n assertRuntimeRunOptionsSupported,\n type AgentRuntime,\n type AgentResult,\n buildRuntimePrompt,\n type RuntimeRunOptions,\n} from \"../runtime.js\";\n\nexport interface CopilotRuntimeConfig {\n /** Copilot model to use. */\n model?: string;\n}\n\nexport class CopilotRuntime implements AgentRuntime {\n static readonly runtimeName = \"copilot\";\n static readonly capabilities = {\n resumeSession: false,\n eventStreaming: false,\n } as const;\n readonly name = CopilotRuntime.runtimeName;\n private readonly config: CopilotRuntimeConfig;\n\n constructor(config?: CopilotRuntimeConfig) {\n this.config = config ?? {};\n }\n\n async run(options: RuntimeRunOptions): Promise<AgentResult> {\n assertRuntimeRunOptionsSupported(CopilotRuntime, options, \"runtime.run\");\n const prompt = applySystemPrompt(\n await buildRuntimePrompt(options),\n options.systemPrompt,\n );\n\n try {\n // Use the CLI-based approach as a fallback\n const { execFile } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execFileAsync = promisify(execFile);\n\n const args = [\"--prompt\", prompt];\n if (this.config.model) args.push(\"--model\", this.config.model);\n\n const { stdout } = await execFileAsync(\"github-copilot-cli\", args, {\n cwd: options.workingDirectory,\n env: { ...process.env, ...options.env },\n timeout: options.timeoutMs,\n signal: options.signal,\n });\n\n return { success: true, output: stdout.trim() };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, output: \"\", error: message };\n }\n }\n}\n\nfunction applySystemPrompt(prompt: string, systemPrompt?: string): string {\n if (!systemPrompt) {\n return prompt;\n }\n\n return [`System instructions:\\n${systemPrompt}`, prompt].join(\"\\n\\n\");\n}\n"],"mappings":";;;;;;AAaO,IAAM,iBAAN,MAAM,gBAAuC;AAAA,EAClD,OAAgB,cAAc;AAAA,EAC9B,OAAgB,eAAe;AAAA,IAC7B,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAAA,EACS,OAAO,gBAAe;AAAA,EACd;AAAA,EAEjB,YAAY,QAA+B;AACzC,SAAK,SAAS,UAAU,CAAC;AAAA,EAC3B;AAAA,EAEA,MAAM,IAAI,SAAkD;AAC1D,qCAAiC,iBAAgB,SAAS,aAAa;AACvE,UAAM,SAAS;AAAA,MACb,MAAM,mBAAmB,OAAO;AAAA,MAChC,QAAQ;AAAA,IACV;AAEA,QAAI;AAEF,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,eAAoB;AACtD,YAAM,EAAE,UAAU,IAAI,MAAM,OAAO,MAAW;AAC9C,YAAM,gBAAgB,UAAU,QAAQ;AAExC,YAAM,OAAO,CAAC,YAAY,MAAM;AAChC,UAAI,KAAK,OAAO,MAAO,MAAK,KAAK,WAAW,KAAK,OAAO,KAAK;AAE7D,YAAM,EAAE,OAAO,IAAI,MAAM,cAAc,sBAAsB,MAAM;AAAA,QACjE,KAAK,QAAQ;AAAA,QACb,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,QAAQ,IAAI;AAAA,QACtC,SAAS,QAAQ;AAAA,QACjB,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAED,aAAO,EAAE,SAAS,MAAM,QAAQ,OAAO,KAAK,EAAE;AAAA,IAChD,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,aAAO,EAAE,SAAS,OAAO,QAAQ,IAAI,OAAO,QAAQ;AAAA,IACtD;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,QAAgB,cAA+B;AACxE,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,SAAO,CAAC;AAAA,EAAyB,YAAY,IAAI,MAAM,EAAE,KAAK,MAAM;AACtE;","names":[]}
@@ -0,0 +1,221 @@
1
+ import {
2
+ assertRuntimeRunOptionsSupported,
3
+ buildRuntimePrompt
4
+ } from "./chunk-YAZLCEAU.js";
5
+
6
+ // src/runtimes/codex.ts
7
+ import {
8
+ Codex
9
+ } from "@openai/codex-sdk";
10
+ var CodexRuntime = class _CodexRuntime {
11
+ static runtimeName = "codex";
12
+ static capabilities = {
13
+ resumeSession: true,
14
+ eventStreaming: true
15
+ };
16
+ name = _CodexRuntime.runtimeName;
17
+ config;
18
+ constructor(config) {
19
+ this.config = config ?? {};
20
+ }
21
+ async run(options) {
22
+ assertRuntimeRunOptionsSupported(_CodexRuntime, options, "runtime.run");
23
+ const prompt = applySystemPrompt(
24
+ await buildRuntimePrompt(options),
25
+ options.systemPrompt
26
+ );
27
+ const abortController = new AbortController();
28
+ if (options.signal) {
29
+ options.signal.addEventListener("abort", () => abortController.abort());
30
+ }
31
+ let timeoutId;
32
+ if (options.timeoutMs) {
33
+ timeoutId = setTimeout(() => abortController.abort(), options.timeoutMs);
34
+ }
35
+ try {
36
+ const env = buildCodexEnv(process.env, this.config.env, options.env);
37
+ const codex = new Codex({
38
+ apiKey: this.config.apiKey,
39
+ baseUrl: this.config.baseUrl,
40
+ codexPathOverride: this.config.codexPathOverride,
41
+ config: this.config.config,
42
+ env
43
+ });
44
+ const threadOptions = {
45
+ model: this.config.model,
46
+ sandboxMode: this.config.sandboxMode,
47
+ workingDirectory: options.workingDirectory,
48
+ skipGitRepoCheck: this.config.skipGitRepoCheck,
49
+ modelReasoningEffort: this.config.modelReasoningEffort,
50
+ networkAccessEnabled: this.config.networkAccessEnabled,
51
+ webSearchMode: this.config.webSearchMode,
52
+ webSearchEnabled: this.config.webSearchEnabled,
53
+ approvalPolicy: this.config.approvalPolicy,
54
+ additionalDirectories: this.config.additionalDirectories
55
+ };
56
+ const thread = options.session?.mode === "resume" ? codex.resumeThread(options.session.sessionId, threadOptions) : codex.startThread(threadOptions);
57
+ const { events } = await thread.runStreamed(prompt, {
58
+ signal: abortController.signal
59
+ });
60
+ const result = await collectRunResult(events, options.onEvent);
61
+ const sessionId = thread.id ?? result.sessionId;
62
+ return {
63
+ success: result.error == null,
64
+ output: result.output,
65
+ ...result.error ? { error: result.error } : {},
66
+ ...sessionId ? { sessionId } : {}
67
+ };
68
+ } catch (error) {
69
+ const message = error instanceof Error ? error.message : String(error);
70
+ if (abortController.signal.aborted && options.timeoutMs) {
71
+ return {
72
+ success: false,
73
+ output: "",
74
+ error: `Timeout after ${options.timeoutMs}ms`
75
+ };
76
+ }
77
+ return { success: false, output: "", error: message };
78
+ } finally {
79
+ if (timeoutId) {
80
+ clearTimeout(timeoutId);
81
+ }
82
+ }
83
+ }
84
+ };
85
+ function applySystemPrompt(prompt, systemPrompt) {
86
+ if (!systemPrompt) {
87
+ return prompt;
88
+ }
89
+ return [`System instructions:
90
+ ${systemPrompt}`, prompt].join("\n\n");
91
+ }
92
+ function buildCodexEnv(...sources) {
93
+ const env = {};
94
+ for (const source of sources) {
95
+ if (!source) {
96
+ continue;
97
+ }
98
+ for (const [key, value] of Object.entries(source)) {
99
+ if (value !== void 0) {
100
+ env[key] = value;
101
+ }
102
+ }
103
+ }
104
+ return env;
105
+ }
106
+ async function collectRunResult(events, onEvent) {
107
+ let output = "";
108
+ let error;
109
+ let sessionId;
110
+ for await (const event of events) {
111
+ switch (event.type) {
112
+ case "thread.started":
113
+ sessionId = event.thread_id;
114
+ break;
115
+ case "item.started":
116
+ case "item.updated":
117
+ case "item.completed":
118
+ if (event.type === "item.completed" && event.item.type === "agent_message") {
119
+ output = event.item.text;
120
+ }
121
+ if (event.type === "item.completed" && event.item.type === "error") {
122
+ error = event.item.message;
123
+ }
124
+ if (onEvent) {
125
+ emitThreadItemEvent(event.item, event.type, onEvent);
126
+ }
127
+ break;
128
+ case "turn.failed":
129
+ error = event.error.message;
130
+ onEvent?.({ type: "error", message: event.error.message });
131
+ break;
132
+ case "error":
133
+ error = event.message;
134
+ onEvent?.({ type: "error", message: event.message });
135
+ break;
136
+ case "turn.started":
137
+ case "turn.completed":
138
+ break;
139
+ }
140
+ }
141
+ return { output, error, sessionId };
142
+ }
143
+ function emitThreadItemEvent(item, stage, onEvent) {
144
+ switch (item.type) {
145
+ case "agent_message":
146
+ if (stage === "item.completed") {
147
+ onEvent({ type: "text", content: item.text });
148
+ }
149
+ return;
150
+ case "reasoning":
151
+ onEvent({ type: "thinking", content: item.text });
152
+ return;
153
+ case "command_execution":
154
+ if (stage === "item.completed") {
155
+ onEvent({
156
+ type: "tool_result",
157
+ tool: "command_execution",
158
+ output: item.aggregated_output,
159
+ isError: item.status === "failed"
160
+ });
161
+ return;
162
+ }
163
+ onEvent({
164
+ type: "tool_use",
165
+ tool: "command_execution",
166
+ input: { command: item.command }
167
+ });
168
+ return;
169
+ case "mcp_tool_call":
170
+ if (stage === "item.completed") {
171
+ onEvent({
172
+ type: "tool_result",
173
+ tool: `${item.server}:${item.tool}`,
174
+ output: item.error?.message ?? serializeMcpResult(item.result),
175
+ isError: item.status === "failed"
176
+ });
177
+ return;
178
+ }
179
+ onEvent({
180
+ type: "tool_use",
181
+ tool: `${item.server}:${item.tool}`,
182
+ input: item.arguments
183
+ });
184
+ return;
185
+ case "web_search":
186
+ if (stage !== "item.completed") {
187
+ onEvent({
188
+ type: "tool_use",
189
+ tool: "web_search",
190
+ input: { query: item.query }
191
+ });
192
+ }
193
+ return;
194
+ case "file_change":
195
+ if (stage === "item.completed") {
196
+ onEvent({
197
+ type: "tool_result",
198
+ tool: "file_change",
199
+ output: item.changes.map((change) => `${change.kind}:${change.path}`).join("\n"),
200
+ isError: item.status === "failed"
201
+ });
202
+ }
203
+ return;
204
+ case "todo_list":
205
+ return;
206
+ case "error":
207
+ onEvent({ type: "error", message: item.message });
208
+ return;
209
+ }
210
+ }
211
+ function serializeMcpResult(result) {
212
+ if (!result) {
213
+ return void 0;
214
+ }
215
+ return JSON.stringify(result);
216
+ }
217
+
218
+ export {
219
+ CodexRuntime
220
+ };
221
+ //# sourceMappingURL=chunk-CGK4TBZD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtimes/codex.ts"],"sourcesContent":["import {\n Codex,\n type ApprovalMode,\n type CodexOptions,\n type ModelReasoningEffort,\n type SandboxMode,\n type ThreadEvent,\n type ThreadItem,\n type WebSearchMode,\n} from \"@openai/codex-sdk\";\nimport {\n assertRuntimeRunOptionsSupported,\n type AgentRuntime,\n type AgentResult,\n buildRuntimePrompt,\n type RuntimeRunOptions,\n} from \"../runtime.js\";\n\nexport interface CodexRuntimeConfig {\n /** Codex model to use. */\n model?: string;\n /** Sandbox mode for Codex. */\n sandboxMode?: SandboxMode;\n /** Approval policy. */\n approvalPolicy?: ApprovalMode;\n /** Skip the Git repository check in the working directory. */\n skipGitRepoCheck?: boolean;\n /** Allow network access in workspace-write or danger-full-access modes. */\n networkAccessEnabled?: boolean;\n /** Configure Codex web search behavior. */\n webSearchMode?: WebSearchMode;\n /** Enable or disable web search. */\n webSearchEnabled?: boolean;\n /** Control model reasoning effort. */\n modelReasoningEffort?: ModelReasoningEffort;\n /** Additional directories to expose to Codex. */\n additionalDirectories?: string[];\n /** Override the Codex binary path. */\n codexPathOverride?: string;\n /** Override the Codex base URL. */\n baseUrl?: string;\n /** Override the API key passed into Codex. */\n apiKey?: string;\n /** Base environment for the Codex SDK process. */\n env?: Record<string, string>;\n /** Additional Codex config overrides passed through the SDK. */\n config?: CodexOptions[\"config\"];\n}\n\nexport class CodexRuntime implements AgentRuntime {\n static readonly runtimeName = \"codex\";\n static readonly capabilities = {\n resumeSession: true,\n eventStreaming: true,\n } as const;\n readonly name = CodexRuntime.runtimeName;\n private readonly config: CodexRuntimeConfig;\n\n constructor(config?: CodexRuntimeConfig) {\n this.config = config ?? {};\n }\n\n async run(options: RuntimeRunOptions): Promise<AgentResult> {\n assertRuntimeRunOptionsSupported(CodexRuntime, options, \"runtime.run\");\n const prompt = applySystemPrompt(\n await buildRuntimePrompt(options),\n options.systemPrompt,\n );\n\n const abortController = new AbortController();\n if (options.signal) {\n options.signal.addEventListener(\"abort\", () => abortController.abort());\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n if (options.timeoutMs) {\n timeoutId = setTimeout(() => abortController.abort(), options.timeoutMs);\n }\n\n try {\n const env = buildCodexEnv(process.env, this.config.env, options.env);\n const codex = new Codex({\n apiKey: this.config.apiKey,\n baseUrl: this.config.baseUrl,\n codexPathOverride: this.config.codexPathOverride,\n config: this.config.config,\n env,\n });\n\n const threadOptions = {\n model: this.config.model,\n sandboxMode: this.config.sandboxMode,\n workingDirectory: options.workingDirectory,\n skipGitRepoCheck: this.config.skipGitRepoCheck,\n modelReasoningEffort: this.config.modelReasoningEffort,\n networkAccessEnabled: this.config.networkAccessEnabled,\n webSearchMode: this.config.webSearchMode,\n webSearchEnabled: this.config.webSearchEnabled,\n approvalPolicy: this.config.approvalPolicy,\n additionalDirectories: this.config.additionalDirectories,\n };\n\n const thread =\n options.session?.mode === \"resume\"\n ? codex.resumeThread(options.session.sessionId, threadOptions)\n : codex.startThread(threadOptions);\n\n const { events } = await thread.runStreamed(prompt, {\n signal: abortController.signal,\n });\n\n const result = await collectRunResult(events, options.onEvent);\n const sessionId = thread.id ?? result.sessionId;\n\n return {\n success: result.error == null,\n output: result.output,\n ...(result.error ? { error: result.error } : {}),\n ...(sessionId ? { sessionId } : {}),\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (abortController.signal.aborted && options.timeoutMs) {\n return {\n success: false,\n output: \"\",\n error: `Timeout after ${options.timeoutMs}ms`,\n };\n }\n return { success: false, output: \"\", error: message };\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n}\n\nfunction applySystemPrompt(prompt: string, systemPrompt?: string): string {\n if (!systemPrompt) {\n return prompt;\n }\n\n return [`System instructions:\\n${systemPrompt}`, prompt].join(\"\\n\\n\");\n}\n\nfunction buildCodexEnv(\n ...sources: (Record<string, string> | NodeJS.ProcessEnv | undefined)[]\n): Record<string, string> {\n const env: Record<string, string> = {};\n\n for (const source of sources) {\n if (!source) {\n continue;\n }\n\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined) {\n env[key] = value;\n }\n }\n }\n\n return env;\n}\n\nasync function collectRunResult(\n events: AsyncGenerator<ThreadEvent>,\n onEvent?: RuntimeRunOptions[\"onEvent\"],\n): Promise<{ output: string; error?: string; sessionId?: string }> {\n let output = \"\";\n let error: string | undefined;\n let sessionId: string | undefined;\n\n for await (const event of events) {\n switch (event.type) {\n case \"thread.started\":\n sessionId = event.thread_id;\n break;\n case \"item.started\":\n case \"item.updated\":\n case \"item.completed\":\n if (\n event.type === \"item.completed\" &&\n event.item.type === \"agent_message\"\n ) {\n output = event.item.text;\n }\n if (event.type === \"item.completed\" && event.item.type === \"error\") {\n error = event.item.message;\n }\n if (onEvent) {\n emitThreadItemEvent(event.item, event.type, onEvent);\n }\n break;\n case \"turn.failed\":\n error = event.error.message;\n onEvent?.({ type: \"error\", message: event.error.message });\n break;\n case \"error\":\n error = event.message;\n onEvent?.({ type: \"error\", message: event.message });\n break;\n case \"turn.started\":\n case \"turn.completed\":\n break;\n }\n }\n\n return { output, error, sessionId };\n}\n\nfunction emitThreadItemEvent(\n item: ThreadItem,\n stage: \"item.started\" | \"item.updated\" | \"item.completed\",\n onEvent: NonNullable<RuntimeRunOptions[\"onEvent\"]>,\n): void {\n switch (item.type) {\n case \"agent_message\":\n if (stage === \"item.completed\") {\n onEvent({ type: \"text\", content: item.text });\n }\n return;\n case \"reasoning\":\n onEvent({ type: \"thinking\", content: item.text });\n return;\n case \"command_execution\":\n if (stage === \"item.completed\") {\n onEvent({\n type: \"tool_result\",\n tool: \"command_execution\",\n output: item.aggregated_output,\n isError: item.status === \"failed\",\n });\n return;\n }\n onEvent({\n type: \"tool_use\",\n tool: \"command_execution\",\n input: { command: item.command },\n });\n return;\n case \"mcp_tool_call\":\n if (stage === \"item.completed\") {\n onEvent({\n type: \"tool_result\",\n tool: `${item.server}:${item.tool}`,\n output: item.error?.message ?? serializeMcpResult(item.result),\n isError: item.status === \"failed\",\n });\n return;\n }\n onEvent({\n type: \"tool_use\",\n tool: `${item.server}:${item.tool}`,\n input: item.arguments,\n });\n return;\n case \"web_search\":\n if (stage !== \"item.completed\") {\n onEvent({\n type: \"tool_use\",\n tool: \"web_search\",\n input: { query: item.query },\n });\n }\n return;\n case \"file_change\":\n if (stage === \"item.completed\") {\n onEvent({\n type: \"tool_result\",\n tool: \"file_change\",\n output: item.changes\n .map((change) => `${change.kind}:${change.path}`)\n .join(\"\\n\"),\n isError: item.status === \"failed\",\n });\n }\n return;\n case \"todo_list\":\n return;\n case \"error\":\n onEvent({ type: \"error\", message: item.message });\n return;\n }\n}\n\nfunction serializeMcpResult(\n result:\n | {\n content: unknown;\n structured_content: unknown;\n }\n | undefined,\n): string | undefined {\n if (!result) {\n return undefined;\n }\n\n return JSON.stringify(result);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,153 @@
1
+ import {
2
+ assertRuntimeRunOptionsSupported,
3
+ buildRuntimePrompt
4
+ } from "./chunk-YAZLCEAU.js";
5
+
6
+ // src/runtimes/claude.ts
7
+ import {
8
+ query
9
+ } from "@anthropic-ai/claude-agent-sdk";
10
+ var DEFAULT_SETTING_SOURCES = [
11
+ "user",
12
+ "project",
13
+ "local"
14
+ ];
15
+ var ClaudeRuntime = class _ClaudeRuntime {
16
+ static runtimeName = "claude";
17
+ static capabilities = {
18
+ resumeSession: true,
19
+ eventStreaming: true
20
+ };
21
+ name = _ClaudeRuntime.runtimeName;
22
+ config;
23
+ constructor(config) {
24
+ this.config = config ?? {};
25
+ }
26
+ async run(options) {
27
+ assertRuntimeRunOptionsSupported(_ClaudeRuntime, options, "runtime.run");
28
+ const prompt = await buildRuntimePrompt(options);
29
+ const abortController = new AbortController();
30
+ if (options.signal) {
31
+ options.signal.addEventListener("abort", () => abortController.abort());
32
+ }
33
+ let timeoutId;
34
+ let didTimeout = false;
35
+ if (options.timeoutMs) {
36
+ timeoutId = setTimeout(() => {
37
+ didTimeout = true;
38
+ abortController.abort();
39
+ }, options.timeoutMs);
40
+ }
41
+ let claudeQuery;
42
+ try {
43
+ const permissionMode = this.config.permissionMode ?? "bypassPermissions";
44
+ const queryOptions = {
45
+ abortController,
46
+ cwd: options.workingDirectory,
47
+ env: buildClaudeEnv(process.env, options.env),
48
+ permissionMode,
49
+ settingSources: [
50
+ ...this.config.settingSources ?? DEFAULT_SETTING_SOURCES
51
+ ],
52
+ systemPrompt: {
53
+ type: "preset",
54
+ preset: "claude_code",
55
+ ...options.systemPrompt ? { append: options.systemPrompt } : {}
56
+ },
57
+ model: this.config.model,
58
+ disallowedTools: this.config.disallowedTools ?? ["AskUserQuestion"],
59
+ ...permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}
60
+ };
61
+ if (options.session?.mode === "resume") {
62
+ queryOptions.resume = options.session.sessionId;
63
+ }
64
+ claudeQuery = query({
65
+ prompt,
66
+ options: queryOptions
67
+ });
68
+ const { output, sessionId, error } = await collectClaudeRunResult(
69
+ claudeQuery,
70
+ options.onEvent
71
+ );
72
+ return {
73
+ success: error == null,
74
+ output,
75
+ ...error ? { error } : {},
76
+ ...sessionId ? { sessionId } : {}
77
+ };
78
+ } catch (error) {
79
+ const message = error instanceof Error ? error.message : String(error);
80
+ if (didTimeout) {
81
+ return {
82
+ success: false,
83
+ output: "",
84
+ error: `Timeout after ${options.timeoutMs}ms`
85
+ };
86
+ }
87
+ return { success: false, output: "", error: message };
88
+ } finally {
89
+ if (timeoutId) clearTimeout(timeoutId);
90
+ claudeQuery?.close();
91
+ }
92
+ }
93
+ };
94
+ function buildClaudeEnv(...sources) {
95
+ const env = {};
96
+ for (const source of sources) {
97
+ if (!source) {
98
+ continue;
99
+ }
100
+ for (const [key, value] of Object.entries(source)) {
101
+ if (value !== void 0) {
102
+ env[key] = value;
103
+ }
104
+ }
105
+ }
106
+ return env;
107
+ }
108
+ async function collectClaudeRunResult(messages, onEvent) {
109
+ let output = "";
110
+ let sessionId;
111
+ let error;
112
+ for await (const message of messages) {
113
+ sessionId = message.session_id ?? sessionId;
114
+ if (message.type === "result") {
115
+ output = "result" in message && typeof message.result === "string" ? message.result : output;
116
+ error = getClaudeResultError(message) ?? error;
117
+ continue;
118
+ }
119
+ if (message.type === "assistant" && onEvent) {
120
+ emitAssistantBlocks(message, onEvent);
121
+ }
122
+ }
123
+ return { output, sessionId, error };
124
+ }
125
+ function getClaudeResultError(message) {
126
+ if (!message.is_error) {
127
+ return void 0;
128
+ }
129
+ if ("errors" in message && message.errors.length > 0) {
130
+ return message.errors.join("; ");
131
+ }
132
+ return `Claude run failed with subtype "${message.subtype}"`;
133
+ }
134
+ function emitAssistantBlocks(message, onEvent) {
135
+ for (const block of message.message.content) {
136
+ switch (block.type) {
137
+ case "text":
138
+ onEvent({ type: "text", content: block.text });
139
+ break;
140
+ case "tool_use":
141
+ onEvent({ type: "tool_use", tool: block.name, input: block.input });
142
+ break;
143
+ case "thinking":
144
+ onEvent({ type: "thinking", content: block.thinking });
145
+ break;
146
+ }
147
+ }
148
+ }
149
+
150
+ export {
151
+ ClaudeRuntime
152
+ };
153
+ //# sourceMappingURL=chunk-EN5WJJ2G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtimes/claude.ts"],"sourcesContent":["import {\n query,\n type Options as ClaudeAgentOptions,\n type PermissionMode,\n type SDKAssistantMessage,\n type SDKMessage,\n type SDKResultMessage,\n type SettingSource,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport {\n assertRuntimeRunOptionsSupported,\n type AgentRuntime,\n type AgentResult,\n buildRuntimePrompt,\n type RuntimeRunOptions,\n} from \"../runtime.js\";\n\nconst DEFAULT_SETTING_SOURCES = [\n \"user\",\n \"project\",\n \"local\",\n] as const satisfies readonly SettingSource[];\n\nexport interface ClaudeRuntimeConfig {\n /** Claude model to use (e.g., \"claude-sonnet-4-20250514\"). */\n model?: string;\n /** Permission mode for the Claude Agent SDK. */\n permissionMode?: PermissionMode;\n /** Tools to disallow (e.g., [\"AskUserQuestion\"]). */\n disallowedTools?: string[];\n /** Filesystem settings sources to load for backwards-compatible behavior. */\n settingSources?: SettingSource[];\n}\n\nexport class ClaudeRuntime implements AgentRuntime {\n static readonly runtimeName = \"claude\";\n static readonly capabilities = {\n resumeSession: true,\n eventStreaming: true,\n } as const;\n readonly name = ClaudeRuntime.runtimeName;\n private readonly config: ClaudeRuntimeConfig;\n\n constructor(config?: ClaudeRuntimeConfig) {\n this.config = config ?? {};\n }\n\n async run(options: RuntimeRunOptions): Promise<AgentResult> {\n assertRuntimeRunOptionsSupported(ClaudeRuntime, options, \"runtime.run\");\n const prompt = await buildRuntimePrompt(options);\n\n const abortController = new AbortController();\n if (options.signal) {\n options.signal.addEventListener(\"abort\", () => abortController.abort());\n }\n\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n let didTimeout = false;\n if (options.timeoutMs) {\n timeoutId = setTimeout(() => {\n didTimeout = true;\n abortController.abort();\n }, options.timeoutMs);\n }\n\n let claudeQuery: ReturnType<typeof query> | undefined;\n\n try {\n const permissionMode = this.config.permissionMode ?? \"bypassPermissions\";\n const queryOptions: ClaudeAgentOptions = {\n abortController,\n cwd: options.workingDirectory,\n env: buildClaudeEnv(process.env, options.env),\n permissionMode,\n settingSources: [\n ...(this.config.settingSources ?? DEFAULT_SETTING_SOURCES),\n ],\n systemPrompt: {\n type: \"preset\",\n preset: \"claude_code\",\n ...(options.systemPrompt\n ? { append: options.systemPrompt }\n : {}),\n },\n model: this.config.model,\n disallowedTools: this.config.disallowedTools ?? [\"AskUserQuestion\"],\n ...(permissionMode === \"bypassPermissions\"\n ? { allowDangerouslySkipPermissions: true }\n : {}),\n };\n\n if (options.session?.mode === \"resume\") {\n queryOptions.resume = options.session.sessionId;\n }\n\n claudeQuery = query({\n prompt,\n options: queryOptions,\n });\n\n const { output, sessionId, error } = await collectClaudeRunResult(\n claudeQuery,\n options.onEvent,\n );\n\n return {\n success: error == null,\n output,\n ...(error ? { error } : {}),\n ...(sessionId ? { sessionId } : {}),\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (didTimeout) {\n return {\n success: false,\n output: \"\",\n error: `Timeout after ${options.timeoutMs}ms`,\n };\n }\n return { success: false, output: \"\", error: message };\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n claudeQuery?.close();\n }\n }\n}\n\nfunction buildClaudeEnv(\n ...sources: (Record<string, string> | NodeJS.ProcessEnv | undefined)[]\n): Record<string, string> {\n const env: Record<string, string> = {};\n\n for (const source of sources) {\n if (!source) {\n continue;\n }\n\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined) {\n env[key] = value;\n }\n }\n }\n\n return env;\n}\n\nasync function collectClaudeRunResult(\n messages: AsyncIterable<SDKMessage>,\n onEvent?: RuntimeRunOptions[\"onEvent\"],\n): Promise<{ output: string; sessionId?: string; error?: string }> {\n let output = \"\";\n let sessionId: string | undefined;\n let error: string | undefined;\n\n for await (const message of messages) {\n sessionId = message.session_id ?? sessionId;\n\n if (message.type === \"result\") {\n output =\n \"result\" in message && typeof message.result === \"string\"\n ? message.result\n : output;\n error = getClaudeResultError(message) ?? error;\n continue;\n }\n\n if (message.type === \"assistant\" && onEvent) {\n emitAssistantBlocks(message, onEvent);\n }\n }\n\n return { output, sessionId, error };\n}\n\nfunction getClaudeResultError(message: SDKResultMessage): string | undefined {\n if (!message.is_error) {\n return undefined;\n }\n\n if (\"errors\" in message && message.errors.length > 0) {\n return message.errors.join(\"; \");\n }\n\n return `Claude run failed with subtype \"${message.subtype}\"`;\n}\n\nfunction emitAssistantBlocks(\n message: SDKAssistantMessage,\n onEvent: NonNullable<RuntimeRunOptions[\"onEvent\"]>,\n): void {\n for (const block of message.message.content) {\n switch (block.type) {\n case \"text\":\n onEvent({ type: \"text\", content: block.text });\n break;\n case \"tool_use\":\n onEvent({ type: \"tool_use\", tool: block.name, input: block.input });\n break;\n case \"thinking\":\n onEvent({ type: \"thinking\", content: block.thinking });\n break;\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,60 @@
1
+ import {
2
+ ClaudeRuntime
3
+ } from "./chunk-EN5WJJ2G.js";
4
+ import {
5
+ CodexRuntime
6
+ } from "./chunk-CGK4TBZD.js";
7
+ import {
8
+ CopilotRuntime
9
+ } from "./chunk-AVSJQKCD.js";
10
+ import {
11
+ GeminiRuntime
12
+ } from "./chunk-ZUMYGBXZ.js";
13
+
14
+ // src/runtimes/registry.ts
15
+ var RUNTIME_CLASSES = [
16
+ ClaudeRuntime,
17
+ CodexRuntime,
18
+ CopilotRuntime,
19
+ GeminiRuntime
20
+ ];
21
+ function getAvailableRuntimeClasses(requiredCapabilities = []) {
22
+ return RUNTIME_CLASSES.filter(
23
+ (runtimeClass) => requiredCapabilities.every((feature) => runtimeClass.capabilities[feature])
24
+ );
25
+ }
26
+ function getAvailableRuntimeNames(requiredCapabilities = []) {
27
+ return getAvailableRuntimeClasses(requiredCapabilities).map(
28
+ (runtimeClass) => runtimeClass.runtimeName
29
+ );
30
+ }
31
+ function createRuntime(options) {
32
+ const requiredCapabilities = options?.requiredCapabilities ?? [];
33
+ const availableRuntimeClasses = getAvailableRuntimeClasses(requiredCapabilities);
34
+ if (availableRuntimeClasses.length === 0) {
35
+ throw new Error(
36
+ `No runtimes support the required capabilities: ${requiredCapabilities.join(", ")}`
37
+ );
38
+ }
39
+ const targetName = options?.name ?? options?.defaultRuntime ?? availableRuntimeClasses[0].runtimeName;
40
+ const selectedRuntimeClass = availableRuntimeClasses.find(
41
+ (runtimeClass) => runtimeClass.runtimeName === targetName
42
+ );
43
+ if (!selectedRuntimeClass) {
44
+ throw new Error(
45
+ `Unknown or unsupported runtime: ${targetName}. Available runtimes: ${availableRuntimeClasses.map((runtimeClass) => runtimeClass.runtimeName).join(", ")}`
46
+ );
47
+ }
48
+ return new selectedRuntimeClass();
49
+ }
50
+ function getRuntimeCapabilities(runtime) {
51
+ return runtime.constructor.capabilities;
52
+ }
53
+
54
+ export {
55
+ getAvailableRuntimeClasses,
56
+ getAvailableRuntimeNames,
57
+ createRuntime,
58
+ getRuntimeCapabilities
59
+ };
60
+ //# sourceMappingURL=chunk-NKMHTQVX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtimes/registry.ts"],"sourcesContent":["import type {\n AgentRuntime,\n RuntimeCapabilities,\n RuntimeFeature,\n RuntimeClass,\n} from \"../runtime.js\";\nimport { ClaudeRuntime } from \"./claude.js\";\nimport { CodexRuntime } from \"./codex.js\";\nimport { CopilotRuntime } from \"./copilot.js\";\nimport { GeminiRuntime } from \"./gemini.js\";\n\nexport type RuntimeName = \"claude\" | \"codex\" | \"copilot\" | \"gemini\";\n\ntype RegisteredRuntimeClass = RuntimeClass<AgentRuntime> & {\n readonly runtimeName: RuntimeName;\n};\n\nconst RUNTIME_CLASSES = [\n ClaudeRuntime,\n CodexRuntime,\n CopilotRuntime,\n GeminiRuntime,\n] as const satisfies readonly RegisteredRuntimeClass[];\n\nexport function getAvailableRuntimeClasses(\n requiredCapabilities: readonly RuntimeFeature[] = [],\n): RegisteredRuntimeClass[] {\n return RUNTIME_CLASSES.filter((runtimeClass) =>\n requiredCapabilities.every((feature) => runtimeClass.capabilities[feature]),\n );\n}\n\nexport function getAvailableRuntimeNames(\n requiredCapabilities: readonly RuntimeFeature[] = [],\n): RuntimeName[] {\n return getAvailableRuntimeClasses(requiredCapabilities).map(\n (runtimeClass) => runtimeClass.runtimeName,\n );\n}\n\nexport function createRuntime(options?: {\n name?: string;\n requiredCapabilities?: readonly RuntimeFeature[];\n defaultRuntime?: RuntimeName;\n}): AgentRuntime {\n const requiredCapabilities = options?.requiredCapabilities ?? [];\n const availableRuntimeClasses =\n getAvailableRuntimeClasses(requiredCapabilities);\n\n if (availableRuntimeClasses.length === 0) {\n throw new Error(\n `No runtimes support the required capabilities: ${requiredCapabilities.join(\", \")}`,\n );\n }\n\n const targetName =\n options?.name ??\n options?.defaultRuntime ??\n availableRuntimeClasses[0]!.runtimeName;\n const selectedRuntimeClass = availableRuntimeClasses.find(\n (runtimeClass) => runtimeClass.runtimeName === targetName,\n );\n\n if (!selectedRuntimeClass) {\n throw new Error(\n `Unknown or unsupported runtime: ${targetName}. Available runtimes: ${availableRuntimeClasses\n .map((runtimeClass) => runtimeClass.runtimeName)\n .join(\", \")}`,\n );\n }\n\n return new selectedRuntimeClass();\n}\n\nexport function getRuntimeCapabilities(\n runtime: AgentRuntime,\n): RuntimeCapabilities {\n return (runtime.constructor as RuntimeClass).capabilities;\n}\n"],"mappings":";;;;;;;;;;;;;;AAiBA,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,2BACd,uBAAkD,CAAC,GACzB;AAC1B,SAAO,gBAAgB;AAAA,IAAO,CAAC,iBAC7B,qBAAqB,MAAM,CAAC,YAAY,aAAa,aAAa,OAAO,CAAC;AAAA,EAC5E;AACF;AAEO,SAAS,yBACd,uBAAkD,CAAC,GACpC;AACf,SAAO,2BAA2B,oBAAoB,EAAE;AAAA,IACtD,CAAC,iBAAiB,aAAa;AAAA,EACjC;AACF;AAEO,SAAS,cAAc,SAIb;AACf,QAAM,uBAAuB,SAAS,wBAAwB,CAAC;AAC/D,QAAM,0BACJ,2BAA2B,oBAAoB;AAEjD,MAAI,wBAAwB,WAAW,GAAG;AACxC,UAAM,IAAI;AAAA,MACR,kDAAkD,qBAAqB,KAAK,IAAI,CAAC;AAAA,IACnF;AAAA,EACF;AAEA,QAAM,aACJ,SAAS,QACT,SAAS,kBACT,wBAAwB,CAAC,EAAG;AAC9B,QAAM,uBAAuB,wBAAwB;AAAA,IACnD,CAAC,iBAAiB,aAAa,gBAAgB;AAAA,EACjD;AAEA,MAAI,CAAC,sBAAsB;AACzB,UAAM,IAAI;AAAA,MACR,mCAAmC,UAAU,yBAAyB,wBACnE,IAAI,CAAC,iBAAiB,aAAa,WAAW,EAC9C,KAAK,IAAI,CAAC;AAAA,IACf;AAAA,EACF;AAEA,SAAO,IAAI,qBAAqB;AAClC;AAEO,SAAS,uBACd,SACqB;AACrB,SAAQ,QAAQ,YAA6B;AAC/C;","names":[]}