@sideboard-ai/core 0.1.109 → 0.1.111

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 +90 -15
  2. package/dist/agents/cursor-runner.js +37 -11
  3. package/dist/{agents-XB332VUJ.js → agents-GH3FWDW2.js} +6 -6
  4. package/dist/{agents-YIMHDI46.js → agents-NN22A4G5.js} +7 -7
  5. package/dist/{app-settings-EBCVMFF6.js → app-settings-5XAGNDX7.js} +3 -1
  6. package/dist/{app-settings-IYSSVZHH.js → app-settings-J4LUWIRN.js} +3 -1
  7. package/dist/{chunk-WD2TARQS.js → chunk-363Z34PY.js} +72 -12
  8. package/dist/{chunk-756EO4GK.js → chunk-4EWPKYOU.js} +4 -4
  9. package/dist/{chunk-4LKD3PGO.js → chunk-4NR5FL46.js} +10 -0
  10. package/dist/{chunk-FBV6NK62.js → chunk-7KWYXGIU.js} +2 -2
  11. package/dist/{chunk-KGSVLZV6.js → chunk-A4VZXJEJ.js} +2 -0
  12. package/dist/{chunk-VRTKGKUW.js → chunk-AROMOP3C.js} +2 -2
  13. package/dist/{chunk-EW7COXYE.js → chunk-C4KHDW3U.js} +2 -2
  14. package/dist/{chunk-Q6B3NRCT.js → chunk-DMJKOFTO.js} +159 -288
  15. package/dist/{chunk-LTPX5N6K.js → chunk-JTQQPJAU.js} +167 -277
  16. package/dist/{chunk-I2OJ2YSP.js → chunk-KQBI5HNT.js} +2 -2
  17. package/dist/{chunk-AY2EQI2P.js → chunk-KVFNTWFG.js} +506 -60
  18. package/dist/{chunk-P3BQ5DOL.js → chunk-KYOTBZ6S.js} +2 -0
  19. package/dist/{chunk-KKHDPV45.js → chunk-NC3U42ZP.js} +473 -37
  20. package/dist/{chunk-NE4TOOKS.js → chunk-SGEVS5SY.js} +10 -0
  21. package/dist/{chunk-TROJ3PVH.js → chunk-VOD3HFLP.js} +4 -4
  22. package/dist/{chunk-MMI4RJ5I.js → chunk-WIHKHR5R.js} +14 -3
  23. package/dist/{chunk-OQDIYVDD.js → chunk-YFAXVUY2.js} +2 -2
  24. package/dist/{chunk-JVIW55KT.js → chunk-YXDR43ZC.js} +2 -2
  25. package/dist/{coordinator-prompt-JKOU6BWV.js → coordinator-prompt-AR66L3N4.js} +4 -4
  26. package/dist/{coordinator-prompt-V66BYTUV.js → coordinator-prompt-BHMLWL64.js} +4 -4
  27. package/dist/{global-workspace-WBQWQQQY.js → global-workspace-SKFODUQQ.js} +5 -5
  28. package/dist/{global-workspace-NCTBE7G7.js → global-workspace-XSUFEIAQ.js} +5 -5
  29. package/dist/index.cjs +880 -512
  30. package/dist/index.d.cts +51 -3
  31. package/dist/index.d.ts +51 -3
  32. package/dist/index.js +44 -23
  33. package/dist/mcp/run-stdio.cjs +858 -511
  34. package/dist/mcp/run-stdio.js +17 -12
  35. package/dist/{orchestrator-JVGVPKLI.js → orchestrator-4T2SXDZ7.js} +8 -8
  36. package/dist/{orchestrator-6W7EKSPO.js → orchestrator-EP57AB5W.js} +10 -10
  37. package/dist/{thread-store-DQJGDKIJ.js → thread-store-LPTBVW5C.js} +1 -1
  38. package/dist/{thread-store-4OUEQ2DB.js → thread-store-OEALWU7Y.js} +1 -1
  39. package/dist/{workspaces-SUBEDSGB.js → workspaces-HV3J4TTW.js} +6 -6
  40. package/dist/{workspaces-I3554R3F.js → workspaces-XAQVKTLO.js} +6 -6
  41. package/dist/{worktree-7H6HB6GW.js → worktree-N2EV24EE.js} +3 -3
  42. package/dist/{worktree-2UWO7VEK.js → worktree-XFJED3VU.js} +3 -3
  43. package/package.json +1 -1
@@ -702,6 +702,7 @@ function normalizeThread(raw) {
702
702
  prTitle: raw.prTitle ?? null,
703
703
  prState: raw.prState ?? null,
704
704
  skipAutoArchiveOnMerge: Boolean(raw.skipAutoArchiveOnMerge),
705
+ cowboy: Boolean(raw.cowboy),
705
706
  stackId: raw.stackId ?? null,
706
707
  stackLayer: raw.stackLayer ?? null,
707
708
  userSetTitle: Boolean(raw.userSetTitle),
@@ -730,6 +731,7 @@ function createEmptyThread(partial) {
730
731
  prTitle: partial.prTitle ?? null,
731
732
  prState: partial.prState ?? null,
732
733
  skipAutoArchiveOnMerge: partial.skipAutoArchiveOnMerge ?? false,
734
+ cowboy: Boolean(partial.cowboy),
733
735
  stackId: partial.stackId ?? null,
734
736
  stackLayer: partial.stackLayer ?? null,
735
737
  userSetTitle: partial.userSetTitle ?? false,
@@ -1417,7 +1419,7 @@ function extractJsonErrorMessage(obj) {
1417
1419
  }
1418
1420
  function isPinnedStderrLine(line) {
1419
1421
  if (/^\s*at\s/.test(line)) return false;
1420
- return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:/i.test(
1422
+ return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:|FATAL ERROR|heap out of memory|javascript heap|OOMErrorHandler|FatalProcessOutOfMemory/i.test(
1421
1423
  line
1422
1424
  );
1423
1425
  }
@@ -1440,12 +1442,17 @@ function looksLikeMinifiedJsDump(line) {
1440
1442
  function looksLikeNestedElectronCrash(line) {
1441
1443
  return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
1442
1444
  }
1443
- function looksLikeHomebrewLibuvCrash(line) {
1444
- const uvRun = /uv_run/i.test(line);
1445
- const spin = /SpinEventLoopInternal/i.test(line);
1446
- const homebrewUv = /Cellar\/libuv|libuv\.\d\.dylib/i.test(line);
1447
- const homebrewNode = /Cellar\/node\//i.test(line);
1448
- return uvRun && (homebrewUv || spin || homebrewNode) || spin && (homebrewUv || homebrewNode);
1445
+ function looksLikeNativeEventLoopCrash(text4) {
1446
+ return /uv_run|uv__io_poll|SpinEventLoopInternal/i.test(text4);
1447
+ }
1448
+ function looksLikeV8Oom(text4) {
1449
+ return /javascript heap|reached heap limit|OOMErrorHandler|FatalProcessOutOfMemory|Allocation failed - JavaScript heap/i.test(
1450
+ text4
1451
+ );
1452
+ }
1453
+ function looksLikeHomebrewLibuvCrash(text4) {
1454
+ if (!looksLikeNativeEventLoopCrash(text4)) return false;
1455
+ return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text4);
1449
1456
  }
1450
1457
  function clipStderr(text4, maxChars) {
1451
1458
  const trimmed = text4.trim();
@@ -1459,7 +1466,12 @@ function summarizeTurnStderr(tail, maxChars = 500) {
1459
1466
  const cursorRunFailed = [...tail].reverse().find((line) => /^cursor run failed\b/i.test(line.trim()));
1460
1467
  if (cursorRunFailed) return clipStderr(cursorRunFailed, maxChars);
1461
1468
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
1462
- if (tail.some(looksLikeHomebrewLibuvCrash)) return HOMEBREW_LIBUV_SUMMARY;
1469
+ const blob = tail.join("\n");
1470
+ if (looksLikeV8Oom(blob)) return V8_OOM_SUMMARY;
1471
+ if (looksLikeHomebrewLibuvCrash(blob)) return HOMEBREW_LIBUV_SUMMARY;
1472
+ if (looksLikeNativeEventLoopCrash(blob)) {
1473
+ return BUNDLED_NODE_CRASH_SUMMARY;
1474
+ }
1463
1475
  if (tail.some(
1464
1476
  (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
1465
1477
  )) {
@@ -1485,10 +1497,11 @@ function looksLikeInvalidAgentSession(text4) {
1485
1497
  function looksLikeRetryableRunnerCrash(text4) {
1486
1498
  if (looksLikeAgentFailureMessage(text4)) return false;
1487
1499
  if (looksLikeInvalidAgentSession(text4)) return false;
1500
+ if (looksLikeV8Oom(text4)) return false;
1488
1501
  const lower = text4.trim().toLowerCase();
1489
1502
  if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
1490
1503
  if (!lower) return true;
1491
- return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
1504
+ return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
1492
1505
  lower
1493
1506
  );
1494
1507
  }
@@ -1540,9 +1553,15 @@ function humanizeAgentFailDetail(detail) {
1540
1553
  if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
1541
1554
  return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
1542
1555
  }
1543
- if (/homebrew node \+ shared libuv|uv_run|spineventloopinternal/i.test(lower)) {
1556
+ if (looksLikeV8Oom(raw) || /javascript heap out of memory/i.test(lower)) {
1557
+ return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
1558
+ }
1559
+ if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
1544
1560
  return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
1545
1561
  }
1562
+ if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
1563
+ return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
1564
+ }
1546
1565
  if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
1547
1566
  return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
1548
1567
  }
@@ -1572,13 +1591,15 @@ function formatTurnExitError(exitCode, stderrSummary) {
1572
1591
  if (looksLikeAgentFailureMessage(raw)) return detail;
1573
1592
  return `exit ${code}: ${detail}`;
1574
1593
  }
1575
- var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, MINIFIED_DUMP_SUMMARY;
1594
+ var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, BUNDLED_NODE_CRASH_SUMMARY, V8_OOM_SUMMARY, MINIFIED_DUMP_SUMMARY;
1576
1595
  var init_error_detail = __esm({
1577
1596
  "src/agents/error-detail.ts"() {
1578
1597
  "use strict";
1579
1598
  NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
1580
1599
  NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
1581
1600
  HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
1601
+ BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
1602
+ V8_OOM_SUMMARY = "Cursor runner ran out of memory (JavaScript heap). Retry; if it keeps happening, exclude large files from the project folder or start a new chat.";
1582
1603
  MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
1583
1604
  }
1584
1605
  });
@@ -2559,6 +2580,7 @@ __export(app_settings_exports, {
2559
2580
  childEnvWithAppSettings: () => childEnvWithAppSettings,
2560
2581
  claudeChromeEnabled: () => claudeChromeEnabled,
2561
2582
  claudeUserSettingsPath: () => claudeUserSettingsPath,
2583
+ cowboyModeEnabled: () => cowboyModeEnabled,
2562
2584
  deleteBranchOnPurgeEnabled: () => deleteBranchOnPurgeEnabled,
2563
2585
  disconnectLinearConnection: () => disconnectLinearConnection,
2564
2586
  ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
@@ -2797,6 +2819,9 @@ function normalizeAdvanced(raw) {
2797
2819
  if (typeof source.deleteBranchOnPurge === "boolean") {
2798
2820
  out.deleteBranchOnPurge = source.deleteBranchOnPurge;
2799
2821
  }
2822
+ if (typeof source.cowboyMode === "boolean") {
2823
+ out.cowboyMode = source.cowboyMode;
2824
+ }
2800
2825
  if (typeof source.autoArchiveOnMerge === "boolean") {
2801
2826
  out.autoArchiveOnMerge = source.autoArchiveOnMerge;
2802
2827
  }
@@ -3321,6 +3346,9 @@ function updateAdvancedSettings(patch) {
3321
3346
  if (typeof patch.deleteBranchOnPurge === "boolean") {
3322
3347
  advanced.deleteBranchOnPurge = patch.deleteBranchOnPurge;
3323
3348
  }
3349
+ if (typeof patch.cowboyMode === "boolean") {
3350
+ advanced.cowboyMode = patch.cowboyMode;
3351
+ }
3324
3352
  if (typeof patch.autoArchiveOnMerge === "boolean") {
3325
3353
  advanced.autoArchiveOnMerge = patch.autoArchiveOnMerge;
3326
3354
  }
@@ -3371,6 +3399,9 @@ function caffeinateWhileCloudConnectEnabled(settings = loadAppSettings()) {
3371
3399
  function deleteBranchOnPurgeEnabled(settings = loadAppSettings()) {
3372
3400
  return Boolean(settings.advanced.deleteBranchOnPurge);
3373
3401
  }
3402
+ function cowboyModeEnabled(settings = loadAppSettings()) {
3403
+ return Boolean(settings.advanced.cowboyMode);
3404
+ }
3374
3405
  function autoArchiveOnMergeEnabled(settings = loadAppSettings()) {
3375
3406
  return Boolean(settings.advanced.autoArchiveOnMerge);
3376
3407
  }
@@ -6675,6 +6706,296 @@ var init_claude_mcp = __esm({
6675
6706
  }
6676
6707
  });
6677
6708
 
6709
+ // src/agents/message-parts.ts
6710
+ function asRecord(input) {
6711
+ if (input && typeof input === "object" && !Array.isArray(input)) {
6712
+ return input;
6713
+ }
6714
+ return void 0;
6715
+ }
6716
+ function str2(v) {
6717
+ return typeof v === "string" && v.trim() ? v : void 0;
6718
+ }
6719
+ function toolDetail(name, input) {
6720
+ if (!input) return void 0;
6721
+ const command = str2(input.command) ?? str2(input.cmd);
6722
+ if (command) return command;
6723
+ const path = str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
6724
+ if (path) return path;
6725
+ const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
6726
+ if (pattern) return pattern;
6727
+ const query = str2(input.query) ?? str2(input.prompt);
6728
+ if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
6729
+ try {
6730
+ const raw = JSON.stringify(input);
6731
+ return raw.length > 80 ? `${raw.slice(0, 77)}\u2026` : raw;
6732
+ } catch {
6733
+ return name;
6734
+ }
6735
+ }
6736
+ function toolDescription(name, input) {
6737
+ const n = name.replace(/^mcp__/, "").replace(/__/g, " \xB7 ");
6738
+ if (/^get_record_types$|recordTypes/i.test(name)) return "List record types";
6739
+ if (/connectedAgentRequest/i.test(name)) {
6740
+ return str2(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
6741
+ }
6742
+ if (/present_artifact$/i.test(name)) {
6743
+ return str2(input?.title) ? `Present ${str2(input?.title)}` : "Present artifact";
6744
+ }
6745
+ if (/present_plan$/i.test(name)) {
6746
+ return str2(input?.title) ? `Plan ${str2(input?.title)}` : "Present plan";
6747
+ }
6748
+ if (/present_schema$/i.test(name)) {
6749
+ return str2(input?.title) ? `Schema ${str2(input?.title)}` : "Present schema";
6750
+ }
6751
+ if (/present_files$/i.test(name)) {
6752
+ return str2(input?.title) ? `Files ${str2(input?.title)}` : "Present files";
6753
+ }
6754
+ if (isSubagentToolName(name)) {
6755
+ const desc = str2(input?.description);
6756
+ const sub = asRecord(input?.subagentType);
6757
+ const kind = str2(sub?.name) ?? str2(sub?.kind) ?? str2(input?.subagent_type) ?? str2(input?.subagentType);
6758
+ if (/^spawn_agent$/i.test(name)) {
6759
+ return str2(input?.prompt) ?? desc ?? "Subagent";
6760
+ }
6761
+ if (/connectedAgentRequest/i.test(name)) {
6762
+ return str2(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
6763
+ }
6764
+ if (desc && kind) return `${kind}: ${desc}`;
6765
+ if (desc) return desc;
6766
+ return "Subagent";
6767
+ }
6768
+ if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
6769
+ return str2(input?.title) ? `Artifact ${str2(input?.title)}` : "Artifact";
6770
+ }
6771
+ if (!input) return n;
6772
+ if (/bash|shell|terminal/i.test(name) && str2(input.command)) {
6773
+ const cmd = str2(input.command);
6774
+ if (/git\s+fetch/i.test(cmd)) return "Fetch latest from origin and check status";
6775
+ if (/git\s+status/i.test(cmd)) return "Check git status";
6776
+ if (/git\s+log/i.test(cmd)) return "Inspect recent commits";
6777
+ if (/git\s+branch/i.test(cmd)) return "List branches";
6778
+ if (/grep|rg\b/i.test(cmd)) return "Search repository";
6779
+ return "Run shell command";
6780
+ }
6781
+ if (/edit|write|apply/i.test(name)) {
6782
+ const path = str2(input.file_path) ?? str2(input.path);
6783
+ return path ? `Edit ${path.split("/").pop()}` : "Edit file";
6784
+ }
6785
+ if (/read/i.test(name)) {
6786
+ const path = str2(input.file_path) ?? str2(input.path);
6787
+ return path ? `Read ${path.split("/").pop()}` : "Read file";
6788
+ }
6789
+ if (/grep/i.test(name)) return "Search files";
6790
+ if (/glob/i.test(name)) return "Find files";
6791
+ return n;
6792
+ }
6793
+ function isSubagentToolName(name) {
6794
+ const n = (name ?? "").trim();
6795
+ if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
6796
+ return /connectedAgentRequest/i.test(n);
6797
+ }
6798
+ function messagePartParentId(part) {
6799
+ if ("parentId" in part && typeof part.parentId === "string" && part.parentId.trim()) {
6800
+ return part.parentId;
6801
+ }
6802
+ return void 0;
6803
+ }
6804
+ function sameParentId(a, b) {
6805
+ return (a ?? "") === (b ?? "");
6806
+ }
6807
+ function withEventParentId(event, parentId) {
6808
+ if (!parentId) return event;
6809
+ if (event.type === "stdout" || event.type === "thinking" || event.type === "tool_use" || event.type === "tool_result") {
6810
+ return { ...event, parentId: event.parentId ?? parentId };
6811
+ }
6812
+ return event;
6813
+ }
6814
+ function toolFilePath(input) {
6815
+ if (!input) return void 0;
6816
+ return str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
6817
+ }
6818
+ function countLines(text4) {
6819
+ if (!text4) return 0;
6820
+ return text4.split("\n").length;
6821
+ }
6822
+ function diffFromInput(input) {
6823
+ if (!input) return {};
6824
+ const oldS = str2(input.old_string) ?? str2(input.oldString);
6825
+ const newS = str2(input.new_string) ?? str2(input.newString) ?? str2(input.content);
6826
+ if (oldS != null || newS != null) {
6827
+ return {
6828
+ additions: countLines(newS),
6829
+ deletions: countLines(oldS)
6830
+ };
6831
+ }
6832
+ return {};
6833
+ }
6834
+ function parseDiffStat(result) {
6835
+ if (!result) return {};
6836
+ const paired = result.match(/\+(\d+)\s+-(\d+)/);
6837
+ if (paired) {
6838
+ return {
6839
+ additions: Number(paired[1]),
6840
+ deletions: Number(paired[2])
6841
+ };
6842
+ }
6843
+ const verbose = result.match(
6844
+ /(\d+)\s+insertions?(?:,\s*(\d+)\s+deletions?)?/i
6845
+ );
6846
+ if (verbose) {
6847
+ return {
6848
+ additions: Number(verbose[1]),
6849
+ deletions: verbose[2] != null ? Number(verbose[2]) : void 0
6850
+ };
6851
+ }
6852
+ return {};
6853
+ }
6854
+ function applyAgentEvent(parts, event) {
6855
+ if (event.type === "stdout") {
6856
+ const data = event.data;
6857
+ if (!data) return parts;
6858
+ const next = [...parts];
6859
+ const last = next[next.length - 1];
6860
+ if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
6861
+ next[next.length - 1] = {
6862
+ type: "text",
6863
+ text: last.text + data,
6864
+ ...event.parentId ? { parentId: event.parentId } : {}
6865
+ };
6866
+ } else {
6867
+ next.push({
6868
+ type: "text",
6869
+ text: data,
6870
+ ...event.parentId ? { parentId: event.parentId } : {}
6871
+ });
6872
+ }
6873
+ return next;
6874
+ }
6875
+ if (event.type === "thinking") {
6876
+ const data = event.data;
6877
+ if (!data) return parts;
6878
+ const next = [...parts];
6879
+ const last = next[next.length - 1];
6880
+ if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
6881
+ next[next.length - 1] = {
6882
+ type: "thinking",
6883
+ text: last.text + data,
6884
+ ...event.parentId ? { parentId: event.parentId } : {}
6885
+ };
6886
+ } else {
6887
+ next.push({
6888
+ type: "thinking",
6889
+ text: data,
6890
+ ...event.parentId ? { parentId: event.parentId } : {}
6891
+ });
6892
+ }
6893
+ return next;
6894
+ }
6895
+ if (event.type === "tool_use") {
6896
+ const input = asRecord(event.input);
6897
+ const diff = diffFromInput(input);
6898
+ const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
6899
+ if (existing >= 0) {
6900
+ const prev = parts[existing];
6901
+ const next = [...parts];
6902
+ const mergedInput = input && Object.keys(input).length > 0 ? input : prev.input ?? input;
6903
+ next[existing] = {
6904
+ ...prev,
6905
+ name: event.name || prev.name,
6906
+ input: mergedInput,
6907
+ description: toolDescription(event.name || prev.name, mergedInput),
6908
+ detail: toolDetail(event.name || prev.name, mergedInput) ?? prev.detail,
6909
+ filePath: toolFilePath(mergedInput) ?? prev.filePath,
6910
+ additions: diff.additions ?? prev.additions,
6911
+ deletions: diff.deletions ?? prev.deletions,
6912
+ parentId: event.parentId ?? prev.parentId
6913
+ };
6914
+ return next;
6915
+ }
6916
+ return [
6917
+ ...parts,
6918
+ {
6919
+ type: "tool",
6920
+ id: event.id,
6921
+ name: event.name,
6922
+ input,
6923
+ description: toolDescription(event.name, input),
6924
+ detail: toolDetail(event.name, input),
6925
+ status: "running",
6926
+ filePath: toolFilePath(input),
6927
+ ...event.parentId ? { parentId: event.parentId } : {},
6928
+ ...diff
6929
+ }
6930
+ ];
6931
+ }
6932
+ if (event.type === "tool_result") {
6933
+ const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
6934
+ const fromResult = parseDiffStat(event.content);
6935
+ if (existing < 0) {
6936
+ return [
6937
+ ...parts,
6938
+ {
6939
+ type: "tool",
6940
+ id: event.id,
6941
+ name: "tool",
6942
+ description: "tool",
6943
+ status: event.isError ? "error" : "done",
6944
+ result: event.content,
6945
+ ...event.parentId ? { parentId: event.parentId } : {},
6946
+ ...fromResult.additions != null ? { additions: fromResult.additions } : {},
6947
+ ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
6948
+ }
6949
+ ];
6950
+ }
6951
+ return parts.map((p, i) => {
6952
+ if (i !== existing || p.type !== "tool") return p;
6953
+ return {
6954
+ ...p,
6955
+ status: event.isError ? "error" : "done",
6956
+ result: event.content,
6957
+ ...fromResult.additions != null ? { additions: fromResult.additions } : {},
6958
+ ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
6959
+ };
6960
+ });
6961
+ }
6962
+ return parts;
6963
+ }
6964
+ function partsToAssistantText(parts) {
6965
+ return parts.filter(
6966
+ (p) => p.type === "text" && !messagePartParentId(p)
6967
+ ).map((p) => p.text).join("").trim();
6968
+ }
6969
+ function stripBrightsyNdjsonNoise(text4) {
6970
+ if (!text4 || !text4.includes('"type"')) return text4;
6971
+ let out = text4;
6972
+ out = out.replace(
6973
+ /\{"type":"(?:tool_use|tool_result|tool|thinking|usage|done|error)"[\s\S]*?\}\s*(?=\{"type":"|$|(?=[A-Za-z*#]))/g,
6974
+ ""
6975
+ );
6976
+ out = out.replace(/\{"type":"(?:tool_use|tool_result|tool)"[\s\S]*$/g, "");
6977
+ return out.trim();
6978
+ }
6979
+ function isBrightsyNdjsonLine(line) {
6980
+ const t = line.trim();
6981
+ if (!t.startsWith("{")) return false;
6982
+ return /"type"\s*:\s*"(tool_use|tool_result|tool|thinking|usage|done|error|text)"/.test(t);
6983
+ }
6984
+ function finalizeParts(parts) {
6985
+ return parts.map(
6986
+ (p) => p.type === "tool" && p.status === "running" ? { ...p, status: "done" } : p
6987
+ );
6988
+ }
6989
+ function normalizeParseResult(parsed) {
6990
+ if (!parsed) return [];
6991
+ return Array.isArray(parsed) ? parsed : [parsed];
6992
+ }
6993
+ var init_message_parts = __esm({
6994
+ "src/agents/message-parts.ts"() {
6995
+ "use strict";
6996
+ }
6997
+ });
6998
+
6678
6999
  // src/mcp/profile.ts
6679
7000
  function sideboardMcpProfile(env = process.env) {
6680
7001
  return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
@@ -7300,41 +7621,58 @@ function claudeResultErrorDetail(obj) {
7300
7621
  }
7301
7622
  return "Claude turn failed";
7302
7623
  }
7303
- function eventsFromContentBlocks(blocks) {
7624
+ function eventsFromContentBlocks(blocks, parentId) {
7304
7625
  if (!blocks?.length) return [];
7305
7626
  const out = [];
7306
7627
  for (const block of blocks) {
7307
7628
  if (!block?.type) continue;
7308
7629
  if (block.type === "text" && block.text) {
7309
- out.push({ type: "stdout", data: block.text });
7630
+ out.push(withEventParentId({ type: "stdout", data: block.text }, parentId));
7310
7631
  continue;
7311
7632
  }
7312
7633
  if ((block.type === "thinking" || block.type === "redacted_thinking") && block.thinking) {
7313
- out.push({ type: "thinking", data: block.thinking });
7634
+ out.push(withEventParentId({ type: "thinking", data: block.thinking }, parentId));
7314
7635
  continue;
7315
7636
  }
7316
7637
  if (block.type === "tool_use" && block.id && block.name) {
7317
- out.push({
7318
- type: "tool_use",
7319
- id: block.id,
7320
- name: block.name,
7321
- input: block.input
7322
- });
7638
+ out.push(
7639
+ withEventParentId(
7640
+ {
7641
+ type: "tool_use",
7642
+ id: block.id,
7643
+ name: block.name,
7644
+ input: block.input
7645
+ },
7646
+ parentId
7647
+ )
7648
+ );
7323
7649
  continue;
7324
7650
  }
7325
7651
  if (block.type === "tool_result" && block.tool_use_id) {
7326
7652
  const content = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map(
7327
7653
  (c) => typeof c === "string" ? c : c && typeof c === "object" && "text" in c ? String(c.text ?? "") : ""
7328
7654
  ).join("") : block.content != null ? JSON.stringify(block.content) : void 0;
7329
- out.push({
7330
- type: "tool_result",
7331
- id: block.tool_use_id,
7332
- content,
7333
- isError: Boolean(block.is_error)
7334
- });
7335
- }
7336
- }
7337
- return out;
7655
+ out.push(
7656
+ withEventParentId(
7657
+ {
7658
+ type: "tool_result",
7659
+ id: block.tool_use_id,
7660
+ content,
7661
+ isError: Boolean(block.is_error)
7662
+ },
7663
+ parentId
7664
+ )
7665
+ );
7666
+ }
7667
+ }
7668
+ return out;
7669
+ }
7670
+ function claudeParentToolUseId(obj) {
7671
+ const nested = obj.event && typeof obj.event === "object" && !Array.isArray(obj.event) ? obj.event : void 0;
7672
+ for (const id of [obj.parent_tool_use_id, nested?.parent_tool_use_id]) {
7673
+ if (typeof id === "string" && id.trim()) return id.trim();
7674
+ }
7675
+ return void 0;
7338
7676
  }
7339
7677
  function parseIssuesJson(raw) {
7340
7678
  const text4 = raw.trim();
@@ -7370,6 +7708,7 @@ var init_claude = __esm({
7370
7708
  init_app_settings();
7371
7709
  init_claude_mcp();
7372
7710
  init_error_detail();
7711
+ init_message_parts();
7373
7712
  init_injected_mcp();
7374
7713
  init_turn_input();
7375
7714
  init_types();
@@ -7381,7 +7720,10 @@ var init_claude = __esm({
7381
7720
  "Glob",
7382
7721
  "Grep",
7383
7722
  "WebFetch",
7384
- "WebSearch"
7723
+ "WebSearch",
7724
+ // Subagents (Claude Code v2.1.63 renamed Task → Agent; allow both).
7725
+ "Task",
7726
+ "Agent"
7385
7727
  ];
7386
7728
  CLAUDE_CHROME_ALLOWED_TOOLS = [
7387
7729
  "mcp__claude-in-chrome",
@@ -7509,7 +7851,9 @@ var init_claude = __esm({
7509
7851
  args,
7510
7852
  cwd: thread.worktreePath,
7511
7853
  stdin: useStdin ? `${promptText}
7512
- ` : void 0
7854
+ ` : void 0,
7855
+ // Nested Task/Agent thinking+text in stream-json (Claude Code 2.1.211+).
7856
+ env: { CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1" }
7513
7857
  };
7514
7858
  },
7515
7859
  parseEvent(line) {
@@ -7526,8 +7870,9 @@ var init_claude = __esm({
7526
7870
  return { type: "session_id", data: obj.session_id };
7527
7871
  }
7528
7872
  if (obj.type === "assistant" || obj.type === "user") {
7873
+ const parentId = claudeParentToolUseId(obj);
7529
7874
  const message = obj.message;
7530
- const events = eventsFromContentBlocks(message?.content);
7875
+ const events = eventsFromContentBlocks(message?.content, parentId);
7531
7876
  if (obj.type === "assistant") {
7532
7877
  const usage = usageFromClaude(message?.usage);
7533
7878
  if (usage) events.push({ type: "usage", data: usage, scope: "request" });
@@ -7536,34 +7881,45 @@ var init_claude = __esm({
7536
7881
  return events.length === 1 ? events[0] : events;
7537
7882
  }
7538
7883
  if (obj.type === "stream_event") {
7884
+ const parentId = claudeParentToolUseId(obj);
7539
7885
  const event = obj.event;
7540
7886
  if (!event) return null;
7541
7887
  if (event.type === "content_block_start" && event.content_block) {
7542
7888
  const block = event.content_block;
7543
7889
  if (block.type === "tool_use" && block.id && block.name) {
7544
- return {
7545
- type: "tool_use",
7546
- id: block.id,
7547
- name: block.name,
7548
- input: block.input
7549
- };
7890
+ return withEventParentId(
7891
+ {
7892
+ type: "tool_use",
7893
+ id: block.id,
7894
+ name: block.name,
7895
+ input: block.input
7896
+ },
7897
+ parentId
7898
+ );
7550
7899
  }
7551
7900
  if (block.type === "thinking" && block.thinking) {
7552
- return { type: "thinking", data: block.thinking };
7901
+ return withEventParentId({ type: "thinking", data: block.thinking }, parentId);
7553
7902
  }
7554
7903
  return null;
7555
7904
  }
7556
7905
  if (event.type === "content_block_delta" && event.delta) {
7557
- if (event.delta.text) return { type: "stdout", data: event.delta.text };
7558
- if (event.delta.thinking) return { type: "thinking", data: event.delta.thinking };
7906
+ if (event.delta.text) {
7907
+ return withEventParentId({ type: "stdout", data: event.delta.text }, parentId);
7908
+ }
7909
+ if (event.delta.thinking) {
7910
+ return withEventParentId({ type: "thinking", data: event.delta.thinking }, parentId);
7911
+ }
7559
7912
  return null;
7560
7913
  }
7561
7914
  return null;
7562
7915
  }
7563
7916
  if (obj.type === "content_block_delta") {
7917
+ const parentId = claudeParentToolUseId(obj);
7564
7918
  const delta = obj.delta;
7565
- if (delta?.text) return { type: "stdout", data: delta.text };
7566
- if (delta?.thinking) return { type: "thinking", data: delta.thinking };
7919
+ if (delta?.text) return withEventParentId({ type: "stdout", data: delta.text }, parentId);
7920
+ if (delta?.thinking) {
7921
+ return withEventParentId({ type: "thinking", data: delta.thinking }, parentId);
7922
+ }
7567
7923
  return null;
7568
7924
  }
7569
7925
  if (obj.type === "result") {
@@ -7696,7 +8052,7 @@ function unwrapCodexMcpResult(result) {
7696
8052
  return String(result);
7697
8053
  }
7698
8054
  }
7699
- function asRecord(value) {
8055
+ function asRecord2(value) {
7700
8056
  if (value && typeof value === "object" && !Array.isArray(value)) {
7701
8057
  return value;
7702
8058
  }
@@ -7861,7 +8217,7 @@ var init_codex = __esm({
7861
8217
  }
7862
8218
  if (itemType === "mcp_tool_call" && item.id && item.server && item.tool) {
7863
8219
  const name = `mcp__${item.server}__${item.tool}`;
7864
- const input = asRecord(item.arguments);
8220
+ const input = asRecord2(item.arguments);
7865
8221
  const events = [
7866
8222
  { type: "tool_use", id: item.id, name, input }
7867
8223
  ];
@@ -7892,6 +8248,36 @@ var init_codex = __esm({
7892
8248
  }
7893
8249
  return events.length === 1 ? events[0] : events;
7894
8250
  }
8251
+ if (itemType === "collab_tool_call" && item.id) {
8252
+ const rawTool = typeof item.tool === "string" ? item.tool : "spawn_agent";
8253
+ const name = /spawn/i.test(rawTool) ? "spawn_agent" : rawTool;
8254
+ const input = {};
8255
+ if (item.prompt) input.prompt = item.prompt;
8256
+ if (Array.isArray(item.receiver_thread_ids)) {
8257
+ input.receiver_thread_ids = item.receiver_thread_ids;
8258
+ }
8259
+ const events = [{ type: "tool_use", id: item.id, name, input }];
8260
+ const finished = type === "item.completed" || item.status === "completed" || item.status === "failed";
8261
+ if (finished) {
8262
+ const nested = [];
8263
+ if (item.agents_states && typeof item.agents_states === "object") {
8264
+ for (const value of Object.values(item.agents_states)) {
8265
+ const msg = value && typeof value === "object" && typeof value.message === "string" ? value.message.trim() : "";
8266
+ if (msg) nested.push(msg);
8267
+ }
8268
+ }
8269
+ for (const text4 of nested) {
8270
+ events.push({ type: "stdout", data: text4, parentId: item.id });
8271
+ }
8272
+ events.push({
8273
+ type: "tool_result",
8274
+ id: item.id,
8275
+ content: nested.join("\n") || void 0,
8276
+ isError: item.status === "failed"
8277
+ });
8278
+ }
8279
+ return events.length === 1 ? events[0] : events;
8280
+ }
7895
8281
  if (item.status === "failed") {
7896
8282
  const detail = item.message?.trim() || extractJsonErrorMessage(item) || `Codex ${itemType ?? "item"} failed`;
7897
8283
  return { type: "stderr", data: detail };
@@ -7980,20 +8366,20 @@ function usageFromCursor(usage) {
7980
8366
  cacheWriteTokens: usage.cacheWriteTokens ? Number(usage.cacheWriteTokens) : void 0
7981
8367
  };
7982
8368
  }
7983
- function asRecord2(value) {
8369
+ function asRecord3(value) {
7984
8370
  if (value && typeof value === "object" && !Array.isArray(value)) {
7985
8371
  return value;
7986
8372
  }
7987
8373
  return void 0;
7988
8374
  }
7989
8375
  function normalizeCursorToolCall(name, args) {
7990
- const raw = asRecord2(args);
8376
+ const raw = asRecord3(args);
7991
8377
  const toolName = typeof raw?.toolName === "string" && raw.toolName.trim() ? raw.toolName.trim() : null;
7992
- const looksLikeMcp = name === "mcp" || toolName != null && (typeof raw?.providerIdentifier === "string" || asRecord2(raw?.args) != null);
8378
+ const looksLikeMcp = name === "mcp" || toolName != null && (typeof raw?.providerIdentifier === "string" || asRecord3(raw?.args) != null);
7993
8379
  if (looksLikeMcp && toolName) {
7994
8380
  const providerRaw = typeof raw.providerIdentifier === "string" && raw.providerIdentifier.trim() ? raw.providerIdentifier.trim() : "sideboard";
7995
8381
  const provider = providerRaw.replace(/[^a-zA-Z0-9_-]/g, "_");
7996
- const nested = asRecord2(raw.args);
8382
+ const nested = asRecord3(raw.args);
7997
8383
  return {
7998
8384
  name: `mcp__${provider}__${toolName}`,
7999
8385
  input: nested ?? { toolName }
@@ -8004,7 +8390,7 @@ function normalizeCursorToolCall(name, args) {
8004
8390
  function unwrapCursorToolResult(result) {
8005
8391
  if (result == null) return void 0;
8006
8392
  if (typeof result === "string") return result;
8007
- const rec = asRecord2(result);
8393
+ const rec = asRecord3(result);
8008
8394
  if (!rec) {
8009
8395
  try {
8010
8396
  return JSON.stringify(result);
@@ -8015,18 +8401,18 @@ function unwrapCursorToolResult(result) {
8015
8401
  const collectTexts = (items) => {
8016
8402
  const texts = [];
8017
8403
  for (const item of items) {
8018
- const row = asRecord2(item);
8404
+ const row = asRecord3(item);
8019
8405
  if (!row) continue;
8020
8406
  if (typeof row.text === "string") {
8021
8407
  texts.push(row.text);
8022
8408
  continue;
8023
8409
  }
8024
- const nested = asRecord2(row.text);
8410
+ const nested = asRecord3(row.text);
8025
8411
  if (typeof nested?.text === "string") texts.push(nested.text);
8026
8412
  }
8027
8413
  return texts;
8028
8414
  };
8029
- const value = asRecord2(rec.value);
8415
+ const value = asRecord3(rec.value);
8030
8416
  if (value && Array.isArray(value.content)) {
8031
8417
  const texts = collectTexts(value.content);
8032
8418
  if (texts.length) return texts.join("\n");
@@ -8043,10 +8429,10 @@ function unwrapCursorToolResult(result) {
8043
8429
  }
8044
8430
  function cursorToolResultIsError(status, result) {
8045
8431
  if (status === "error") return true;
8046
- const rec = asRecord2(result);
8432
+ const rec = asRecord3(result);
8047
8433
  if (!rec) return false;
8048
8434
  if (rec.status === "error") return true;
8049
- const value = asRecord2(rec.value);
8435
+ const value = asRecord3(rec.value);
8050
8436
  return value?.isError === true;
8051
8437
  }
8052
8438
  function cursorSdkMessageToEvents(msg) {
@@ -8188,24 +8574,24 @@ function resolveCursorRipgrepPath(opts) {
8188
8574
  packagedCursorRipgrepCandidate(platformRipgrepPackage(), rgBinaryName())
8189
8575
  );
8190
8576
  if (fromPackaged) return fromPackaged;
8191
- const start = opts?.startFile?.trim() || process.argv[1] || (0, import_node_url2.fileURLToPath)(import_meta2.url);
8577
+ const start = opts?.startFile?.trim() || process.argv[1] || // CJS bundle only — ESM has no __filename; argv[1] is the running script.
8578
+ // eslint-disable-next-line camelcase
8579
+ (typeof __filename !== "undefined" ? __filename : "");
8192
8580
  return walkForBundledRipgrep(start) ?? requireResolveBundledRipgrep(start);
8193
8581
  }
8194
8582
  function cursorRipgrepEnv(opts) {
8195
8583
  const path = resolveCursorRipgrepPath(opts);
8196
8584
  return path ? { [RIPGREP_ENV]: path } : {};
8197
8585
  }
8198
- var import_node_fs23, import_node_module2, import_node_path23, import_node_url2, import_meta2, RIPGREP_ENV;
8586
+ var import_node_fs23, import_node_module2, import_node_path23, RIPGREP_ENV;
8199
8587
  var init_cursor_ripgrep = __esm({
8200
8588
  "src/agents/cursor-ripgrep.ts"() {
8201
8589
  "use strict";
8202
8590
  import_node_fs23 = require("fs");
8203
8591
  import_node_module2 = require("module");
8204
8592
  import_node_path23 = require("path");
8205
- import_node_url2 = require("url");
8206
8593
  init_node_launch();
8207
8594
  init_packaged_runtime();
8208
- import_meta2 = {};
8209
8595
  RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
8210
8596
  }
8211
8597
  });
@@ -8249,7 +8635,7 @@ function entryDir() {
8249
8635
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
8250
8636
  if (cjsDir) return cjsDir;
8251
8637
  try {
8252
- return (0, import_node_path24.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
8638
+ return (0, import_node_path24.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
8253
8639
  } catch {
8254
8640
  try {
8255
8641
  const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
@@ -8278,14 +8664,14 @@ function cursorRunnerPath() {
8278
8664
  }
8279
8665
  return candidates[0];
8280
8666
  }
8281
- var import_node_fs24, import_node_module3, import_node_path24, import_node_url3, import_sdk, import_meta3, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
8667
+ var import_node_fs24, import_node_module3, import_node_path24, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
8282
8668
  var init_cursor = __esm({
8283
8669
  "src/agents/cursor.ts"() {
8284
8670
  "use strict";
8285
8671
  import_node_fs24 = require("fs");
8286
8672
  import_node_module3 = require("module");
8287
8673
  import_node_path24 = require("path");
8288
- import_node_url3 = require("url");
8674
+ import_node_url2 = require("url");
8289
8675
  import_sdk = require("@cursor/sdk");
8290
8676
  init_run();
8291
8677
  init_app_settings();
@@ -8297,7 +8683,7 @@ var init_cursor = __esm({
8297
8683
  init_packaged_runtime();
8298
8684
  init_turn_input();
8299
8685
  init_cursor_events();
8300
- import_meta3 = {};
8686
+ import_meta2 = {};
8301
8687
  FALLBACK_CURSOR_MODELS = [
8302
8688
  { id: "default", displayName: "Auto" },
8303
8689
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -8389,6 +8775,24 @@ var init_cursor = __esm({
8389
8775
  });
8390
8776
 
8391
8777
  // src/agents/opencode.ts
8778
+ function asRecord4(value) {
8779
+ if (value && typeof value === "object" && !Array.isArray(value)) {
8780
+ return value;
8781
+ }
8782
+ return void 0;
8783
+ }
8784
+ function str3(v) {
8785
+ return typeof v === "string" && v.trim() ? v.trim() : void 0;
8786
+ }
8787
+ function opencodeToolId(name, callId, metadata) {
8788
+ const sessionId = str3(metadata?.sessionId) ?? str3(metadata?.sessionID);
8789
+ if (name === "task" && sessionId) return sessionId;
8790
+ return callId || `tool-${Date.now()}`;
8791
+ }
8792
+ function withTaskParent(parentId, nested) {
8793
+ const events = Array.isArray(nested) ? nested : [nested];
8794
+ return [{ type: "tool_use", id: parentId, name: "task" }, ...events];
8795
+ }
8392
8796
  function displayNameFromOpencodeId(id) {
8393
8797
  const slash = id.indexOf("/");
8394
8798
  if (slash <= 0) return id;
@@ -8455,6 +8859,7 @@ var init_opencode = __esm({
8455
8859
  init_app_settings();
8456
8860
  init_global_workspace();
8457
8861
  init_error_detail();
8862
+ init_message_parts();
8458
8863
  init_injected_mcp();
8459
8864
  init_turn_input();
8460
8865
  init_types();
@@ -8571,10 +8976,15 @@ var init_opencode = __esm({
8571
8976
  }
8572
8977
  if (obj.type === "tool_use") {
8573
8978
  const part = obj.part;
8574
- const id = part?.callID ?? part?.id ?? obj.id ?? `tool-${Date.now()}`;
8575
8979
  const name = part?.tool ?? part?.name ?? obj.tool ?? obj.name ?? "tool";
8576
8980
  const state = part?.state;
8577
8981
  const input = (state?.input && typeof state.input === "object" ? state.input : void 0) ?? part?.input ?? obj.input;
8982
+ const metadata = asRecord4(state?.metadata);
8983
+ const id = opencodeToolId(
8984
+ name,
8985
+ part?.callID ?? part?.id ?? obj.id,
8986
+ metadata
8987
+ );
8578
8988
  const events = [{ type: "tool_use", id, name, input }];
8579
8989
  const output = state?.output;
8580
8990
  if (output != null || state?.status === "completed" || state?.status === "error") {
@@ -8588,6 +8998,53 @@ var init_opencode = __esm({
8588
8998
  }
8589
8999
  return events.length === 1 ? events[0] : events;
8590
9000
  }
9001
+ if (obj.type === "subtask_delta") {
9002
+ const parentId = str3(obj.childSessionID) ?? str3(obj.childSessionId);
9003
+ const delta = str3(obj.delta);
9004
+ if (parentId && delta) {
9005
+ return withTaskParent(
9006
+ parentId,
9007
+ withEventParentId({ type: "thinking", data: delta }, parentId)
9008
+ );
9009
+ }
9010
+ return null;
9011
+ }
9012
+ if (obj.type === "subtask_event") {
9013
+ const parentId = str3(obj.childSessionID) ?? str3(obj.childSessionId);
9014
+ const part = asRecord4(obj.part);
9015
+ if (!parentId || !part) return null;
9016
+ if (part.type === "text" && str3(part.text)) {
9017
+ return withTaskParent(
9018
+ parentId,
9019
+ withEventParentId({ type: "stdout", data: str3(part.text) }, parentId)
9020
+ );
9021
+ }
9022
+ if (part.type === "tool" || str3(part.tool)) {
9023
+ const name = str3(part.tool) ?? str3(part.name) ?? "tool";
9024
+ const id = str3(part.callID) ?? str3(part.id) ?? `${parentId}-${name}`;
9025
+ const state = asRecord4(part.state);
9026
+ const input = asRecord4(state?.input) ?? asRecord4(part.input);
9027
+ const nested = [
9028
+ withEventParentId({ type: "tool_use", id, name, input }, parentId)
9029
+ ];
9030
+ const output = state?.output ?? part.output;
9031
+ if (output != null || state?.status === "completed" || state?.status === "error") {
9032
+ nested.push(
9033
+ withEventParentId(
9034
+ {
9035
+ type: "tool_result",
9036
+ id,
9037
+ content: typeof output === "string" ? output : output != null ? JSON.stringify(output) : void 0,
9038
+ isError: state?.status === "error" || state?.status === "failed"
9039
+ },
9040
+ parentId
9041
+ )
9042
+ );
9043
+ }
9044
+ return withTaskParent(parentId, nested);
9045
+ }
9046
+ return null;
9047
+ }
8591
9048
  if (obj.type === "tool_result") {
8592
9049
  const part = obj.part;
8593
9050
  const id = part?.tool_use_id ?? part?.id ?? obj.tool_use_id ?? obj.id;
@@ -9015,424 +9472,191 @@ async function installAgent(agent) {
9015
9472
  stderr: result.stderr,
9016
9473
  message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
9017
9474
  };
9018
- }
9019
- }
9020
- enrichPathWithNpmGlobalBin();
9021
- let binPath = null;
9022
- if (cliBin) {
9023
- binPath = await whichCli(cliBin);
9024
- }
9025
- return {
9026
- ok: true,
9027
- command: info.installCommand,
9028
- exitCode: 0,
9029
- stdout: result.stdout,
9030
- stderr: result.stderr,
9031
- message: binPath ? `Installed ${info.npmPackage} \u2192 ${binPath}` : `Installed ${info.npmPackage} (CLI not yet on PATH \u2014 Log in still exports Electron\u2019s PATH into Terminal)`
9032
- };
9033
- }
9034
- async function loginAgent(agent) {
9035
- const info = getAgentSetupInfo(agent);
9036
- const loginCommand = resolveLoginCommand(agent);
9037
- if (!loginCommand) {
9038
- return {
9039
- ok: true,
9040
- message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
9041
- };
9042
- }
9043
- const prepared = await prepareTerminalCommand(loginCommand);
9044
- await openInSystemTerminal(prepared);
9045
- return {
9046
- ok: true,
9047
- openedTerminal: true,
9048
- command: prepared,
9049
- message: `Opened Terminal to run: ${prepared}`
9050
- };
9051
- }
9052
- var SETUP, CLI_BIN, CLI_LOGIN_AGENTS;
9053
- var init_install = __esm({
9054
- "src/agents/install.ts"() {
9055
- "use strict";
9056
- init_run();
9057
- init_app_settings();
9058
- init_path();
9059
- SETUP = {
9060
- claude: {
9061
- agent: "claude",
9062
- kind: "cli",
9063
- summary: "Install the Claude Code CLI, then complete login in a terminal.",
9064
- docsUrl: "https://code.claude.com/docs/en/install",
9065
- installCommand: "npm install -g @anthropic-ai/claude-code",
9066
- loginCommand: "claude auth login",
9067
- npmPackage: "@anthropic-ai/claude-code"
9068
- },
9069
- codex: {
9070
- agent: "codex",
9071
- kind: "cli",
9072
- summary: "Install the Codex CLI, then run login in a terminal.",
9073
- docsUrl: "https://github.com/openai/codex",
9074
- installCommand: "npm install -g @openai/codex",
9075
- loginCommand: "codex login",
9076
- npmPackage: "@openai/codex"
9077
- },
9078
- opencode: {
9079
- agent: "opencode",
9080
- kind: "cli",
9081
- summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
9082
- docsUrl: "https://opencode.ai/docs",
9083
- // Prefer the official installer; npm package name is opencode-ai.
9084
- installCommand: "curl -fsSL https://opencode.ai/install | bash",
9085
- loginCommand: "opencode auth login",
9086
- npmPackage: "opencode-ai@latest"
9087
- },
9088
- cursor: {
9089
- agent: "cursor",
9090
- kind: "bundled-sdk",
9091
- summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
9092
- docsUrl: "https://cursor.com/dashboard/integrations",
9093
- installCommand: null,
9094
- loginCommand: null
9095
- },
9096
- brightsy: {
9097
- agent: "brightsy",
9098
- kind: "cli",
9099
- summary: "Install the Brightsy CLI, then run `brightsy login`.",
9100
- docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
9101
- installCommand: "npm install -g @brightsy/cli",
9102
- loginCommand: "brightsy login",
9103
- npmPackage: "@brightsy/cli"
9104
- }
9105
- };
9106
- CLI_BIN = {
9107
- claude: "claude",
9108
- codex: "codex",
9109
- opencode: "opencode",
9110
- brightsy: "brightsy"
9111
- };
9112
- CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
9113
- "claude",
9114
- "codex",
9115
- "opencode",
9116
- "brightsy"
9117
- ]);
9118
- }
9119
- });
9120
-
9121
- // src/agents/index.ts
9122
- var agents_exports = {};
9123
- __export(agents_exports, {
9124
- CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
9125
- ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
9126
- PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
9127
- allAdapters: () => allAdapters,
9128
- assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
9129
- brightsyAdapter: () => brightsyAdapter,
9130
- claudeAdapter: () => claudeAdapter,
9131
- codexAdapter: () => codexAdapter,
9132
- coerceOrchestratorAgent: () => coerceOrchestratorAgent,
9133
- conductorBundledBinDir: () => conductorBundledBinDir,
9134
- cursorAdapter: () => cursorAdapter,
9135
- cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
9136
- decodeBrightsyTarget: () => decodeBrightsyTarget,
9137
- encodeBrightsyTarget: () => encodeBrightsyTarget,
9138
- enrichPathWithNpmGlobalBin: () => enrichPathWithNpmGlobalBin,
9139
- ensureAgentPath: () => ensureAgentPath,
9140
- getAdapter: () => getAdapter,
9141
- getAgentSetupInfo: () => getAgentSetupInfo,
9142
- installAgent: () => installAgent,
9143
- isConductorBundledCli: () => isConductorBundledCli,
9144
- isCursorAutoModel: () => isCursorAutoModel,
9145
- isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
9146
- isSessionQuotaLimit: () => isSessionQuotaLimit,
9147
- listAgentSetupInfo: () => listAgentSetupInfo,
9148
- listBrightsyChatTargets: () => listBrightsyChatTargets,
9149
- listCodexModels: () => listCodexModels,
9150
- listCursorModels: () => listCursorModels,
9151
- listModelsForAgent: () => listModelsForAgent,
9152
- listOpencodeModels: () => listOpencodeModels,
9153
- loginAgent: () => loginAgent,
9154
- openInSystemTerminal: () => openInSystemTerminal,
9155
- opencodeAdapter: () => opencodeAdapter,
9156
- parseCursorRunnerLine: () => parseCursorRunnerLine,
9157
- parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
9158
- permissionMode: () => permissionMode,
9159
- posixShellSingleQuote: () => posixShellSingleQuote,
9160
- prepareTerminalCommand: () => prepareTerminalCommand,
9161
- resolveCommandBinarySync: () => resolveCommandBinarySync,
9162
- resolveCursorModelId: () => resolveCursorModelId,
9163
- resolveLoginCommand: () => resolveLoginCommand,
9164
- resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
9165
- withExportedPath: () => withExportedPath
9166
- });
9167
- function getAdapter(kind) {
9168
- return adapters[kind];
9169
- }
9170
- function allAdapters() {
9171
- return Object.values(adapters);
9172
- }
9173
- var adapters;
9174
- var init_agents = __esm({
9175
- "src/agents/index.ts"() {
9176
- "use strict";
9177
- init_brightsy();
9178
- init_claude();
9179
- init_codex();
9180
- init_cursor();
9181
- init_opencode();
9182
- init_types();
9183
- init_brightsy();
9184
- init_brightsy_targets();
9185
- init_claude();
9186
- init_codex();
9187
- init_cursor();
9188
- init_cursor_events();
9189
- init_cursor();
9190
- init_opencode();
9191
- init_list_models();
9192
- init_session_quota();
9193
- init_orchestrator_capable();
9194
- init_path();
9195
- init_install();
9196
- adapters = {
9197
- claude: claudeAdapter,
9198
- codex: codexAdapter,
9199
- opencode: opencodeAdapter,
9200
- brightsy: brightsyAdapter,
9201
- cursor: cursorAdapter
9202
- };
9203
- }
9204
- });
9205
-
9206
- // src/agents/message-parts.ts
9207
- function asRecord3(input) {
9208
- if (input && typeof input === "object" && !Array.isArray(input)) {
9209
- return input;
9210
- }
9211
- return void 0;
9212
- }
9213
- function str2(v) {
9214
- return typeof v === "string" && v.trim() ? v : void 0;
9215
- }
9216
- function toolDetail(name, input) {
9217
- if (!input) return void 0;
9218
- const command = str2(input.command) ?? str2(input.cmd);
9219
- if (command) return command;
9220
- const path = str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
9221
- if (path) return path;
9222
- const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
9223
- if (pattern) return pattern;
9224
- const query = str2(input.query) ?? str2(input.prompt);
9225
- if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
9226
- try {
9227
- const raw = JSON.stringify(input);
9228
- return raw.length > 80 ? `${raw.slice(0, 77)}\u2026` : raw;
9229
- } catch {
9230
- return name;
9231
- }
9232
- }
9233
- function toolDescription(name, input) {
9234
- const n = name.replace(/^mcp__/, "").replace(/__/g, " \xB7 ");
9235
- if (/^get_record_types$|recordTypes/i.test(name)) return "List record types";
9236
- if (/connectedAgentRequest/i.test(name)) {
9237
- return str2(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
9238
- }
9239
- if (/present_artifact$/i.test(name)) {
9240
- return str2(input?.title) ? `Present ${str2(input?.title)}` : "Present artifact";
9241
- }
9242
- if (/present_plan$/i.test(name)) {
9243
- return str2(input?.title) ? `Plan ${str2(input?.title)}` : "Present plan";
9244
- }
9245
- if (/present_schema$/i.test(name)) {
9246
- return str2(input?.title) ? `Schema ${str2(input?.title)}` : "Present schema";
9247
- }
9248
- if (/present_files$/i.test(name)) {
9249
- return str2(input?.title) ? `Files ${str2(input?.title)}` : "Present files";
9250
- }
9251
- if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
9252
- return str2(input?.title) ? `Artifact ${str2(input?.title)}` : "Artifact";
9253
- }
9254
- if (!input) return n;
9255
- if (/bash|shell|terminal/i.test(name) && str2(input.command)) {
9256
- const cmd = str2(input.command);
9257
- if (/git\s+fetch/i.test(cmd)) return "Fetch latest from origin and check status";
9258
- if (/git\s+status/i.test(cmd)) return "Check git status";
9259
- if (/git\s+log/i.test(cmd)) return "Inspect recent commits";
9260
- if (/git\s+branch/i.test(cmd)) return "List branches";
9261
- if (/grep|rg\b/i.test(cmd)) return "Search repository";
9262
- return "Run shell command";
9263
- }
9264
- if (/edit|write|apply/i.test(name)) {
9265
- const path = str2(input.file_path) ?? str2(input.path);
9266
- return path ? `Edit ${path.split("/").pop()}` : "Edit file";
9267
- }
9268
- if (/read/i.test(name)) {
9269
- const path = str2(input.file_path) ?? str2(input.path);
9270
- return path ? `Read ${path.split("/").pop()}` : "Read file";
9271
- }
9272
- if (/grep/i.test(name)) return "Search files";
9273
- if (/glob/i.test(name)) return "Find files";
9274
- return n;
9275
- }
9276
- function toolFilePath(input) {
9277
- if (!input) return void 0;
9278
- return str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
9279
- }
9280
- function countLines(text4) {
9281
- if (!text4) return 0;
9282
- return text4.split("\n").length;
9283
- }
9284
- function diffFromInput(input) {
9285
- if (!input) return {};
9286
- const oldS = str2(input.old_string) ?? str2(input.oldString);
9287
- const newS = str2(input.new_string) ?? str2(input.newString) ?? str2(input.content);
9288
- if (oldS != null || newS != null) {
9289
- return {
9290
- additions: countLines(newS),
9291
- deletions: countLines(oldS)
9292
- };
9293
- }
9294
- return {};
9295
- }
9296
- function parseDiffStat(result) {
9297
- if (!result) return {};
9298
- const paired = result.match(/\+(\d+)\s+-(\d+)/);
9299
- if (paired) {
9300
- return {
9301
- additions: Number(paired[1]),
9302
- deletions: Number(paired[2])
9303
- };
9304
- }
9305
- const verbose = result.match(
9306
- /(\d+)\s+insertions?(?:,\s*(\d+)\s+deletions?)?/i
9307
- );
9308
- if (verbose) {
9309
- return {
9310
- additions: Number(verbose[1]),
9311
- deletions: verbose[2] != null ? Number(verbose[2]) : void 0
9312
- };
9313
- }
9314
- return {};
9315
- }
9316
- function applyAgentEvent(parts, event) {
9317
- if (event.type === "stdout") {
9318
- const data = event.data;
9319
- if (!data) return parts;
9320
- const next = [...parts];
9321
- const last = next[next.length - 1];
9322
- if (last?.type === "text") {
9323
- next[next.length - 1] = { type: "text", text: last.text + data };
9324
- } else {
9325
- next.push({ type: "text", text: data });
9326
- }
9327
- return next;
9328
- }
9329
- if (event.type === "thinking") {
9330
- const data = event.data;
9331
- if (!data) return parts;
9332
- const next = [...parts];
9333
- const last = next[next.length - 1];
9334
- if (last?.type === "thinking") {
9335
- next[next.length - 1] = { type: "thinking", text: last.text + data };
9336
- } else {
9337
- next.push({ type: "thinking", text: data });
9338
- }
9339
- return next;
9340
- }
9341
- if (event.type === "tool_use") {
9342
- const input = asRecord3(event.input);
9343
- const diff = diffFromInput(input);
9344
- const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
9345
- if (existing >= 0) {
9346
- const prev = parts[existing];
9347
- const next = [...parts];
9348
- next[existing] = {
9349
- ...prev,
9350
- name: event.name || prev.name,
9351
- input: input ?? prev.input,
9352
- description: toolDescription(event.name || prev.name, input ?? prev.input),
9353
- detail: toolDetail(event.name || prev.name, input ?? prev.input) ?? prev.detail,
9354
- filePath: toolFilePath(input) ?? prev.filePath,
9355
- additions: diff.additions ?? prev.additions,
9356
- deletions: diff.deletions ?? prev.deletions
9357
- };
9358
- return next;
9359
- }
9360
- return [
9361
- ...parts,
9362
- {
9363
- type: "tool",
9364
- id: event.id,
9365
- name: event.name,
9366
- input,
9367
- description: toolDescription(event.name, input),
9368
- detail: toolDetail(event.name, input),
9369
- status: "running",
9370
- filePath: toolFilePath(input),
9371
- ...diff
9372
- }
9373
- ];
9374
- }
9375
- if (event.type === "tool_result") {
9376
- const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
9377
- const fromResult = parseDiffStat(event.content);
9378
- if (existing < 0) {
9379
- return [
9380
- ...parts,
9381
- {
9382
- type: "tool",
9383
- id: event.id,
9384
- name: "tool",
9385
- description: "tool",
9386
- status: event.isError ? "error" : "done",
9387
- result: event.content,
9388
- ...fromResult.additions != null ? { additions: fromResult.additions } : {},
9389
- ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
9390
- }
9391
- ];
9392
- }
9393
- return parts.map((p, i) => {
9394
- if (i !== existing || p.type !== "tool") return p;
9395
- return {
9396
- ...p,
9397
- status: event.isError ? "error" : "done",
9398
- result: event.content,
9399
- ...fromResult.additions != null ? { additions: fromResult.additions } : {},
9400
- ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
9401
- };
9402
- });
9475
+ }
9403
9476
  }
9404
- return parts;
9405
- }
9406
- function partsToAssistantText(parts) {
9407
- return parts.filter((p) => p.type === "text").map((p) => p.text).join("").trim();
9408
- }
9409
- function stripBrightsyNdjsonNoise(text4) {
9410
- if (!text4 || !text4.includes('"type"')) return text4;
9411
- let out = text4;
9412
- out = out.replace(
9413
- /\{"type":"(?:tool_use|tool_result|tool|thinking|usage|done|error)"[\s\S]*?\}\s*(?=\{"type":"|$|(?=[A-Za-z*#]))/g,
9414
- ""
9415
- );
9416
- out = out.replace(/\{"type":"(?:tool_use|tool_result|tool)"[\s\S]*$/g, "");
9417
- return out.trim();
9477
+ enrichPathWithNpmGlobalBin();
9478
+ let binPath = null;
9479
+ if (cliBin) {
9480
+ binPath = await whichCli(cliBin);
9481
+ }
9482
+ return {
9483
+ ok: true,
9484
+ command: info.installCommand,
9485
+ exitCode: 0,
9486
+ stdout: result.stdout,
9487
+ stderr: result.stderr,
9488
+ message: binPath ? `Installed ${info.npmPackage} \u2192 ${binPath}` : `Installed ${info.npmPackage} (CLI not yet on PATH \u2014 Log in still exports Electron\u2019s PATH into Terminal)`
9489
+ };
9418
9490
  }
9419
- function isBrightsyNdjsonLine(line) {
9420
- const t = line.trim();
9421
- if (!t.startsWith("{")) return false;
9422
- return /"type"\s*:\s*"(tool_use|tool_result|tool|thinking|usage|done|error|text)"/.test(t);
9491
+ async function loginAgent(agent) {
9492
+ const info = getAgentSetupInfo(agent);
9493
+ const loginCommand = resolveLoginCommand(agent);
9494
+ if (!loginCommand) {
9495
+ return {
9496
+ ok: true,
9497
+ message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
9498
+ };
9499
+ }
9500
+ const prepared = await prepareTerminalCommand(loginCommand);
9501
+ await openInSystemTerminal(prepared);
9502
+ return {
9503
+ ok: true,
9504
+ openedTerminal: true,
9505
+ command: prepared,
9506
+ message: `Opened Terminal to run: ${prepared}`
9507
+ };
9423
9508
  }
9424
- function finalizeParts(parts) {
9425
- return parts.map(
9426
- (p) => p.type === "tool" && p.status === "running" ? { ...p, status: "done" } : p
9427
- );
9509
+ var SETUP, CLI_BIN, CLI_LOGIN_AGENTS;
9510
+ var init_install = __esm({
9511
+ "src/agents/install.ts"() {
9512
+ "use strict";
9513
+ init_run();
9514
+ init_app_settings();
9515
+ init_path();
9516
+ SETUP = {
9517
+ claude: {
9518
+ agent: "claude",
9519
+ kind: "cli",
9520
+ summary: "Install the Claude Code CLI, then complete login in a terminal.",
9521
+ docsUrl: "https://code.claude.com/docs/en/install",
9522
+ installCommand: "npm install -g @anthropic-ai/claude-code",
9523
+ loginCommand: "claude auth login",
9524
+ npmPackage: "@anthropic-ai/claude-code"
9525
+ },
9526
+ codex: {
9527
+ agent: "codex",
9528
+ kind: "cli",
9529
+ summary: "Install the Codex CLI, then run login in a terminal.",
9530
+ docsUrl: "https://github.com/openai/codex",
9531
+ installCommand: "npm install -g @openai/codex",
9532
+ loginCommand: "codex login",
9533
+ npmPackage: "@openai/codex"
9534
+ },
9535
+ opencode: {
9536
+ agent: "opencode",
9537
+ kind: "cli",
9538
+ summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
9539
+ docsUrl: "https://opencode.ai/docs",
9540
+ // Prefer the official installer; npm package name is opencode-ai.
9541
+ installCommand: "curl -fsSL https://opencode.ai/install | bash",
9542
+ loginCommand: "opencode auth login",
9543
+ npmPackage: "opencode-ai@latest"
9544
+ },
9545
+ cursor: {
9546
+ agent: "cursor",
9547
+ kind: "bundled-sdk",
9548
+ summary: "No CLI install \u2014 Sideboard ships the Cursor SDK. Add a CURSOR_API_KEY from the Cursor dashboard.",
9549
+ docsUrl: "https://cursor.com/dashboard/integrations",
9550
+ installCommand: null,
9551
+ loginCommand: null
9552
+ },
9553
+ brightsy: {
9554
+ agent: "brightsy",
9555
+ kind: "cli",
9556
+ summary: "Install the Brightsy CLI, then run `brightsy login`.",
9557
+ docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
9558
+ installCommand: "npm install -g @brightsy/cli",
9559
+ loginCommand: "brightsy login",
9560
+ npmPackage: "@brightsy/cli"
9561
+ }
9562
+ };
9563
+ CLI_BIN = {
9564
+ claude: "claude",
9565
+ codex: "codex",
9566
+ opencode: "opencode",
9567
+ brightsy: "brightsy"
9568
+ };
9569
+ CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
9570
+ "claude",
9571
+ "codex",
9572
+ "opencode",
9573
+ "brightsy"
9574
+ ]);
9575
+ }
9576
+ });
9577
+
9578
+ // src/agents/index.ts
9579
+ var agents_exports = {};
9580
+ __export(agents_exports, {
9581
+ CLAUDE_MODEL_CATALOG: () => CLAUDE_MODEL_CATALOG,
9582
+ ORCHESTRATOR_AGENT_KINDS: () => ORCHESTRATOR_AGENT_KINDS,
9583
+ PLAN_MODE_INSTRUCTION: () => PLAN_MODE_INSTRUCTION,
9584
+ allAdapters: () => allAdapters,
9585
+ assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
9586
+ brightsyAdapter: () => brightsyAdapter,
9587
+ claudeAdapter: () => claudeAdapter,
9588
+ codexAdapter: () => codexAdapter,
9589
+ coerceOrchestratorAgent: () => coerceOrchestratorAgent,
9590
+ conductorBundledBinDir: () => conductorBundledBinDir,
9591
+ cursorAdapter: () => cursorAdapter,
9592
+ cursorSdkMessageToEvents: () => cursorSdkMessageToEvents,
9593
+ decodeBrightsyTarget: () => decodeBrightsyTarget,
9594
+ encodeBrightsyTarget: () => encodeBrightsyTarget,
9595
+ enrichPathWithNpmGlobalBin: () => enrichPathWithNpmGlobalBin,
9596
+ ensureAgentPath: () => ensureAgentPath,
9597
+ getAdapter: () => getAdapter,
9598
+ getAgentSetupInfo: () => getAgentSetupInfo,
9599
+ installAgent: () => installAgent,
9600
+ isConductorBundledCli: () => isConductorBundledCli,
9601
+ isCursorAutoModel: () => isCursorAutoModel,
9602
+ isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
9603
+ isSessionQuotaLimit: () => isSessionQuotaLimit,
9604
+ listAgentSetupInfo: () => listAgentSetupInfo,
9605
+ listBrightsyChatTargets: () => listBrightsyChatTargets,
9606
+ listCodexModels: () => listCodexModels,
9607
+ listCursorModels: () => listCursorModels,
9608
+ listModelsForAgent: () => listModelsForAgent,
9609
+ listOpencodeModels: () => listOpencodeModels,
9610
+ loginAgent: () => loginAgent,
9611
+ openInSystemTerminal: () => openInSystemTerminal,
9612
+ opencodeAdapter: () => opencodeAdapter,
9613
+ parseCursorRunnerLine: () => parseCursorRunnerLine,
9614
+ parseSessionQuotaResetAt: () => parseSessionQuotaResetAt,
9615
+ permissionMode: () => permissionMode,
9616
+ posixShellSingleQuote: () => posixShellSingleQuote,
9617
+ prepareTerminalCommand: () => prepareTerminalCommand,
9618
+ resolveCommandBinarySync: () => resolveCommandBinarySync,
9619
+ resolveCursorModelId: () => resolveCursorModelId,
9620
+ resolveLoginCommand: () => resolveLoginCommand,
9621
+ resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
9622
+ withExportedPath: () => withExportedPath
9623
+ });
9624
+ function getAdapter(kind) {
9625
+ return adapters[kind];
9428
9626
  }
9429
- function normalizeParseResult(parsed) {
9430
- if (!parsed) return [];
9431
- return Array.isArray(parsed) ? parsed : [parsed];
9627
+ function allAdapters() {
9628
+ return Object.values(adapters);
9432
9629
  }
9433
- var init_message_parts = __esm({
9434
- "src/agents/message-parts.ts"() {
9630
+ var adapters;
9631
+ var init_agents = __esm({
9632
+ "src/agents/index.ts"() {
9435
9633
  "use strict";
9634
+ init_brightsy();
9635
+ init_claude();
9636
+ init_codex();
9637
+ init_cursor();
9638
+ init_opencode();
9639
+ init_types();
9640
+ init_brightsy();
9641
+ init_brightsy_targets();
9642
+ init_claude();
9643
+ init_codex();
9644
+ init_cursor();
9645
+ init_cursor_events();
9646
+ init_cursor();
9647
+ init_opencode();
9648
+ init_list_models();
9649
+ init_session_quota();
9650
+ init_orchestrator_capable();
9651
+ init_path();
9652
+ init_install();
9653
+ adapters = {
9654
+ claude: claudeAdapter,
9655
+ codex: codexAdapter,
9656
+ opencode: opencodeAdapter,
9657
+ brightsy: brightsyAdapter,
9658
+ cursor: cursorAdapter
9659
+ };
9436
9660
  }
9437
9661
  });
9438
9662
 
@@ -9440,6 +9664,9 @@ var init_message_parts = __esm({
9440
9664
  function isTextEvent(event) {
9441
9665
  return event.type === "stdout" || event.type === "thinking";
9442
9666
  }
9667
+ function parentKey(event) {
9668
+ return event.parentId ?? "";
9669
+ }
9443
9670
  function createAgentStreamCoalescer(emit, opts) {
9444
9671
  const intervalMs = opts?.intervalMs ?? 32;
9445
9672
  let pending = null;
@@ -9452,7 +9679,11 @@ function createAgentStreamCoalescer(emit, opts) {
9452
9679
  if (!pending) return;
9453
9680
  const event = pending;
9454
9681
  pending = null;
9455
- emit({ type: event.type, data: event.data });
9682
+ emit({
9683
+ type: event.type,
9684
+ data: event.data,
9685
+ ...event.parentId ? { parentId: event.parentId } : {}
9686
+ });
9456
9687
  };
9457
9688
  const schedule = () => {
9458
9689
  if (timer) return;
@@ -9467,11 +9698,15 @@ function createAgentStreamCoalescer(emit, opts) {
9467
9698
  return;
9468
9699
  }
9469
9700
  if (!event.data) return;
9470
- if (pending && pending.type === event.type) {
9701
+ if (pending && pending.type === event.type && parentKey(pending) === parentKey(event)) {
9471
9702
  pending.data += event.data;
9472
9703
  } else {
9473
9704
  flush2();
9474
- pending = { type: event.type, data: event.data };
9705
+ pending = {
9706
+ type: event.type,
9707
+ data: event.data,
9708
+ ...event.parentId ? { parentId: event.parentId } : {}
9709
+ };
9475
9710
  }
9476
9711
  schedule();
9477
9712
  },
@@ -10101,7 +10336,8 @@ function worktreeBindingFrom(from) {
10101
10336
  prState: from.prState,
10102
10337
  skipAutoArchiveOnMerge: from.skipAutoArchiveOnMerge,
10103
10338
  stackId: from.stackId,
10104
- stackLayer: from.stackLayer
10339
+ stackLayer: from.stackLayer,
10340
+ cowboy: from.cowboy
10105
10341
  };
10106
10342
  }
10107
10343
  function threadsSharingWorktree(worktreePath) {
@@ -11294,6 +11530,55 @@ async function createThread(input, _onSetupLine) {
11294
11530
  if (!(0, import_node_fs32.existsSync)(repoPath)) {
11295
11531
  throw new Error(`Repo not found: ${repoPath}`);
11296
11532
  }
11533
+ if (input.cowboy) {
11534
+ const { cowboyModeEnabled: cowboyModeEnabled2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
11535
+ if (!cowboyModeEnabled2()) {
11536
+ throw new Error(
11537
+ "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
11538
+ );
11539
+ }
11540
+ if (input.sourceType === "pr" || input.sourceType === "ticket" || input.sourceType === "adopt") {
11541
+ throw new Error(
11542
+ "Cowboy mode works on the project folder (default branch), not a PR, ticket, or adopt."
11543
+ );
11544
+ }
11545
+ const defaultBranch = await resolveDefaultBranch(repoPath, { network: false });
11546
+ const head = await currentBranch(repoPath);
11547
+ if (head === "HEAD") {
11548
+ throw new Error(
11549
+ "Cowboy mode needs a named branch in the project folder (not a detached HEAD)."
11550
+ );
11551
+ }
11552
+ if (head !== defaultBranch) {
11553
+ throw new Error(
11554
+ `Cowboy mode uses ${defaultBranch} in the project folder. Switch that checkout to ${defaultBranch} first (currently ${head}).`
11555
+ );
11556
+ }
11557
+ const explicitTitle2 = input.title?.trim();
11558
+ const thread2 = createEmptyThread({
11559
+ title: explicitTitle2 || `Cowboy \xB7 ${head}`,
11560
+ userSetTitle: Boolean(explicitTitle2),
11561
+ sourceType: "branch",
11562
+ sourceRef: head,
11563
+ branchName: head,
11564
+ worktreePath: repoPath,
11565
+ repoPath,
11566
+ agent: resolved.agent,
11567
+ autonomy: input.autonomy ?? "default",
11568
+ model: resolved.model,
11569
+ effort: resolved.effort,
11570
+ fast: resolved.fast,
11571
+ planMode: Boolean(input.planMode),
11572
+ attachments: input.attachments ?? [],
11573
+ sourceIsFork: false,
11574
+ parentThreadId: input.parentThreadId ?? null,
11575
+ status: "idle",
11576
+ cowboy: true
11577
+ });
11578
+ writeThread(thread2);
11579
+ await ensureWorkspace(repoPath);
11580
+ return readThread(thread2.id) ?? thread2;
11581
+ }
11297
11582
  let sourceRef = input.sourceRef;
11298
11583
  let sourceIsFork = false;
11299
11584
  let prUrl = null;
@@ -11379,6 +11664,24 @@ var init_create = __esm({
11379
11664
  }
11380
11665
  });
11381
11666
 
11667
+ // src/threads/cowboy.ts
11668
+ function isCowboyThread(thread) {
11669
+ return Boolean(thread?.cowboy);
11670
+ }
11671
+ function isPrimaryCheckoutThread(thread) {
11672
+ if (!thread?.worktreePath || !thread.repoPath) return false;
11673
+ return normalizeWorktreePath(thread.worktreePath) === normalizeWorktreePath(thread.repoPath);
11674
+ }
11675
+ function shouldRemoveWorktreeOnTeardown(thread) {
11676
+ return !isCowboyThread(thread) && !isPrimaryCheckoutThread(thread);
11677
+ }
11678
+ var init_cowboy = __esm({
11679
+ "src/threads/cowboy.ts"() {
11680
+ "use strict";
11681
+ init_worktree_labels();
11682
+ }
11683
+ });
11684
+
11382
11685
  // src/store/turn-live.ts
11383
11686
  function trimParts(parts) {
11384
11687
  if (parts.length <= MAX_PARTS) return parts;
@@ -11672,8 +11975,12 @@ var init_quota_failover = __esm({
11672
11975
  });
11673
11976
 
11674
11977
  // src/threads/adopt.ts
11978
+ function thisModuleFile() {
11979
+ const cjsFile = typeof __filename !== "undefined" ? __filename : "";
11980
+ return cjsFile || process.argv[1] || (0, import_node_path31.join)(process.cwd(), "package.json");
11981
+ }
11675
11982
  function openReadonlySqlite(file) {
11676
- const req = (0, import_node_module4.createRequire)(import_meta4.url);
11983
+ const req = (0, import_node_module4.createRequire)(thisModuleFile());
11677
11984
  const Database = req("better-sqlite3");
11678
11985
  return new Database(file, { readonly: true, fileMustExist: true });
11679
11986
  }
@@ -11939,7 +12246,7 @@ function importConductorWorkspace(workspaceId) {
11939
12246
  async function importConductorWorkspaceAsync(workspaceId) {
11940
12247
  return importConductorWorkspace(workspaceId);
11941
12248
  }
11942
- var import_node_child_process3, import_node_fs34, import_node_os10, import_node_path31, import_node_module4, import_meta4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
12249
+ var import_node_child_process3, import_node_fs34, import_node_os10, import_node_path31, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
11943
12250
  var init_adopt = __esm({
11944
12251
  "src/threads/adopt.ts"() {
11945
12252
  "use strict";
@@ -11950,7 +12257,6 @@ var init_adopt = __esm({
11950
12257
  import_node_module4 = require("module");
11951
12258
  init_worktree();
11952
12259
  init_thread_store();
11953
- import_meta4 = {};
11954
12260
  CONDUCTOR_APP_SUPPORT = (0, import_node_path31.join)(
11955
12261
  process.env.HOME ?? "",
11956
12262
  "Library",
@@ -13021,13 +13327,22 @@ async function previewLand(thread) {
13021
13327
  isFork: true
13022
13328
  };
13023
13329
  }
13024
- const target = await resolveDefaultBranch(thread.repoPath);
13025
- if (thread.branchName === target || thread.branchName === "main" || thread.branchName === "master") {
13330
+ if (isCowboyThread(thread)) {
13331
+ const current2 = await currentBranch(thread.worktreePath);
13332
+ const dirty = await isDirty(thread.worktreePath);
13333
+ const diff2 = await getDiff(thread.worktreePath, thread.repoPath, { base: current2 });
13334
+ return {
13335
+ branch: current2,
13336
+ target: current2,
13337
+ diffStat: diff2.stat,
13338
+ dirty,
13339
+ blocked: false,
13340
+ isFork: false,
13341
+ cowboy: true
13342
+ };
13026
13343
  }
13027
- const { stdout: head } = await Promise.resolve().then(() => (init_run(), run_exports)).then(
13028
- ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], thread.worktreePath)
13029
- );
13030
- const current = head.trim();
13344
+ const target = await resolveDefaultBranch(thread.repoPath);
13345
+ const current = await currentBranch(thread.worktreePath);
13031
13346
  if (current === target) {
13032
13347
  return {
13033
13348
  branch: current,
@@ -13054,6 +13369,19 @@ async function confirmLand(thread, opts) {
13054
13369
  if (preview.blocked) {
13055
13370
  throw new Error(preview.blockReason ?? "Land blocked");
13056
13371
  }
13372
+ if (preview.cowboy) {
13373
+ const meta2 = await suggestPrMetadata(thread.worktreePath, {
13374
+ base: preview.branch,
13375
+ fallbackTitle: thread.title,
13376
+ sourceLabel: `${thread.sourceType}:${thread.sourceRef}`
13377
+ });
13378
+ let committed2 = false;
13379
+ if (preview.dirty) {
13380
+ committed2 = await commitAll(thread.worktreePath, meta2.commitMessage);
13381
+ }
13382
+ await pushBranch(thread.worktreePath, preview.branch);
13383
+ return { prUrl: null, pushed: true, committed: committed2 };
13384
+ }
13057
13385
  const meta = await suggestPrMetadata(thread.worktreePath, {
13058
13386
  base: preview.target,
13059
13387
  fallbackTitle: thread.title,
@@ -13098,6 +13426,7 @@ var init_land = __esm({
13098
13426
  init_diff();
13099
13427
  init_pr_metadata();
13100
13428
  init_gh_errors();
13429
+ init_cowboy();
13101
13430
  }
13102
13431
  });
13103
13432
 
@@ -13683,7 +14012,7 @@ var init_instructions = __esm({
13683
14012
  });
13684
14013
 
13685
14014
  // src/plan/plan-present.ts
13686
- function asRecord4(v) {
14015
+ function asRecord5(v) {
13687
14016
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
13688
14017
  }
13689
14018
  function isPresentPlanToolName(name) {
@@ -13695,7 +14024,7 @@ function extractPresentedPlan(parts) {
13695
14024
  for (let i = parts.length - 1; i >= 0; i--) {
13696
14025
  const p = parts[i];
13697
14026
  if (p.type !== "tool" || !isPresentPlanToolName(p.name)) continue;
13698
- const input = asRecord4(p.input) ?? {};
14027
+ const input = asRecord5(p.input) ?? {};
13699
14028
  const content = typeof input.content === "string" ? input.content : typeof input.plan === "string" ? input.plan : typeof input.markdown === "string" ? input.markdown : "";
13700
14029
  if (!content.trim()) continue;
13701
14030
  const title = typeof input.title === "string" && input.title.trim() ? input.title.trim() : "Plan";
@@ -14558,6 +14887,7 @@ var init_orchestrator = __esm({
14558
14887
  init_thread_store();
14559
14888
  init_desktop_host();
14560
14889
  init_create();
14890
+ init_cowboy();
14561
14891
  init_orchestrator_capable();
14562
14892
  init_chat_tabs();
14563
14893
  init_enqueue_by_key();
@@ -14834,7 +15164,9 @@ var init_orchestrator = __esm({
14834
15164
  return thread;
14835
15165
  }
14836
15166
  async finishCreateThread(threadId, prompt) {
14837
- const setup = this.runSetupAfterCreate(threadId);
15167
+ const created = this.getThread(threadId);
15168
+ const skipSetup = isCowboyThread(created);
15169
+ const setup = skipSetup ? Promise.resolve() : this.runSetupAfterCreate(threadId);
14838
15170
  if (prompt) {
14839
15171
  try {
14840
15172
  await this.send(threadId, prompt);
@@ -14846,6 +15178,7 @@ var init_orchestrator = __esm({
14846
15178
  }
14847
15179
  }
14848
15180
  await setup;
15181
+ if (skipSetup) return;
14849
15182
  const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
14850
15183
  if (autoRunAfterSetupEnabled2()) {
14851
15184
  try {
@@ -16177,17 +16510,19 @@ var init_orchestrator = __esm({
16177
16510
  const siblings = threadsSharingWorktree(thread.worktreePath).filter((t) => t.id !== thread.id);
16178
16511
  if (siblings.length === 0) {
16179
16512
  this.stopDev(thread.id);
16180
- try {
16181
- await runArchiveScript(thread.repoPath, thread.worktreePath, (line) => {
16182
- this.emit({
16183
- type: "turn_output",
16184
- threadId: thread.id,
16185
- event: { type: "stdout", data: `[archive] ${line}` }
16513
+ if (shouldRemoveWorktreeOnTeardown(thread)) {
16514
+ try {
16515
+ await runArchiveScript(thread.repoPath, thread.worktreePath, (line) => {
16516
+ this.emit({
16517
+ type: "turn_output",
16518
+ threadId: thread.id,
16519
+ event: { type: "stdout", data: `[archive] ${line}` }
16520
+ });
16186
16521
  });
16187
- });
16188
- } catch {
16522
+ } catch {
16523
+ }
16524
+ await removeWorktree(thread.repoPath, thread.worktreePath);
16189
16525
  }
16190
- await removeWorktree(thread.repoPath, thread.worktreePath);
16191
16526
  }
16192
16527
  const archived = setStatus(thread.id, "archived");
16193
16528
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
@@ -16215,15 +16550,17 @@ var init_orchestrator = __esm({
16215
16550
  const siblings = threadsSharingWorktree(thread.worktreePath).filter((t) => t.id !== thread.id);
16216
16551
  if (siblings.length === 0) {
16217
16552
  this.stopDev(thread.id);
16218
- try {
16219
- await runArchiveScript(thread.repoPath, thread.worktreePath);
16220
- } catch {
16553
+ if (shouldRemoveWorktreeOnTeardown(thread)) {
16554
+ try {
16555
+ await runArchiveScript(thread.repoPath, thread.worktreePath);
16556
+ } catch {
16557
+ }
16558
+ const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
16559
+ const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled2();
16560
+ await removeWorktree(thread.repoPath, thread.worktreePath, {
16561
+ deleteBranch: deleteBranch ? thread.branchName : void 0
16562
+ });
16221
16563
  }
16222
- const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
16223
- const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled2();
16224
- await removeWorktree(thread.repoPath, thread.worktreePath, {
16225
- deleteBranch: deleteBranch ? thread.branchName : void 0
16226
- });
16227
16564
  }
16228
16565
  deleteThreadRecord(thread.id);
16229
16566
  }
@@ -16240,6 +16577,11 @@ var init_orchestrator = __esm({
16240
16577
  return restored2;
16241
16578
  }
16242
16579
  if (!(0, import_node_fs44.existsSync)(thread.worktreePath)) {
16580
+ if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
16581
+ throw new Error(
16582
+ `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
16583
+ );
16584
+ }
16243
16585
  const { createThreadWorktree: createThreadWorktree2 } = await Promise.resolve().then(() => (init_worktree(), worktree_exports));
16244
16586
  const slug = thread.worktreePath.split("/").pop();
16245
16587
  const dest = thread.worktreePath;
@@ -17886,7 +18228,7 @@ async function startMcpServer() {
17886
18228
  );
17887
18229
  server.tool(
17888
18230
  "create_thread",
17889
- `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Setup (settings.toml, .cursor/worktrees.json, or script/setup) runs in the background in parallel with the first turn. Then use send_to_thread to chat.`,
18231
+ `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. cowboy=true uses the project folder on the default branch (no isolated worktree; land is commit+push). From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Setup (settings.toml, .cursor/worktrees.json, or script/setup) runs in the background in parallel with the first turn (skipped for cowboy). Then use send_to_thread to chat.`,
17890
18232
  {
17891
18233
  sourceType: import_zod4.z.enum(["branch", "pr", "ticket"]),
17892
18234
  sourceRef: import_zod4.z.string(),
@@ -17896,6 +18238,9 @@ async function startMcpServer() {
17896
18238
  ),
17897
18239
  repoPath: import_zod4.z.string(),
17898
18240
  title: import_zod4.z.string().optional(),
18241
+ cowboy: import_zod4.z.boolean().optional().describe(
18242
+ "If true, work in the project folder on the default branch (no thread/* worktree). Requires Settings \u2192 Advanced \u2192 Cowboy mode. Land is commit+push to that branch. Archive does not delete the folder."
18243
+ ),
17899
18244
  parentThreadId: import_zod4.z.string().optional().describe(
17900
18245
  "Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
17901
18246
  )
@@ -17956,7 +18301,8 @@ async function startMcpServer() {
17956
18301
  fast: opts.fast,
17957
18302
  repoPath: args.repoPath,
17958
18303
  title: args.title,
17959
- parentThreadId: parentId || null
18304
+ parentThreadId: parentId || null,
18305
+ cowboy: args.cowboy || void 0
17960
18306
  }),
17961
18307
  CREATE_THREAD_TIMEOUT_MS,
17962
18308
  "create_thread"
@@ -17974,6 +18320,7 @@ async function startMcpServer() {
17974
18320
  agent: thread.agent,
17975
18321
  model: thread.model,
17976
18322
  status: thread.status,
18323
+ cowboy: Boolean(thread.cowboy),
17977
18324
  link: `sideboard://thread/${thread.id}`,
17978
18325
  parentThreadId: thread.parentThreadId,
17979
18326
  ...agentCoercedFrom ? {