@sandagent/runner-cli 0.1.2 → 0.2.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 +39 -4
- package/dist/__tests__/runner-cli.integration.test.d.ts +6 -0
- package/dist/__tests__/runner-cli.integration.test.d.ts.map +1 -0
- package/dist/__tests__/runner-cli.integration.test.js +76 -0
- package/dist/__tests__/runner-cli.integration.test.js.map +1 -0
- package/dist/__tests__/runner.test.js +7 -3
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/bundle.mjs +334 -198
- package/dist/cli.js +14 -0
- package/dist/cli.js.map +1 -1
- package/dist/runner.d.ts +2 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +31 -14
- package/dist/runner.js.map +1 -1
- package/package.json +19 -2
package/README.md
CHANGED
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
# @sandagent/runner-cli
|
|
2
2
|
|
|
3
|
-
SandAgent Runner CLI - A command-line interface for running AI agents
|
|
3
|
+
SandAgent Runner CLI - A **lightweight, local** command-line interface for running AI agents in your terminal.
|
|
4
4
|
|
|
5
|
-
Like gemini-cli
|
|
5
|
+
Like gemini-cli, claude-code, or codex-cli, this tool runs **directly on your local filesystem** and streams AI SDK UI messages to stdout.
|
|
6
|
+
|
|
7
|
+
## 🎯 Key Features
|
|
8
|
+
|
|
9
|
+
- 🔌 **Choose Different Runners**: Switch between Claude, Codex, Copilot with `--runner` flag
|
|
10
|
+
- 🚀 **Local Execution**: Runs directly on your filesystem, no sandbox required
|
|
11
|
+
- 💨 **Lightweight**: No manager dependency, minimal overhead
|
|
12
|
+
- 📡 **Streaming**: Real-time AI SDK UI streaming
|
|
13
|
+
|
|
14
|
+
## 📐 Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
runner-cli → runner-* (direct, NO dependencies on manager or sandbox)
|
|
18
|
+
├─ runner-claude ✅
|
|
19
|
+
├─ runner-codex 🚧
|
|
20
|
+
└─ runner-copilot 🚧
|
|
21
|
+
|
|
22
|
+
Dependencies:
|
|
23
|
+
✅ @sandagent/runner-claude (runtime)
|
|
24
|
+
❌ NO @sandagent/manager
|
|
25
|
+
❌ NO @sandagent/sandbox-*
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Difference from manager-cli:**
|
|
29
|
+
- `runner-cli`: Local filesystem, no isolation, lightweight, direct runner usage
|
|
30
|
+
- `manager-cli`: Sandboxed execution, uses manager + sandbox adapters + runner
|
|
6
31
|
|
|
7
32
|
## Installation
|
|
8
33
|
|
|
@@ -19,17 +44,27 @@ sandagent run [options] -- "<user input>"
|
|
|
19
44
|
### Basic Examples
|
|
20
45
|
|
|
21
46
|
```bash
|
|
22
|
-
#
|
|
47
|
+
# Using Claude (default)
|
|
23
48
|
sandagent run -- "Create a hello world script"
|
|
24
49
|
|
|
50
|
+
# Explicitly choose Claude
|
|
51
|
+
sandagent run --runner claude -- "Create a hello world script"
|
|
52
|
+
|
|
53
|
+
# Using Codex (when implemented)
|
|
54
|
+
sandagent run --runner codex -- "Build a REST API with Express"
|
|
55
|
+
|
|
56
|
+
# Using GitHub Copilot (when implemented)
|
|
57
|
+
sandagent run --runner copilot -- "Refactor this code"
|
|
58
|
+
|
|
25
59
|
# With custom system prompt
|
|
26
|
-
sandagent run --system-prompt "You are a coding assistant" -- "Build a REST API with Express"
|
|
60
|
+
sandagent run --runner claude --system-prompt "You are a coding assistant" -- "Build a REST API with Express"
|
|
27
61
|
```
|
|
28
62
|
|
|
29
63
|
## Options
|
|
30
64
|
|
|
31
65
|
| Option | Short | Description | Default |
|
|
32
66
|
|--------|-------|-------------|---------|
|
|
67
|
+
| `--runner <runner>` | `-r` | Runner to use: `claude`, `codex`, `copilot` | `claude` |
|
|
33
68
|
| `--model <model>` | `-m` | Model to use | `claude-sonnet-4-20250514` |
|
|
34
69
|
| `--cwd <path>` | `-c` | Working directory | Current directory |
|
|
35
70
|
| `--system-prompt <prompt>` | `-s` | Custom system prompt | - |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-cli.integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/runner-cli.integration.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for runner-cli
|
|
3
|
+
* Tests actual process execution
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { describe, expect, it } from "vitest";
|
|
8
|
+
// Get CLI path - works in both compiled and source context
|
|
9
|
+
const CLI_PATH = join(process.cwd(), "dist/bundle.mjs");
|
|
10
|
+
describe("runner-cli Integration Tests", () => {
|
|
11
|
+
const TIMEOUT = 10000;
|
|
12
|
+
it("should display help message", async () => {
|
|
13
|
+
const output = await runCLI(["--help"]);
|
|
14
|
+
expect(output.stdout).toContain("SandAgent Runner CLI");
|
|
15
|
+
expect(output.stdout).toContain("--runner");
|
|
16
|
+
expect(output.stdout).toContain("--model");
|
|
17
|
+
expect(output.exitCode).toBe(0);
|
|
18
|
+
}, TIMEOUT);
|
|
19
|
+
it("should show error when no user input provided", async () => {
|
|
20
|
+
const output = await runCLI(["run"]);
|
|
21
|
+
expect(output.stderr).toContain("User input is required");
|
|
22
|
+
expect(output.exitCode).toBe(1);
|
|
23
|
+
}, TIMEOUT);
|
|
24
|
+
it("should show error for invalid runner", async () => {
|
|
25
|
+
const output = await runCLI([
|
|
26
|
+
"run",
|
|
27
|
+
"--runner",
|
|
28
|
+
"invalid",
|
|
29
|
+
"--",
|
|
30
|
+
"test task",
|
|
31
|
+
]);
|
|
32
|
+
expect(output.stderr).toContain("must be one of");
|
|
33
|
+
expect(output.exitCode).toBe(1);
|
|
34
|
+
}, TIMEOUT);
|
|
35
|
+
it("should accept claude runner option", async () => {
|
|
36
|
+
// This will fail without API key, but should parse arguments correctly
|
|
37
|
+
const output = await runCLI(["run", "--runner", "claude", "--", "echo hello"], {
|
|
38
|
+
env: { ...process.env, ANTHROPIC_API_KEY: "" },
|
|
39
|
+
});
|
|
40
|
+
// Should fail due to missing API key, not argument parsing
|
|
41
|
+
expect(output.stderr).toContain("ANTHROPIC_API_KEY");
|
|
42
|
+
}, TIMEOUT);
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Helper to run CLI and capture output
|
|
46
|
+
*/
|
|
47
|
+
function runCLI(args, options = {}) {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const proc = spawn("node", [CLI_PATH, ...args], {
|
|
50
|
+
env: options.env || process.env,
|
|
51
|
+
stdio: "pipe",
|
|
52
|
+
});
|
|
53
|
+
let stdout = "";
|
|
54
|
+
let stderr = "";
|
|
55
|
+
proc.stdout?.on("data", (data) => {
|
|
56
|
+
stdout += data.toString();
|
|
57
|
+
});
|
|
58
|
+
proc.stderr?.on("data", (data) => {
|
|
59
|
+
stderr += data.toString();
|
|
60
|
+
});
|
|
61
|
+
proc.on("close", (code) => {
|
|
62
|
+
resolve({
|
|
63
|
+
stdout,
|
|
64
|
+
stderr,
|
|
65
|
+
exitCode: code || 0,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
proc.on("error", reject);
|
|
69
|
+
// Timeout
|
|
70
|
+
setTimeout(() => {
|
|
71
|
+
proc.kill();
|
|
72
|
+
reject(new Error("Process timed out"));
|
|
73
|
+
}, 15000);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=runner-cli.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner-cli.integration.test.js","sourceRoot":"","sources":["../../src/__tests__/runner-cli.integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,7 @@ describe("runAgent", () => {
|
|
|
27
27
|
});
|
|
28
28
|
it("should create a Claude runner with correct options (with default template)", async () => {
|
|
29
29
|
await runAgent({
|
|
30
|
+
runner: "claude",
|
|
30
31
|
model: "claude-sonnet-4-20250514",
|
|
31
32
|
userInput: "Hello, world!",
|
|
32
33
|
});
|
|
@@ -40,6 +41,7 @@ describe("runAgent", () => {
|
|
|
40
41
|
});
|
|
41
42
|
it("should pass optional parameters to runner (overriding template)", async () => {
|
|
42
43
|
await runAgent({
|
|
44
|
+
runner: "claude",
|
|
43
45
|
model: "claude-sonnet-4-20250514",
|
|
44
46
|
userInput: "Hello, world!",
|
|
45
47
|
systemPrompt: "You are a helpful assistant",
|
|
@@ -47,15 +49,16 @@ describe("runAgent", () => {
|
|
|
47
49
|
allowedTools: ["bash", "write_file"],
|
|
48
50
|
});
|
|
49
51
|
// Explicit parameters override template values
|
|
50
|
-
expect(createClaudeRunner).toHaveBeenCalledWith({
|
|
52
|
+
expect(createClaudeRunner).toHaveBeenCalledWith(expect.objectContaining({
|
|
51
53
|
model: "claude-sonnet-4-20250514",
|
|
52
54
|
systemPrompt: "You are a helpful assistant",
|
|
53
55
|
maxTurns: 5,
|
|
54
56
|
allowedTools: ["bash", "write_file"],
|
|
55
|
-
});
|
|
57
|
+
}));
|
|
56
58
|
});
|
|
57
59
|
it("should stream output to stdout without modification", async () => {
|
|
58
60
|
await runAgent({
|
|
61
|
+
runner: "claude",
|
|
59
62
|
model: "claude-sonnet-4-20250514",
|
|
60
63
|
userInput: "Hello, world!",
|
|
61
64
|
});
|
|
@@ -70,10 +73,11 @@ describe("runAgent", () => {
|
|
|
70
73
|
};
|
|
71
74
|
vi.mocked(createClaudeRunner).mockReturnValue(mockRunner);
|
|
72
75
|
await runAgent({
|
|
76
|
+
runner: "claude",
|
|
73
77
|
model: "claude-sonnet-4-20250514",
|
|
74
78
|
userInput: "Create a file",
|
|
75
79
|
});
|
|
76
|
-
expect(mockRunner.run).toHaveBeenCalledWith("Create a file"
|
|
80
|
+
expect(mockRunner.run).toHaveBeenCalledWith("Create a file");
|
|
77
81
|
});
|
|
78
82
|
});
|
|
79
83
|
//# sourceMappingURL=runner.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.test.js","sourceRoot":"","sources":["../../src/__tests__/runner.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEzE,gCAAgC;AAChC,EAAE,CAAC,IAAI,CAAC,0BAA0B,EAAE,GAAG,EAAE,CAAC,CAAC;IACzC,kBAAkB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;QAC1C,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,SAAS,CAAC;YAC7C,MAAM,wBAAwB,CAAC;QACjC,CAAC,CAAC;KACH,CAAC;CACH,CAAC,CAAC,CAAC;AAEJ,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,IAAI,aAA0C,CAAC;IAC/C,IAAI,WAAqB,CAAC;IAE1B,UAAU,CAAC,GAAG,EAAE;QACd,WAAW,GAAG,EAAE,CAAC;QACjB,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACrC,oCAAoC;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,IAAY,EAAE,EAAE;YAC5C,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,aAAa,CAAC;QACrC,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,KAAK,IAAI,EAAE;QAC1F,MAAM,QAAQ,CAAC;YACb,KAAK,EAAE,0BAA0B;YACjC,SAAS,EAAE,eAAe;SAC3B,CAAC,CAAC;QAEH,0DAA0D;QAC1D,MAAM,CAAC,kBAAkB,CAAC,CAAC,gBAAgB,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACxD,uDAAuD;QACvD,uCAAuC;QACvC,MAAM,CACJ,OAAO,QAAQ,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,CACzE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,QAAQ,CAAC;YACb,KAAK,EAAE,0BAA0B;YACjC,SAAS,EAAE,eAAe;YAC1B,YAAY,EAAE,6BAA6B;YAC3C,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC;SACrC,CAAC,CAAC;QAEH,+CAA+C;QAC/C,MAAM,CAAC,kBAAkB,CAAC,CAAC,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.test.js","sourceRoot":"","sources":["../../src/__tests__/runner.test.ts"],"names":[],"mappings":"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"}
|
package/dist/bundle.mjs
CHANGED
|
@@ -3,6 +3,243 @@
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
|
|
6
|
+
// ../../packages/runner-claude/dist/ai-sdk-stream.js
|
|
7
|
+
import { writeFile } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
var UNKNOWN_TOOL_NAME = "unknown-tool";
|
|
10
|
+
function formatDataStream(data) {
|
|
11
|
+
return `data: ${JSON.stringify(data)}
|
|
12
|
+
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
function generateId() {
|
|
16
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
17
|
+
}
|
|
18
|
+
function convertUsageToAISDK(usage) {
|
|
19
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
20
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
21
|
+
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
|
|
22
|
+
const cacheRead = usage.cache_read_input_tokens ?? 0;
|
|
23
|
+
return {
|
|
24
|
+
inputTokens: {
|
|
25
|
+
total: inputTokens + cacheWrite + cacheRead,
|
|
26
|
+
noCache: inputTokens,
|
|
27
|
+
cacheRead,
|
|
28
|
+
cacheWrite
|
|
29
|
+
},
|
|
30
|
+
outputTokens: { total: outputTokens },
|
|
31
|
+
raw: usage
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function mapFinishReason(subtype, isError) {
|
|
35
|
+
if (isError)
|
|
36
|
+
return "error";
|
|
37
|
+
switch (subtype) {
|
|
38
|
+
case "success":
|
|
39
|
+
return "stop";
|
|
40
|
+
case "error_max_turns":
|
|
41
|
+
return "length";
|
|
42
|
+
case "error_during_execution":
|
|
43
|
+
case "error_max_structured_output_retries":
|
|
44
|
+
return "error";
|
|
45
|
+
case void 0:
|
|
46
|
+
return "stop";
|
|
47
|
+
default:
|
|
48
|
+
return "other";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function extractToolUses(content) {
|
|
52
|
+
if (!Array.isArray(content))
|
|
53
|
+
return [];
|
|
54
|
+
return content.filter((item) => typeof item === "object" && item !== null && "type" in item && item.type === "tool_use").map((item) => ({
|
|
55
|
+
id: item.id || generateId(),
|
|
56
|
+
name: item.name || UNKNOWN_TOOL_NAME,
|
|
57
|
+
input: item.input
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
var AISDKStreamConverter = class {
|
|
61
|
+
systemMessage;
|
|
62
|
+
hasEmittedStart = false;
|
|
63
|
+
accumulatedText = "";
|
|
64
|
+
textPartId;
|
|
65
|
+
streamedTextLength = 0;
|
|
66
|
+
// Track text already emitted via stream_events
|
|
67
|
+
hasReceivedStreamEvents = false;
|
|
68
|
+
sessionId;
|
|
69
|
+
partIdMap = /* @__PURE__ */ new Map();
|
|
70
|
+
/**
|
|
71
|
+
* Get the current session ID from the stream
|
|
72
|
+
*/
|
|
73
|
+
get currentSessionId() {
|
|
74
|
+
if (!this.sessionId) {
|
|
75
|
+
throw new Error("Session ID is not set");
|
|
76
|
+
}
|
|
77
|
+
return this.sessionId;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Helper to emit SSE data
|
|
81
|
+
*/
|
|
82
|
+
emit(data) {
|
|
83
|
+
return formatDataStream(data);
|
|
84
|
+
}
|
|
85
|
+
setPartId(index, partId) {
|
|
86
|
+
const partIdKey = `${this.currentSessionId}-${index}`;
|
|
87
|
+
this.partIdMap.set(partIdKey, partId);
|
|
88
|
+
}
|
|
89
|
+
getPartId(index) {
|
|
90
|
+
const partIdKey = `${this.currentSessionId}-${index}`;
|
|
91
|
+
if (this.partIdMap.has(partIdKey)) {
|
|
92
|
+
return this.partIdMap.get(partIdKey) ?? "";
|
|
93
|
+
}
|
|
94
|
+
throw new Error("Part ID not found");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Helper to emit tool call
|
|
98
|
+
*/
|
|
99
|
+
*emitToolCall(message) {
|
|
100
|
+
const event = message.event;
|
|
101
|
+
if (event.type === "content_block_start" && event.content_block.type === "tool_use") {
|
|
102
|
+
const toolCallId = event.content_block.id;
|
|
103
|
+
this.setPartId(event.index, toolCallId);
|
|
104
|
+
yield this.emit({
|
|
105
|
+
type: "tool-input-start",
|
|
106
|
+
toolCallId,
|
|
107
|
+
toolName: event.content_block.name,
|
|
108
|
+
dynamic: true,
|
|
109
|
+
providerExecuted: true
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (event.type === "content_block_delta" && event.delta?.type === "input_json_delta") {
|
|
113
|
+
yield this.emit({
|
|
114
|
+
type: "tool-input-delta",
|
|
115
|
+
toolCallId: this.getPartId(event.index),
|
|
116
|
+
inputTextDelta: event.delta.partial_json
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
*emitTextBlockEvent(event) {
|
|
121
|
+
if (event.type === "content_block_start" && event.content_block.type === "text") {
|
|
122
|
+
const partId = `text_${generateId()}`;
|
|
123
|
+
this.setPartId(event.index, partId);
|
|
124
|
+
yield this.emit({
|
|
125
|
+
type: "text-start",
|
|
126
|
+
id: partId
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (event.type === "content_block_delta" && event.delta?.type === "text_delta") {
|
|
130
|
+
yield this.emit({
|
|
131
|
+
type: "text-delta",
|
|
132
|
+
id: this.getPartId(event.index),
|
|
133
|
+
delta: event.delta.text
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (event.type === "content_block_stop") {
|
|
137
|
+
const partId = this.getPartId(event.index);
|
|
138
|
+
if (partId.startsWith("text_")) {
|
|
139
|
+
yield this.emit({ type: "text-end", id: partId });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Stream SDK messages and convert to AI SDK UI Data Stream format
|
|
145
|
+
*/
|
|
146
|
+
async *stream(messageIterator, options) {
|
|
147
|
+
const debugMessages = [];
|
|
148
|
+
const debugFile = `ai-sdk-stream-debug-${Date.now()}.json`;
|
|
149
|
+
try {
|
|
150
|
+
for await (const message of messageIterator) {
|
|
151
|
+
debugMessages.push(message);
|
|
152
|
+
if (message.type === "system" && message.subtype === "init") {
|
|
153
|
+
this.systemMessage = message;
|
|
154
|
+
this.sessionId = this.systemMessage.session_id;
|
|
155
|
+
}
|
|
156
|
+
if (message.type === "stream_event") {
|
|
157
|
+
const streamEvent = message;
|
|
158
|
+
const event = streamEvent.event;
|
|
159
|
+
if (event.type === "message_start" && !this.hasEmittedStart) {
|
|
160
|
+
this.hasEmittedStart = true;
|
|
161
|
+
yield this.emit({ type: "start", messageId: event.message.id });
|
|
162
|
+
yield this.emit({
|
|
163
|
+
type: "message-metadata",
|
|
164
|
+
messageMetadata: {
|
|
165
|
+
tools: this.systemMessage?.tools,
|
|
166
|
+
model: this.systemMessage?.model,
|
|
167
|
+
sessionId: this.systemMessage?.session_id,
|
|
168
|
+
agents: this.systemMessage?.agents,
|
|
169
|
+
skills: this.systemMessage?.skills
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
yield* this.emitTextBlockEvent(event);
|
|
174
|
+
yield* this.emitToolCall(streamEvent);
|
|
175
|
+
}
|
|
176
|
+
if (message.type === "assistant") {
|
|
177
|
+
const assistantMsg = message;
|
|
178
|
+
const content = assistantMsg.message?.content;
|
|
179
|
+
if (!content)
|
|
180
|
+
continue;
|
|
181
|
+
const tools = extractToolUses(content);
|
|
182
|
+
for (const tool of tools) {
|
|
183
|
+
yield this.emit({
|
|
184
|
+
type: "tool-input-available",
|
|
185
|
+
toolCallId: tool.id,
|
|
186
|
+
toolName: tool.name,
|
|
187
|
+
input: tool.input,
|
|
188
|
+
dynamic: true,
|
|
189
|
+
providerExecuted: true
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (message.type === "user") {
|
|
194
|
+
const userMsg = message;
|
|
195
|
+
const content = userMsg.message?.content;
|
|
196
|
+
for (const part of content) {
|
|
197
|
+
if (part.type === "tool_result") {
|
|
198
|
+
yield this.emit({
|
|
199
|
+
type: "tool-output-available",
|
|
200
|
+
toolCallId: part.tool_use_id,
|
|
201
|
+
output: message.tool_use_result || part.content,
|
|
202
|
+
dynamic: true,
|
|
203
|
+
providerExecuted: true
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (message.type === "result") {
|
|
209
|
+
const resultMsg = message;
|
|
210
|
+
const finishTime = (/* @__PURE__ */ new Date()).toISOString();
|
|
211
|
+
console.error(`[AISDKStream] Processing result message at ${finishTime}`);
|
|
212
|
+
const finishEvent = this.emit({
|
|
213
|
+
type: "finish",
|
|
214
|
+
finishReason: mapFinishReason(resultMsg.subtype, resultMsg.is_error),
|
|
215
|
+
messageMetadata: {
|
|
216
|
+
usage: convertUsageToAISDK(resultMsg.usage ?? {})
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
console.error(`[AISDKStream] Emitting finish event at ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
220
|
+
yield finishEvent;
|
|
221
|
+
console.error(`[AISDKStream] Emitted [DONE] at ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch (error) {
|
|
225
|
+
debugMessages.push(error);
|
|
226
|
+
} finally {
|
|
227
|
+
if (debugMessages.length > 0) {
|
|
228
|
+
writeFile(join(process.cwd(), debugFile), JSON.stringify(debugMessages, null, 2), "utf-8").catch((writeError) => {
|
|
229
|
+
console.error(`[AISDKStream] Failed to write debug file:`, writeError);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
options?.onCleanup?.();
|
|
233
|
+
yield `data: [DONE]
|
|
234
|
+
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
function streamSDKMessagesToAISDKUI(messageIterator, options) {
|
|
240
|
+
return new AISDKStreamConverter().stream(messageIterator, options);
|
|
241
|
+
}
|
|
242
|
+
|
|
6
243
|
// ../../packages/runner-claude/dist/claude-runner.js
|
|
7
244
|
function createCanUseToolCallback(claudeOptions) {
|
|
8
245
|
return async (toolName, input, options) => {
|
|
@@ -43,7 +280,7 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
43
280
|
}
|
|
44
281
|
};
|
|
45
282
|
}
|
|
46
|
-
} catch
|
|
283
|
+
} catch {
|
|
47
284
|
}
|
|
48
285
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
49
286
|
}
|
|
@@ -78,22 +315,19 @@ var OPTIONAL_MODULES = {
|
|
|
78
315
|
};
|
|
79
316
|
function createClaudeRunner(options) {
|
|
80
317
|
return {
|
|
81
|
-
async *run(userInput
|
|
82
|
-
if (signal?.aborted) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
318
|
+
async *run(userInput) {
|
|
85
319
|
const apiKey = process.env.ANTHROPIC_API_KEY || process.env.AWS_BEARER_TOKEN_BEDROCK;
|
|
86
320
|
if (!apiKey) {
|
|
87
321
|
console.error("[SandAgent] Warning: ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK not set. Using mock response.\nTo use the real Claude Agent SDK:\n1. Set ANTHROPIC_API_KEY or AWS_BEARER_TOKEN_BEDROCK environment variable\n2. Install the SDK: npm install @anthropic-ai/claude-agent-sdk");
|
|
88
|
-
yield* runMockAgent(options, userInput, signal);
|
|
322
|
+
yield* runMockAgent(options, userInput, options.abortController?.signal);
|
|
89
323
|
return;
|
|
90
324
|
}
|
|
91
325
|
const sdk = await loadClaudeAgentSDK();
|
|
92
326
|
if (sdk) {
|
|
93
|
-
yield* runWithClaudeAgentSDK(sdk, options, userInput
|
|
327
|
+
yield* runWithClaudeAgentSDK(sdk, options, userInput);
|
|
94
328
|
} else {
|
|
95
329
|
console.error("[SandAgent] Warning: @anthropic-ai/claude-agent-sdk not installed. Using mock response.\nInstall the SDK: npm install @anthropic-ai/claude-agent-sdk");
|
|
96
|
-
yield* runMockAgent(options, userInput, signal);
|
|
330
|
+
yield* runMockAgent(options, userInput, options.abortController?.signal);
|
|
97
331
|
}
|
|
98
332
|
}
|
|
99
333
|
};
|
|
@@ -110,21 +344,21 @@ async function loadClaudeAgentSDK() {
|
|
|
110
344
|
return null;
|
|
111
345
|
}
|
|
112
346
|
}
|
|
113
|
-
async function* runWithClaudeAgentSDK(sdk, options, userInput
|
|
347
|
+
async function* runWithClaudeAgentSDK(sdk, options, userInput) {
|
|
114
348
|
const outputFormat = options.outputFormat || "stream-json";
|
|
115
349
|
switch (outputFormat) {
|
|
116
350
|
case "text":
|
|
117
|
-
yield* runWithTextOutput(sdk, options, userInput
|
|
351
|
+
yield* runWithTextOutput(sdk, options, userInput);
|
|
118
352
|
break;
|
|
119
353
|
case "json":
|
|
120
|
-
yield* runWithJSONOutput(sdk, options, userInput
|
|
354
|
+
yield* runWithJSONOutput(sdk, options, userInput);
|
|
121
355
|
break;
|
|
122
356
|
case "stream-json":
|
|
123
|
-
yield* runWithStreamJSONOutput(sdk, options, userInput
|
|
357
|
+
yield* runWithStreamJSONOutput(sdk, options, userInput);
|
|
124
358
|
break;
|
|
125
359
|
// case "stream":
|
|
126
360
|
default:
|
|
127
|
-
yield* runWithAISDKUIOutput(sdk, options, userInput
|
|
361
|
+
yield* runWithAISDKUIOutput(sdk, options, userInput);
|
|
128
362
|
break;
|
|
129
363
|
}
|
|
130
364
|
}
|
|
@@ -133,7 +367,12 @@ function createSDKOptions(options) {
|
|
|
133
367
|
model: options.model,
|
|
134
368
|
systemPrompt: options.systemPrompt,
|
|
135
369
|
maxTurns: options.maxTurns,
|
|
136
|
-
allowedTools: [
|
|
370
|
+
allowedTools: [
|
|
371
|
+
...options.allowedTools ?? [],
|
|
372
|
+
"Skill",
|
|
373
|
+
"WebSearch",
|
|
374
|
+
"WebFetch"
|
|
375
|
+
],
|
|
137
376
|
cwd: options.cwd,
|
|
138
377
|
env: options.env,
|
|
139
378
|
resume: options.resume,
|
|
@@ -141,13 +380,16 @@ function createSDKOptions(options) {
|
|
|
141
380
|
canUseTool: createCanUseToolCallback(options),
|
|
142
381
|
// Bypass all permission checks for automated execution
|
|
143
382
|
permissionMode: "bypassPermissions",
|
|
144
|
-
allowDangerouslySkipPermissions: true
|
|
383
|
+
allowDangerouslySkipPermissions: true,
|
|
384
|
+
// Enable partial messages for streaming
|
|
385
|
+
includePartialMessages: options.includePartialMessages
|
|
145
386
|
};
|
|
146
387
|
}
|
|
147
388
|
function setupAbortHandler(queryIterator, signal) {
|
|
148
389
|
const abortHandler = async () => {
|
|
149
|
-
console.error("[ClaudeRunner]
|
|
390
|
+
console.error("[ClaudeRunner] Abort signal received, will call query.interrupt()...");
|
|
150
391
|
await queryIterator.interrupt();
|
|
392
|
+
console.error("[ClaudeRunner] query.interrupt() completed");
|
|
151
393
|
};
|
|
152
394
|
if (signal) {
|
|
153
395
|
console.error("[ClaudeRunner] Signal provided, adding abort listener");
|
|
@@ -163,7 +405,7 @@ function setupAbortHandler(queryIterator, signal) {
|
|
|
163
405
|
async function* runWithTextOutput(sdk, options, userInput, signal) {
|
|
164
406
|
const sdkOptions = createSDKOptions(options);
|
|
165
407
|
const queryIterator = sdk.query({ prompt: userInput, options: sdkOptions });
|
|
166
|
-
const abortHandler = setupAbortHandler(queryIterator, signal);
|
|
408
|
+
const abortHandler = setupAbortHandler(queryIterator, options.abortController?.signal);
|
|
167
409
|
try {
|
|
168
410
|
let resultText = "";
|
|
169
411
|
for await (const message of queryIterator) {
|
|
@@ -215,170 +457,14 @@ async function* runWithStreamJSONOutput(sdk, options, userInput, signal) {
|
|
|
215
457
|
}
|
|
216
458
|
}
|
|
217
459
|
}
|
|
218
|
-
async function* runWithAISDKUIOutput(sdk, options, userInput
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
460
|
+
async function* runWithAISDKUIOutput(sdk, options, userInput) {
|
|
461
|
+
const sdkOptions = createSDKOptions({
|
|
462
|
+
...options,
|
|
463
|
+
includePartialMessages: true
|
|
464
|
+
});
|
|
223
465
|
const queryIterator = sdk.query({ prompt: userInput, options: sdkOptions });
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
for await (const message of queryIterator) {
|
|
227
|
-
if (message.type === "system" && message.subtype === "init") {
|
|
228
|
-
systemMessage = message;
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
if (message.type === "assistant" && !messageId && systemMessage) {
|
|
232
|
-
messageId = message.message.id;
|
|
233
|
-
yield formatDataStream({
|
|
234
|
-
type: "start",
|
|
235
|
-
messageId
|
|
236
|
-
});
|
|
237
|
-
yield formatDataStream({
|
|
238
|
-
type: "message-metadata",
|
|
239
|
-
messageMetadata: {
|
|
240
|
-
tools: systemMessage.tools,
|
|
241
|
-
model: systemMessage.model,
|
|
242
|
-
sessionId: systemMessage.session_id
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
const chunks = convertSDKMessageToAISDKUI(message);
|
|
247
|
-
for (const chunk of chunks) {
|
|
248
|
-
yield chunk;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} catch (error) {
|
|
252
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
253
|
-
console.error("[ClaudeRunner] Error:", errorMessage);
|
|
254
|
-
yield formatDataStream({ type: "error", errorText: errorMessage });
|
|
255
|
-
yield formatDataStream({
|
|
256
|
-
type: "finish",
|
|
257
|
-
finishReason: "error",
|
|
258
|
-
usage: {
|
|
259
|
-
promptTokens: usage.inputTokens,
|
|
260
|
-
completionTokens: usage.outputTokens
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
} finally {
|
|
264
|
-
if (signal) {
|
|
265
|
-
signal.removeEventListener("abort", abortHandler);
|
|
266
|
-
}
|
|
267
|
-
yield `data: [DONE]
|
|
268
|
-
|
|
269
|
-
`;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
function convertSDKMessageToAISDKUI(message) {
|
|
273
|
-
const chunks = [];
|
|
274
|
-
switch (message.type) {
|
|
275
|
-
case "assistant": {
|
|
276
|
-
const assistantMsg = message;
|
|
277
|
-
if (assistantMsg.error) {
|
|
278
|
-
const errorDetail = message.message.content.map((c) => c.text).join("\n");
|
|
279
|
-
chunks.push(formatDataStream({
|
|
280
|
-
type: "error",
|
|
281
|
-
errorText: `${assistantMsg.error}: ${errorDetail}`
|
|
282
|
-
}));
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
if (assistantMsg.message) {
|
|
286
|
-
if (typeof assistantMsg.message === "string") {
|
|
287
|
-
const textId = generateId();
|
|
288
|
-
chunks.push(formatDataStream({ type: "text-start", id: textId }));
|
|
289
|
-
chunks.push(formatDataStream({
|
|
290
|
-
type: "text-delta",
|
|
291
|
-
id: textId,
|
|
292
|
-
delta: assistantMsg.message
|
|
293
|
-
}));
|
|
294
|
-
chunks.push(formatDataStream({ type: "text-end", id: textId }));
|
|
295
|
-
} else if (assistantMsg.message.content && Array.isArray(assistantMsg.message.content)) {
|
|
296
|
-
for (const block of assistantMsg.message.content) {
|
|
297
|
-
if (block.type === "text" && block.text) {
|
|
298
|
-
const textId = generateId();
|
|
299
|
-
chunks.push(formatDataStream({ type: "text-start", id: textId }));
|
|
300
|
-
chunks.push(formatDataStream({
|
|
301
|
-
type: "text-delta",
|
|
302
|
-
id: textId,
|
|
303
|
-
delta: block.text
|
|
304
|
-
}));
|
|
305
|
-
chunks.push(formatDataStream({ type: "text-end", id: textId }));
|
|
306
|
-
} else if (block.type === "tool_use") {
|
|
307
|
-
const toolCallId = block.id || generateId();
|
|
308
|
-
chunks.push(formatDataStream({
|
|
309
|
-
type: "tool-input-start",
|
|
310
|
-
toolCallId,
|
|
311
|
-
toolName: block.name,
|
|
312
|
-
dynamic: true
|
|
313
|
-
}));
|
|
314
|
-
if (block.input) {
|
|
315
|
-
chunks.push(formatDataStream({
|
|
316
|
-
type: "tool-input-available",
|
|
317
|
-
toolCallId,
|
|
318
|
-
toolName: block.name,
|
|
319
|
-
dynamic: true,
|
|
320
|
-
input: block.input
|
|
321
|
-
}));
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
case "result": {
|
|
330
|
-
const resultMsg = message;
|
|
331
|
-
chunks.push(formatDataStream({
|
|
332
|
-
type: "finish",
|
|
333
|
-
finishReason: resultMsg.is_error ? "error" : "stop",
|
|
334
|
-
messageMetadata: {
|
|
335
|
-
usage: resultMsg.usage,
|
|
336
|
-
duration_ms: resultMsg.duration_ms,
|
|
337
|
-
num_turns: resultMsg.num_turns,
|
|
338
|
-
total_cost_usd: resultMsg.total_cost_usd
|
|
339
|
-
}
|
|
340
|
-
}));
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
case "user": {
|
|
344
|
-
const usrMsg = message;
|
|
345
|
-
if (usrMsg.isSynthetic) {
|
|
346
|
-
break;
|
|
347
|
-
}
|
|
348
|
-
const contentArray = usrMsg.message.content;
|
|
349
|
-
if (usrMsg.tool_use_result || Array.isArray(contentArray) && contentArray.some((c) => c.type === "tool_result")) {
|
|
350
|
-
for (const tool of contentArray) {
|
|
351
|
-
if (tool.is_error) {
|
|
352
|
-
chunks.push(formatDataStream({
|
|
353
|
-
type: "tool-output-error",
|
|
354
|
-
toolCallId: tool.tool_use_id,
|
|
355
|
-
errorText: tool.content,
|
|
356
|
-
dynamic: true
|
|
357
|
-
}));
|
|
358
|
-
} else {
|
|
359
|
-
chunks.push(formatDataStream({
|
|
360
|
-
type: "tool-output-available",
|
|
361
|
-
toolCallId: tool.tool_use_id,
|
|
362
|
-
output: usrMsg.tool_use_result || tool.content,
|
|
363
|
-
dynamic: true
|
|
364
|
-
}));
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
break;
|
|
369
|
-
}
|
|
370
|
-
default:
|
|
371
|
-
break;
|
|
372
|
-
}
|
|
373
|
-
return chunks;
|
|
374
|
-
}
|
|
375
|
-
function formatDataStream(data) {
|
|
376
|
-
return `data: ${JSON.stringify(data)}
|
|
377
|
-
|
|
378
|
-
`;
|
|
379
|
-
}
|
|
380
|
-
function generateId() {
|
|
381
|
-
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
466
|
+
setupAbortHandler(queryIterator, options.abortController?.signal);
|
|
467
|
+
yield* streamSDKMessagesToAISDKUI(queryIterator);
|
|
382
468
|
}
|
|
383
469
|
async function* runMockAgent(options, userInput, signal) {
|
|
384
470
|
if (signal?.aborted) {
|
|
@@ -386,6 +472,11 @@ async function* runMockAgent(options, userInput, signal) {
|
|
|
386
472
|
return;
|
|
387
473
|
}
|
|
388
474
|
try {
|
|
475
|
+
const messageId = generateId();
|
|
476
|
+
yield formatDataStream({
|
|
477
|
+
type: "start",
|
|
478
|
+
messageId
|
|
479
|
+
});
|
|
389
480
|
const response = `I received your request: "${userInput}"
|
|
390
481
|
|
|
391
482
|
Model: ${options.model}
|
|
@@ -413,7 +504,13 @@ Documentation: https://platform.claude.com/docs/en/agent-sdk/typescript-v2-previ
|
|
|
413
504
|
yield formatDataStream({ type: "text-end", id: textId });
|
|
414
505
|
yield formatDataStream({
|
|
415
506
|
type: "finish",
|
|
416
|
-
finishReason: "
|
|
507
|
+
finishReason: mapFinishReason("success"),
|
|
508
|
+
usage: convertUsageToAISDK({
|
|
509
|
+
input_tokens: 0,
|
|
510
|
+
output_tokens: 0,
|
|
511
|
+
cache_creation_input_tokens: 0,
|
|
512
|
+
cache_read_input_tokens: 0
|
|
513
|
+
})
|
|
417
514
|
});
|
|
418
515
|
yield `data: [DONE]
|
|
419
516
|
|
|
@@ -424,7 +521,13 @@ Documentation: https://platform.claude.com/docs/en/agent-sdk/typescript-v2-previ
|
|
|
424
521
|
yield formatDataStream({ type: "error", errorText: errorMessage });
|
|
425
522
|
yield formatDataStream({
|
|
426
523
|
type: "finish",
|
|
427
|
-
finishReason: "
|
|
524
|
+
finishReason: mapFinishReason("error_during_execution", true),
|
|
525
|
+
usage: convertUsageToAISDK({
|
|
526
|
+
input_tokens: 0,
|
|
527
|
+
output_tokens: 0,
|
|
528
|
+
cache_creation_input_tokens: 0,
|
|
529
|
+
cache_read_input_tokens: 0
|
|
530
|
+
})
|
|
428
531
|
});
|
|
429
532
|
yield `data: [DONE]
|
|
430
533
|
|
|
@@ -435,29 +538,47 @@ Documentation: https://platform.claude.com/docs/en/agent-sdk/typescript-v2-previ
|
|
|
435
538
|
// src/runner.ts
|
|
436
539
|
async function runAgent(options) {
|
|
437
540
|
const abortController = new AbortController();
|
|
438
|
-
const signalHandler = () => {
|
|
541
|
+
const signalHandler = async () => {
|
|
439
542
|
console.error("[Runner] Received termination signal, stopping...");
|
|
440
543
|
abortController.abort();
|
|
441
|
-
console.error(
|
|
544
|
+
console.error(
|
|
545
|
+
"[Runner] AbortController.abort() completed (listeners triggered)"
|
|
546
|
+
);
|
|
442
547
|
};
|
|
443
548
|
process.on("SIGTERM", signalHandler);
|
|
444
549
|
process.on("SIGINT", signalHandler);
|
|
445
550
|
console.error("[Runner] Signal handlers registered");
|
|
446
551
|
try {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
552
|
+
let runner;
|
|
553
|
+
switch (options.runner) {
|
|
554
|
+
case "claude": {
|
|
555
|
+
const runnerOptions = {
|
|
556
|
+
model: options.model,
|
|
557
|
+
systemPrompt: options.systemPrompt,
|
|
558
|
+
maxTurns: options.maxTurns,
|
|
559
|
+
allowedTools: options.allowedTools,
|
|
560
|
+
resume: options.resume,
|
|
561
|
+
approvalDir: options.approvalDir,
|
|
562
|
+
outputFormat: options.outputFormat,
|
|
563
|
+
abortController
|
|
564
|
+
};
|
|
565
|
+
runner = createClaudeRunner(runnerOptions);
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
case "codex":
|
|
569
|
+
throw new Error(
|
|
570
|
+
"Codex runner not yet implemented. Use --runner=claude for now."
|
|
571
|
+
);
|
|
572
|
+
case "copilot":
|
|
573
|
+
throw new Error(
|
|
574
|
+
"Copilot runner not yet implemented. Use --runner=claude for now."
|
|
575
|
+
);
|
|
576
|
+
default:
|
|
577
|
+
throw new Error(
|
|
578
|
+
`Unknown runner: ${options.runner}. Supported runners: claude, codex, copilot`
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
for await (const chunk of runner.run(options.userInput)) {
|
|
461
582
|
process.stdout.write(chunk);
|
|
462
583
|
}
|
|
463
584
|
} finally {
|
|
@@ -470,6 +591,11 @@ async function runAgent(options) {
|
|
|
470
591
|
function parseCliArgs() {
|
|
471
592
|
const { values, positionals } = parseArgs({
|
|
472
593
|
options: {
|
|
594
|
+
runner: {
|
|
595
|
+
type: "string",
|
|
596
|
+
short: "r",
|
|
597
|
+
default: "claude"
|
|
598
|
+
},
|
|
473
599
|
model: {
|
|
474
600
|
type: "string",
|
|
475
601
|
short: "m",
|
|
@@ -532,6 +658,13 @@ function parseCliArgs() {
|
|
|
532
658
|
console.error('Usage: sandagent run [options] -- "<user input>"');
|
|
533
659
|
process.exit(1);
|
|
534
660
|
}
|
|
661
|
+
const runner = values.runner;
|
|
662
|
+
if (!["claude", "codex", "copilot"].includes(runner)) {
|
|
663
|
+
console.error(
|
|
664
|
+
'Error: --runner must be one of: "claude", "codex", "copilot"'
|
|
665
|
+
);
|
|
666
|
+
process.exit(1);
|
|
667
|
+
}
|
|
535
668
|
const outputFormat = values["output-format"];
|
|
536
669
|
if (outputFormat && !["text", "json", "stream-json", "stream"].includes(outputFormat)) {
|
|
537
670
|
console.error(
|
|
@@ -540,6 +673,7 @@ function parseCliArgs() {
|
|
|
540
673
|
process.exit(1);
|
|
541
674
|
}
|
|
542
675
|
return {
|
|
676
|
+
runner,
|
|
543
677
|
model: values.model,
|
|
544
678
|
cwd: values.cwd,
|
|
545
679
|
systemPrompt: values["system-prompt"],
|
|
@@ -562,6 +696,7 @@ Usage:
|
|
|
562
696
|
sandagent run [options] -- "<user input>"
|
|
563
697
|
|
|
564
698
|
Options:
|
|
699
|
+
-r, --runner <runner> Runner to use: claude, codex, copilot (default: claude)
|
|
565
700
|
-m, --model <model> Model to use (default: claude-sonnet-4-20250514)
|
|
566
701
|
-c, --cwd <path> Working directory (default: current directory)
|
|
567
702
|
-s, --system-prompt <prompt> Custom system prompt
|
|
@@ -592,6 +727,7 @@ async function main() {
|
|
|
592
727
|
const args = parseCliArgs();
|
|
593
728
|
process.chdir(args.cwd);
|
|
594
729
|
await runAgent({
|
|
730
|
+
runner: args.runner,
|
|
595
731
|
model: args.model,
|
|
596
732
|
userInput: args.userInput,
|
|
597
733
|
systemPrompt: args.systemPrompt,
|
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,11 @@ import { runAgent } from "./runner.js";
|
|
|
16
16
|
function parseCliArgs() {
|
|
17
17
|
const { values, positionals } = parseArgs({
|
|
18
18
|
options: {
|
|
19
|
+
runner: {
|
|
20
|
+
type: "string",
|
|
21
|
+
short: "r",
|
|
22
|
+
default: "claude",
|
|
23
|
+
},
|
|
19
24
|
model: {
|
|
20
25
|
type: "string",
|
|
21
26
|
short: "m",
|
|
@@ -81,6 +86,12 @@ function parseCliArgs() {
|
|
|
81
86
|
console.error('Usage: sandagent run [options] -- "<user input>"');
|
|
82
87
|
process.exit(1);
|
|
83
88
|
}
|
|
89
|
+
// Validate runner
|
|
90
|
+
const runner = values.runner;
|
|
91
|
+
if (!["claude", "codex", "copilot"].includes(runner)) {
|
|
92
|
+
console.error('Error: --runner must be one of: "claude", "codex", "copilot"');
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
84
95
|
// Validate output-format
|
|
85
96
|
const outputFormat = values["output-format"];
|
|
86
97
|
if (outputFormat &&
|
|
@@ -89,6 +100,7 @@ function parseCliArgs() {
|
|
|
89
100
|
process.exit(1);
|
|
90
101
|
}
|
|
91
102
|
return {
|
|
103
|
+
runner,
|
|
92
104
|
model: values.model,
|
|
93
105
|
cwd: values.cwd,
|
|
94
106
|
systemPrompt: values["system-prompt"],
|
|
@@ -113,6 +125,7 @@ Usage:
|
|
|
113
125
|
sandagent run [options] -- "<user input>"
|
|
114
126
|
|
|
115
127
|
Options:
|
|
128
|
+
-r, --runner <runner> Runner to use: claude, codex, copilot (default: claude)
|
|
116
129
|
-m, --model <model> Model to use (default: claude-sonnet-4-20250514)
|
|
117
130
|
-c, --cwd <path> Working directory (default: current directory)
|
|
118
131
|
-s, --system-prompt <prompt> Custom system prompt
|
|
@@ -145,6 +158,7 @@ async function main() {
|
|
|
145
158
|
process.chdir(args.cwd);
|
|
146
159
|
// Run the agent and stream output to stdout
|
|
147
160
|
await runAgent({
|
|
161
|
+
runner: args.runner,
|
|
148
162
|
model: args.model,
|
|
149
163
|
userInput: args.userInput,
|
|
150
164
|
systemPrompt: args.systemPrompt,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type BaseRunnerOptions } from "@sandagent/runner-claude";
|
|
|
4
4
|
* Extends BaseRunnerOptions with CLI-specific fields
|
|
5
5
|
*/
|
|
6
6
|
export interface RunAgentOptions extends BaseRunnerOptions {
|
|
7
|
+
/** Which runner to use: claude, codex, copilot */
|
|
8
|
+
runner: string;
|
|
7
9
|
/** User input/task */
|
|
8
10
|
userInput: string;
|
|
9
11
|
/** Template to use (e.g., "default", "coder", "analyst", "researcher") */
|
package/dist/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,0BAA0B,CAAC;AAElC;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EAGvB,MAAM,0BAA0B,CAAC;AAElC;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkEtE"}
|
package/dist/runner.js
CHANGED
|
@@ -15,28 +15,45 @@ export async function runAgent(options) {
|
|
|
15
15
|
// Create an AbortController to handle process signals
|
|
16
16
|
const abortController = new AbortController();
|
|
17
17
|
// Handle SIGTERM and SIGINT signals
|
|
18
|
-
const signalHandler = () => {
|
|
18
|
+
const signalHandler = async () => {
|
|
19
19
|
console.error("[Runner] Received termination signal, stopping...");
|
|
20
|
+
// Note: abort() synchronously triggers all abort event listeners,
|
|
20
21
|
abortController.abort();
|
|
21
|
-
console.error("[Runner] AbortController.abort()
|
|
22
|
+
console.error("[Runner] AbortController.abort() completed (listeners triggered)");
|
|
22
23
|
};
|
|
23
24
|
process.on("SIGTERM", signalHandler);
|
|
24
25
|
process.on("SIGINT", signalHandler);
|
|
25
26
|
console.error("[Runner] Signal handlers registered");
|
|
26
27
|
try {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
// Select the appropriate runner based on options.runner
|
|
29
|
+
let runner;
|
|
30
|
+
switch (options.runner) {
|
|
31
|
+
case "claude": {
|
|
32
|
+
// Build runner options - cwd is already set by cli.ts via process.chdir()
|
|
33
|
+
const runnerOptions = {
|
|
34
|
+
model: options.model,
|
|
35
|
+
systemPrompt: options.systemPrompt,
|
|
36
|
+
maxTurns: options.maxTurns,
|
|
37
|
+
allowedTools: options.allowedTools,
|
|
38
|
+
resume: options.resume,
|
|
39
|
+
approvalDir: options.approvalDir,
|
|
40
|
+
outputFormat: options.outputFormat,
|
|
41
|
+
abortController: abortController,
|
|
42
|
+
};
|
|
43
|
+
runner = createClaudeRunner(runnerOptions);
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
case "codex":
|
|
47
|
+
// TODO: Implement Codex runner
|
|
48
|
+
throw new Error("Codex runner not yet implemented. Use --runner=claude for now.");
|
|
49
|
+
case "copilot":
|
|
50
|
+
// TODO: Implement Copilot runner
|
|
51
|
+
throw new Error("Copilot runner not yet implemented. Use --runner=claude for now.");
|
|
52
|
+
default:
|
|
53
|
+
throw new Error(`Unknown runner: ${options.runner}. Supported runners: claude, codex, copilot`);
|
|
54
|
+
}
|
|
38
55
|
// Stream AI SDK UI messages to stdout
|
|
39
|
-
for await (const chunk of runner.run(options.userInput
|
|
56
|
+
for await (const chunk of runner.run(options.userInput)) {
|
|
40
57
|
// Write directly to stdout without modification
|
|
41
58
|
// This ensures the stream is a valid AI SDK UI stream
|
|
42
59
|
process.stdout.write(chunk);
|
package/dist/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAelC;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAwB;IACrD,sDAAsD;IACtD,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAE9C,oCAAoC;IACpC,MAAM,aAAa,GAAG,KAAK,IAAI,EAAE;QAC/B,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,kEAAkE;QAClE,eAAe,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CACX,kEAAkE,CACnE,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IAEpC,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAErD,IAAI,CAAC;QACH,wDAAwD;QACxD,IAAI,MAAyD,CAAC;QAE9D,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;YACvB,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,0EAA0E;gBAC1E,MAAM,aAAa,GAAwB;oBACzC,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,MAAM,EAAE,OAAO,CAAC,MAAM;oBACtB,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,eAAe,EAAE,eAAe;iBACjC,CAAC;gBACF,MAAM,GAAG,kBAAkB,CAAC,aAAa,CAAC,CAAC;gBAC3C,MAAM;YACR,CAAC;YACD,KAAK,OAAO;gBACV,+BAA+B;gBAC/B,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;YACJ,KAAK,SAAS;gBACZ,iCAAiC;gBACjC,MAAM,IAAI,KAAK,CACb,kEAAkE,CACnE,CAAC;YACJ;gBACE,MAAM,IAAI,KAAK,CACb,mBAAmB,OAAO,CAAC,MAAM,6CAA6C,CAC/E,CAAC;QACN,CAAC;QAED,sCAAsC;QACtC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACxD,gDAAgD;YAChD,sDAAsD;YACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;YAAS,CAAC;QACT,2BAA2B;QAC3B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACvC,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandagent/runner-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "SandAgent Runner CLI - Like gemini-cli or claude-code, runs in your local terminal with AI SDK UI streaming",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,24 @@
|
|
|
24
24
|
"directory": "apps/runner-cli"
|
|
25
25
|
},
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
|
-
"
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"tag": "beta"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.0.0"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"cli",
|
|
36
|
+
"agent",
|
|
37
|
+
"sandagent",
|
|
38
|
+
"runner",
|
|
39
|
+
"claude",
|
|
40
|
+
"anthropic"
|
|
41
|
+
],
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@anthropic-ai/claude-agent-sdk": ">=0.1.70"
|
|
44
|
+
},
|
|
28
45
|
"devDependencies": {
|
|
29
46
|
"@types/node": "^20.10.0",
|
|
30
47
|
"esbuild": "^0.27.2",
|