@sideboard-ai/core 0.1.111 → 0.1.116

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 (43) hide show
  1. package/dist/agents/cursor-runner.cjs +51 -21
  2. package/dist/agents/cursor-runner.js +3 -3
  3. package/dist/{agents-NN22A4G5.js → agents-7NIX44RB.js} +7 -7
  4. package/dist/{agents-GH3FWDW2.js → agents-DU7DHY7A.js} +10 -10
  5. package/dist/{chunk-JTQQPJAU.js → chunk-4HOFVKPC.js} +52 -38
  6. package/dist/{chunk-4EWPKYOU.js → chunk-4OJMZ6P2.js} +2 -2
  7. package/dist/{chunk-NC3U42ZP.js → chunk-5KSLD4MU.js} +317 -33
  8. package/dist/{chunk-KQBI5HNT.js → chunk-7WC5UWEB.js} +2 -2
  9. package/dist/{chunk-WIHKHR5R.js → chunk-AXQ4ZWHK.js} +5 -0
  10. package/dist/{chunk-LGXBYZZA.js → chunk-DVM4ID64.js} +69 -13
  11. package/dist/{chunk-DMJKOFTO.js → chunk-DWP25N32.js} +44 -35
  12. package/dist/{chunk-2GO3YKBA.js → chunk-EKIDHL2T.js} +4 -4
  13. package/dist/{chunk-C4KHDW3U.js → chunk-FZCIQYNQ.js} +1 -1
  14. package/dist/{chunk-363Z34PY.js → chunk-GBY7OOMB.js} +273 -218
  15. package/dist/{chunk-7KWYXGIU.js → chunk-K3TIQXOH.js} +2 -2
  16. package/dist/{chunk-3KETJKYA.js → chunk-KPIYENTF.js} +69 -13
  17. package/dist/{chunk-KVFNTWFG.js → chunk-OFF5AFCR.js} +300 -43
  18. package/dist/{chunk-VOD3HFLP.js → chunk-XOYQ7LNQ.js} +2 -2
  19. package/dist/{chunk-7YKXHBIW.js → chunk-YMRT2DU6.js} +3 -3
  20. package/dist/{chunk-YXDR43ZC.js → chunk-ZMROW673.js} +5 -5
  21. package/dist/{chunk-YFAXVUY2.js → chunk-ZRCX43LS.js} +2 -2
  22. package/dist/{chunk-AROMOP3C.js → chunk-ZYEFCSZJ.js} +2 -2
  23. package/dist/{connected-teams-M5XNXRI5.js → connected-teams-O6D4PM7A.js} +2 -2
  24. package/dist/{connected-teams-J4I5AKMR.js → connected-teams-ZCOU6KCD.js} +2 -2
  25. package/dist/{coordinator-prompt-AR66L3N4.js → coordinator-prompt-4KCALEKD.js} +3 -3
  26. package/dist/{coordinator-prompt-BHMLWL64.js → coordinator-prompt-FML4I5AR.js} +3 -3
  27. package/dist/{global-workspace-XSUFEIAQ.js → global-workspace-CSWABOG5.js} +4 -4
  28. package/dist/{global-workspace-SKFODUQQ.js → global-workspace-H4YNASM6.js} +4 -4
  29. package/dist/index.cjs +855 -440
  30. package/dist/index.d.cts +59 -1
  31. package/dist/index.d.ts +59 -1
  32. package/dist/index.js +37 -17
  33. package/dist/mcp/run-stdio.cjs +966 -635
  34. package/dist/mcp/run-stdio.js +20 -16
  35. package/dist/{orchestrator-4T2SXDZ7.js → orchestrator-NXPANCZA.js} +8 -8
  36. package/dist/{orchestrator-EP57AB5W.js → orchestrator-ZY4RUJKT.js} +10 -10
  37. package/dist/{run-XKTAJRWF.js → run-USF6FRKV.js} +3 -1
  38. package/dist/{run-CFKZPY7F.js → run-XQKGHQZ2.js} +3 -1
  39. package/dist/{workspaces-XAQVKTLO.js → workspaces-HJ3EVATC.js} +5 -5
  40. package/dist/{workspaces-HV3J4TTW.js → workspaces-QG6PGFQR.js} +5 -5
  41. package/dist/{worktree-XFJED3VU.js → worktree-IW3BX26B.js} +2 -2
  42. package/dist/{worktree-N2EV24EE.js → worktree-OTFQO2W7.js} +2 -2
  43. package/package.json +1 -1
@@ -4,11 +4,12 @@ import {
4
4
  ensureCliTeamTracked,
5
5
  ensureConnectedBrightsyTeamTokens,
6
6
  loadBrightsyConfig
7
- } from "./chunk-2GO3YKBA.js";
7
+ } from "./chunk-EKIDHL2T.js";
8
8
  import {
9
9
  isOrchestratorThread
10
- } from "./chunk-4EWPKYOU.js";
10
+ } from "./chunk-4OJMZ6P2.js";
11
11
  import {
12
+ applyAgentRunnerHeapEnv,
12
13
  applyNodeLaunch,
13
14
  cursorRipgrepEnv,
14
15
  extractJsonErrorMessage,
@@ -19,13 +20,13 @@ import {
19
20
  packagedMcpStdioPath,
20
21
  parseCursorRunnerLine,
21
22
  resolveNodeLaunch
22
- } from "./chunk-363Z34PY.js";
23
+ } from "./chunk-GBY7OOMB.js";
23
24
  import {
24
25
  codexUnattendedGitConfigArgs,
25
26
  mergeAgentGitAuthEnv,
26
27
  resolveAgentGitAuthEnv,
27
28
  resolveCodexGitWritableRoots
28
- } from "./chunk-C4KHDW3U.js";
29
+ } from "./chunk-FZCIQYNQ.js";
29
30
  import {
30
31
  claudeChromeEnabled,
31
32
  loadAppSettings,
@@ -45,7 +46,7 @@ import {
45
46
  resolveCommandBinarySync,
46
47
  run,
47
48
  withExportedPath
48
- } from "./chunk-LGXBYZZA.js";
49
+ } from "./chunk-DVM4ID64.js";
49
50
 
50
51
  // src/agents/brightsy.ts
51
52
  import { existsSync } from "fs";
@@ -582,9 +583,9 @@ function toolDescription(name, input) {
582
583
  if (/connectedAgentRequest/i.test(name)) {
583
584
  return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
584
585
  }
585
- if (desc && kind) return `${kind}: ${desc}`;
586
- if (desc) return desc;
587
- return "Subagent";
586
+ if (desc && kind) return `${kind}: ${desc}${subagentLiveSuffix(input)}`;
587
+ if (desc) return `${desc}${subagentLiveSuffix(input)}`;
588
+ return `Subagent${subagentLiveSuffix(input)}`;
588
589
  }
589
590
  if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
590
591
  return str(input?.title) ? `Artifact ${str(input?.title)}` : "Artifact";
@@ -609,13 +610,151 @@ function toolDescription(name, input) {
609
610
  }
610
611
  if (/grep/i.test(name)) return "Search files";
611
612
  if (/glob/i.test(name)) return "Find files";
613
+ const compact = n.replace(/[_-]/g, "");
614
+ if (/^taskoutput$/i.test(compact)) {
615
+ return str(input.task_id) ? `Wait for ${str(input.task_id)}` : "Wait for background task";
616
+ }
617
+ if (/^taskstop$/i.test(compact)) {
618
+ return str(input.task_id) ? `Stop ${str(input.task_id)}` : "Stop background task";
619
+ }
620
+ if (/^monitor$/i.test(compact)) {
621
+ const command = str(input.command);
622
+ return command ? `Watch ${command.length > 48 ? `${command.slice(0, 45)}\u2026` : command}` : "Watch command";
623
+ }
612
624
  return n;
613
625
  }
626
+ function subagentLiveSuffix(input) {
627
+ if (!input) return "";
628
+ const bits = [];
629
+ const status = str(input.live_status);
630
+ if (status && !/^runn(ing)?$|^working$/i.test(status)) bits.push(status);
631
+ if (typeof input.live_tool_uses === "number") bits.push(`${input.live_tool_uses} tools`);
632
+ if (typeof input.live_duration_ms === "number") {
633
+ bits.push(`${Math.max(0, Math.round(Number(input.live_duration_ms) / 1e3))}s`);
634
+ }
635
+ const last = str(input.live_last_tool);
636
+ if (last) bits.push(last);
637
+ return bits.length ? ` \xB7 ${bits.join(" \xB7 ")}` : "";
638
+ }
614
639
  function isSubagentToolName(name) {
615
640
  const n = (name ?? "").trim();
616
641
  if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
617
642
  return /connectedAgentRequest/i.test(n);
618
643
  }
644
+ function isPollWrapperToolName(name) {
645
+ const n = (name ?? "").replace(/[_-]/g, "");
646
+ return /^(taskoutput|taskstop|sleep)$/i.test(n);
647
+ }
648
+ function lastTextPart(parts, type) {
649
+ for (let i = parts.length - 1; i >= 0; i--) {
650
+ const p = parts[i];
651
+ if (p.type === type && p.text.trim()) return p.text.trim();
652
+ }
653
+ return "";
654
+ }
655
+ function toolLabel(tool) {
656
+ return tool.description || toolDescription(tool.name, tool.input) || tool.name;
657
+ }
658
+ function fileBasename(path) {
659
+ const parts = path.replace(/\/$/, "").split(/[/\\]/);
660
+ return parts[parts.length - 1] || path;
661
+ }
662
+ function classifyTool(name) {
663
+ const compact = name.replace(/^mcp__[^_]+__/, "").replace(/[_-]/g, "");
664
+ if (/bash|shell|terminal|^zsh$|^sh$/i.test(compact)) return "shell";
665
+ if (/grep|glob|search|ripgrep|findfiles|semsearch/i.test(compact)) return "search";
666
+ if (/^(read|cat)$/i.test(compact) || /^read/i.test(compact)) return "read";
667
+ if (/edit|write|apply|strreplace|multiedit|updatefile|createfile/i.test(compact)) {
668
+ return "edit";
669
+ }
670
+ return "other";
671
+ }
672
+ function isShellToolName(name) {
673
+ return classifyTool(name ?? "") === "shell";
674
+ }
675
+ function toolActivityLine(parts) {
676
+ const tools = parts.filter((p) => {
677
+ if (p.type !== "tool" || p.parentId) return false;
678
+ if (isPollWrapperToolName(p.name)) return false;
679
+ if (/present_plan$/i.test(p.name ?? "")) return false;
680
+ if (/ask_user|AskUserQuestion/i.test(p.name ?? "")) return false;
681
+ return true;
682
+ });
683
+ if (tools.length === 0) return null;
684
+ const edited = [];
685
+ let reads = 0;
686
+ let searches = 0;
687
+ let shells = 0;
688
+ let others = 0;
689
+ let additions = 0;
690
+ let deletions = 0;
691
+ for (const tool of tools) {
692
+ const kind = classifyTool(tool.name);
693
+ if (kind === "edit") {
694
+ const path = tool.filePath ?? toolFilePath(tool.input);
695
+ edited.push({
696
+ name: path ? fileBasename(path) : tool.name,
697
+ running: tool.status === "running"
698
+ });
699
+ } else if (kind === "read") reads += 1;
700
+ else if (kind === "search") searches += 1;
701
+ else if (kind === "shell") shells += 1;
702
+ else others += 1;
703
+ if (typeof tool.additions === "number") additions += tool.additions;
704
+ if (typeof tool.deletions === "number") deletions += tool.deletions;
705
+ }
706
+ const bits = [];
707
+ const editing = edited.filter((e) => e.running);
708
+ const editedDone = edited.filter((e) => !e.running);
709
+ if (editing.length === 1) bits.push(`Editing ${editing[0].name}`);
710
+ else if (editing.length > 1) bits.push(`Editing ${editing.length} files`);
711
+ if (editedDone.length === 1) bits.push(`${editing.length ? "edited" : "Edited"} ${editedDone[0].name}`);
712
+ else if (editedDone.length > 1) {
713
+ bits.push(`${editing.length ? "edited" : "Edited"} ${editedDone.length} files`);
714
+ }
715
+ if (reads === 1) bits.push("explored 1 file");
716
+ else if (reads > 1) bits.push(`explored ${reads} files`);
717
+ if (searches === 1) bits.push("1 search");
718
+ else if (searches > 1) bits.push(`${searches} searches`);
719
+ if (shells === 1) bits.push("ran 1 command");
720
+ else if (shells > 1) bits.push(`ran ${shells} commands`);
721
+ if (others === 1) bits.push("1 tool");
722
+ else if (others > 1) bits.push(`${others} tools`);
723
+ if (bits.length === 0) return null;
724
+ return { text: bits.join(", "), additions, deletions };
725
+ }
726
+ function liveActivitySummary(parts, opts) {
727
+ if (opts?.queued && parts.length === 0) {
728
+ return "Queued \u2014 waiting for a slot";
729
+ }
730
+ const tools = parts.filter((p) => p.type === "tool");
731
+ const runningSubs = tools.filter(
732
+ (t) => t.status === "running" && !t.parentId && isSubagentToolName(t.name)
733
+ );
734
+ const runningNested = [...tools].reverse().find((t) => t.status === "running" && t.parentId && !isPollWrapperToolName(t.name));
735
+ const runningTop = [...tools].reverse().find(
736
+ (t) => t.status === "running" && !t.parentId && !isPollWrapperToolName(t.name) && !isSubagentToolName(t.name)
737
+ );
738
+ const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
739
+ const thinking = lastTextPart(parts, "thinking");
740
+ const text = lastTextPart(parts, "text");
741
+ if (runningSubs.length > 0) {
742
+ const heads = runningSubs.map(toolLabel);
743
+ const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
744
+ if (runningNested) return `${head} \xB7 ${toolLabel(runningNested)}`;
745
+ return head;
746
+ }
747
+ if (runningTop) return toolLabel(runningTop);
748
+ if (runningPoll) return toolLabel(runningPoll);
749
+ if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
750
+ if (text) return "Writing reply\u2026";
751
+ const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
752
+ if (last) {
753
+ const label = toolLabel(last);
754
+ return last.status === "running" ? label : `Finished ${label}`;
755
+ }
756
+ return "Working\u2026";
757
+ }
619
758
  function messagePartParentId(part) {
620
759
  if ("parentId" in part && typeof part.parentId === "string" && part.parentId.trim()) {
621
760
  return part.parentId;
@@ -701,6 +840,25 @@ function applyAgentEvent(parts, event) {
701
840
  const data = event.data;
702
841
  if (!data) return parts;
703
842
  const next = [...parts];
843
+ if (event.replace) {
844
+ for (let i = next.length - 1; i >= 0; i--) {
845
+ const prev = next[i];
846
+ if (prev?.type === "thinking" && sameParentId(prev.parentId, event.parentId)) {
847
+ next[i] = {
848
+ type: "thinking",
849
+ text: data,
850
+ ...event.parentId ? { parentId: event.parentId } : {}
851
+ };
852
+ return next;
853
+ }
854
+ }
855
+ next.push({
856
+ type: "thinking",
857
+ text: data,
858
+ ...event.parentId ? { parentId: event.parentId } : {}
859
+ });
860
+ return next;
861
+ }
704
862
  const last = next[next.length - 1];
705
863
  if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
706
864
  next[next.length - 1] = {
@@ -724,14 +882,18 @@ function applyAgentEvent(parts, event) {
724
882
  if (existing >= 0) {
725
883
  const prev = parts[existing];
726
884
  const next = [...parts];
727
- const mergedInput = input && Object.keys(input).length > 0 ? input : prev.input ?? input;
885
+ const mergedInput = {
886
+ ...prev.input ?? {},
887
+ ...input ?? {}
888
+ };
889
+ const mergedRecord = Object.keys(mergedInput).length > 0 ? mergedInput : void 0;
728
890
  next[existing] = {
729
891
  ...prev,
730
892
  name: event.name || prev.name,
731
- input: mergedInput,
732
- description: toolDescription(event.name || prev.name, mergedInput),
733
- detail: toolDetail(event.name || prev.name, mergedInput) ?? prev.detail,
734
- filePath: toolFilePath(mergedInput) ?? prev.filePath,
893
+ input: mergedRecord,
894
+ description: toolDescription(event.name || prev.name, mergedRecord),
895
+ detail: toolDetail(event.name || prev.name, mergedRecord) ?? prev.detail,
896
+ filePath: toolFilePath(mergedRecord) ?? prev.filePath,
735
897
  additions: diff.additions ?? prev.additions,
736
898
  deletions: diff.deletions ?? prev.deletions,
737
899
  parentId: event.parentId ?? prev.parentId
@@ -757,6 +919,30 @@ function applyAgentEvent(parts, event) {
757
919
  if (event.type === "tool_result") {
758
920
  const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
759
921
  const fromResult = parseDiffStat(event.content);
922
+ if (event.partial) {
923
+ if (existing < 0) {
924
+ return [
925
+ ...parts,
926
+ {
927
+ type: "tool",
928
+ id: event.id,
929
+ name: "tool",
930
+ description: "tool",
931
+ status: event.isError ? "error" : "running",
932
+ result: event.content,
933
+ ...event.parentId ? { parentId: event.parentId } : {}
934
+ }
935
+ ];
936
+ }
937
+ return parts.map((p, i) => {
938
+ if (i !== existing || p.type !== "tool") return p;
939
+ if (p.status === "done" || p.status === "error") return p;
940
+ return {
941
+ ...p,
942
+ result: event.content ?? p.result
943
+ };
944
+ });
945
+ }
760
946
  if (existing < 0) {
761
947
  return [
762
948
  ...parts,
@@ -1014,6 +1200,7 @@ async function buildInjectedMcpServers(opts) {
1014
1200
  );
1015
1201
  } catch {
1016
1202
  }
1203
+ applyAgentRunnerHeapEnv(sideboard.env);
1017
1204
  servers.push(sideboard);
1018
1205
  }
1019
1206
  if (opts.includeBrightsy && isBrightsyConnected()) {
@@ -1169,8 +1356,14 @@ var BASE_ALLOWED_TOOLS = [
1169
1356
  "WebSearch",
1170
1357
  // Subagents (Claude Code v2.1.63 renamed Task → Agent; allow both).
1171
1358
  "Task",
1172
- "Agent"
1359
+ "Agent",
1360
+ "TaskOutput",
1361
+ "TaskStop",
1362
+ "EnterWorktree",
1363
+ "ExitWorktree",
1364
+ "Skill"
1173
1365
  ];
1366
+ var CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
1174
1367
  var CLAUDE_CHROME_ALLOWED_TOOLS = [
1175
1368
  "mcp__claude-in-chrome",
1176
1369
  "mcp__claude-in-chrome__*",
@@ -1274,6 +1467,80 @@ function claudeParentToolUseId(obj) {
1274
1467
  }
1275
1468
  return void 0;
1276
1469
  }
1470
+ function claudeString(obj, key) {
1471
+ const v = obj[key];
1472
+ return typeof v === "string" && v.trim() ? v.trim() : void 0;
1473
+ }
1474
+ function eventsFromClaudeSystem(obj) {
1475
+ const subtype = claudeString(obj, "subtype") ?? "";
1476
+ const parentId = claudeParentToolUseId(obj);
1477
+ if (subtype === "init") {
1478
+ if (parentId) return null;
1479
+ const sid = claudeString(obj, "session_id");
1480
+ return sid ? { type: "session_id", data: sid } : null;
1481
+ }
1482
+ if (subtype === "task_started") {
1483
+ const id = claudeString(obj, "tool_use_id") ?? claudeString(obj, "task_id");
1484
+ if (!id) return null;
1485
+ const description = claudeString(obj, "description");
1486
+ const taskType = claudeString(obj, "task_type");
1487
+ const prompt = claudeString(obj, "prompt");
1488
+ return withEventParentId(
1489
+ {
1490
+ type: "tool_use",
1491
+ id,
1492
+ name: taskType || "Agent",
1493
+ input: {
1494
+ ...description ? { description } : {},
1495
+ ...prompt ? { prompt } : {},
1496
+ ...claudeString(obj, "task_id") ? { task_id: claudeString(obj, "task_id") } : {}
1497
+ }
1498
+ },
1499
+ parentId
1500
+ );
1501
+ }
1502
+ if (subtype === "task_notification") {
1503
+ const id = claudeString(obj, "tool_use_id") ?? claudeString(obj, "task_id") ?? parentId;
1504
+ if (!id) return null;
1505
+ const status = claudeString(obj, "status") ?? "working";
1506
+ const tools = typeof obj.tool_uses === "number" ? obj.tool_uses : void 0;
1507
+ const durationMs = typeof obj.duration_ms === "number" ? obj.duration_ms : void 0;
1508
+ const lastTool = claudeString(obj, "last_tool") ?? claudeString(obj, "current_tool") ?? claudeString(obj, "tool");
1509
+ const snapshot = [
1510
+ status,
1511
+ tools != null ? `${tools} tools` : null,
1512
+ durationMs != null ? `${Math.round(durationMs / 1e3)}s` : null,
1513
+ lastTool
1514
+ ].filter((bit) => Boolean(bit)).join(" \xB7 ");
1515
+ return [
1516
+ {
1517
+ type: "tool_use",
1518
+ id,
1519
+ name: claudeString(obj, "task_type") || "Agent",
1520
+ input: {
1521
+ live_status: status,
1522
+ ...tools != null ? { live_tool_uses: tools } : {},
1523
+ ...durationMs != null ? { live_duration_ms: durationMs } : {},
1524
+ ...lastTool ? { live_last_tool: lastTool } : {}
1525
+ }
1526
+ },
1527
+ withEventParentId(
1528
+ { type: "thinking", data: snapshot, replace: true },
1529
+ id
1530
+ )
1531
+ ];
1532
+ }
1533
+ if (subtype === "api_retry") {
1534
+ const attempt = obj.attempt;
1535
+ const max = obj.max_retries;
1536
+ const delay = obj.retry_delay_ms;
1537
+ return {
1538
+ type: "thinking",
1539
+ data: `API retry ${attempt ?? "?"}/${max ?? "?"}${typeof delay === "number" ? ` (wait ${delay}ms)` : ""}`
1540
+ };
1541
+ }
1542
+ return null;
1543
+ }
1277
1544
  var claudeAdapter = {
1278
1545
  kind: "claude",
1279
1546
  async detect() {
@@ -1328,7 +1595,7 @@ var claudeAdapter = {
1328
1595
  );
1329
1596
  }
1330
1597
  const mode = permissionMode(thread);
1331
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-XSUFEIAQ.js");
1598
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-CSWABOG5.js");
1332
1599
  const isOrchestrator = isOrchestratorThread2(thread);
1333
1600
  const injectedServers = await buildInjectedMcpServers({
1334
1601
  includeSideboard: true,
@@ -1396,7 +1663,12 @@ var claudeAdapter = {
1396
1663
  stdin: useStdin ? `${promptText}
1397
1664
  ` : void 0,
1398
1665
  // Nested Task/Agent thinking+text in stream-json (Claude Code 2.1.211+).
1399
- env: { CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1" }
1666
+ // Raise the -p background-agent wait so long TaskOutput polls are not
1667
+ // abandoned at Claude Code’s 10-minute default.
1668
+ env: {
1669
+ CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
1670
+ CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS)
1671
+ }
1400
1672
  };
1401
1673
  },
1402
1674
  parseEvent(line) {
@@ -1404,13 +1676,8 @@ var claudeAdapter = {
1404
1676
  if (!trimmed) return null;
1405
1677
  try {
1406
1678
  const obj = JSON.parse(trimmed);
1407
- if (obj.type === "system" && obj.subtype === "init") {
1408
- const sid = obj.session_id;
1409
- if (typeof sid === "string") return { type: "session_id", data: sid };
1410
- return null;
1411
- }
1412
- if (obj.type === "system" && typeof obj.session_id === "string") {
1413
- return { type: "session_id", data: obj.session_id };
1679
+ if (obj.type === "system") {
1680
+ return eventsFromClaudeSystem(obj);
1414
1681
  }
1415
1682
  if (obj.type === "assistant" || obj.type === "user") {
1416
1683
  const parentId = claudeParentToolUseId(obj);
@@ -1791,13 +2058,22 @@ var codexAdapter = {
1791
2058
  const events = [
1792
2059
  { type: "tool_use", id: item.id, name: "Bash", input }
1793
2060
  ];
1794
- if (type === "item.completed" || item.status === "completed" || item.status === "failed") {
2061
+ const finished = type === "item.completed" || item.status === "completed" || item.status === "failed";
2062
+ const output = typeof item.aggregated_output === "string" && item.aggregated_output ? item.aggregated_output : void 0;
2063
+ if (finished) {
1795
2064
  events.push({
1796
2065
  type: "tool_result",
1797
2066
  id: item.id,
1798
- content: item.aggregated_output,
2067
+ content: output,
1799
2068
  isError: item.status === "failed"
1800
2069
  });
2070
+ } else if (output) {
2071
+ events.push({
2072
+ type: "tool_result",
2073
+ id: item.id,
2074
+ content: output,
2075
+ partial: true
2076
+ });
1801
2077
  }
1802
2078
  return events.length === 1 ? events[0] : events;
1803
2079
  }
@@ -1840,9 +2116,6 @@ var codexAdapter = {
1840
2116
  if (sid && (type === "thread.started" || type === "session" || !type)) {
1841
2117
  return { type: "session_id", data: sid };
1842
2118
  }
1843
- if (sid && type.endsWith(".started")) {
1844
- return { type: "session_id", data: sid };
1845
- }
1846
2119
  if (type === "turn.completed" || type === "turn_completed") {
1847
2120
  const usage = usageFromCodex(obj.usage);
1848
2121
  return usage ? { type: "usage", data: usage, scope: "turn" } : null;
@@ -2246,7 +2519,8 @@ var opencodeAdapter = {
2246
2519
  return { type: "stderr", data: detail };
2247
2520
  }
2248
2521
  const sid = typeof obj.sessionID === "string" && obj.sessionID || typeof obj.sessionId === "string" && obj.sessionId || typeof obj.session_id === "string" && obj.session_id;
2249
- if (sid && (!obj.type || obj.type === "step_start" || obj.type === "session")) {
2522
+ const childSid = str2(obj.childSessionID) ?? str2(obj.childSessionId) ?? str2(obj.parentID) ?? str2(obj.parentId);
2523
+ if (sid && !childSid && (!obj.type || obj.type === "step_start" || obj.type === "session")) {
2250
2524
  return { type: "session_id", data: sid };
2251
2525
  }
2252
2526
  if (obj.type === "text") {
@@ -2266,13 +2540,16 @@ var opencodeAdapter = {
2266
2540
  );
2267
2541
  const events = [{ type: "tool_use", id, name, input }];
2268
2542
  const output = state?.output;
2269
- if (output != null || state?.status === "completed" || state?.status === "error") {
2543
+ const finished = state?.status === "completed" || state?.status === "error" || state?.status === "failed";
2544
+ const running = state?.status === "running" || state?.status === "in_progress" || state?.status === "pending";
2545
+ if (output != null || finished) {
2270
2546
  const content = typeof output === "string" ? output : output != null ? JSON.stringify(output) : formatUnknownDetail(state?.error) || void 0;
2271
2547
  events.push({
2272
2548
  type: "tool_result",
2273
2549
  id,
2274
2550
  content,
2275
- isError: state?.status === "error" || state?.status === "failed"
2551
+ isError: state?.status === "error" || state?.status === "failed",
2552
+ ...running && !finished ? { partial: true } : {}
2276
2553
  });
2277
2554
  }
2278
2555
  return events.length === 1 ? events[0] : events;
@@ -2307,14 +2584,17 @@ var opencodeAdapter = {
2307
2584
  withEventParentId({ type: "tool_use", id, name, input }, parentId)
2308
2585
  ];
2309
2586
  const output = state?.output ?? part.output;
2310
- if (output != null || state?.status === "completed" || state?.status === "error") {
2587
+ const finished = state?.status === "completed" || state?.status === "error" || state?.status === "failed";
2588
+ const running = state?.status === "running" || state?.status === "in_progress" || state?.status === "pending";
2589
+ if (output != null || finished) {
2311
2590
  nested.push(
2312
2591
  withEventParentId(
2313
2592
  {
2314
2593
  type: "tool_result",
2315
2594
  id,
2316
2595
  content: typeof output === "string" ? output : output != null ? JSON.stringify(output) : void 0,
2317
- isError: state?.status === "error" || state?.status === "failed"
2596
+ isError: state?.status === "error" || state?.status === "failed",
2597
+ ...running && !finished ? { partial: true } : {}
2318
2598
  },
2319
2599
  parentId
2320
2600
  )
@@ -2868,6 +3148,10 @@ export {
2868
3148
  toolDetail,
2869
3149
  toolDescription,
2870
3150
  isSubagentToolName,
3151
+ isPollWrapperToolName,
3152
+ isShellToolName,
3153
+ toolActivityLine,
3154
+ liveActivitySummary,
2871
3155
  messagePartParentId,
2872
3156
  withEventParentId,
2873
3157
  withEventsParentId,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-C4KHDW3U.js";
3
+ } from "./chunk-FZCIQYNQ.js";
4
4
  import {
5
5
  resolveThreadDefaults
6
6
  } from "./chunk-4NR5FL46.js";
@@ -61,7 +61,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
61
61
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
62
62
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
63
63
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
64
- "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
64
+ "- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply. wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success.",
65
65
  "- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
66
66
  "- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
67
67
  "Setup / run:",
@@ -36,6 +36,11 @@ function createAgentStreamCoalescer(emit, opts) {
36
36
  return;
37
37
  }
38
38
  if (!event.data) return;
39
+ if (event.type === "thinking" && event.replace) {
40
+ flush();
41
+ emit(event);
42
+ return;
43
+ }
39
44
  if (pending && pending.type === event.type && parentKey(pending) === parentKey(event)) {
40
45
  pending.data += event.data;
41
46
  } else {
@@ -96,6 +96,34 @@ function withExportedPath(command, pathValue) {
96
96
  return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
97
97
  }
98
98
 
99
+ // src/git/stale-lock.ts
100
+ import { existsSync as existsSync2, statSync, unlinkSync } from "fs";
101
+ import { join as join2 } from "path";
102
+ var STALE_INDEX_LOCK_MS = 2e4;
103
+ function isIndexLockError(text) {
104
+ return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text);
105
+ }
106
+ function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
107
+ const lockPath = join2(gitDir, "index.lock");
108
+ try {
109
+ if (!existsSync2(lockPath)) return null;
110
+ if (now - statSync(lockPath).mtimeMs < maxAgeMs) return null;
111
+ unlinkSync(lockPath);
112
+ return lockPath;
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+ function clearStaleIndexLocks(gitDirs, maxAgeMs = STALE_INDEX_LOCK_MS) {
118
+ const now = Date.now();
119
+ const removed = [];
120
+ for (const dir of new Set(gitDirs)) {
121
+ const cleared = clearStaleIndexLock(dir, maxAgeMs, now);
122
+ if (cleared) removed.push(cleared);
123
+ }
124
+ return removed;
125
+ }
126
+
99
127
  // src/git/run.ts
100
128
  async function run(file, args, opts) {
101
129
  ensureAgentPath();
@@ -123,6 +151,21 @@ async function run(file, args, opts) {
123
151
  throw err;
124
152
  }
125
153
  }
154
+ async function resolveGitDirsForLockRecovery(cwd, env = {}) {
155
+ const dirs = /* @__PURE__ */ new Set();
156
+ const [gitDir, commonDir] = await Promise.all([
157
+ run("git", ["rev-parse", "--absolute-git-dir"], { cwd, reject: false, env, timeoutMs: 5e3 }),
158
+ run("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
159
+ cwd,
160
+ reject: false,
161
+ env,
162
+ timeoutMs: 5e3
163
+ })
164
+ ]);
165
+ if (gitDir.exitCode === 0 && gitDir.stdout.trim()) dirs.add(gitDir.stdout.trim());
166
+ if (commonDir.exitCode === 0 && commonDir.stdout.trim()) dirs.add(commonDir.stdout.trim());
167
+ return [...dirs];
168
+ }
126
169
  async function git(args, cwd, opts) {
127
170
  const prefix = [];
128
171
  if (opts?.config) {
@@ -131,21 +174,32 @@ async function git(args, cwd, opts) {
131
174
  prefix.push("-c", `${key}=${value}`);
132
175
  }
133
176
  }
134
- return run("git", ["--no-pager", ...prefix, ...args], {
135
- cwd,
136
- reject: opts?.reject,
137
- timeoutMs: opts?.timeoutMs,
177
+ const gitArgs = ["--no-pager", ...prefix, ...args];
178
+ const env = {
138
179
  // Never block forever on a credential/SSH prompt inside MCP / Electron.
139
- env: {
140
- GIT_TERMINAL_PROMPT: "0",
141
- GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
142
- SSH_ASKPASS: process.env.SSH_ASKPASS || "echo",
143
- GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
144
- GCM_INTERACTIVE: "never",
145
- GH_PROMPT_DISABLED: "1",
146
- ...opts?.env
180
+ GIT_TERMINAL_PROMPT: "0",
181
+ GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
182
+ SSH_ASKPASS: process.env.SSH_ASKPASS || "echo",
183
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
184
+ GCM_INTERACTIVE: "never",
185
+ GH_PROMPT_DISABLED: "1",
186
+ ...opts?.env
187
+ };
188
+ let result = await run("git", gitArgs, { cwd, reject: false, timeoutMs: opts?.timeoutMs, env });
189
+ if (result.exitCode !== 0 && isIndexLockError(result.stderr)) {
190
+ const gitDirs = await resolveGitDirsForLockRecovery(cwd, env);
191
+ const cleared = clearStaleIndexLocks(gitDirs);
192
+ if (cleared.length > 0) {
193
+ result = await run("git", gitArgs, { cwd, reject: false, timeoutMs: opts?.timeoutMs, env });
147
194
  }
148
- });
195
+ }
196
+ if ((opts?.reject ?? true) && result.exitCode !== 0) {
197
+ throw new Error(
198
+ `Command failed with exit code ${result.exitCode}: git ${gitArgs.join(" ")}
199
+ ${result.stderr}`
200
+ );
201
+ }
202
+ return result;
149
203
  }
150
204
  async function gh(args, cwd, opts) {
151
205
  return run("gh", args, {
@@ -173,7 +227,9 @@ export {
173
227
  posixShellSingleQuote,
174
228
  resolveCommandBinarySync,
175
229
  withExportedPath,
230
+ clearStaleIndexLocks,
176
231
  run,
232
+ resolveGitDirsForLockRecovery,
177
233
  git,
178
234
  gh,
179
235
  resolveGhAuthToken