@sideboard-ai/core 0.1.283 → 0.1.284

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.
@@ -359,6 +359,12 @@ function sanitizeCursorStoreSegment(threadId) {
359
359
  return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
360
360
  }
361
361
 
362
+ // src/agents/cursor-stream-cutoff.ts
363
+ var CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
364
+ function looksLikeCursorStreamCutOff(text) {
365
+ return CURSOR_STREAM_CUTOFF.test(text.trim());
366
+ }
367
+
362
368
  // src/agents/error-detail.ts
363
369
  function formatUnknownDetail(err) {
364
370
  if (err == null) return "";
@@ -475,9 +481,6 @@ ${content.slice(-tail)}`;
475
481
  }
476
482
  var HUGE_TOOL_RESULT_SUMMARY = "Agent crashed mid-turn after a huge tool result. Write CLI/HTTP output to .context/cli/ and read a slice \u2014 never dump raw --json/--expand into the tool result.";
477
483
  var TOOL_RESULT_STORE_MAX_CHARS = 8e3;
478
- function looksLikeCursorStreamCutOff(text) {
479
- return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text.trim());
480
- }
481
484
 
482
485
  // src/agents/cursor-session.ts
483
486
  function cursorErrorMessage(err) {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  clipAgentEventForEmit,
4
4
  sideboardCursorRpcTools
5
- } from "../chunk-UZUXWBXK.js";
5
+ } from "../chunk-S2OOM7AU.js";
6
6
  import {
7
7
  createAgentStreamCoalescer
8
8
  } from "../chunk-AXQ4ZWHK.js";
@@ -17,12 +17,12 @@ import {
17
17
  fetchCursorTurnCostUsd,
18
18
  importCursorSdk,
19
19
  resolveCursorSdkRoot
20
- } from "../chunk-IFURHRAR.js";
20
+ } from "../chunk-VOIWX5HA.js";
21
21
  import {
22
22
  TOOL_RESULT_STORE_MAX_CHARS,
23
23
  formatUnknownDetail,
24
24
  looksLikeCursorStreamCutOff
25
- } from "../chunk-K2S33ZCB.js";
25
+ } from "../chunk-U6QDXT4K.js";
26
26
  import "../chunk-6K64FJDD.js";
27
27
  import {
28
28
  cursorSdkStoreDir
@@ -47,9 +47,9 @@ import {
47
47
  resolveLoginCommand,
48
48
  resolveQuotaFallbackAgent,
49
49
  whichOnPath
50
- } from "./chunk-OCUIZD4Y.js";
50
+ } from "./chunk-COQLZNKQ.js";
51
51
  import "./chunk-GWFVCCJZ.js";
52
- import "./chunk-BDAUPNHL.js";
52
+ import "./chunk-XSDCLM3F.js";
53
53
  import "./chunk-WY2IAB7J.js";
54
54
  import "./chunk-K5XSTHHP.js";
55
55
  import "./chunk-N5UGX3JL.js";
@@ -64,8 +64,8 @@ import {
64
64
  preferredCursorCostCents,
65
65
  resolveCursorSdkRoot,
66
66
  turnCostUsdFromCursorUsage
67
- } from "./chunk-IFURHRAR.js";
68
- import "./chunk-K2S33ZCB.js";
67
+ } from "./chunk-VOIWX5HA.js";
68
+ import "./chunk-U6QDXT4K.js";
69
69
  import "./chunk-6K64FJDD.js";
70
70
  import "./chunk-UWQ6UCIB.js";
71
71
  import {
@@ -56,11 +56,11 @@ import {
56
56
  resolveQuotaFallbackAgent,
57
57
  turnCostUsdFromCursorUsage,
58
58
  whichOnPath
59
- } from "./chunk-ADXVTKLC.js";
59
+ } from "./chunk-BSN6DJ4L.js";
60
60
  import "./chunk-TQRSVE7D.js";
61
61
  import "./chunk-P2BSMNHB.js";
62
62
  import "./chunk-VKQGAWHY.js";
63
- import "./chunk-W7HIK2A6.js";
63
+ import "./chunk-5QOLFOAX.js";
64
64
  import "./chunk-2SJXQ4UX.js";
65
65
  import "./chunk-5MGLNVNK.js";
66
66
  import "./chunk-N2WW62LF.js";
@@ -1,6 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
 
4
+ // src/agents/cursor-stream-cutoff.ts
5
+ var CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
6
+ var CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
7
+ function looksLikeCursorStreamCutOff(text) {
8
+ return CURSOR_STREAM_CUTOFF.test(text.trim());
9
+ }
10
+ function cursorStreamCutOffContinueLimit(detail) {
11
+ if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
12
+ return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
13
+ }
14
+ return null;
15
+ }
16
+ function nextCrashContinueCount(detail, used) {
17
+ const limit = cursorStreamCutOffContinueLimit(detail) ?? 1;
18
+ if (used >= limit) return null;
19
+ return used + 1;
20
+ }
21
+
4
22
  // src/agents/error-detail.ts
5
23
  function formatUnknownDetail(err) {
6
24
  if (err == null) return "";
@@ -199,9 +217,6 @@ function looksLikeInvalidAgentSession(text) {
199
217
  if (!lower) return false;
200
218
  return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
201
219
  }
202
- function looksLikeCursorStreamCutOff(text) {
203
- return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text.trim());
204
- }
205
220
  function looksLikeBrightsyEmptyCompletion(text) {
206
221
  const core = text.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
207
222
  return /^i did not receive a valid model response\. please try again\.$/i.test(core);
@@ -1185,6 +1200,7 @@ function normalizeParseResult(parsed) {
1185
1200
  }
1186
1201
 
1187
1202
  export {
1203
+ nextCrashContinueCount,
1188
1204
  formatUnknownDetail,
1189
1205
  extractJsonErrorMessage,
1190
1206
  pushTurnStderr,
@@ -2,7 +2,7 @@ import {
2
2
  compactSummaryPart,
3
3
  isInternalAgentStatusText,
4
4
  lastAssistantMessageText
5
- } from "./chunk-BDAUPNHL.js";
5
+ } from "./chunk-XSDCLM3F.js";
6
6
  import {
7
7
  isCloudCoordinatorThread,
8
8
  isGlobalThread,
@@ -29,7 +29,7 @@ import {
29
29
  } from "./chunk-2P4XKWV2.js";
30
30
  import {
31
31
  clipToolResultForStore
32
- } from "./chunk-K2S33ZCB.js";
32
+ } from "./chunk-U6QDXT4K.js";
33
33
  import {
34
34
  ATTACHMENTS_DIR,
35
35
  DETACHED_JOBS_DIR,
@@ -1776,7 +1776,7 @@ var PORT_RANGE_SIZE = 10;
1776
1776
  var RECLAIM_RETRY_DELAY_MS = 40;
1777
1777
  var RECLAIM_TRIES = 8;
1778
1778
  async function killReclaimable(ports, worktreePath, signal) {
1779
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-U776JSXQ.js");
1779
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-GBX6LSP2.js");
1780
1780
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1781
1781
  else killListenersOnPorts2(ports);
1782
1782
  }
@@ -21,7 +21,7 @@ import {
21
21
  looksLikeSkillBody,
22
22
  skillCommandFromBody,
23
23
  withEventParentId
24
- } from "./chunk-W7HIK2A6.js";
24
+ } from "./chunk-5QOLFOAX.js";
25
25
  import {
26
26
  isOrchestratorThread
27
27
  } from "./chunk-2SJXQ4UX.js";
@@ -9,7 +9,7 @@ import {
9
9
  looksLikeSkillBody,
10
10
  skillCommandFromBody,
11
11
  withEventParentId
12
- } from "./chunk-BDAUPNHL.js";
12
+ } from "./chunk-XSDCLM3F.js";
13
13
  import {
14
14
  isOrchestratorThread
15
15
  } from "./chunk-WY2IAB7J.js";
@@ -38,13 +38,13 @@ import {
38
38
  packagedMcpStdioPath,
39
39
  parseCursorRunnerLine,
40
40
  resolveNodeLaunch
41
- } from "./chunk-IFURHRAR.js";
41
+ } from "./chunk-VOIWX5HA.js";
42
42
  import {
43
43
  extractJsonErrorMessage,
44
44
  formatUnknownDetail,
45
45
  looksLikeAgentFailureMessage,
46
46
  looksLikeBrightsyEmptyCompletion
47
- } from "./chunk-K2S33ZCB.js";
47
+ } from "./chunk-U6QDXT4K.js";
48
48
  import {
49
49
  enrichPathWithNpmGlobalBin,
50
50
  isConductorBundledCli,
@@ -5,7 +5,7 @@ import {
5
5
  compactSummaryPart,
6
6
  isInternalAgentStatusText,
7
7
  lastAssistantMessageText
8
- } from "./chunk-W7HIK2A6.js";
8
+ } from "./chunk-5QOLFOAX.js";
9
9
  import {
10
10
  isCloudCoordinatorThread,
11
11
  isGlobalThread,
@@ -1674,7 +1674,7 @@ var PORT_RANGE_SIZE = 10;
1674
1674
  var RECLAIM_RETRY_DELAY_MS = 40;
1675
1675
  var RECLAIM_TRIES = 8;
1676
1676
  async function killReclaimable(ports, worktreePath, signal) {
1677
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-CNSCOC54.js");
1677
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-MU3TYVCD.js");
1678
1678
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1679
1679
  else killListenersOnPorts2(ports);
1680
1680
  }
@@ -23,7 +23,7 @@ import {
23
23
  parseSessionQuotaResetAt,
24
24
  planModeTurnInstruction,
25
25
  resolveQuotaFallbackAgent
26
- } from "./chunk-ADXVTKLC.js";
26
+ } from "./chunk-BSN6DJ4L.js";
27
27
  import {
28
28
  REVIEW_TAB_TITLE,
29
29
  applyWorktreePkgCacheEnv,
@@ -62,7 +62,7 @@ import {
62
62
  worktreeDevProcessKey,
63
63
  worktreeRunProcessKey,
64
64
  worktreeSetupProcessKey
65
- } from "./chunk-EIEAR62M.js";
65
+ } from "./chunk-LMWPVC5L.js";
66
66
  import {
67
67
  applyAgentEvent,
68
68
  clipAgentEventForPaint,
@@ -78,6 +78,7 @@ import {
78
78
  looksLikeInvalidAgentSession,
79
79
  looksLikeV8Oom,
80
80
  messagePartParentId,
81
+ nextCrashContinueCount,
81
82
  normalizeParseResult,
82
83
  partsToAssistantText,
83
84
  pushTurnStderr,
@@ -88,7 +89,7 @@ import {
88
89
  summarizeTurnStderr,
89
90
  toolDescription,
90
91
  turnFailChatText
91
- } from "./chunk-W7HIK2A6.js";
92
+ } from "./chunk-5QOLFOAX.js";
92
93
  import {
93
94
  SLACK_REPLY_FORMATTING,
94
95
  addWorkspace,
@@ -6093,7 +6094,7 @@ function formatScheduledPrompt(name, prompt) {
6093
6094
  ${prompt}`;
6094
6095
  }
6095
6096
  async function defaultDeps() {
6096
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-HWJHK5NL.js");
6097
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-CRBIW2RG.js");
6097
6098
  const orch = getOrchestrator2();
6098
6099
  return {
6099
6100
  findThread: (id) => findThreadByRef(id),
@@ -6261,10 +6262,10 @@ var Orchestrator = class {
6261
6262
  /** Timers for orchestration session-quota auto-resume. */
6262
6263
  quotaResumeTimers = /* @__PURE__ */ new Map();
6263
6264
  /**
6264
- * Threads that already got a crash-continue turn. Cleared on a successful
6265
- * finish or a user send so a later crash can recover again.
6265
+ * Crash-continue count per thread. Cleared on a successful finish or a user
6266
+ * send. Stream cutoffs may resume more than once; other crashes once.
6266
6267
  */
6267
- crashContinued = /* @__PURE__ */ new Set();
6268
+ crashContinued = /* @__PURE__ */ new Map();
6268
6269
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
6269
6270
  jobContinueCount = /* @__PURE__ */ new Map();
6270
6271
  jobContinueNudged = /* @__PURE__ */ new Set();
@@ -6703,7 +6704,6 @@ var Orchestrator = class {
6703
6704
  * next prompt so the same agent can continue instead of sitting on lastError.
6704
6705
  */
6705
6706
  maybeEnqueueCrashContinue(threadId, opts) {
6706
- if (this.crashContinued.has(threadId)) return;
6707
6707
  if (this.haltDrain.has(threadId)) return;
6708
6708
  if (!shouldFeedErrorBackToAgent({
6709
6709
  detail: opts.detail,
@@ -6712,9 +6712,11 @@ var Orchestrator = class {
6712
6712
  })) {
6713
6713
  return;
6714
6714
  }
6715
+ const resumeCount = nextCrashContinueCount(opts.detail, this.crashContinued.get(threadId) ?? 0);
6716
+ if (resumeCount == null) return;
6715
6717
  const thread = readThread(threadId);
6716
6718
  if (!thread || thread.status === "archived") return;
6717
- this.crashContinued.add(threadId);
6719
+ this.crashContinued.set(threadId, resumeCount);
6718
6720
  const prompt = formatAgentErrorContinuePrompt(opts.detail);
6719
6721
  const next = prependQueuedItem(thread.queue, thread.queueAttachments, prompt);
6720
6722
  updateThread(threadId, next);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  clipToolResultForStore,
3
3
  looksLikeHugeToolResultDump
4
- } from "./chunk-K2S33ZCB.js";
4
+ } from "./chunk-U6QDXT4K.js";
5
5
  import {
6
6
  CLI_DIR
7
7
  } from "./chunk-6K64FJDD.js";
@@ -1,3 +1,21 @@
1
+ // src/agents/cursor-stream-cutoff.ts
2
+ var CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
3
+ var CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
4
+ function looksLikeCursorStreamCutOff(text) {
5
+ return CURSOR_STREAM_CUTOFF.test(text.trim());
6
+ }
7
+ function cursorStreamCutOffContinueLimit(detail) {
8
+ if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
9
+ return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
10
+ }
11
+ return null;
12
+ }
13
+ function nextCrashContinueCount(detail, used) {
14
+ const limit = cursorStreamCutOffContinueLimit(detail) ?? 1;
15
+ if (used >= limit) return null;
16
+ return used + 1;
17
+ }
18
+
1
19
  // src/agents/error-detail.ts
2
20
  function formatUnknownDetail(err) {
3
21
  if (err == null) return "";
@@ -196,9 +214,6 @@ function looksLikeInvalidAgentSession(text) {
196
214
  if (!lower) return false;
197
215
  return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
198
216
  }
199
- function looksLikeCursorStreamCutOff(text) {
200
- return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text.trim());
201
- }
202
217
  function looksLikeBrightsyEmptyCompletion(text) {
203
218
  const core = text.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
204
219
  return /^i did not receive a valid model response\. please try again\.$/i.test(core);
@@ -370,6 +385,8 @@ function formatTurnExitError(exitCode, stderrSummary) {
370
385
  }
371
386
 
372
387
  export {
388
+ looksLikeCursorStreamCutOff,
389
+ nextCrashContinueCount,
373
390
  formatUnknownDetail,
374
391
  extractJsonErrorMessage,
375
392
  pushTurnStderr,
@@ -379,7 +396,6 @@ export {
379
396
  TOOL_RESULT_STORE_MAX_CHARS,
380
397
  summarizeTurnStderr,
381
398
  looksLikeInvalidAgentSession,
382
- looksLikeCursorStreamCutOff,
383
399
  looksLikeBrightsyEmptyCompletion,
384
400
  shouldRetryFailedAgentTurn,
385
401
  looksLikeAgentFailureMessage,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  extractJsonErrorMessage,
3
3
  formatUnknownDetail
4
- } from "./chunk-K2S33ZCB.js";
4
+ } from "./chunk-U6QDXT4K.js";
5
5
  import {
6
6
  npmGlobalNodeModules,
7
7
  run
@@ -8,7 +8,7 @@ import {
8
8
  parseSessionQuotaResetAt,
9
9
  planModeTurnInstruction,
10
10
  resolveQuotaFallbackAgent
11
- } from "./chunk-OCUIZD4Y.js";
11
+ } from "./chunk-COQLZNKQ.js";
12
12
  import {
13
13
  REVIEW_TAB_TITLE,
14
14
  applyWorktreePkgCacheEnv,
@@ -47,7 +47,7 @@ import {
47
47
  worktreeDevProcessKey,
48
48
  worktreeRunProcessKey,
49
49
  worktreeSetupProcessKey
50
- } from "./chunk-DQZPF6WL.js";
50
+ } from "./chunk-BMUVNTT4.js";
51
51
  import {
52
52
  applyAgentEvent,
53
53
  clipAgentEventForPaint,
@@ -62,7 +62,7 @@ import {
62
62
  partsToAssistantText,
63
63
  stripBrightsyNdjsonNoise,
64
64
  toolDescription
65
- } from "./chunk-BDAUPNHL.js";
65
+ } from "./chunk-XSDCLM3F.js";
66
66
  import {
67
67
  titleFromPrompt
68
68
  } from "./chunk-7H655NEW.js";
@@ -171,7 +171,7 @@ import {
171
171
  import {
172
172
  applyAgentRunnerHeapEnv,
173
173
  packagedMcpDir
174
- } from "./chunk-IFURHRAR.js";
174
+ } from "./chunk-VOIWX5HA.js";
175
175
  import {
176
176
  fallbackTurnFailDetail,
177
177
  formatAgentErrorContinuePrompt,
@@ -179,13 +179,14 @@ import {
179
179
  looksLikeAgentFailureMessage,
180
180
  looksLikeInvalidAgentSession,
181
181
  looksLikeV8Oom,
182
+ nextCrashContinueCount,
182
183
  pushTurnStderr,
183
184
  shouldFeedErrorBackToAgent,
184
185
  shouldRetryCodexPluginIsolate,
185
186
  shouldRetryFailedAgentTurn,
186
187
  summarizeTurnStderr,
187
188
  turnFailChatText
188
- } from "./chunk-K2S33ZCB.js";
189
+ } from "./chunk-U6QDXT4K.js";
189
190
  import {
190
191
  clearStaleIndexLocks,
191
192
  enrichPathWithNpmGlobalBin,
@@ -2738,7 +2739,7 @@ async function createThread(input, _onSetupLine) {
2738
2739
  return readThread(thread.id) ?? thread;
2739
2740
  }
2740
2741
  async function listLinearIssues(agent, repoPath) {
2741
- const { getAdapter: getAdapter2 } = await import("./agents-2IE4HKHA.js");
2742
+ const { getAdapter: getAdapter2 } = await import("./agents-6U2RQK7P.js");
2742
2743
  await requireAgent(agent, { requireLinear: true });
2743
2744
  const adapter = getAdapter2(agent);
2744
2745
  if (!adapter.listLinearIssues) {
@@ -6435,7 +6436,7 @@ function formatScheduledPrompt(name, prompt) {
6435
6436
  ${prompt}`;
6436
6437
  }
6437
6438
  async function defaultDeps() {
6438
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-FPGVKEID.js");
6439
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-6YVY6T5I.js");
6439
6440
  const orch = getOrchestrator2();
6440
6441
  return {
6441
6442
  findThread: (id) => findThreadByRef(id),
@@ -6603,10 +6604,10 @@ var Orchestrator = class {
6603
6604
  /** Timers for orchestration session-quota auto-resume. */
6604
6605
  quotaResumeTimers = /* @__PURE__ */ new Map();
6605
6606
  /**
6606
- * Threads that already got a crash-continue turn. Cleared on a successful
6607
- * finish or a user send so a later crash can recover again.
6607
+ * Crash-continue count per thread. Cleared on a successful finish or a user
6608
+ * send. Stream cutoffs may resume more than once; other crashes once.
6608
6609
  */
6609
- crashContinued = /* @__PURE__ */ new Set();
6610
+ crashContinued = /* @__PURE__ */ new Map();
6610
6611
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
6611
6612
  jobContinueCount = /* @__PURE__ */ new Map();
6612
6613
  jobContinueNudged = /* @__PURE__ */ new Set();
@@ -7045,7 +7046,6 @@ var Orchestrator = class {
7045
7046
  * next prompt so the same agent can continue instead of sitting on lastError.
7046
7047
  */
7047
7048
  maybeEnqueueCrashContinue(threadId, opts) {
7048
- if (this.crashContinued.has(threadId)) return;
7049
7049
  if (this.haltDrain.has(threadId)) return;
7050
7050
  if (!shouldFeedErrorBackToAgent({
7051
7051
  detail: opts.detail,
@@ -7054,9 +7054,11 @@ var Orchestrator = class {
7054
7054
  })) {
7055
7055
  return;
7056
7056
  }
7057
+ const resumeCount = nextCrashContinueCount(opts.detail, this.crashContinued.get(threadId) ?? 0);
7058
+ if (resumeCount == null) return;
7057
7059
  const thread = readThread(threadId);
7058
7060
  if (!thread || thread.status === "archived") return;
7059
- this.crashContinued.add(threadId);
7061
+ this.crashContinued.set(threadId, resumeCount);
7060
7062
  const prompt = formatAgentErrorContinuePrompt(opts.detail);
7061
7063
  const next = prependQueuedItem(thread.queue, thread.queueAttachments, prompt);
7062
7064
  updateThread(threadId, next);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clipToolResultForStore
3
- } from "./chunk-K2S33ZCB.js";
3
+ } from "./chunk-U6QDXT4K.js";
4
4
 
5
5
  // src/agents/message-parts.ts
6
6
  function asRecord(input) {
@@ -31,13 +31,13 @@ import {
31
31
  tryReservePort,
32
32
  tryReservePorts,
33
33
  worktreeRunPortsPath
34
- } from "./chunk-DQZPF6WL.js";
35
- import "./chunk-BDAUPNHL.js";
34
+ } from "./chunk-BMUVNTT4.js";
35
+ import "./chunk-XSDCLM3F.js";
36
36
  import "./chunk-WY2IAB7J.js";
37
37
  import "./chunk-K5XSTHHP.js";
38
38
  import "./chunk-N5UGX3JL.js";
39
39
  import "./chunk-2P4XKWV2.js";
40
- import "./chunk-K2S33ZCB.js";
40
+ import "./chunk-U6QDXT4K.js";
41
41
  import "./chunk-6K64FJDD.js";
42
42
  import "./chunk-UWQ6UCIB.js";
43
43
  import "./chunk-QVN2WOKJ.js";
@@ -33,8 +33,8 @@ import {
33
33
  tryReservePort,
34
34
  tryReservePorts,
35
35
  worktreeRunPortsPath
36
- } from "./chunk-EIEAR62M.js";
37
- import "./chunk-W7HIK2A6.js";
36
+ } from "./chunk-LMWPVC5L.js";
37
+ import "./chunk-5QOLFOAX.js";
38
38
  import "./chunk-2SJXQ4UX.js";
39
39
  import "./chunk-5MGLNVNK.js";
40
40
  import "./chunk-N2WW62LF.js";
package/dist/index.cjs CHANGED
@@ -4812,6 +4812,30 @@ var init_thread_store = __esm({
4812
4812
  }
4813
4813
  });
4814
4814
 
4815
+ // src/agents/cursor-stream-cutoff.ts
4816
+ function looksLikeCursorStreamCutOff(text7) {
4817
+ return CURSOR_STREAM_CUTOFF.test(text7.trim());
4818
+ }
4819
+ function cursorStreamCutOffContinueLimit(detail) {
4820
+ if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
4821
+ return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
4822
+ }
4823
+ return null;
4824
+ }
4825
+ function nextCrashContinueCount(detail, used) {
4826
+ const limit = cursorStreamCutOffContinueLimit(detail) ?? 1;
4827
+ if (used >= limit) return null;
4828
+ return used + 1;
4829
+ }
4830
+ var CURSOR_STREAM_CUTOFF, CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
4831
+ var init_cursor_stream_cutoff = __esm({
4832
+ "src/agents/cursor-stream-cutoff.ts"() {
4833
+ "use strict";
4834
+ CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
4835
+ CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
4836
+ }
4837
+ });
4838
+
4815
4839
  // src/agents/error-detail.ts
4816
4840
  function formatUnknownDetail(err) {
4817
4841
  if (err == null) return "";
@@ -5002,9 +5026,6 @@ function looksLikeInvalidAgentSession(text7) {
5002
5026
  if (!lower) return false;
5003
5027
  return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
5004
5028
  }
5005
- function looksLikeCursorStreamCutOff(text7) {
5006
- return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text7.trim());
5007
- }
5008
5029
  function looksLikeBrightsyEmptyCompletion(text7) {
5009
5030
  const core = text7.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
5010
5031
  return /^i did not receive a valid model response\. please try again\.$/i.test(core);
@@ -5178,6 +5199,8 @@ var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, BUNDLE
5178
5199
  var init_error_detail = __esm({
5179
5200
  "src/agents/error-detail.ts"() {
5180
5201
  "use strict";
5202
+ init_cursor_stream_cutoff();
5203
+ init_cursor_stream_cutoff();
5181
5204
  NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
5182
5205
  NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
5183
5206
  HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
@@ -27436,10 +27459,10 @@ var init_orchestrator = __esm({
27436
27459
  /** Timers for orchestration session-quota auto-resume. */
27437
27460
  quotaResumeTimers = /* @__PURE__ */ new Map();
27438
27461
  /**
27439
- * Threads that already got a crash-continue turn. Cleared on a successful
27440
- * finish or a user send so a later crash can recover again.
27462
+ * Crash-continue count per thread. Cleared on a successful finish or a user
27463
+ * send. Stream cutoffs may resume more than once; other crashes once.
27441
27464
  */
27442
- crashContinued = /* @__PURE__ */ new Set();
27465
+ crashContinued = /* @__PURE__ */ new Map();
27443
27466
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
27444
27467
  jobContinueCount = /* @__PURE__ */ new Map();
27445
27468
  jobContinueNudged = /* @__PURE__ */ new Set();
@@ -27878,7 +27901,6 @@ var init_orchestrator = __esm({
27878
27901
  * next prompt so the same agent can continue instead of sitting on lastError.
27879
27902
  */
27880
27903
  maybeEnqueueCrashContinue(threadId, opts) {
27881
- if (this.crashContinued.has(threadId)) return;
27882
27904
  if (this.haltDrain.has(threadId)) return;
27883
27905
  if (!shouldFeedErrorBackToAgent({
27884
27906
  detail: opts.detail,
@@ -27887,9 +27909,11 @@ var init_orchestrator = __esm({
27887
27909
  })) {
27888
27910
  return;
27889
27911
  }
27912
+ const resumeCount = nextCrashContinueCount(opts.detail, this.crashContinued.get(threadId) ?? 0);
27913
+ if (resumeCount == null) return;
27890
27914
  const thread = readThread(threadId);
27891
27915
  if (!thread || thread.status === "archived") return;
27892
- this.crashContinued.add(threadId);
27916
+ this.crashContinued.set(threadId, resumeCount);
27893
27917
  const prompt = formatAgentErrorContinuePrompt(opts.detail);
27894
27918
  const next = prependQueuedItem(thread.queue, thread.queueAttachments, prompt);
27895
27919
  updateThread(threadId, next);
package/dist/index.d.cts CHANGED
@@ -5536,8 +5536,8 @@ declare class Orchestrator {
5536
5536
  /** Timers for orchestration session-quota auto-resume. */
5537
5537
  private readonly quotaResumeTimers;
5538
5538
  /**
5539
- * Threads that already got a crash-continue turn. Cleared on a successful
5540
- * finish or a user send so a later crash can recover again.
5539
+ * Crash-continue count per thread. Cleared on a successful finish or a user
5540
+ * send. Stream cutoffs may resume more than once; other crashes once.
5541
5541
  */
5542
5542
  private readonly crashContinued;
5543
5543
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
package/dist/index.d.ts CHANGED
@@ -5536,8 +5536,8 @@ declare class Orchestrator {
5536
5536
  /** Timers for orchestration session-quota auto-resume. */
5537
5537
  private readonly quotaResumeTimers;
5538
5538
  /**
5539
- * Threads that already got a crash-continue turn. Cleared on a successful
5540
- * finish or a user send so a later crash can recover again.
5539
+ * Crash-continue count per thread. Cleared on a successful finish or a user
5540
+ * send. Stream cutoffs may resume more than once; other crashes once.
5541
5541
  */
5542
5542
  private readonly crashContinued;
5543
5543
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
package/dist/index.js CHANGED
@@ -198,7 +198,7 @@ import {
198
198
  worktreeBoardStatus,
199
199
  worktreeCleanupSettings,
200
200
  writeWorktreeFile
201
- } from "./chunk-2KNO2GJQ.js";
201
+ } from "./chunk-WQ4M2L44.js";
202
202
  import {
203
203
  BASE_ALLOWED_TOOLS,
204
204
  BRIGHTSY_MCP_ALLOWED_TOOLS,
@@ -288,7 +288,7 @@ import {
288
288
  whichOnPath,
289
289
  worktreeMcpToolNames,
290
290
  writeInjectedMcpConfig
291
- } from "./chunk-OCUIZD4Y.js";
291
+ } from "./chunk-COQLZNKQ.js";
292
292
  import {
293
293
  brightsyMcpServerName,
294
294
  connectBrightsyTeam,
@@ -415,7 +415,7 @@ import {
415
415
  workspaceAgentChatSummaries,
416
416
  worktreeRunPortsPath,
417
417
  wrapReviewSkillMarkdown
418
- } from "./chunk-DQZPF6WL.js";
418
+ } from "./chunk-BMUVNTT4.js";
419
419
  import {
420
420
  STDERR_EVENT_MAX_CHARS,
421
421
  STDOUT_EVENT_MAX_CHARS,
@@ -457,7 +457,7 @@ import {
457
457
  visibleToolRowDetail,
458
458
  withEventParentId,
459
459
  withEventsParentId
460
- } from "./chunk-BDAUPNHL.js";
460
+ } from "./chunk-XSDCLM3F.js";
461
461
  import "./chunk-7H655NEW.js";
462
462
  import {
463
463
  ABLETIME_OAUTH_CALLBACK_PATH,
@@ -736,7 +736,7 @@ import {
736
736
  } from "./chunk-N7WZ6NIN.js";
737
737
  import {
738
738
  clipMcpToolResult
739
- } from "./chunk-UZUXWBXK.js";
739
+ } from "./chunk-S2OOM7AU.js";
740
740
  import "./chunk-AXQ4ZWHK.js";
741
741
  import {
742
742
  AGENT_RUNNER_MAX_OLD_SPACE_MB,
@@ -752,8 +752,8 @@ import {
752
752
  trustSystemCertificates,
753
753
  turnCostUsdFromCursorUsage,
754
754
  withMaxOldSpaceSize
755
- } from "./chunk-IFURHRAR.js";
756
- import "./chunk-K2S33ZCB.js";
755
+ } from "./chunk-VOIWX5HA.js";
756
+ import "./chunk-U6QDXT4K.js";
757
757
  import {
758
758
  ATTACHMENTS_DIR,
759
759
  CLI_DIR,
@@ -5015,7 +5015,7 @@ async function handleJobStop(params, _ctx) {
5015
5015
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
5016
5016
  }
5017
5017
  async function defaultTurnWait(ref, timeoutMs) {
5018
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-FPGVKEID.js");
5018
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6YVY6T5I.js");
5019
5019
  const orch = getOrchestrator2();
5020
5020
  const thread = await orch.waitForTurn(ref, timeoutMs, {
5021
5021
  resolveIfStillRunning: true
@@ -12411,7 +12411,7 @@ async function continueSourceThread(threadId, prompt) {
12411
12411
  await continueOnReply(threadId, prompt);
12412
12412
  return;
12413
12413
  }
12414
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-FPGVKEID.js");
12414
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6YVY6T5I.js");
12415
12415
  await getOrchestrator2().send(threadId, prompt);
12416
12416
  } catch {
12417
12417
  }
@@ -800,6 +800,30 @@ var init_workspace_scratch = __esm({
800
800
  }
801
801
  });
802
802
 
803
+ // src/agents/cursor-stream-cutoff.ts
804
+ function looksLikeCursorStreamCutOff(text7) {
805
+ return CURSOR_STREAM_CUTOFF.test(text7.trim());
806
+ }
807
+ function cursorStreamCutOffContinueLimit(detail) {
808
+ if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
809
+ return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
810
+ }
811
+ return null;
812
+ }
813
+ function nextCrashContinueCount(detail, used) {
814
+ const limit = cursorStreamCutOffContinueLimit(detail) ?? 1;
815
+ if (used >= limit) return null;
816
+ return used + 1;
817
+ }
818
+ var CURSOR_STREAM_CUTOFF, CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
819
+ var init_cursor_stream_cutoff = __esm({
820
+ "src/agents/cursor-stream-cutoff.ts"() {
821
+ "use strict";
822
+ CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
823
+ CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
824
+ }
825
+ });
826
+
803
827
  // src/agents/error-detail.ts
804
828
  function formatUnknownDetail(err) {
805
829
  if (err == null) return "";
@@ -990,9 +1014,6 @@ function looksLikeInvalidAgentSession(text7) {
990
1014
  if (!lower) return false;
991
1015
  return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
992
1016
  }
993
- function looksLikeCursorStreamCutOff(text7) {
994
- return /nghttp2|premature close|\[unavailable\]\s+error\b/i.test(text7.trim());
995
- }
996
1017
  function looksLikeBrightsyEmptyCompletion(text7) {
997
1018
  const core = text7.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
998
1019
  return /^i did not receive a valid model response\. please try again\.$/i.test(core);
@@ -1166,6 +1187,8 @@ var NODE_VERSION_FOOTER, NESTED_ELECTRON_SUMMARY, HOMEBREW_LIBUV_SUMMARY, BUNDLE
1166
1187
  var init_error_detail = __esm({
1167
1188
  "src/agents/error-detail.ts"() {
1168
1189
  "use strict";
1190
+ init_cursor_stream_cutoff();
1191
+ init_cursor_stream_cutoff();
1169
1192
  NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
1170
1193
  NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
1171
1194
  HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
@@ -25408,10 +25431,10 @@ var init_orchestrator = __esm({
25408
25431
  /** Timers for orchestration session-quota auto-resume. */
25409
25432
  quotaResumeTimers = /* @__PURE__ */ new Map();
25410
25433
  /**
25411
- * Threads that already got a crash-continue turn. Cleared on a successful
25412
- * finish or a user send so a later crash can recover again.
25434
+ * Crash-continue count per thread. Cleared on a successful finish or a user
25435
+ * send. Stream cutoffs may resume more than once; other crashes once.
25413
25436
  */
25414
- crashContinued = /* @__PURE__ */ new Set();
25437
+ crashContinued = /* @__PURE__ */ new Map();
25415
25438
  /** Auto-continues after a worktree turn ended while a detached job still runs. */
25416
25439
  jobContinueCount = /* @__PURE__ */ new Map();
25417
25440
  jobContinueNudged = /* @__PURE__ */ new Set();
@@ -25850,7 +25873,6 @@ var init_orchestrator = __esm({
25850
25873
  * next prompt so the same agent can continue instead of sitting on lastError.
25851
25874
  */
25852
25875
  maybeEnqueueCrashContinue(threadId, opts) {
25853
- if (this.crashContinued.has(threadId)) return;
25854
25876
  if (this.haltDrain.has(threadId)) return;
25855
25877
  if (!shouldFeedErrorBackToAgent({
25856
25878
  detail: opts.detail,
@@ -25859,9 +25881,11 @@ var init_orchestrator = __esm({
25859
25881
  })) {
25860
25882
  return;
25861
25883
  }
25884
+ const resumeCount = nextCrashContinueCount(opts.detail, this.crashContinued.get(threadId) ?? 0);
25885
+ if (resumeCount == null) return;
25862
25886
  const thread = readThread(threadId);
25863
25887
  if (!thread || thread.status === "archived") return;
25864
- this.crashContinued.add(threadId);
25888
+ this.crashContinued.set(threadId, resumeCount);
25865
25889
  const prompt = formatAgentErrorContinuePrompt(opts.detail);
25866
25890
  const next = prependQueuedItem(thread.queue, thread.queueAttachments, prompt);
25867
25891
  updateThread(threadId, next);
@@ -71,7 +71,7 @@ import {
71
71
  syncBoardPins,
72
72
  updateSchedule,
73
73
  workspaceTagTargetRef
74
- } from "../chunk-BYZ7F2BQ.js";
74
+ } from "../chunk-OEJQK7CY.js";
75
75
  import "../chunk-LX5R5JOR.js";
76
76
  import {
77
77
  PRESENT_PLAN_REQUIRES_PLAN_MODE,
@@ -90,7 +90,7 @@ import {
90
90
  sideboardMcpProfile,
91
91
  trustSystemCertificates,
92
92
  worktreeMcpToolNames
93
- } from "../chunk-ADXVTKLC.js";
93
+ } from "../chunk-BSN6DJ4L.js";
94
94
  import "../chunk-TQRSVE7D.js";
95
95
  import "../chunk-P2BSMNHB.js";
96
96
  import {
@@ -106,12 +106,12 @@ import {
106
106
  waitForDetachedJob,
107
107
  waitForTurnToolResult,
108
108
  workspaceAgentChatSummaries
109
- } from "../chunk-EIEAR62M.js";
109
+ } from "../chunk-LMWPVC5L.js";
110
110
  import {
111
111
  clipToolResultForStore,
112
112
  isInternalAgentStatusText,
113
113
  looksLikeHugeToolResultDump
114
- } from "../chunk-W7HIK2A6.js";
114
+ } from "../chunk-5QOLFOAX.js";
115
115
  import {
116
116
  GLOBAL_WORKSPACE_ID,
117
117
  isCloudCoordinatorThread
@@ -9,11 +9,11 @@ import {
9
9
  resolveSendFollowUp,
10
10
  startOrchestration,
11
11
  waitForPidExit
12
- } from "./chunk-2KNO2GJQ.js";
13
- import "./chunk-OCUIZD4Y.js";
12
+ } from "./chunk-WQ4M2L44.js";
13
+ import "./chunk-COQLZNKQ.js";
14
14
  import "./chunk-GWFVCCJZ.js";
15
- import "./chunk-DQZPF6WL.js";
16
- import "./chunk-BDAUPNHL.js";
15
+ import "./chunk-BMUVNTT4.js";
16
+ import "./chunk-XSDCLM3F.js";
17
17
  import "./chunk-7H655NEW.js";
18
18
  import "./chunk-PGPSIEMW.js";
19
19
  import "./chunk-WY2IAB7J.js";
@@ -23,8 +23,8 @@ import "./chunk-2P4XKWV2.js";
23
23
  import "./chunk-ROPGQRPU.js";
24
24
  import "./chunk-N7WZ6NIN.js";
25
25
  import "./chunk-AXQ4ZWHK.js";
26
- import "./chunk-IFURHRAR.js";
27
- import "./chunk-K2S33ZCB.js";
26
+ import "./chunk-VOIWX5HA.js";
27
+ import "./chunk-U6QDXT4K.js";
28
28
  import "./chunk-6K64FJDD.js";
29
29
  import "./chunk-UWQ6UCIB.js";
30
30
  import "./chunk-QVN2WOKJ.js";
@@ -11,16 +11,16 @@ import {
11
11
  resolveSendFollowUp,
12
12
  startOrchestration,
13
13
  waitForPidExit
14
- } from "./chunk-BYZ7F2BQ.js";
14
+ } from "./chunk-OEJQK7CY.js";
15
15
  import "./chunk-LX5R5JOR.js";
16
16
  import "./chunk-4GK32AYX.js";
17
17
  import "./chunk-5DZUWGKV.js";
18
- import "./chunk-ADXVTKLC.js";
18
+ import "./chunk-BSN6DJ4L.js";
19
19
  import "./chunk-TQRSVE7D.js";
20
20
  import "./chunk-P2BSMNHB.js";
21
21
  import "./chunk-VKQGAWHY.js";
22
- import "./chunk-EIEAR62M.js";
23
- import "./chunk-W7HIK2A6.js";
22
+ import "./chunk-LMWPVC5L.js";
23
+ import "./chunk-5QOLFOAX.js";
24
24
  import "./chunk-2SJXQ4UX.js";
25
25
  import "./chunk-5MGLNVNK.js";
26
26
  import "./chunk-N2WW62LF.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.283",
3
+ "version": "0.1.284",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",