@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 +104 -0
- package/cli.js +9 -0
- package/dist/chunk-AVSJQKCD.js +54 -0
- package/dist/chunk-AVSJQKCD.js.map +1 -0
- package/dist/chunk-CGK4TBZD.js +221 -0
- package/dist/chunk-CGK4TBZD.js.map +1 -0
- package/dist/chunk-EN5WJJ2G.js +153 -0
- package/dist/chunk-EN5WJJ2G.js.map +1 -0
- package/dist/chunk-NKMHTQVX.js +60 -0
- package/dist/chunk-NKMHTQVX.js.map +1 -0
- package/dist/chunk-YAZLCEAU.js +123 -0
- package/dist/chunk-YAZLCEAU.js.map +1 -0
- package/dist/chunk-ZUMYGBXZ.js +228 -0
- package/dist/chunk-ZUMYGBXZ.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +84 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-DxAkSUZk.d.ts +97 -0
- package/dist/runtimes/claude.d.ts +26 -0
- package/dist/runtimes/claude.js +8 -0
- package/dist/runtimes/claude.js.map +1 -0
- package/dist/runtimes/codex.d.ts +46 -0
- package/dist/runtimes/codex.js +8 -0
- package/dist/runtimes/codex.js.map +1 -0
- package/dist/runtimes/copilot.d.ts +19 -0
- package/dist/runtimes/copilot.js +8 -0
- package/dist/runtimes/copilot.js.map +1 -0
- package/dist/runtimes/gemini.d.ts +32 -0
- package/dist/runtimes/gemini.js +8 -0
- package/dist/runtimes/gemini.js.map +1 -0
- package/package.json +79 -0
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,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":[]}
|