@sandagent/runner-cli 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.mjs +104 -22
- package/package.json +3 -3
package/dist/bundle.mjs
CHANGED
|
@@ -477,20 +477,20 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
477
477
|
}
|
|
478
478
|
const cwd = claudeOptions.cwd || process.cwd();
|
|
479
479
|
try {
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
const approvalDir =
|
|
483
|
-
const approvalFile =
|
|
480
|
+
const fs2 = await import("node:fs");
|
|
481
|
+
const path2 = await import("node:path");
|
|
482
|
+
const approvalDir = path2.join(cwd, ".sandagent", "approvals");
|
|
483
|
+
const approvalFile = path2.join(approvalDir, `${toolUseID}.json`);
|
|
484
484
|
const timeout = Date.now() + 6e4;
|
|
485
485
|
let lastApproval = null;
|
|
486
486
|
while (Date.now() < timeout) {
|
|
487
487
|
try {
|
|
488
|
-
const data =
|
|
488
|
+
const data = fs2.readFileSync(approvalFile, "utf-8");
|
|
489
489
|
const approval = JSON.parse(data);
|
|
490
490
|
lastApproval = approval;
|
|
491
491
|
if (approval.status === "completed") {
|
|
492
492
|
try {
|
|
493
|
-
|
|
493
|
+
fs2.unlinkSync(approvalFile);
|
|
494
494
|
} catch {
|
|
495
495
|
}
|
|
496
496
|
return {
|
|
@@ -506,7 +506,7 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
506
506
|
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
507
507
|
}
|
|
508
508
|
try {
|
|
509
|
-
|
|
509
|
+
fs2.unlinkSync(approvalFile);
|
|
510
510
|
} catch {
|
|
511
511
|
}
|
|
512
512
|
if (lastApproval && Object.keys(lastApproval.answers).length > 0) {
|
|
@@ -708,6 +708,9 @@ Documentation: https://platform.claude.com/docs/en/agent-sdk/typescript-v2-previ
|
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
// ../../packages/runner-codex/dist/codex-runner.js
|
|
711
|
+
import * as fs from "node:fs";
|
|
712
|
+
import * as os from "node:os";
|
|
713
|
+
import * as path from "node:path";
|
|
711
714
|
import { Codex } from "@openai/codex-sdk";
|
|
712
715
|
function normalizeCodexModel(model) {
|
|
713
716
|
const trimmed = model.trim();
|
|
@@ -767,13 +770,15 @@ function toToolEndPayload(event) {
|
|
|
767
770
|
status: item.status,
|
|
768
771
|
exitCode: item.exit_code,
|
|
769
772
|
output: item.aggregated_output
|
|
770
|
-
}
|
|
773
|
+
},
|
|
774
|
+
isError: item.exit_code !== 0
|
|
771
775
|
};
|
|
772
776
|
}
|
|
773
777
|
if (item.type === "mcp_tool_call") {
|
|
774
778
|
return {
|
|
775
779
|
toolCallId: item.id,
|
|
776
|
-
result: item.result ?? item.error ?? { status: item.status }
|
|
780
|
+
result: item.result ?? item.error ?? { status: item.status },
|
|
781
|
+
isError: item.error != null || item.status === "failed"
|
|
777
782
|
};
|
|
778
783
|
}
|
|
779
784
|
if (item.type === "web_search") {
|
|
@@ -815,7 +820,36 @@ function createCodexRunner(options) {
|
|
|
815
820
|
approvalPolicy: options.approvalPolicy
|
|
816
821
|
};
|
|
817
822
|
const thread = options.resume ? codex.resumeThread(options.resume, threadOptions) : codex.startThread(threadOptions);
|
|
818
|
-
|
|
823
|
+
let inputToCodex = userInput;
|
|
824
|
+
const tempFiles = [];
|
|
825
|
+
try {
|
|
826
|
+
if (userInput.startsWith("[") && userInput.endsWith("]")) {
|
|
827
|
+
const parsed = JSON.parse(userInput);
|
|
828
|
+
if (Array.isArray(parsed)) {
|
|
829
|
+
const parts = [];
|
|
830
|
+
for (const p of parsed) {
|
|
831
|
+
if (p.type === "image" && typeof p.data === "string") {
|
|
832
|
+
const match = /^data:([^;]+);base64,(.+)$/.exec(p.data);
|
|
833
|
+
if (match) {
|
|
834
|
+
const ext = match[1].split("/")[1] ?? "png";
|
|
835
|
+
const tmpPath = path.join(os.tmpdir(), `sandagent-img-${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`);
|
|
836
|
+
fs.writeFileSync(tmpPath, Buffer.from(match[2], "base64"));
|
|
837
|
+
tempFiles.push(tmpPath);
|
|
838
|
+
parts.push({ type: "local_image", path: tmpPath });
|
|
839
|
+
}
|
|
840
|
+
} else {
|
|
841
|
+
const text = typeof p.text === "string" ? p.text : JSON.stringify(p);
|
|
842
|
+
parts.push({ type: "text", text });
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
if (parts.length > 0) {
|
|
846
|
+
inputToCodex = parts;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
} catch (e) {
|
|
851
|
+
}
|
|
852
|
+
const streamedTurn = await thread.runStreamed(inputToCodex, {
|
|
819
853
|
signal: options.abortController?.signal
|
|
820
854
|
});
|
|
821
855
|
for await (const event of streamedTurn.events) {
|
|
@@ -836,7 +870,7 @@ function createCodexRunner(options) {
|
|
|
836
870
|
}
|
|
837
871
|
const toolEnd = toToolEndPayload(event);
|
|
838
872
|
if (toolEnd) {
|
|
839
|
-
yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: toolEnd.toolCallId, output: toolEnd.result })}
|
|
873
|
+
yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: toolEnd.toolCallId, output: toolEnd.result, isError: toolEnd.isError })}
|
|
840
874
|
|
|
841
875
|
`;
|
|
842
876
|
}
|
|
@@ -871,6 +905,12 @@ function createCodexRunner(options) {
|
|
|
871
905
|
`;
|
|
872
906
|
}
|
|
873
907
|
}
|
|
908
|
+
for (const tmpFile of tempFiles) {
|
|
909
|
+
try {
|
|
910
|
+
fs.unlinkSync(tmpFile);
|
|
911
|
+
} catch {
|
|
912
|
+
}
|
|
913
|
+
}
|
|
874
914
|
}
|
|
875
915
|
};
|
|
876
916
|
}
|
|
@@ -1156,19 +1196,19 @@ function createOpenCodeRunner(options = {}) {
|
|
|
1156
1196
|
}
|
|
1157
1197
|
|
|
1158
1198
|
// ../../packages/runner-pi/dist/pi-runner.js
|
|
1159
|
-
import { appendFileSync as appendFileSync2, existsSync as existsSync3, unlinkSync as
|
|
1160
|
-
import { join as
|
|
1199
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync3, unlinkSync as unlinkSync3 } from "node:fs";
|
|
1200
|
+
import { join as join5 } from "node:path";
|
|
1161
1201
|
import { getModel } from "@mariozechner/pi-ai";
|
|
1162
1202
|
import { AuthStorage, ModelRegistry, SessionManager, createAgentSession } from "@mariozechner/pi-coding-agent";
|
|
1163
1203
|
|
|
1164
1204
|
// ../../packages/runner-pi/dist/sandagent-resource-loader.js
|
|
1165
|
-
import { join as join3 } from "node:path";
|
|
1166
1205
|
import { homedir } from "node:os";
|
|
1206
|
+
import { join as join4 } from "node:path";
|
|
1167
1207
|
import { DefaultResourceLoader, loadSkills } from "@mariozechner/pi-coding-agent";
|
|
1168
1208
|
var SandagentResourceLoader = class {
|
|
1169
1209
|
constructor(options = {}) {
|
|
1170
1210
|
this.cwd = options.cwd ?? process.cwd();
|
|
1171
|
-
this.agentDir = options.agentDir ??
|
|
1211
|
+
this.agentDir = options.agentDir ?? join4(homedir(), ".pi", "agent");
|
|
1172
1212
|
this.skillPaths = options.skillPaths ?? [];
|
|
1173
1213
|
this.delegate = new DefaultResourceLoader({
|
|
1174
1214
|
cwd: this.cwd,
|
|
@@ -1257,6 +1297,24 @@ function emitStreamError(errorText) {
|
|
|
1257
1297
|
"data: [DONE]\n\n"
|
|
1258
1298
|
];
|
|
1259
1299
|
}
|
|
1300
|
+
function extractToolResultText(result) {
|
|
1301
|
+
if (result !== null && typeof result === "object") {
|
|
1302
|
+
const r = result;
|
|
1303
|
+
if (Array.isArray(r.content) && r.content.length > 0) {
|
|
1304
|
+
const text = r.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
|
|
1305
|
+
if (text.length > 0) {
|
|
1306
|
+
return text;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
if (typeof result === "string")
|
|
1311
|
+
return result;
|
|
1312
|
+
try {
|
|
1313
|
+
return JSON.stringify(result);
|
|
1314
|
+
} catch {
|
|
1315
|
+
return String(result);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1260
1318
|
function usageToMessageMetadata(usage) {
|
|
1261
1319
|
return {
|
|
1262
1320
|
input_tokens: usage.input,
|
|
@@ -1288,9 +1346,9 @@ function traceRawMessage(debugCwd, data, reset = false) {
|
|
|
1288
1346
|
if (!enabled)
|
|
1289
1347
|
return;
|
|
1290
1348
|
try {
|
|
1291
|
-
const file =
|
|
1349
|
+
const file = join5(debugCwd, "pi-message-stream-debug.json");
|
|
1292
1350
|
if (reset && existsSync3(file))
|
|
1293
|
-
|
|
1351
|
+
unlinkSync3(file);
|
|
1294
1352
|
const type = data !== null && typeof data === "object" ? data.type : void 0;
|
|
1295
1353
|
let payload = data;
|
|
1296
1354
|
try {
|
|
@@ -1353,16 +1411,20 @@ function createPiRunner(options = {}) {
|
|
|
1353
1411
|
}
|
|
1354
1412
|
const sessions = await SessionManager.list(cwd);
|
|
1355
1413
|
const found = sessions.find((s) => s.id === resume);
|
|
1356
|
-
return found ? SessionManager.open(found.path) : SessionManager.
|
|
1414
|
+
return found ? SessionManager.open(found.path) : SessionManager.create(cwd);
|
|
1357
1415
|
}
|
|
1358
|
-
return SessionManager.
|
|
1416
|
+
return SessionManager.create(cwd);
|
|
1359
1417
|
})();
|
|
1418
|
+
const resourceLoader = options.skillPaths ? new SandagentResourceLoader({ cwd, skillPaths: options.skillPaths }) : void 0;
|
|
1419
|
+
if (resourceLoader) {
|
|
1420
|
+
await resourceLoader.reload();
|
|
1421
|
+
}
|
|
1360
1422
|
const { session } = await createAgentSession({
|
|
1361
1423
|
cwd,
|
|
1362
1424
|
model,
|
|
1363
1425
|
sessionManager,
|
|
1364
1426
|
modelRegistry,
|
|
1365
|
-
resourceLoader
|
|
1427
|
+
resourceLoader
|
|
1366
1428
|
});
|
|
1367
1429
|
if (options.systemPrompt != null && options.systemPrompt !== "") {
|
|
1368
1430
|
session.agent.setSystemPrompt(options.systemPrompt);
|
|
@@ -1399,7 +1461,26 @@ function createPiRunner(options = {}) {
|
|
|
1399
1461
|
}
|
|
1400
1462
|
try {
|
|
1401
1463
|
traceRawMessage(cwd, null, true);
|
|
1402
|
-
|
|
1464
|
+
let promptText = userInput;
|
|
1465
|
+
let images = void 0;
|
|
1466
|
+
try {
|
|
1467
|
+
if (userInput.startsWith("[") && userInput.endsWith("]")) {
|
|
1468
|
+
const parsed = JSON.parse(userInput);
|
|
1469
|
+
if (Array.isArray(parsed)) {
|
|
1470
|
+
promptText = parsed.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
1471
|
+
const imageParts = parsed.filter((p) => p.type === "image");
|
|
1472
|
+
if (imageParts.length > 0) {
|
|
1473
|
+
images = imageParts.map((p) => ({
|
|
1474
|
+
type: "image",
|
|
1475
|
+
data: p.data,
|
|
1476
|
+
mimeType: p.mimeType
|
|
1477
|
+
}));
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
} catch (e) {
|
|
1482
|
+
}
|
|
1483
|
+
const promptPromise = session.prompt(promptText, images ? { images } : void 0);
|
|
1403
1484
|
const messageId = `msg_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
1404
1485
|
const textId = `text_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
1405
1486
|
let hasStarted = false;
|
|
@@ -1471,7 +1552,8 @@ function createPiRunner(options = {}) {
|
|
|
1471
1552
|
|
|
1472
1553
|
`;
|
|
1473
1554
|
} else if (event.type === "tool_execution_end") {
|
|
1474
|
-
|
|
1555
|
+
const output = extractToolResultText(event.result);
|
|
1556
|
+
yield `data: ${JSON.stringify({ type: "tool-output-available", toolCallId: event.toolCallId, output, isError: event.isError, dynamic: true })}
|
|
1475
1557
|
|
|
1476
1558
|
`;
|
|
1477
1559
|
} else if (event.type === "agent_end") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandagent/runner-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
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": {
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"vitest": "^1.6.1",
|
|
56
56
|
"@sandagent/runner-claude": "0.6.2",
|
|
57
57
|
"@sandagent/runner-codex": "0.6.2",
|
|
58
|
+
"@sandagent/runner-gemini": "0.6.2",
|
|
58
59
|
"@sandagent/runner-opencode": "0.6.2",
|
|
59
|
-
"@sandagent/runner-pi": "0.6.3"
|
|
60
|
-
"@sandagent/runner-gemini": "0.6.2"
|
|
60
|
+
"@sandagent/runner-pi": "0.6.3"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsc && pnpm bundle",
|