@sideboard-ai/core 0.1.107 → 0.1.110

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 (44) hide show
  1. package/dist/agents/cursor-runner.cjs +87 -12
  2. package/dist/agents/cursor-runner.js +38 -12
  3. package/dist/{agents-T4RHL5UX.js → agents-MQDW3YXL.js} +6 -6
  4. package/dist/{agents-4XQANGFO.js → agents-WK54VP7J.js} +8 -8
  5. package/dist/{app-settings-2WH6DVOW.js → app-settings-5XAGNDX7.js} +3 -1
  6. package/dist/{app-settings-6AXBWM3K.js → app-settings-J4LUWIRN.js} +4 -2
  7. package/dist/{chunk-HUKCGRAT.js → chunk-3UOKB6VQ.js} +47 -2
  8. package/dist/{chunk-SMWVSSE5.js → chunk-4EWPKYOU.js} +4 -4
  9. package/dist/{chunk-7ZTQHC2Q.js → chunk-4NR5FL46.js} +11 -1
  10. package/dist/{chunk-TLPJHLLM.js → chunk-4TR3HZFT.js} +1 -1
  11. package/dist/{chunk-VTTTV2LM.js → chunk-7KWYXGIU.js} +2 -2
  12. package/dist/{chunk-KGSVLZV6.js → chunk-A4VZXJEJ.js} +2 -0
  13. package/dist/{chunk-5XUKY2JY.js → chunk-AROMOP3C.js} +8 -16
  14. package/dist/{chunk-PZVA2VDF.js → chunk-C4KHDW3U.js} +2 -2
  15. package/dist/{chunk-3SIFRHJ3.js → chunk-EAAB4EK5.js} +1597 -1704
  16. package/dist/{chunk-GYFNFU62.js → chunk-KQBI5HNT.js} +8 -16
  17. package/dist/{chunk-P3BQ5DOL.js → chunk-KYOTBZ6S.js} +2 -0
  18. package/dist/{chunk-6HRR4T4P.js → chunk-RSIWPLRG.js} +483 -46
  19. package/dist/{chunk-EX4NZN3O.js → chunk-SGEVS5SY.js} +11 -1
  20. package/dist/{chunk-THXSFETX.js → chunk-VOD3HFLP.js} +4 -4
  21. package/dist/{chunk-XOYH3OMI.js → chunk-VOJSO3RM.js} +484 -55
  22. package/dist/{chunk-MMI4RJ5I.js → chunk-WIHKHR5R.js} +14 -3
  23. package/dist/{chunk-XEFHG6VG.js → chunk-XOZDAVOP.js} +1449 -1518
  24. package/dist/{chunk-LRO7YVLJ.js → chunk-YFAXVUY2.js} +2 -2
  25. package/dist/{chunk-6JJTMI7G.js → chunk-YXDR43ZC.js} +2 -2
  26. package/dist/{coordinator-prompt-4TUQUEHY.js → coordinator-prompt-AR66L3N4.js} +5 -5
  27. package/dist/{coordinator-prompt-YQWRXCPX.js → coordinator-prompt-BHMLWL64.js} +4 -4
  28. package/dist/{global-workspace-H37LFFXI.js → global-workspace-SKFODUQQ.js} +5 -5
  29. package/dist/{global-workspace-V6TMECDU.js → global-workspace-XSUFEIAQ.js} +6 -6
  30. package/dist/index.cjs +2388 -2006
  31. package/dist/index.d.cts +115 -26
  32. package/dist/index.d.ts +115 -26
  33. package/dist/index.js +141 -98
  34. package/dist/mcp/run-stdio.cjs +2354 -1988
  35. package/dist/mcp/run-stdio.js +90 -82
  36. package/dist/{orchestrator-DEHSKERK.js → orchestrator-FCZVCKBK.js} +11 -11
  37. package/dist/{orchestrator-2P7DX44Q.js → orchestrator-SCATSB3O.js} +8 -8
  38. package/dist/{thread-store-DQJGDKIJ.js → thread-store-LPTBVW5C.js} +1 -1
  39. package/dist/{thread-store-4OUEQ2DB.js → thread-store-OEALWU7Y.js} +1 -1
  40. package/dist/{workspaces-UPEVANU4.js → workspaces-HV3J4TTW.js} +7 -7
  41. package/dist/{workspaces-JU3P6FHB.js → workspaces-XAQVKTLO.js} +6 -6
  42. package/dist/{worktree-6MFKE465.js → worktree-N2EV24EE.js} +3 -3
  43. package/dist/{worktree-NR5YJG2E.js → worktree-XFJED3VU.js} +4 -4
  44. package/package.json +1 -1
@@ -204,27 +204,36 @@ function withCursorLocalHangGuards(local) {
204
204
  return { ...local, enableAgentRetries: false };
205
205
  }
206
206
  var CURSOR_STREAM_IDLE_MS = 18e4;
207
- async function* iterateUntilIdle(iterable, idleMs, onIdle) {
207
+ async function* iterateUntilIdle(iterable, idleMs, onIdle, activity) {
208
208
  const iterator = iterable[Symbol.asyncIterator]();
209
+ const bump = () => {
210
+ if (activity) activity.at = Date.now();
211
+ };
209
212
  try {
213
+ let pending = iterator.next();
210
214
  while (true) {
215
+ const waitMs = activity ? Math.max(0, idleMs - (Date.now() - activity.at)) : idleMs;
211
216
  let idleTimer;
212
- const next = iterator.next();
213
217
  const raced = await Promise.race([
214
- next.then((result) => ({ kind: "item", result })),
218
+ pending.then((result) => ({ kind: "item", result })),
215
219
  new Promise((resolve) => {
216
- idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
220
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), waitMs);
217
221
  idleTimer.unref?.();
218
222
  })
219
223
  ]);
220
224
  if (idleTimer) clearTimeout(idleTimer);
221
225
  if (raced.kind === "idle") {
226
+ if (activity && Date.now() - activity.at < idleMs) {
227
+ continue;
228
+ }
222
229
  onIdle?.();
223
230
  void iterator.return?.();
224
231
  return;
225
232
  }
226
233
  if (raced.result.done) return;
234
+ bump();
227
235
  yield raced.result.value;
236
+ pending = iterator.next();
228
237
  }
229
238
  } catch (err) {
230
239
  void iterator.return?.();
@@ -427,11 +436,53 @@ function cursorSdkMessageToEvents(msg) {
427
436
  }
428
437
  return [];
429
438
  }
439
+ function nestedUpdateToEvents(update, parentId) {
440
+ if (update.type === "thinking-delta" && update.text) {
441
+ return [{ type: "thinking", data: update.text, parentId }];
442
+ }
443
+ if (update.type === "text-delta" && update.text) {
444
+ return [{ type: "stdout", data: update.text, parentId }];
445
+ }
446
+ if ((update.type === "tool-call-started" || update.type === "tool-call-completed") && update.callId && update.toolCall) {
447
+ const rawName = typeof update.toolCall.type === "string" ? update.toolCall.type : "tool";
448
+ const normalized = normalizeCursorToolCall(rawName, update.toolCall.args);
449
+ const events = [
450
+ {
451
+ type: "tool_use",
452
+ id: update.callId,
453
+ name: normalized.name,
454
+ input: normalized.input,
455
+ parentId
456
+ }
457
+ ];
458
+ if (update.type === "tool-call-completed") {
459
+ events.push({
460
+ type: "tool_result",
461
+ id: update.callId,
462
+ content: unwrapCursorToolResult(update.toolCall.result),
463
+ isError: cursorToolResultIsError(void 0, update.toolCall.result),
464
+ parentId
465
+ });
466
+ }
467
+ return events;
468
+ }
469
+ return [];
470
+ }
471
+ function cursorDeltaToEvents(update) {
472
+ if (!update?.type) return [];
473
+ if (update.type === "tool-call-delta" && update.callId && update.taskUpdate) {
474
+ return nestedUpdateToEvents(update.taskUpdate, update.callId);
475
+ }
476
+ return [];
477
+ }
430
478
 
431
479
  // src/agents/cursor-stream-coalesce.ts
432
480
  function isTextEvent(event) {
433
481
  return event.type === "stdout" || event.type === "thinking";
434
482
  }
483
+ function parentKey(event) {
484
+ return event.parentId ?? "";
485
+ }
435
486
  function createAgentStreamCoalescer(emit2, opts) {
436
487
  const intervalMs = opts?.intervalMs ?? 32;
437
488
  let pending = null;
@@ -444,7 +495,11 @@ function createAgentStreamCoalescer(emit2, opts) {
444
495
  if (!pending) return;
445
496
  const event = pending;
446
497
  pending = null;
447
- emit2({ type: event.type, data: event.data });
498
+ emit2({
499
+ type: event.type,
500
+ data: event.data,
501
+ ...event.parentId ? { parentId: event.parentId } : {}
502
+ });
448
503
  };
449
504
  const schedule = () => {
450
505
  if (timer) return;
@@ -459,11 +514,15 @@ function createAgentStreamCoalescer(emit2, opts) {
459
514
  return;
460
515
  }
461
516
  if (!event.data) return;
462
- if (pending && pending.type === event.type) {
517
+ if (pending && pending.type === event.type && parentKey(pending) === parentKey(event)) {
463
518
  pending.data += event.data;
464
519
  } else {
465
520
  flush();
466
- pending = { type: event.type, data: event.data };
521
+ pending = {
522
+ type: event.type,
523
+ data: event.data,
524
+ ...event.parentId ? { parentId: event.parentId } : {}
525
+ };
467
526
  }
468
527
  schedule();
469
528
  },
@@ -584,8 +643,11 @@ async function main() {
584
643
  return createAgent();
585
644
  }
586
645
  }
587
- async function sendPrompt(agent) {
588
- const sendOpts = cursorSendOptions(mcpServers);
646
+ async function sendPrompt(agent, extra) {
647
+ const sendOpts = {
648
+ ...cursorSendOptions(mcpServers),
649
+ ...extra
650
+ };
589
651
  try {
590
652
  return await agent.send(req.prompt, sendOpts);
591
653
  } catch (err) {
@@ -626,9 +688,20 @@ async function main() {
626
688
  process.once("SIGINT", onSignal);
627
689
  async function runTurn(agent) {
628
690
  emit({ type: "session_id", data: agent.agentId });
629
- const run2 = await sendPrompt(agent);
630
- liveRun = run2;
631
691
  const stream = createAgentStreamCoalescer(emit);
692
+ const activity = { at: Date.now() };
693
+ const bump = () => {
694
+ activity.at = Date.now();
695
+ };
696
+ const run2 = await sendPrompt(agent, {
697
+ onDelta: ({ update }) => {
698
+ bump();
699
+ for (const event of cursorDeltaToEvents(update)) {
700
+ stream.push(event);
701
+ }
702
+ }
703
+ });
704
+ liveRun = run2;
632
705
  let streamIdle = false;
633
706
  try {
634
707
  for await (const msg of iterateUntilIdle(
@@ -641,8 +714,10 @@ async function main() {
641
714
  data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
642
715
  });
643
716
  void cancelLiveRun();
644
- }
717
+ },
718
+ activity
645
719
  )) {
720
+ bump();
646
721
  for (const event of cursorSdkMessageToEvents(msg)) {
647
722
  stream.push(event);
648
723
  }
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createAgentStreamCoalescer
4
- } from "../chunk-MMI4RJ5I.js";
4
+ } from "../chunk-WIHKHR5R.js";
5
5
  import {
6
+ cursorDeltaToEvents,
6
7
  cursorSdkMessageToEvents,
7
8
  ensureCursorRipgrepPath,
8
9
  formatUnknownDetail
9
- } from "../chunk-HUKCGRAT.js";
10
+ } from "../chunk-3UOKB6VQ.js";
10
11
  import {
11
12
  dropNestedElectronEnvFromProcess
12
- } from "../chunk-TLPJHLLM.js";
13
+ } from "../chunk-4TR3HZFT.js";
13
14
  import {
14
15
  appDataDir
15
16
  } from "../chunk-QZQEXME2.js";
@@ -57,27 +58,36 @@ function withCursorLocalHangGuards(local) {
57
58
  return { ...local, enableAgentRetries: false };
58
59
  }
59
60
  var CURSOR_STREAM_IDLE_MS = 18e4;
60
- async function* iterateUntilIdle(iterable, idleMs, onIdle) {
61
+ async function* iterateUntilIdle(iterable, idleMs, onIdle, activity) {
61
62
  const iterator = iterable[Symbol.asyncIterator]();
63
+ const bump = () => {
64
+ if (activity) activity.at = Date.now();
65
+ };
62
66
  try {
67
+ let pending = iterator.next();
63
68
  while (true) {
69
+ const waitMs = activity ? Math.max(0, idleMs - (Date.now() - activity.at)) : idleMs;
64
70
  let idleTimer;
65
- const next = iterator.next();
66
71
  const raced = await Promise.race([
67
- next.then((result) => ({ kind: "item", result })),
72
+ pending.then((result) => ({ kind: "item", result })),
68
73
  new Promise((resolve) => {
69
- idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
74
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), waitMs);
70
75
  idleTimer.unref?.();
71
76
  })
72
77
  ]);
73
78
  if (idleTimer) clearTimeout(idleTimer);
74
79
  if (raced.kind === "idle") {
80
+ if (activity && Date.now() - activity.at < idleMs) {
81
+ continue;
82
+ }
75
83
  onIdle?.();
76
84
  void iterator.return?.();
77
85
  return;
78
86
  }
79
87
  if (raced.result.done) return;
88
+ bump();
80
89
  yield raced.result.value;
90
+ pending = iterator.next();
81
91
  }
82
92
  } catch (err) {
83
93
  void iterator.return?.();
@@ -198,8 +208,11 @@ async function main() {
198
208
  return createAgent();
199
209
  }
200
210
  }
201
- async function sendPrompt(agent) {
202
- const sendOpts = cursorSendOptions(mcpServers);
211
+ async function sendPrompt(agent, extra) {
212
+ const sendOpts = {
213
+ ...cursorSendOptions(mcpServers),
214
+ ...extra
215
+ };
203
216
  try {
204
217
  return await agent.send(req.prompt, sendOpts);
205
218
  } catch (err) {
@@ -240,9 +253,20 @@ async function main() {
240
253
  process.once("SIGINT", onSignal);
241
254
  async function runTurn(agent) {
242
255
  emit({ type: "session_id", data: agent.agentId });
243
- const run = await sendPrompt(agent);
244
- liveRun = run;
245
256
  const stream = createAgentStreamCoalescer(emit);
257
+ const activity = { at: Date.now() };
258
+ const bump = () => {
259
+ activity.at = Date.now();
260
+ };
261
+ const run = await sendPrompt(agent, {
262
+ onDelta: ({ update }) => {
263
+ bump();
264
+ for (const event of cursorDeltaToEvents(update)) {
265
+ stream.push(event);
266
+ }
267
+ }
268
+ });
269
+ liveRun = run;
246
270
  let streamIdle = false;
247
271
  try {
248
272
  for await (const msg of iterateUntilIdle(
@@ -255,8 +279,10 @@ async function main() {
255
279
  data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
256
280
  });
257
281
  void cancelLiveRun();
258
- }
282
+ },
283
+ activity
259
284
  )) {
285
+ bump();
260
286
  for (const event of cursorSdkMessageToEvents(msg)) {
261
287
  stream.push(event);
262
288
  }
@@ -32,19 +32,19 @@ import {
32
32
  resolveCursorModelId,
33
33
  resolveLoginCommand,
34
34
  resolveQuotaFallbackAgent
35
- } from "./chunk-XOYH3OMI.js";
35
+ } from "./chunk-VOJSO3RM.js";
36
36
  import "./chunk-7YKXHBIW.js";
37
37
  import {
38
38
  ORCHESTRATOR_AGENT_KINDS,
39
39
  assertOrchestratorCapableAgent,
40
40
  coerceOrchestratorAgent,
41
41
  isOrchestratorCapableAgent
42
- } from "./chunk-THXSFETX.js";
43
- import "./chunk-5XUKY2JY.js";
44
- import "./chunk-6JJTMI7G.js";
42
+ } from "./chunk-VOD3HFLP.js";
43
+ import "./chunk-AROMOP3C.js";
44
+ import "./chunk-YXDR43ZC.js";
45
45
  import "./chunk-B3SJXYIJ.js";
46
- import "./chunk-P3BQ5DOL.js";
47
- import "./chunk-EX4NZN3O.js";
46
+ import "./chunk-KYOTBZ6S.js";
47
+ import "./chunk-SGEVS5SY.js";
48
48
  import "./chunk-NSTQ6QKD.js";
49
49
  import "./chunk-KGZBYWZ3.js";
50
50
  import "./chunk-BD2ICC4D.js";
@@ -28,25 +28,25 @@ import {
28
28
  resolveCursorModelId,
29
29
  resolveLoginCommand,
30
30
  resolveQuotaFallbackAgent
31
- } from "./chunk-6HRR4T4P.js";
31
+ } from "./chunk-RSIWPLRG.js";
32
32
  import "./chunk-2GO3YKBA.js";
33
33
  import {
34
34
  ORCHESTRATOR_AGENT_KINDS,
35
35
  assertOrchestratorCapableAgent,
36
36
  coerceOrchestratorAgent,
37
37
  isOrchestratorCapableAgent
38
- } from "./chunk-SMWVSSE5.js";
39
- import "./chunk-GYFNFU62.js";
38
+ } from "./chunk-4EWPKYOU.js";
39
+ import "./chunk-KQBI5HNT.js";
40
40
  import {
41
41
  cursorSdkMessageToEvents,
42
42
  parseCursorRunnerLine
43
- } from "./chunk-HUKCGRAT.js";
44
- import "./chunk-PZVA2VDF.js";
43
+ } from "./chunk-3UOKB6VQ.js";
44
+ import "./chunk-C4KHDW3U.js";
45
45
  import "./chunk-FKOIHGKV.js";
46
- import "./chunk-7ZTQHC2Q.js";
47
- import "./chunk-TLPJHLLM.js";
46
+ import "./chunk-4NR5FL46.js";
47
+ import "./chunk-4TR3HZFT.js";
48
48
  import "./chunk-JT7R45JB.js";
49
- import "./chunk-KGSVLZV6.js";
49
+ import "./chunk-A4VZXJEJ.js";
50
50
  import "./chunk-77WWLBCI.js";
51
51
  import "./chunk-QZQEXME2.js";
52
52
  import {
@@ -19,6 +19,7 @@ import {
19
19
  childEnvWithAppSettings,
20
20
  claudeChromeEnabled,
21
21
  claudeUserSettingsPath,
22
+ cowboyModeEnabled,
22
23
  deleteBranchOnPurgeEnabled,
23
24
  disconnectLinearConnection,
24
25
  ensureSlackDeviceIdentity,
@@ -55,7 +56,7 @@ import {
55
56
  updateDefaultsSettings,
56
57
  updateIntegrationsSettings,
57
58
  updateOpencodeSettings
58
- } from "./chunk-EX4NZN3O.js";
59
+ } from "./chunk-SGEVS5SY.js";
59
60
  import "./chunk-NSTQ6QKD.js";
60
61
  import "./chunk-KGZBYWZ3.js";
61
62
  import "./chunk-BD2ICC4D.js";
@@ -78,6 +79,7 @@ export {
78
79
  childEnvWithAppSettings,
79
80
  claudeChromeEnabled,
80
81
  claudeUserSettingsPath,
82
+ cowboyModeEnabled,
81
83
  deleteBranchOnPurgeEnabled,
82
84
  disconnectLinearConnection,
83
85
  ensureSlackDeviceIdentity,
@@ -17,6 +17,7 @@ import {
17
17
  childEnvWithAppSettings,
18
18
  claudeChromeEnabled,
19
19
  claudeUserSettingsPath,
20
+ cowboyModeEnabled,
20
21
  deleteBranchOnPurgeEnabled,
21
22
  disconnectLinearConnection,
22
23
  ensureSlackDeviceIdentity,
@@ -53,8 +54,8 @@ import {
53
54
  updateDefaultsSettings,
54
55
  updateIntegrationsSettings,
55
56
  updateOpencodeSettings
56
- } from "./chunk-7ZTQHC2Q.js";
57
- import "./chunk-TLPJHLLM.js";
57
+ } from "./chunk-4NR5FL46.js";
58
+ import "./chunk-4TR3HZFT.js";
58
59
  import "./chunk-JT7R45JB.js";
59
60
  import "./chunk-77WWLBCI.js";
60
61
  import "./chunk-QZQEXME2.js";
@@ -77,6 +78,7 @@ export {
77
78
  childEnvWithAppSettings,
78
79
  claudeChromeEnabled,
79
80
  claudeUserSettingsPath,
81
+ cowboyModeEnabled,
80
82
  deleteBranchOnPurgeEnabled,
81
83
  disconnectLinearConnection,
82
84
  ensureSlackDeviceIdentity,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isElectronLikeCommand,
3
3
  wrapElectronAsNodeLaunch
4
- } from "./chunk-TLPJHLLM.js";
4
+ } from "./chunk-4TR3HZFT.js";
5
5
  import {
6
6
  run
7
7
  } from "./chunk-LGXBYZZA.js";
@@ -94,6 +94,8 @@ function summarizeTurnStderr(tail, maxChars = 500) {
94
94
  if (tail.length === 0) return "";
95
95
  const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
96
96
  if (cursorStartup) return clipStderr(cursorStartup, maxChars);
97
+ const cursorRunFailed = [...tail].reverse().find((line) => /^cursor run failed\b/i.test(line.trim()));
98
+ if (cursorRunFailed) return clipStderr(cursorRunFailed, maxChars);
97
99
  if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
98
100
  if (tail.some(looksLikeHomebrewLibuvCrash)) return HOMEBREW_LIBUV_SUMMARY;
99
101
  if (tail.some(
@@ -124,7 +126,7 @@ function looksLikeRetryableRunnerCrash(text) {
124
126
  const lower = text.trim().toLowerCase();
125
127
  if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
126
128
  if (!lower) return true;
127
- return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
129
+ 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(
128
130
  lower
129
131
  );
130
132
  }
@@ -182,6 +184,9 @@ function humanizeAgentFailDetail(detail) {
182
184
  if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
183
185
  return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
184
186
  }
187
+ if (/connection stalled/.test(lower)) {
188
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
189
+ }
185
190
  return raw;
186
191
  }
187
192
  function turnFailChatText(opts) {
@@ -357,6 +362,45 @@ function cursorSdkMessageToEvents(msg) {
357
362
  }
358
363
  return [];
359
364
  }
365
+ function nestedUpdateToEvents(update, parentId) {
366
+ if (update.type === "thinking-delta" && update.text) {
367
+ return [{ type: "thinking", data: update.text, parentId }];
368
+ }
369
+ if (update.type === "text-delta" && update.text) {
370
+ return [{ type: "stdout", data: update.text, parentId }];
371
+ }
372
+ if ((update.type === "tool-call-started" || update.type === "tool-call-completed") && update.callId && update.toolCall) {
373
+ const rawName = typeof update.toolCall.type === "string" ? update.toolCall.type : "tool";
374
+ const normalized = normalizeCursorToolCall(rawName, update.toolCall.args);
375
+ const events = [
376
+ {
377
+ type: "tool_use",
378
+ id: update.callId,
379
+ name: normalized.name,
380
+ input: normalized.input,
381
+ parentId
382
+ }
383
+ ];
384
+ if (update.type === "tool-call-completed") {
385
+ events.push({
386
+ type: "tool_result",
387
+ id: update.callId,
388
+ content: unwrapCursorToolResult(update.toolCall.result),
389
+ isError: cursorToolResultIsError(void 0, update.toolCall.result),
390
+ parentId
391
+ });
392
+ }
393
+ return events;
394
+ }
395
+ return [];
396
+ }
397
+ function cursorDeltaToEvents(update) {
398
+ if (!update?.type) return [];
399
+ if (update.type === "tool-call-delta" && update.callId && update.taskUpdate) {
400
+ return nestedUpdateToEvents(update.taskUpdate, update.callId);
401
+ }
402
+ return [];
403
+ }
360
404
  function parseCursorRunnerLine(line) {
361
405
  const trimmed = line.trim();
362
406
  if (!trimmed) return null;
@@ -672,6 +716,7 @@ export {
672
716
  applyNodeLaunch,
673
717
  resolveNodeLaunch,
674
718
  cursorSdkMessageToEvents,
719
+ cursorDeltaToEvents,
675
720
  parseCursorRunnerLine,
676
721
  cursorRipgrepEnv,
677
722
  ensureCursorRipgrepPath
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-GYFNFU62.js";
3
+ } from "./chunk-KQBI5HNT.js";
4
4
  import {
5
5
  allocateTeamName,
6
6
  takenSlugsFromThread,
7
7
  teamSlugFromName
8
- } from "./chunk-PZVA2VDF.js";
8
+ } from "./chunk-C4KHDW3U.js";
9
9
  import {
10
10
  resolveNewThreadOptions,
11
11
  resolveThreadDefaults
12
- } from "./chunk-7ZTQHC2Q.js";
12
+ } from "./chunk-4NR5FL46.js";
13
13
  import {
14
14
  createEmptyThread,
15
15
  listThreads,
16
16
  updateThread,
17
17
  writeThread
18
- } from "./chunk-KGSVLZV6.js";
18
+ } from "./chunk-A4VZXJEJ.js";
19
19
  import {
20
20
  globalAgentCwd
21
21
  } from "./chunk-QZQEXME2.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  stripNestedElectronEnv
3
- } from "./chunk-TLPJHLLM.js";
3
+ } from "./chunk-4TR3HZFT.js";
4
4
  import {
5
5
  chmodOwnerOnly,
6
6
  writePrivateFile
@@ -430,6 +430,9 @@ function normalizeAdvanced(raw) {
430
430
  if (typeof source.deleteBranchOnPurge === "boolean") {
431
431
  out.deleteBranchOnPurge = source.deleteBranchOnPurge;
432
432
  }
433
+ if (typeof source.cowboyMode === "boolean") {
434
+ out.cowboyMode = source.cowboyMode;
435
+ }
433
436
  if (typeof source.autoArchiveOnMerge === "boolean") {
434
437
  out.autoArchiveOnMerge = source.autoArchiveOnMerge;
435
438
  }
@@ -964,6 +967,9 @@ function updateAdvancedSettings(patch) {
964
967
  if (typeof patch.deleteBranchOnPurge === "boolean") {
965
968
  advanced.deleteBranchOnPurge = patch.deleteBranchOnPurge;
966
969
  }
970
+ if (typeof patch.cowboyMode === "boolean") {
971
+ advanced.cowboyMode = patch.cowboyMode;
972
+ }
967
973
  if (typeof patch.autoArchiveOnMerge === "boolean") {
968
974
  advanced.autoArchiveOnMerge = patch.autoArchiveOnMerge;
969
975
  }
@@ -1014,6 +1020,9 @@ function caffeinateWhileCloudConnectEnabled(settings = loadAppSettings()) {
1014
1020
  function deleteBranchOnPurgeEnabled(settings = loadAppSettings()) {
1015
1021
  return Boolean(settings.advanced.deleteBranchOnPurge);
1016
1022
  }
1023
+ function cowboyModeEnabled(settings = loadAppSettings()) {
1024
+ return Boolean(settings.advanced.cowboyMode);
1025
+ }
1017
1026
  function autoArchiveOnMergeEnabled(settings = loadAppSettings()) {
1018
1027
  return Boolean(settings.advanced.autoArchiveOnMerge);
1019
1028
  }
@@ -1153,6 +1162,7 @@ export {
1153
1162
  caffeinateWhileSchedulesEnabled,
1154
1163
  caffeinateWhileCloudConnectEnabled,
1155
1164
  deleteBranchOnPurgeEnabled,
1165
+ cowboyModeEnabled,
1156
1166
  autoArchiveOnMergeEnabled,
1157
1167
  autoCleanupOrphansEnabled,
1158
1168
  orchestrationQuotaOnLimit,
@@ -35,7 +35,7 @@ function isElectronLikeCommand(command) {
35
35
  const name = command.trim();
36
36
  if (!name) return false;
37
37
  if (process.versions.electron && name === process.execPath) return true;
38
- return /(?:^|[/\\])Electron(?:\.exe)?$/i.test(name) || /Sideboard\.app[/\\]/i.test(name) || /Electron\.app[/\\]/i.test(name);
38
+ return /(?:^|[/\\])Electron(?:\.exe)?$/i.test(name) || /(?:^|[/\\])Sideboard(?:\.exe)?$/i.test(name) || /(?:Sideboard|Electron)\.app[/\\]Contents[/\\]MacOS[/\\]/i.test(name);
39
39
  }
40
40
  function unwrapStrippedElectronLaunch(command, args) {
41
41
  if (!isStrippedElectronLaunch(command, args) || !args || args.length < 4) {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-SMWVSSE5.js";
3
+ } from "./chunk-4EWPKYOU.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-PZVA2VDF.js";
7
+ } from "./chunk-C4KHDW3U.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-QZQEXME2.js";
@@ -41,6 +41,7 @@ function normalizeThread(raw) {
41
41
  prTitle: raw.prTitle ?? null,
42
42
  prState: raw.prState ?? null,
43
43
  skipAutoArchiveOnMerge: Boolean(raw.skipAutoArchiveOnMerge),
44
+ cowboy: Boolean(raw.cowboy),
44
45
  stackId: raw.stackId ?? null,
45
46
  stackLayer: raw.stackLayer ?? null,
46
47
  userSetTitle: Boolean(raw.userSetTitle),
@@ -69,6 +70,7 @@ function createEmptyThread(partial) {
69
70
  prTitle: partial.prTitle ?? null,
70
71
  prState: partial.prState ?? null,
71
72
  skipAutoArchiveOnMerge: partial.skipAutoArchiveOnMerge ?? false,
73
+ cowboy: Boolean(partial.cowboy),
72
74
  stackId: partial.stackId ?? null,
73
75
  stackLayer: partial.stackLayer ?? null,
74
76
  userSetTitle: partial.userSetTitle ?? false,
@@ -2,10 +2,10 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-6JJTMI7G.js";
5
+ } from "./chunk-YXDR43ZC.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
- } from "./chunk-EX4NZN3O.js";
8
+ } from "./chunk-SGEVS5SY.js";
9
9
  import {
10
10
  globalAgentCwd,
11
11
  sideboardReposDir
@@ -71,14 +71,14 @@ var COORDINATOR_TOOL_PLAYBOOK = [
71
71
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
72
72
  "Inspect / review / PRs:",
73
73
  "- get_diff \u2014 compact diff summary",
74
- '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
74
+ '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else seeds that skill / local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
75
75
  "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing.",
76
76
  '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
77
77
  '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
78
78
  "Process guides:",
79
79
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
80
- "- Recurring shapes: have the worktree agent write `.claude/skills/<kebab-name>/SKILL.md` (commit it) so later threads and native Claude Code / attach see it. Do not use `.sideboard/skills` for new guides. Codex/OpenCode: one line in AGENTS.md pointing at that file.",
81
- "- One-offs: no guide. Same miss across threads: edit the skill or `.sideboard/review.md`, then rerun the batch \u2014 do not patch three threads.",
80
+ "- Recurring shapes: have the worktree agent write `.claude/skills/<kebab-name>/SKILL.md` (commit it) so later threads and native Claude Code / attach see it. Merge-review sentences go in `.claude/skills/review/SKILL.md` (create it \u2014 that is allowed). Do not use `.sideboard/skills/` (that folder only). Codex/OpenCode: one line in AGENTS.md pointing at that file.",
81
+ "- One-offs: no guide. Same miss across threads: edit the skill or `.claude/skills/review/SKILL.md`, then rerun the batch \u2014 do not patch three threads.",
82
82
  "Human-only (do not attempt): ready-for-review land (confirm_land), purge_thread.",
83
83
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
84
84
  "Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
@@ -99,19 +99,11 @@ function coordinatorTurnReminder(opts) {
99
99
  const goal = opts.goal?.trim();
100
100
  return [
101
101
  "Sideboard Orchestration (mandatory):",
102
- "- You oversee Sideboard worktree agents. You are not yourself checked out in a project worktree.",
103
- "- This cwd is a synthetic empty home (not a git repo). Emptiness here is expected \u2014 it is not a problem to fix.",
104
- "- Registered workspaces / child threads are the fleet you manage via Sideboard MCP.",
105
- `- YOUR orchestration thread id is ${opts.parentId}`,
106
- `- Always pass parentThreadId="${opts.parentId}" on create_thread (never invent or reuse another uuid).`,
107
- `- Or omit parentThreadId \u2014 Sideboard MCP already binds children to ${opts.parentId}.`,
102
+ "- You oversee worktree agents from a synthetic empty cwd (not a git repo). Follow AGENTS.md / CLAUDE.md.",
103
+ `- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
108
104
  goal ? `- Goal / title: ${goal}` : null,
109
105
  accountDefaultsPlaybookLine(),
110
- `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
111
- "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn. If stillRunning, the child is working (progress is tools/thinking) \u2014 wait_for_turn again; do not ping it. If status is error, lastError/text is the failure \u2014 adapt (switch agent, tell the user). Commit/push/draft PR with ask_git on the child, then wait_for_turn \u2014 never git/gh from this cwd. Call ask_git merge only if the user explicitly asked to merge.",
112
- "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
113
- "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
114
- "- If they will wait on Slack, leave the Mac, or rely on overnight schedules, call set_caffeinate enabled=true (or they can enable Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled). When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false. Closing this chat also turns it off."
106
+ "- Status: list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked."
115
107
  ].filter(Boolean).join("\n");
116
108
  }
117
109
  function ensureGlobalCoordinatorCwd(opts) {
@@ -4,10 +4,10 @@ import {
4
4
  import {
5
5
  getGithubGitAuthMode,
6
6
  getGithubPat
7
- } from "./chunk-7ZTQHC2Q.js";
7
+ } from "./chunk-4NR5FL46.js";
8
8
  import {
9
9
  listThreads
10
- } from "./chunk-KGSVLZV6.js";
10
+ } from "./chunk-A4VZXJEJ.js";
11
11
  import {
12
12
  worktreesRoot
13
13
  } from "./chunk-QZQEXME2.js";