@aiden-ade/sandbox-agent 0.1.7 → 0.1.8

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.
Files changed (2) hide show
  1. package/dist/index.cjs +208 -6
  2. package/package.json +13 -11
package/dist/index.cjs CHANGED
@@ -5160,6 +5160,7 @@ function createGenericCliBackend(options) {
5160
5160
  runtimeSessionId: state.runtimeSessionId
5161
5161
  });
5162
5162
  }
5163
+ await options.afterExit?.(context, state);
5163
5164
  const hasRenderableTurn = state.summary.trim().length > 0 || state.iterations > 0;
5164
5165
  if (hasRenderableTurn) {
5165
5166
  await presenter.onTurnComplete([]);
@@ -5551,6 +5552,110 @@ function parseCodexStructuredLine(line, context, state) {
5551
5552
  break;
5552
5553
  }
5553
5554
  }
5555
+ function parseJsonObject(value2) {
5556
+ try {
5557
+ const parsed = JSON.parse(value2);
5558
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
5559
+ } catch {
5560
+ return null;
5561
+ }
5562
+ }
5563
+ function parseMaybeJson(value2) {
5564
+ if (typeof value2 !== "string") return value2;
5565
+ return parseJsonObject(value2) ?? value2;
5566
+ }
5567
+ function normalizeCodexMcpToolResult(output) {
5568
+ if (typeof output !== "string") return JSON.stringify(output ?? {}, null, 2);
5569
+ const outputMarker = "\nOutput:\n";
5570
+ const raw = output.includes(outputMarker) ? output.slice(output.indexOf(outputMarker) + outputMarker.length).trim() : output.trim();
5571
+ let parsed;
5572
+ try {
5573
+ parsed = JSON.parse(raw);
5574
+ } catch {
5575
+ return raw;
5576
+ }
5577
+ if (Array.isArray(parsed)) {
5578
+ const textBlocks = parsed.filter(
5579
+ (entry) => typeof entry === "object" && entry !== null && "text" in entry
5580
+ ).map((entry) => typeof entry.text === "string" ? entry.text : "").filter(Boolean);
5581
+ if (textBlocks.length > 0) return textBlocks.join("\n");
5582
+ }
5583
+ return raw;
5584
+ }
5585
+ function findCodexSessionLog(runtimeSessionId, codexHome) {
5586
+ if (!runtimeSessionId || !(0, import_fs.existsSync)(codexHome)) return null;
5587
+ const root = (0, import_path.join)(codexHome, "sessions");
5588
+ if (!(0, import_fs.existsSync)(root)) return null;
5589
+ const matches = [];
5590
+ const stack = [root];
5591
+ while (stack.length > 0) {
5592
+ const dir = stack.pop();
5593
+ let entries;
5594
+ try {
5595
+ entries = (0, import_fs.readdirSync)(dir, { withFileTypes: true });
5596
+ } catch {
5597
+ continue;
5598
+ }
5599
+ for (const entry of entries) {
5600
+ const path = (0, import_path.join)(dir, entry.name);
5601
+ if (entry.isDirectory()) {
5602
+ stack.push(path);
5603
+ } else if (entry.isFile() && entry.name.includes(runtimeSessionId) && entry.name.endsWith(".jsonl")) {
5604
+ try {
5605
+ matches.push({ path, mtimeMs: (0, import_fs.statSync)(path).mtimeMs });
5606
+ } catch {
5607
+ matches.push({ path, mtimeMs: 0 });
5608
+ }
5609
+ }
5610
+ }
5611
+ }
5612
+ matches.sort((a, b) => b.mtimeMs - a.mtimeMs);
5613
+ return matches[0]?.path ?? null;
5614
+ }
5615
+ async function replayCodexMcpToolEventsFromSessionLog(context, state) {
5616
+ const runtimeSessionId = state.runtimeSessionId;
5617
+ if (!runtimeSessionId) return;
5618
+ const codexHome = context.env.CODEX_HOME || process.env.CODEX_HOME || (0, import_path.join)((0, import_os.homedir)(), ".codex");
5619
+ const logPath = findCodexSessionLog(runtimeSessionId, codexHome);
5620
+ if (!logPath) return;
5621
+ const emittedToolIds = /* @__PURE__ */ new Set();
5622
+ const lines = (0, import_fs.readFileSync)(logPath, "utf8").split(/\r?\n/).filter(Boolean);
5623
+ for (const line of lines) {
5624
+ const entry = parseJsonObject(line);
5625
+ const payload = entry && typeof entry.payload === "object" && entry.payload !== null ? entry.payload : null;
5626
+ if (!payload) continue;
5627
+ if (payload.type === "function_call") {
5628
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
5629
+ const name = typeof payload.name === "string" ? payload.name : "";
5630
+ const namespace = typeof payload.namespace === "string" ? payload.namespace : "";
5631
+ if (!callId || !name || !namespace.startsWith("mcp__")) continue;
5632
+ const toolName = `${namespace}${name}`;
5633
+ context.presenter.onToolUse(toolName, parseMaybeJson(payload.arguments), callId);
5634
+ emittedToolIds.add(callId);
5635
+ continue;
5636
+ }
5637
+ if (payload.type === "tool_search_call") {
5638
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
5639
+ if (!callId) continue;
5640
+ context.presenter.onToolUse("tool_search", payload.arguments ?? {}, callId);
5641
+ emittedToolIds.add(callId);
5642
+ }
5643
+ }
5644
+ if (emittedToolIds.size === 0) return;
5645
+ for (const line of lines) {
5646
+ const entry = parseJsonObject(line);
5647
+ const payload = entry && typeof entry.payload === "object" && entry.payload !== null ? entry.payload : null;
5648
+ if (!payload || payload.type !== "function_call_output" && payload.type !== "tool_search_output") continue;
5649
+ const callId = typeof payload.call_id === "string" ? payload.call_id : "";
5650
+ if (!emittedToolIds.has(callId)) continue;
5651
+ try {
5652
+ const result = payload.type === "tool_search_output" ? JSON.stringify(payload.tools ?? [], null, 2) : normalizeCodexMcpToolResult(payload.output);
5653
+ context.presenter.onToolResult?.(callId, result);
5654
+ } catch {
5655
+ context.presenter.onToolResult?.(callId, String(payload.output ?? ""));
5656
+ }
5657
+ }
5658
+ }
5554
5659
  function extractCursorToolEntry(toolCall) {
5555
5660
  const [rawName, rawPayload] = Object.entries(toolCall)[0] ?? [];
5556
5661
  if (!rawName || typeof rawPayload !== "object" || rawPayload === null) return null;
@@ -5892,10 +5997,13 @@ function kimiSessionId(cwd) {
5892
5997
  }
5893
5998
  return (0, import_crypto.createHash)("md5").update(resolved).digest("hex");
5894
5999
  }
6000
+ function shouldEnableKimiCliThinking(model2) {
6001
+ return model2?.trim() === "kimi-k2.6-thinking";
6002
+ }
5895
6003
  function resolveKimiCliModelArg(model2) {
5896
6004
  const trimmed = model2?.trim();
5897
6005
  if (!trimmed) return void 0;
5898
- if (trimmed === "kimi-latest" || trimmed === "kimi-k2.5" || trimmed === "kimi-k2.6") {
6006
+ if (trimmed === "kimi-latest" || trimmed === "kimi-k2.5" || trimmed === "kimi-k2.6" || shouldEnableKimiCliThinking(trimmed)) {
5899
6007
  return void 0;
5900
6008
  }
5901
6009
  if (trimmed.startsWith("claude-")) return void 0;
@@ -5921,6 +6029,11 @@ function parseKimiStructuredLine(line, context, state) {
5921
6029
  const contentBlocks = Array.isArray(parsed.content) ? parsed.content : [];
5922
6030
  const toolCalls = Array.isArray(parsed.tool_calls) ? parsed.tool_calls : [];
5923
6031
  if (role === "assistant") {
6032
+ const thinking = contentBlocks.filter((b) => b.type === "think" && typeof b.think === "string").map((b) => b.think).join("");
6033
+ if (thinking) {
6034
+ state.iterations = Math.max(state.iterations, 1);
6035
+ void presenter.onThinking(thinking);
6036
+ }
5924
6037
  if (toolCalls.length > 0) {
5925
6038
  state.iterations = Math.max(state.iterations, 1);
5926
6039
  for (const tc of toolCalls) {
@@ -5972,6 +6085,9 @@ function createKimiCliBackend(command = "kimi", defaultArgs = []) {
5972
6085
  ];
5973
6086
  const resumeId = context.config.runtimeSessionId?.trim() || context.config.providerSessionId?.trim();
5974
6087
  if (resumeId) args.push("--session", resumeId);
6088
+ if (shouldEnableKimiCliThinking(context.config.selectedModel)) {
6089
+ args.push("--thinking");
6090
+ }
5975
6091
  const model2 = resolveKimiCliModelArg(context.config.selectedModel);
5976
6092
  if (model2) args.push("--model", model2);
5977
6093
  return [...args, ...defaultArgs, "--prompt", prompt];
@@ -6308,7 +6424,8 @@ function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
6308
6424
  const basePrompt = buildPromptWithSystem(ctx.config, ctx.promptText);
6309
6425
  return ctx.config.mode === "plan" ? buildPlanModePrefix(basePrompt) : basePrompt;
6310
6426
  },
6311
- parseStructuredLine: parseCodexStructuredLine
6427
+ parseStructuredLine: parseCodexStructuredLine,
6428
+ afterExit: replayCodexMcpToolEventsFromSessionLog
6312
6429
  }).run(context);
6313
6430
  } finally {
6314
6431
  cleanup();
@@ -6316,12 +6433,37 @@ function createCodexRuntimeBackend(command = "codex", defaultArgs = []) {
6316
6433
  }
6317
6434
  };
6318
6435
  }
6436
+ function createCopilotCliBackend(command = "copilot", defaultArgs = []) {
6437
+ return createGenericCliBackend({
6438
+ kind: "copilot_cli",
6439
+ supportTier: "text",
6440
+ command,
6441
+ args: [],
6442
+ buildArgs: (context, prompt) => {
6443
+ const args = [
6444
+ "--autopilot",
6445
+ "--yolo",
6446
+ "--max-autopilot-continues",
6447
+ "20",
6448
+ "-s",
6449
+ "-p",
6450
+ prompt
6451
+ ];
6452
+ if (context.config.selectedModel?.trim()) {
6453
+ args.push("--model", context.config.selectedModel.trim());
6454
+ }
6455
+ return [...args, ...defaultArgs];
6456
+ }
6457
+ });
6458
+ }
6319
6459
  var DEFAULT_MODEL = "claude-sonnet-4-6";
6320
6460
  var DROID_DEFAULT_MODEL = "claude-opus-4-7";
6321
6461
  function defaultSelectedModelForBackend(backendKind2) {
6322
6462
  switch (backendKind2) {
6323
6463
  case "droid_cli":
6324
6464
  return DROID_DEFAULT_MODEL;
6465
+ case "copilot_cli":
6466
+ return "claude-sonnet-4.5";
6325
6467
  case "kimi_cli":
6326
6468
  return void 0;
6327
6469
  default:
@@ -6424,6 +6566,7 @@ var BaseMachineAgent = class _BaseMachineAgent {
6424
6566
  case "gemini_cli":
6425
6567
  case "opencode_cli":
6426
6568
  return "structured";
6569
+ case "copilot_cli":
6427
6570
  case "generic_cli":
6428
6571
  default:
6429
6572
  return "text";
@@ -6469,7 +6612,7 @@ Prefer relative paths and keep your work scoped to this project.`
6469
6612
  const promptText = this.buildPromptText(runtimeConfig);
6470
6613
  const runtimeCommand = runtimeConfig.runtimeCommand || this.runtime.runtimeCommand;
6471
6614
  const runtimeArgs = runtimeConfig.runtimeArgs || this.runtime.runtimeArgs || [];
6472
- const backend = backendKind2 === "claude_cli" ? createClaudeCliBackend(runtimeCommand || "claude", runtimeArgs) : backendKind2 === "codex_app_server" ? createCodexRuntimeBackend(runtimeCommand || "codex", runtimeArgs) : backendKind2 === "cursor_agent_cli" ? createCursorAgentCliBackend(runtimeCommand || "cursor-agent", runtimeArgs) : backendKind2 === "gemini_cli" ? createGeminiCliBackend(runtimeCommand || "gemini", runtimeArgs) : backendKind2 === "droid_cli" ? createDroidCliBackend(runtimeCommand || "droid", runtimeArgs) : backendKind2 === "opencode_cli" ? createOpencodeCliBackend(runtimeCommand || "opencode", runtimeArgs) : backendKind2 === "kimi_cli" ? createKimiCliBackend(runtimeCommand || "kimi", runtimeArgs) : createGenericCliPassthroughBackend(runtimeCommand || "generic-cli", runtimeArgs);
6615
+ const backend = backendKind2 === "claude_cli" ? createClaudeCliBackend(runtimeCommand || "claude", runtimeArgs) : backendKind2 === "codex_app_server" ? createCodexRuntimeBackend(runtimeCommand || "codex", runtimeArgs) : backendKind2 === "copilot_cli" ? createCopilotCliBackend(runtimeCommand || "copilot", runtimeArgs) : backendKind2 === "cursor_agent_cli" ? createCursorAgentCliBackend(runtimeCommand || "cursor-agent", runtimeArgs) : backendKind2 === "gemini_cli" ? createGeminiCliBackend(runtimeCommand || "gemini", runtimeArgs) : backendKind2 === "droid_cli" ? createDroidCliBackend(runtimeCommand || "droid", runtimeArgs) : backendKind2 === "opencode_cli" ? createOpencodeCliBackend(runtimeCommand || "opencode", runtimeArgs) : backendKind2 === "kimi_cli" ? createKimiCliBackend(runtimeCommand || "kimi", runtimeArgs) : createGenericCliPassthroughBackend(runtimeCommand || "generic-cli", runtimeArgs);
6473
6616
  let lastResult = null;
6474
6617
  for (let attempt = 0; attempt <= _BaseMachineAgent.MAX_RETRIES; attempt++) {
6475
6618
  if (this.abortController?.signal.aborted) break;
@@ -6607,11 +6750,61 @@ Prefer relative paths and keep your work scoped to this project.`
6607
6750
  };
6608
6751
 
6609
6752
  // src/core-agent.ts
6610
- var CoreAgent = class extends BaseMachineAgent {
6753
+ var CoreAgent = class _CoreAgent extends BaseMachineAgent {
6611
6754
  childProcess = null;
6755
+ _aborted = false;
6756
+ /** How long to wait after SIGTERM before escalating to SIGKILL. */
6757
+ static SIGKILL_DELAY_MS = 3e3;
6612
6758
  constructor(presenter, runtime) {
6613
6759
  super(presenter, runtime);
6614
6760
  }
6761
+ abort() {
6762
+ this._aborted = true;
6763
+ super.abort();
6764
+ }
6765
+ kill() {
6766
+ this._aborted = true;
6767
+ super.abort();
6768
+ const child = this.childProcess;
6769
+ if (!child || child.killed || child.exitCode !== null) return false;
6770
+ return this.killChildProcess(child);
6771
+ }
6772
+ killChildProcess(child) {
6773
+ const pid = child.pid;
6774
+ if (!pid) return false;
6775
+ console.info("[CoreAgent] Killing agent process", { pid });
6776
+ try {
6777
+ if (process.platform === "win32") {
6778
+ child.kill("SIGTERM");
6779
+ } else {
6780
+ process.kill(-pid, "SIGTERM");
6781
+ }
6782
+ } catch (err) {
6783
+ if (err.code !== "ESRCH") {
6784
+ console.warn("[CoreAgent] SIGTERM failed", { pid, err });
6785
+ }
6786
+ try {
6787
+ child.kill("SIGTERM");
6788
+ } catch {
6789
+ }
6790
+ }
6791
+ setTimeout(() => {
6792
+ if (child.killed || child.exitCode !== null) return;
6793
+ console.warn("[CoreAgent] Escalating to SIGKILL", { pid });
6794
+ try {
6795
+ if (process.platform === "win32") {
6796
+ child.kill("SIGKILL");
6797
+ } else {
6798
+ process.kill(-pid, "SIGKILL");
6799
+ }
6800
+ } catch (err) {
6801
+ if (err.code !== "ESRCH") {
6802
+ console.warn("[CoreAgent] SIGKILL failed", { pid, err });
6803
+ }
6804
+ }
6805
+ }, _CoreAgent.SIGKILL_DELAY_MS);
6806
+ return true;
6807
+ }
6615
6808
  // ── Interactive tool response (WS relay → stdin) ───────────────────────
6616
6809
  /**
6617
6810
  * Send a tool_result to the CLI's stdin (stream-json format).
@@ -6652,6 +6845,12 @@ var CoreAgent = class extends BaseMachineAgent {
6652
6845
  child.on("exit", () => {
6653
6846
  this.childProcess = null;
6654
6847
  });
6848
+ child.on("error", () => {
6849
+ this.childProcess = null;
6850
+ });
6851
+ if (this._aborted) {
6852
+ this.killChildProcess(child);
6853
+ }
6655
6854
  };
6656
6855
  }
6657
6856
  async buildCliEnvironment() {
@@ -10447,7 +10646,7 @@ var WSClient = class {
10447
10646
  };
10448
10647
 
10449
10648
  // src/version.ts
10450
- var AGENT_VERSION = "0.1.7";
10649
+ var AGENT_VERSION = "0.1.8";
10451
10650
 
10452
10651
  // src/sandbox.ts
10453
10652
  async function runSandbox(config) {
@@ -10479,7 +10678,10 @@ async function runSandbox(config) {
10479
10678
  },
10480
10679
  onStop: () => {
10481
10680
  console.info("[sandbox] Stop signal received");
10482
- if (currentAgent) currentAgent.abort();
10681
+ if (currentAgent) {
10682
+ const killed = currentAgent.kill();
10683
+ if (!killed) currentAgent.abort();
10684
+ }
10483
10685
  },
10484
10686
  onToolResponse: (toolId, response) => {
10485
10687
  if (currentAgent) {
package/package.json CHANGED
@@ -1,27 +1,29 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aiden-agent": "./dist/index.cjs"
7
7
  },
8
- "files": ["dist/"],
8
+ "files": [
9
+ "dist/"
10
+ ],
9
11
  "publishConfig": {
10
12
  "access": "public"
11
13
  },
12
- "scripts": {
13
- "build": "tsup",
14
- "dev": "tsx src/index.ts",
15
- "type-check": "tsc --noEmit"
16
- },
17
14
  "dependencies": {},
18
15
  "devDependencies": {
19
- "@aiden/agent-core": "workspace:*",
20
- "@aiden/shared": "workspace:*",
21
16
  "socket.io-client": "^4.8.0",
22
17
  "@types/node": "^22.0.0",
23
18
  "tsup": "^8.5.1",
24
19
  "tsx": "^4.19.0",
25
- "typescript": "~5.9.3"
20
+ "typescript": "~5.9.3",
21
+ "@aiden/agent-core": "0.1.0",
22
+ "@aiden/shared": "0.1.0"
23
+ },
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsx src/index.ts",
27
+ "type-check": "tsc --noEmit"
26
28
  }
27
- }
29
+ }