@sideboard-ai/core 0.1.294 → 0.1.295

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.
@@ -1402,6 +1402,113 @@ function clipAgentEventForEmit(event, cwd) {
1402
1402
  return event;
1403
1403
  }
1404
1404
 
1405
+ // src/agents/cursor-tool-guard.ts
1406
+ var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
1407
+ function cursorToolErrorText(err) {
1408
+ const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
1409
+ const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
1410
+ return `Error: ${message}
1411
+ ${CURSOR_TOOL_RECOVERY_HINT}`;
1412
+ }
1413
+ function cursorToolErrorResult(err) {
1414
+ return {
1415
+ isError: true,
1416
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
1417
+ };
1418
+ }
1419
+ function boundedCursorToolResult(result, opts) {
1420
+ const prefix = opts?.name ?? "cursor-tool";
1421
+ if (typeof result === "string") {
1422
+ return spillAndClipToolResult(result, { cwd: opts?.cwd, prefix });
1423
+ }
1424
+ if (result == null) {
1425
+ return cursorToolErrorText(new Error("tool returned no result"));
1426
+ }
1427
+ let json;
1428
+ try {
1429
+ json = JSON.stringify(result);
1430
+ } catch (err) {
1431
+ return cursorToolErrorText(err);
1432
+ }
1433
+ return spillAndClipToolResult(json, { cwd: opts?.cwd, prefix });
1434
+ }
1435
+ function guardCursorCustomTool(tool, opts) {
1436
+ const execute = tool.execute.bind(tool);
1437
+ return {
1438
+ ...tool,
1439
+ execute: async (args, context) => {
1440
+ try {
1441
+ const result = await execute(args, context);
1442
+ return boundedCursorToolResult(result, opts);
1443
+ } catch (err) {
1444
+ return cursorToolErrorResult(err);
1445
+ }
1446
+ }
1447
+ };
1448
+ }
1449
+ var NON_RECOVERABLE_RUN_ERROR = /invalid (?:user )?api key|not logged in|not authenticated|unauthorized|credit balance|out of credits|insufficient.?quota|usage limit|you've hit your|too many requests|rate.?limit/;
1450
+ function shouldReturnRunErrorToAgent(detail) {
1451
+ const text = detail.trim();
1452
+ if (!text) return false;
1453
+ if (looksLikeHugeToolResultDump(text) || looksLikeCursorStreamCutOff(text)) return true;
1454
+ const head = text.slice(0, 2e3).toLowerCase();
1455
+ if (NON_RECOVERABLE_RUN_ERROR.test(head)) return false;
1456
+ return true;
1457
+ }
1458
+ function cursorRunErrorRecoveryPrompt(detail) {
1459
+ const summary = looksLikeHugeToolResultDump(detail) ? HUGE_TOOL_RESULT_SUMMARY : detail.replace(/\s+/g, " ").trim().slice(0, 400);
1460
+ return [
1461
+ "A tool call failed before its result reached you. The session is still open.",
1462
+ `Error: ${summary || "unknown"}`,
1463
+ CURSOR_TOOL_RECOVERY_HINT
1464
+ ].join("\n");
1465
+ }
1466
+
1467
+ // src/agents/cursor-stale-runs.ts
1468
+ async function cancelStaleCursorRuns(Agent, agentId, opts) {
1469
+ let cancelled = 0;
1470
+ const listed = await Agent.listRuns(agentId, {
1471
+ runtime: "local",
1472
+ cwd: opts.cwd,
1473
+ store: opts.store,
1474
+ limit: 20
1475
+ });
1476
+ for (const run2 of listed.items) {
1477
+ if (run2.status !== "running") continue;
1478
+ try {
1479
+ await Agent.cancelRun(run2.id, {
1480
+ runtime: "local",
1481
+ cwd: opts.cwd,
1482
+ store: opts.store
1483
+ });
1484
+ cancelled += 1;
1485
+ } catch {
1486
+ }
1487
+ }
1488
+ if (cancelled > 0 || !opts.apiKey) return cancelled;
1489
+ try {
1490
+ const cloud = await Agent.listRuns(agentId, {
1491
+ runtime: "cloud",
1492
+ apiKey: opts.apiKey,
1493
+ limit: 20
1494
+ });
1495
+ for (const run2 of cloud.items) {
1496
+ if (run2.status !== "running") continue;
1497
+ try {
1498
+ await Agent.cancelRun(run2.id, {
1499
+ runtime: "cloud",
1500
+ agentId,
1501
+ apiKey: opts.apiKey
1502
+ });
1503
+ cancelled += 1;
1504
+ } catch {
1505
+ }
1506
+ }
1507
+ } catch {
1508
+ }
1509
+ return cancelled;
1510
+ }
1511
+
1405
1512
  // src/agents/cursor-events.ts
1406
1513
  function usageFromCursor(usage) {
1407
1514
  if (!usage) return null;
@@ -1784,49 +1891,6 @@ function localAgentStore(Store, threadId) {
1784
1891
  (0, import_node_fs18.mkdirSync)(root, { recursive: true });
1785
1892
  return new Store(root);
1786
1893
  }
1787
- async function cancelStaleRuns(Agent, agentId, opts) {
1788
- let cancelled = 0;
1789
- const listed = await Agent.listRuns(agentId, {
1790
- runtime: "local",
1791
- cwd: opts.cwd,
1792
- store: opts.store,
1793
- limit: 20
1794
- });
1795
- for (const run2 of listed.items) {
1796
- if (run2.status !== "running") continue;
1797
- try {
1798
- await Agent.cancelRun(run2.id, {
1799
- runtime: "local",
1800
- cwd: opts.cwd,
1801
- store: opts.store
1802
- });
1803
- cancelled += 1;
1804
- } catch {
1805
- }
1806
- }
1807
- if (cancelled > 0 || !opts.apiKey) return cancelled;
1808
- try {
1809
- const cloud = await Agent.listRuns(agentId, {
1810
- runtime: "cloud",
1811
- apiKey: opts.apiKey,
1812
- limit: 20
1813
- });
1814
- for (const run2 of cloud.items) {
1815
- if (run2.status !== "running") continue;
1816
- try {
1817
- await Agent.cancelRun(run2.id, {
1818
- runtime: "cloud",
1819
- agentId,
1820
- apiKey: opts.apiKey
1821
- });
1822
- cancelled += 1;
1823
- } catch {
1824
- }
1825
- }
1826
- } catch {
1827
- }
1828
- return cancelled;
1829
- }
1830
1894
  async function readStdinJson() {
1831
1895
  const rl = (0, import_node_readline2.createInterface)({ input: process.stdin, crlfDelay: Infinity });
1832
1896
  const chunks = [];
@@ -1896,10 +1960,16 @@ async function main() {
1896
1960
  }
1897
1961
  }
1898
1962
  }) : {};
1899
- const customTools = {
1963
+ const rawCustomTools = {
1900
1964
  read: slicedReadCustomToolConfig(req.cwd),
1901
1965
  ...rpcTools
1902
1966
  };
1967
+ const customTools = Object.fromEntries(
1968
+ Object.entries(rawCustomTools).map(([name, tool]) => [
1969
+ name,
1970
+ guardCursorCustomTool(tool, { cwd: req.cwd, name })
1971
+ ])
1972
+ );
1903
1973
  const local = withCursorLocalHangGuards({
1904
1974
  cwd: req.cwd,
1905
1975
  store,
@@ -1946,7 +2016,7 @@ async function main() {
1946
2016
  }
1947
2017
  }
1948
2018
  async function retryAfterBusy(agent) {
1949
- const n = await cancelStaleRuns(Agent, agent.agentId, {
2019
+ const n = await cancelStaleCursorRuns(Agent, agent.agentId, {
1950
2020
  cwd: req.cwd,
1951
2021
  store,
1952
2022
  ...apiKey ? { apiKey } : {}
@@ -1959,17 +2029,17 @@ async function main() {
1959
2029
  await new Promise((resolve2) => setTimeout(resolve2, CURSOR_BUSY_RETRY_DELAY_MS));
1960
2030
  }
1961
2031
  }
1962
- async function sendPrompt(agent, extra) {
2032
+ async function sendPrompt(agent, prompt, extra) {
1963
2033
  const sendOpts = {
1964
2034
  ...cursorSendOptions(mcpServers),
1965
2035
  ...extra
1966
2036
  };
1967
2037
  try {
1968
- return await retryTransport(() => agent.send(req.prompt, sendOpts));
2038
+ return await retryTransport(() => agent.send(prompt, sendOpts));
1969
2039
  } catch (err) {
1970
2040
  if (!isAgentBusyError(err)) throw err;
1971
2041
  await retryAfterBusy(agent);
1972
- return retryTransport(() => agent.send(req.prompt, sendOpts));
2042
+ return retryTransport(() => agent.send(prompt, sendOpts));
1973
2043
  }
1974
2044
  }
1975
2045
  let liveRun = null;
@@ -1997,7 +2067,7 @@ async function main() {
1997
2067
  };
1998
2068
  process.once("SIGTERM", onSignal);
1999
2069
  process.once("SIGINT", onSignal);
2000
- async function runTurn(agent) {
2070
+ async function runTurn(agent, prompt = req.prompt, recoveryLeft = 1) {
2001
2071
  emit({ type: "session_id", data: agent.agentId });
2002
2072
  const stream = createAgentStreamCoalescer(emit);
2003
2073
  const activity = { at: Date.now() };
@@ -2011,7 +2081,7 @@ async function main() {
2011
2081
  } catch {
2012
2082
  }
2013
2083
  let lastUsageRunId;
2014
- const run2 = await sendPrompt(agent, {
2084
+ const run2 = await sendPrompt(agent, prompt, {
2015
2085
  onDelta: ({ update }) => {
2016
2086
  bump();
2017
2087
  for (const event of cursorDeltaToEvents(update)) {
@@ -2056,6 +2126,14 @@ async function main() {
2056
2126
  if (isAgentBusyError(detail)) {
2057
2127
  throw Object.assign(new Error(detail || "agent still running"), { name: "AgentBusyError" });
2058
2128
  }
2129
+ if (recoveryLeft > 0 && shouldReturnRunErrorToAgent(detail)) {
2130
+ const brief = detail.replace(/\s+/g, " ").trim().slice(0, 240);
2131
+ emit({
2132
+ type: "stderr",
2133
+ data: `Cursor tool error \u2014 handing it back to the agent (${brief})`
2134
+ });
2135
+ return runTurn(agent, cursorRunErrorRecoveryPrompt(detail), 0);
2136
+ }
2059
2137
  emit({
2060
2138
  type: "stderr",
2061
2139
  data: detail ? `Cursor run failed (${result.id}): ${detail}` : `Cursor run failed (${result.id})`
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  clipAgentEventForEmit,
4
+ cursorRunErrorRecoveryPrompt,
5
+ guardCursorCustomTool,
6
+ shouldReturnRunErrorToAgent,
4
7
  sideboardCursorRpcTools
5
- } from "../chunk-K6IOJI3L.js";
8
+ } from "../chunk-ER6BGGME.js";
6
9
  import {
7
10
  createAgentStreamCoalescer
8
11
  } from "../chunk-AXQ4ZWHK.js";
@@ -17,12 +20,12 @@ import {
17
20
  fetchCursorTurnCostUsd,
18
21
  importCursorSdk,
19
22
  resolveCursorSdkRoot
20
- } from "../chunk-7UUILVMV.js";
23
+ } from "../chunk-IOY2LF3Y.js";
21
24
  import {
22
25
  TOOL_RESULT_STORE_MAX_CHARS,
23
26
  formatUnknownDetail,
24
27
  looksLikeCursorStreamCutOff
25
- } from "../chunk-MIVX7QKI.js";
28
+ } from "../chunk-HO5R3ZRH.js";
26
29
  import "../chunk-6K64FJDD.js";
27
30
  import {
28
31
  cursorSdkStoreDir
@@ -559,39 +562,8 @@ function slicedReadCustomToolConfig(cwd) {
559
562
  };
560
563
  }
561
564
 
562
- // src/agents/cursor-model-selection.ts
563
- function buildCursorModelSelection(model, opts) {
564
- const raw = model && model.trim() || "";
565
- const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
566
- const isGrok47 = /^grok-4\.7(?:$|-)/i.test(id);
567
- const params = [];
568
- if (isGrok47) {
569
- params.push({ id: "context", value: "256k" });
570
- }
571
- const effort = (opts.effort ?? "").trim().toLowerCase();
572
- const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
573
- if (normalized) {
574
- params.push({
575
- id: isGrok47 ? "reasoning_effort" : "effort",
576
- value: isGrok47 && normalized === "max" ? "xhigh" : normalized
577
- });
578
- }
579
- params.push({ id: "fast", value: opts.fast ? "true" : "false" });
580
- return { id, params };
581
- }
582
-
583
- // src/agents/cursor-runner.ts
584
- dropNestedElectronEnvFromProcess();
585
- function emit(event) {
586
- process.stdout.write(`${JSON.stringify(clipAgentEventForEmit(event, process.cwd()))}
587
- `);
588
- }
589
- function localAgentStore(Store, threadId) {
590
- const root = cursorSdkStoreDir(threadId);
591
- mkdirSync2(root, { recursive: true });
592
- return new Store(root);
593
- }
594
- async function cancelStaleRuns(Agent, agentId, opts) {
565
+ // src/agents/cursor-stale-runs.ts
566
+ async function cancelStaleCursorRuns(Agent, agentId, opts) {
595
567
  let cancelled = 0;
596
568
  const listed = await Agent.listRuns(agentId, {
597
569
  runtime: "local",
@@ -634,6 +606,39 @@ async function cancelStaleRuns(Agent, agentId, opts) {
634
606
  }
635
607
  return cancelled;
636
608
  }
609
+
610
+ // src/agents/cursor-model-selection.ts
611
+ function buildCursorModelSelection(model, opts) {
612
+ const raw = model && model.trim() || "";
613
+ const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
614
+ const isGrok47 = /^grok-4\.7(?:$|-)/i.test(id);
615
+ const params = [];
616
+ if (isGrok47) {
617
+ params.push({ id: "context", value: "256k" });
618
+ }
619
+ const effort = (opts.effort ?? "").trim().toLowerCase();
620
+ const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
621
+ if (normalized) {
622
+ params.push({
623
+ id: isGrok47 ? "reasoning_effort" : "effort",
624
+ value: isGrok47 && normalized === "max" ? "xhigh" : normalized
625
+ });
626
+ }
627
+ params.push({ id: "fast", value: opts.fast ? "true" : "false" });
628
+ return { id, params };
629
+ }
630
+
631
+ // src/agents/cursor-runner.ts
632
+ dropNestedElectronEnvFromProcess();
633
+ function emit(event) {
634
+ process.stdout.write(`${JSON.stringify(clipAgentEventForEmit(event, process.cwd()))}
635
+ `);
636
+ }
637
+ function localAgentStore(Store, threadId) {
638
+ const root = cursorSdkStoreDir(threadId);
639
+ mkdirSync2(root, { recursive: true });
640
+ return new Store(root);
641
+ }
637
642
  async function readStdinJson() {
638
643
  const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
639
644
  const chunks = [];
@@ -703,10 +708,16 @@ async function main() {
703
708
  }
704
709
  }
705
710
  }) : {};
706
- const customTools = {
711
+ const rawCustomTools = {
707
712
  read: slicedReadCustomToolConfig(req.cwd),
708
713
  ...rpcTools
709
714
  };
715
+ const customTools = Object.fromEntries(
716
+ Object.entries(rawCustomTools).map(([name, tool]) => [
717
+ name,
718
+ guardCursorCustomTool(tool, { cwd: req.cwd, name })
719
+ ])
720
+ );
710
721
  const local = withCursorLocalHangGuards({
711
722
  cwd: req.cwd,
712
723
  store,
@@ -753,7 +764,7 @@ async function main() {
753
764
  }
754
765
  }
755
766
  async function retryAfterBusy(agent) {
756
- const n = await cancelStaleRuns(Agent, agent.agentId, {
767
+ const n = await cancelStaleCursorRuns(Agent, agent.agentId, {
757
768
  cwd: req.cwd,
758
769
  store,
759
770
  ...apiKey ? { apiKey } : {}
@@ -766,17 +777,17 @@ async function main() {
766
777
  await new Promise((resolve2) => setTimeout(resolve2, CURSOR_BUSY_RETRY_DELAY_MS));
767
778
  }
768
779
  }
769
- async function sendPrompt(agent, extra) {
780
+ async function sendPrompt(agent, prompt, extra) {
770
781
  const sendOpts = {
771
782
  ...cursorSendOptions(mcpServers),
772
783
  ...extra
773
784
  };
774
785
  try {
775
- return await retryTransport(() => agent.send(req.prompt, sendOpts));
786
+ return await retryTransport(() => agent.send(prompt, sendOpts));
776
787
  } catch (err) {
777
788
  if (!isAgentBusyError(err)) throw err;
778
789
  await retryAfterBusy(agent);
779
- return retryTransport(() => agent.send(req.prompt, sendOpts));
790
+ return retryTransport(() => agent.send(prompt, sendOpts));
780
791
  }
781
792
  }
782
793
  let liveRun = null;
@@ -804,7 +815,7 @@ async function main() {
804
815
  };
805
816
  process.once("SIGTERM", onSignal);
806
817
  process.once("SIGINT", onSignal);
807
- async function runTurn(agent) {
818
+ async function runTurn(agent, prompt = req.prompt, recoveryLeft = 1) {
808
819
  emit({ type: "session_id", data: agent.agentId });
809
820
  const stream = createAgentStreamCoalescer(emit);
810
821
  const activity = { at: Date.now() };
@@ -818,7 +829,7 @@ async function main() {
818
829
  } catch {
819
830
  }
820
831
  let lastUsageRunId;
821
- const run = await sendPrompt(agent, {
832
+ const run = await sendPrompt(agent, prompt, {
822
833
  onDelta: ({ update }) => {
823
834
  bump();
824
835
  for (const event of cursorDeltaToEvents(update)) {
@@ -863,6 +874,14 @@ async function main() {
863
874
  if (isAgentBusyError(detail)) {
864
875
  throw Object.assign(new Error(detail || "agent still running"), { name: "AgentBusyError" });
865
876
  }
877
+ if (recoveryLeft > 0 && shouldReturnRunErrorToAgent(detail)) {
878
+ const brief = detail.replace(/\s+/g, " ").trim().slice(0, 240);
879
+ emit({
880
+ type: "stderr",
881
+ data: `Cursor tool error \u2014 handing it back to the agent (${brief})`
882
+ });
883
+ return runTurn(agent, cursorRunErrorRecoveryPrompt(detail), 0);
884
+ }
866
885
  emit({
867
886
  type: "stderr",
868
887
  data: detail ? `Cursor run failed (${result.id}): ${detail}` : `Cursor run failed (${result.id})`
@@ -37,9 +37,9 @@ import {
37
37
  planModeTurnInstruction,
38
38
  resolveCursorModelId,
39
39
  resolveQuotaFallbackAgent
40
- } from "./chunk-JEYJGQ33.js";
40
+ } from "./chunk-RWIYYFID.js";
41
41
  import "./chunk-VGNLMGBK.js";
42
- import "./chunk-YSLCWCMJ.js";
42
+ import "./chunk-Q3DPZ4DE.js";
43
43
  import {
44
44
  getAgentSetupInfo,
45
45
  installAgent,
@@ -66,8 +66,8 @@ import {
66
66
  preferredCursorCostCents,
67
67
  resolveCursorSdkRoot,
68
68
  turnCostUsdFromCursorUsage
69
- } from "./chunk-7UUILVMV.js";
70
- import "./chunk-MIVX7QKI.js";
69
+ } from "./chunk-IOY2LF3Y.js";
70
+ import "./chunk-HO5R3ZRH.js";
71
71
  import "./chunk-6K64FJDD.js";
72
72
  import "./chunk-UWQ6UCIB.js";
73
73
  import {
@@ -46,7 +46,7 @@ import {
46
46
  resolveCursorSdkRoot,
47
47
  resolveQuotaFallbackAgent,
48
48
  turnCostUsdFromCursorUsage
49
- } from "./chunk-SVQTKVXH.js";
49
+ } from "./chunk-ABLHTRRG.js";
50
50
  import {
51
51
  getAgentSetupInfo,
52
52
  installAgent,
@@ -62,7 +62,7 @@ import {
62
62
  import "./chunk-7IAMHN2N.js";
63
63
  import "./chunk-PXMLMBMI.js";
64
64
  import "./chunk-2GPQZZLY.js";
65
- import "./chunk-AFLNFGGB.js";
65
+ import "./chunk-ED4ZXQVO.js";
66
66
  import "./chunk-E7G7RY6T.js";
67
67
  import "./chunk-6SGYGYH7.js";
68
68
  import "./chunk-N2WW62LF.js";
@@ -21,7 +21,7 @@ import {
21
21
  looksLikeSkillBody,
22
22
  skillCommandFromBody,
23
23
  withEventParentId
24
- } from "./chunk-AFLNFGGB.js";
24
+ } from "./chunk-ED4ZXQVO.js";
25
25
  import {
26
26
  isOrchestratorThread
27
27
  } from "./chunk-E7G7RY6T.js";
@@ -1207,6 +1207,7 @@ export {
1207
1207
  looksLikeHugeToolResultDump,
1208
1208
  clipToolResultForStore,
1209
1209
  looksLikeV8Oom,
1210
+ HUGE_TOOL_RESULT_SUMMARY,
1210
1211
  summarizeTurnStderr,
1211
1212
  looksLikeInvalidAgentSession,
1212
1213
  looksLikeBrightsyEmptyCompletion,
@@ -1,7 +1,10 @@
1
1
  import {
2
+ HUGE_TOOL_RESULT_SUMMARY,
2
3
  clipToolResultForStore,
4
+ formatUnknownDetail,
5
+ looksLikeCursorStreamCutOff,
3
6
  looksLikeHugeToolResultDump
4
- } from "./chunk-MIVX7QKI.js";
7
+ } from "./chunk-HO5R3ZRH.js";
5
8
  import {
6
9
  CLI_DIR
7
10
  } from "./chunk-6K64FJDD.js";
@@ -73,6 +76,68 @@ function clipAgentEventForEmit(event, cwd) {
73
76
  return event;
74
77
  }
75
78
 
79
+ // src/agents/cursor-tool-guard.ts
80
+ var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
81
+ function cursorToolErrorText(err) {
82
+ const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
83
+ const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
84
+ return `Error: ${message}
85
+ ${CURSOR_TOOL_RECOVERY_HINT}`;
86
+ }
87
+ function cursorToolErrorResult(err) {
88
+ return {
89
+ isError: true,
90
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
91
+ };
92
+ }
93
+ function boundedCursorToolResult(result, opts) {
94
+ const prefix = opts?.name ?? "cursor-tool";
95
+ if (typeof result === "string") {
96
+ return spillAndClipToolResult(result, { cwd: opts?.cwd, prefix });
97
+ }
98
+ if (result == null) {
99
+ return cursorToolErrorText(new Error("tool returned no result"));
100
+ }
101
+ let json;
102
+ try {
103
+ json = JSON.stringify(result);
104
+ } catch (err) {
105
+ return cursorToolErrorText(err);
106
+ }
107
+ return spillAndClipToolResult(json, { cwd: opts?.cwd, prefix });
108
+ }
109
+ function guardCursorCustomTool(tool, opts) {
110
+ const execute = tool.execute.bind(tool);
111
+ return {
112
+ ...tool,
113
+ execute: async (args, context) => {
114
+ try {
115
+ const result = await execute(args, context);
116
+ return boundedCursorToolResult(result, opts);
117
+ } catch (err) {
118
+ return cursorToolErrorResult(err);
119
+ }
120
+ }
121
+ };
122
+ }
123
+ var NON_RECOVERABLE_RUN_ERROR = /invalid (?:user )?api key|not logged in|not authenticated|unauthorized|credit balance|out of credits|insufficient.?quota|usage limit|you've hit your|too many requests|rate.?limit/;
124
+ function shouldReturnRunErrorToAgent(detail) {
125
+ const text = detail.trim();
126
+ if (!text) return false;
127
+ if (looksLikeHugeToolResultDump(text) || looksLikeCursorStreamCutOff(text)) return true;
128
+ const head = text.slice(0, 2e3).toLowerCase();
129
+ if (NON_RECOVERABLE_RUN_ERROR.test(head)) return false;
130
+ return true;
131
+ }
132
+ function cursorRunErrorRecoveryPrompt(detail) {
133
+ const summary = looksLikeHugeToolResultDump(detail) ? HUGE_TOOL_RESULT_SUMMARY : detail.replace(/\s+/g, " ").trim().slice(0, 400);
134
+ return [
135
+ "A tool call failed before its result reached you. The session is still open.",
136
+ `Error: ${summary || "unknown"}`,
137
+ CURSOR_TOOL_RECOVERY_HINT
138
+ ].join("\n");
139
+ }
140
+
76
141
  // src/agent-rpc/cursor-tools.ts
77
142
  function sideboardCursorRpcTools(opts) {
78
143
  const exec = createPilotRpcExecutors(opts);
@@ -106,5 +171,9 @@ function sideboardCursorRpcTools(opts) {
106
171
  export {
107
172
  clipMcpToolResult,
108
173
  clipAgentEventForEmit,
174
+ cursorToolErrorText,
175
+ guardCursorCustomTool,
176
+ shouldReturnRunErrorToAgent,
177
+ cursorRunErrorRecoveryPrompt,
109
178
  sideboardCursorRpcTools
110
179
  };
@@ -393,6 +393,7 @@ export {
393
393
  looksLikeHugeToolResultDump,
394
394
  clipToolResultForStore,
395
395
  looksLikeV8Oom,
396
+ HUGE_TOOL_RESULT_SUMMARY,
396
397
  TOOL_RESULT_STORE_MAX_CHARS,
397
398
  summarizeTurnStderr,
398
399
  looksLikeInvalidAgentSession,
@@ -5,7 +5,7 @@ import {
5
5
  compactSummaryPart,
6
6
  isInternalAgentStatusText,
7
7
  lastAssistantMessageText
8
- } from "./chunk-AFLNFGGB.js";
8
+ } from "./chunk-ED4ZXQVO.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-7DEMFEIO.js");
1677
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-GURU5XD7.js");
1678
1678
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1679
1679
  else killListenersOnPorts2(ports);
1680
1680
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  extractJsonErrorMessage,
3
3
  formatUnknownDetail
4
- } from "./chunk-MIVX7QKI.js";
4
+ } from "./chunk-HO5R3ZRH.js";
5
5
  import {
6
6
  npmGlobalNodeModules,
7
7
  run
@@ -2,7 +2,7 @@ import {
2
2
  compactSummaryPart,
3
3
  isInternalAgentStatusText,
4
4
  lastAssistantMessageText
5
- } from "./chunk-YSLCWCMJ.js";
5
+ } from "./chunk-Q3DPZ4DE.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-MIVX7QKI.js";
32
+ } from "./chunk-HO5R3ZRH.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-ZQZTYXSX.js");
1779
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-HT2UANDY.js");
1780
1780
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1781
1781
  else killListenersOnPorts2(ports);
1782
1782
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  clipToolResultForStore
3
- } from "./chunk-MIVX7QKI.js";
3
+ } from "./chunk-HO5R3ZRH.js";
4
4
 
5
5
  // src/agents/message-parts.ts
6
6
  function asRecord(input) {
@@ -9,7 +9,7 @@ import {
9
9
  looksLikeSkillBody,
10
10
  skillCommandFromBody,
11
11
  withEventParentId
12
- } from "./chunk-YSLCWCMJ.js";
12
+ } from "./chunk-Q3DPZ4DE.js";
13
13
  import {
14
14
  isOrchestratorThread
15
15
  } from "./chunk-YEIPPZ5W.js";
@@ -38,13 +38,13 @@ import {
38
38
  packagedMcpStdioPath,
39
39
  parseCursorRunnerLine,
40
40
  resolveNodeLaunch
41
- } from "./chunk-7UUILVMV.js";
41
+ } from "./chunk-IOY2LF3Y.js";
42
42
  import {
43
43
  extractJsonErrorMessage,
44
44
  formatUnknownDetail,
45
45
  looksLikeAgentFailureMessage,
46
46
  looksLikeBrightsyEmptyCompletion
47
- } from "./chunk-MIVX7QKI.js";
47
+ } from "./chunk-HO5R3ZRH.js";
48
48
  import {
49
49
  run
50
50
  } from "./chunk-QVN2WOKJ.js";
@@ -14,7 +14,7 @@ import {
14
14
  parseSessionQuotaResetAt,
15
15
  planModeTurnInstruction,
16
16
  resolveQuotaFallbackAgent
17
- } from "./chunk-JEYJGQ33.js";
17
+ } from "./chunk-RWIYYFID.js";
18
18
  import {
19
19
  REVIEW_TAB_TITLE,
20
20
  applyWorktreePkgCacheEnv,
@@ -53,7 +53,7 @@ import {
53
53
  worktreeDevProcessKey,
54
54
  worktreeRunProcessKey,
55
55
  worktreeSetupProcessKey
56
- } from "./chunk-YKO6HG74.js";
56
+ } from "./chunk-KCP6IVRI.js";
57
57
  import {
58
58
  applyAgentEvent,
59
59
  clipAgentEventForPaint,
@@ -68,7 +68,7 @@ import {
68
68
  partsToAssistantText,
69
69
  stripBrightsyNdjsonNoise,
70
70
  toolDescription
71
- } from "./chunk-YSLCWCMJ.js";
71
+ } from "./chunk-Q3DPZ4DE.js";
72
72
  import {
73
73
  titleFromPrompt
74
74
  } from "./chunk-7H655NEW.js";
@@ -173,7 +173,7 @@ import {
173
173
  import {
174
174
  applyAgentRunnerHeapEnv,
175
175
  packagedMcpDir
176
- } from "./chunk-7UUILVMV.js";
176
+ } from "./chunk-IOY2LF3Y.js";
177
177
  import {
178
178
  fallbackTurnFailDetail,
179
179
  formatAgentErrorContinuePrompt,
@@ -188,7 +188,7 @@ import {
188
188
  shouldRetryFailedAgentTurn,
189
189
  summarizeTurnStderr,
190
190
  turnFailChatText
191
- } from "./chunk-MIVX7QKI.js";
191
+ } from "./chunk-HO5R3ZRH.js";
192
192
  import {
193
193
  clearStaleIndexLocks,
194
194
  enrichPathWithNpmGlobalBin,
@@ -2740,7 +2740,7 @@ async function createThread(input, _onSetupLine) {
2740
2740
  return readThread(thread.id) ?? thread;
2741
2741
  }
2742
2742
  async function listLinearIssues(agent, repoPath) {
2743
- const { getAdapter: getAdapter2 } = await import("./agents-73JXQXF2.js");
2743
+ const { getAdapter: getAdapter2 } = await import("./agents-EFHYZUZT.js");
2744
2744
  await requireAgent(agent, { requireLinear: true });
2745
2745
  const adapter = getAdapter2(agent);
2746
2746
  if (!adapter.listLinearIssues) {
@@ -6170,7 +6170,7 @@ function formatScheduledPrompt(name, prompt) {
6170
6170
  ${prompt}`;
6171
6171
  }
6172
6172
  async function defaultDeps() {
6173
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-YNEEEP6O.js");
6173
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VDYZSZWY.js");
6174
6174
  const orch = getOrchestrator2();
6175
6175
  return {
6176
6176
  findThread: (id) => findThreadByRef(id),
@@ -27,7 +27,7 @@ import {
27
27
  parseSessionQuotaResetAt,
28
28
  planModeTurnInstruction,
29
29
  resolveQuotaFallbackAgent
30
- } from "./chunk-SVQTKVXH.js";
30
+ } from "./chunk-ABLHTRRG.js";
31
31
  import {
32
32
  REVIEW_TAB_TITLE,
33
33
  applyWorktreePkgCacheEnv,
@@ -66,7 +66,7 @@ import {
66
66
  worktreeDevProcessKey,
67
67
  worktreeRunProcessKey,
68
68
  worktreeSetupProcessKey
69
- } from "./chunk-BJUHZSZQ.js";
69
+ } from "./chunk-HWIIRVYE.js";
70
70
  import {
71
71
  applyAgentEvent,
72
72
  clipAgentEventForPaint,
@@ -93,7 +93,7 @@ import {
93
93
  summarizeTurnStderr,
94
94
  toolDescription,
95
95
  turnFailChatText
96
- } from "./chunk-AFLNFGGB.js";
96
+ } from "./chunk-ED4ZXQVO.js";
97
97
  import {
98
98
  SLACK_REPLY_FORMATTING,
99
99
  addWorkspace,
@@ -5994,7 +5994,7 @@ function formatScheduledPrompt(name, prompt) {
5994
5994
  ${prompt}`;
5995
5995
  }
5996
5996
  async function defaultDeps() {
5997
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-LIEGSQ6M.js");
5997
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VNSEXL62.js");
5998
5998
  const orch = getOrchestrator2();
5999
5999
  return {
6000
6000
  findThread: (id) => findThreadByRef(id),
@@ -33,8 +33,8 @@ import {
33
33
  tryReservePort,
34
34
  tryReservePorts,
35
35
  worktreeRunPortsPath
36
- } from "./chunk-BJUHZSZQ.js";
37
- import "./chunk-AFLNFGGB.js";
36
+ } from "./chunk-HWIIRVYE.js";
37
+ import "./chunk-ED4ZXQVO.js";
38
38
  import "./chunk-E7G7RY6T.js";
39
39
  import "./chunk-6SGYGYH7.js";
40
40
  import "./chunk-N2WW62LF.js";
@@ -31,13 +31,13 @@ import {
31
31
  tryReservePort,
32
32
  tryReservePorts,
33
33
  worktreeRunPortsPath
34
- } from "./chunk-YKO6HG74.js";
35
- import "./chunk-YSLCWCMJ.js";
34
+ } from "./chunk-KCP6IVRI.js";
35
+ import "./chunk-Q3DPZ4DE.js";
36
36
  import "./chunk-YEIPPZ5W.js";
37
37
  import "./chunk-ZEP6JIRF.js";
38
38
  import "./chunk-QB5MDOHL.js";
39
39
  import "./chunk-2P4XKWV2.js";
40
- import "./chunk-MIVX7QKI.js";
40
+ import "./chunk-HO5R3ZRH.js";
41
41
  import "./chunk-6K64FJDD.js";
42
42
  import "./chunk-UWQ6UCIB.js";
43
43
  import "./chunk-QVN2WOKJ.js";
package/dist/index.cjs CHANGED
@@ -34179,6 +34179,10 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
34179
34179
  // src/mcp/wrap-mcp-tools.ts
34180
34180
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
34181
34181
 
34182
+ // src/agents/cursor-tool-guard.ts
34183
+ init_error_detail();
34184
+ init_cursor_stream_cutoff();
34185
+
34182
34186
  // src/agents/tool-result-clip.ts
34183
34187
  var import_node_fs67 = require("fs");
34184
34188
  var import_node_path62 = require("path");
@@ -34227,11 +34231,30 @@ function clipMcpToolResult(result, cwd) {
34227
34231
  };
34228
34232
  }
34229
34233
 
34234
+ // src/agents/cursor-tool-guard.ts
34235
+ var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
34236
+ function cursorToolErrorText(err) {
34237
+ const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
34238
+ const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
34239
+ return `Error: ${message}
34240
+ ${CURSOR_TOOL_RECOVERY_HINT}`;
34241
+ }
34242
+
34230
34243
  // src/mcp/wrap-mcp-tools.ts
34231
34244
  function wrapToolCallback(fn, cwd) {
34232
34245
  return async (...args) => {
34233
- const result = await fn(...args);
34234
- return clipMcpToolResult(result, cwd());
34246
+ try {
34247
+ const result = await fn(...args);
34248
+ return clipMcpToolResult(
34249
+ result,
34250
+ cwd()
34251
+ );
34252
+ } catch (err) {
34253
+ return {
34254
+ isError: true,
34255
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
34256
+ };
34257
+ }
34235
34258
  };
34236
34259
  }
34237
34260
  function wrapRegistrar(orig, cwd) {
package/dist/index.js CHANGED
@@ -186,7 +186,7 @@ import {
186
186
  worktreeBoardStatus,
187
187
  worktreeCleanupSettings,
188
188
  writeWorktreeFile
189
- } from "./chunk-BYAFYLLZ.js";
189
+ } from "./chunk-XXT3C2EF.js";
190
190
  import {
191
191
  LEGACY_PLAN_FILE_REL,
192
192
  PLAN_FILE_NAME,
@@ -282,7 +282,7 @@ import {
282
282
  userMcpNamesToDisable,
283
283
  worktreeMcpToolNames,
284
284
  writeInjectedMcpConfig
285
- } from "./chunk-JEYJGQ33.js";
285
+ } from "./chunk-RWIYYFID.js";
286
286
  import {
287
287
  brightsyMcpServerName,
288
288
  connectBrightsyTeam,
@@ -410,7 +410,7 @@ import {
410
410
  workspaceAgentChatSummaries,
411
411
  worktreeRunPortsPath,
412
412
  wrapReviewSkillMarkdown
413
- } from "./chunk-YKO6HG74.js";
413
+ } from "./chunk-KCP6IVRI.js";
414
414
  import {
415
415
  STDERR_EVENT_MAX_CHARS,
416
416
  STDOUT_EVENT_MAX_CHARS,
@@ -452,7 +452,7 @@ import {
452
452
  visibleToolRowDetail,
453
453
  withEventParentId,
454
454
  withEventsParentId
455
- } from "./chunk-YSLCWCMJ.js";
455
+ } from "./chunk-Q3DPZ4DE.js";
456
456
  import "./chunk-7H655NEW.js";
457
457
  import {
458
458
  ABLETIME_OAUTH_CALLBACK_PATH,
@@ -752,8 +752,9 @@ import {
752
752
  setHttpFetchImpl
753
753
  } from "./chunk-JAT3JFOS.js";
754
754
  import {
755
- clipMcpToolResult
756
- } from "./chunk-K6IOJI3L.js";
755
+ clipMcpToolResult,
756
+ cursorToolErrorText
757
+ } from "./chunk-ER6BGGME.js";
757
758
  import "./chunk-AXQ4ZWHK.js";
758
759
  import {
759
760
  AGENT_RUNNER_MAX_OLD_SPACE_MB,
@@ -769,8 +770,8 @@ import {
769
770
  trustSystemCertificates,
770
771
  turnCostUsdFromCursorUsage,
771
772
  withMaxOldSpaceSize
772
- } from "./chunk-7UUILVMV.js";
773
- import "./chunk-MIVX7QKI.js";
773
+ } from "./chunk-IOY2LF3Y.js";
774
+ import "./chunk-HO5R3ZRH.js";
774
775
  import {
775
776
  ATTACHMENTS_DIR,
776
777
  CLI_DIR,
@@ -3596,8 +3597,18 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3596
3597
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3597
3598
  function wrapToolCallback(fn, cwd) {
3598
3599
  return async (...args) => {
3599
- const result = await fn(...args);
3600
- return clipMcpToolResult(result, cwd());
3600
+ try {
3601
+ const result = await fn(...args);
3602
+ return clipMcpToolResult(
3603
+ result,
3604
+ cwd()
3605
+ );
3606
+ } catch (err) {
3607
+ return {
3608
+ isError: true,
3609
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
3610
+ };
3611
+ }
3601
3612
  };
3602
3613
  }
3603
3614
  function wrapRegistrar(orig, cwd) {
@@ -5130,7 +5141,7 @@ async function handleJobStop(params, _ctx) {
5130
5141
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
5131
5142
  }
5132
5143
  async function defaultTurnWait(ref, timeoutMs) {
5133
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-YNEEEP6O.js");
5144
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-VDYZSZWY.js");
5134
5145
  const orch = getOrchestrator2();
5135
5146
  const thread = await orch.waitForTurn(ref, timeoutMs, {
5136
5147
  resolveIfStillRunning: true
@@ -13243,7 +13254,7 @@ async function continueSourceThread(threadId, prompt) {
13243
13254
  await continueOnReply(threadId, prompt);
13244
13255
  return;
13245
13256
  }
13246
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-YNEEEP6O.js");
13257
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-VDYZSZWY.js");
13247
13258
  await getOrchestrator2().send(threadId, prompt);
13248
13259
  } catch {
13249
13260
  }
@@ -776,30 +776,6 @@ var init_system_ca = __esm({
776
776
  }
777
777
  });
778
778
 
779
- // src/paths/workspace-scratch.ts
780
- function attachmentsGitignoreBody() {
781
- return ATTACHMENTS_GITIGNORE;
782
- }
783
- function isWorkspaceScratchPath(relativePath) {
784
- const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
785
- return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
786
- }
787
- var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
788
- var init_workspace_scratch = __esm({
789
- "src/paths/workspace-scratch.ts"() {
790
- "use strict";
791
- ATTACHMENTS_DIR = ".context/attachments";
792
- CLI_DIR = ".context/cli";
793
- DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
794
- LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
795
- LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
796
- ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
797
- *
798
- !.gitignore
799
- `;
800
- }
801
- });
802
-
803
779
  // src/agents/cursor-stream-cutoff.ts
804
780
  function looksLikeCursorStreamCutOff(text7) {
805
781
  return CURSOR_STREAM_CUTOFF.test(text7.trim());
@@ -1200,6 +1176,30 @@ var init_error_detail = __esm({
1200
1176
  }
1201
1177
  });
1202
1178
 
1179
+ // src/paths/workspace-scratch.ts
1180
+ function attachmentsGitignoreBody() {
1181
+ return ATTACHMENTS_GITIGNORE;
1182
+ }
1183
+ function isWorkspaceScratchPath(relativePath) {
1184
+ const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
1185
+ return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === CLI_DIR || p.startsWith(`${CLI_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
1186
+ }
1187
+ var ATTACHMENTS_DIR, CLI_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
1188
+ var init_workspace_scratch = __esm({
1189
+ "src/paths/workspace-scratch.ts"() {
1190
+ "use strict";
1191
+ ATTACHMENTS_DIR = ".context/attachments";
1192
+ CLI_DIR = ".context/cli";
1193
+ DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
1194
+ LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
1195
+ LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
1196
+ ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
1197
+ *
1198
+ !.gitignore
1199
+ `;
1200
+ }
1201
+ });
1202
+
1203
1203
  // src/agents/message-parts.ts
1204
1204
  function asRecord(input) {
1205
1205
  if (input && typeof input === "object" && !Array.isArray(input)) {
@@ -28440,6 +28440,10 @@ var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
28440
28440
  // src/mcp/wrap-mcp-tools.ts
28441
28441
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
28442
28442
 
28443
+ // src/agents/cursor-tool-guard.ts
28444
+ init_error_detail();
28445
+ init_cursor_stream_cutoff();
28446
+
28443
28447
  // src/agents/tool-result-clip.ts
28444
28448
  var import_node_fs7 = require("fs");
28445
28449
  var import_node_path8 = require("path");
@@ -28488,11 +28492,30 @@ function clipMcpToolResult(result, cwd) {
28488
28492
  };
28489
28493
  }
28490
28494
 
28495
+ // src/agents/cursor-tool-guard.ts
28496
+ var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
28497
+ function cursorToolErrorText(err) {
28498
+ const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
28499
+ const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
28500
+ return `Error: ${message}
28501
+ ${CURSOR_TOOL_RECOVERY_HINT}`;
28502
+ }
28503
+
28491
28504
  // src/mcp/wrap-mcp-tools.ts
28492
28505
  function wrapToolCallback(fn, cwd) {
28493
28506
  return async (...args) => {
28494
- const result = await fn(...args);
28495
- return clipMcpToolResult(result, cwd());
28507
+ try {
28508
+ const result = await fn(...args);
28509
+ return clipMcpToolResult(
28510
+ result,
28511
+ cwd()
28512
+ );
28513
+ } catch (err) {
28514
+ return {
28515
+ isError: true,
28516
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
28517
+ };
28518
+ }
28496
28519
  };
28497
28520
  }
28498
28521
  function wrapRegistrar(orig, cwd) {
@@ -50,7 +50,7 @@ import {
50
50
  syncBoardPins,
51
51
  updateSchedule,
52
52
  workspaceTagTargetRef
53
- } from "../chunk-CECZUHA5.js";
53
+ } from "../chunk-YFKAC4LB.js";
54
54
  import "../chunk-LX5R5JOR.js";
55
55
  import {
56
56
  commentAbleTimeTask,
@@ -93,7 +93,7 @@ import {
93
93
  sideboardMcpProfile,
94
94
  trustSystemCertificates,
95
95
  worktreeMcpToolNames
96
- } from "../chunk-SVQTKVXH.js";
96
+ } from "../chunk-ABLHTRRG.js";
97
97
  import "../chunk-WZCPZVUC.js";
98
98
  import "../chunk-7IAMHN2N.js";
99
99
  import "../chunk-PXMLMBMI.js";
@@ -110,12 +110,14 @@ import {
110
110
  waitForDetachedJob,
111
111
  waitForTurnToolResult,
112
112
  workspaceAgentChatSummaries
113
- } from "../chunk-BJUHZSZQ.js";
113
+ } from "../chunk-HWIIRVYE.js";
114
114
  import {
115
+ HUGE_TOOL_RESULT_SUMMARY,
115
116
  clipToolResultForStore,
117
+ formatUnknownDetail,
116
118
  isInternalAgentStatusText,
117
119
  looksLikeHugeToolResultDump
118
- } from "../chunk-AFLNFGGB.js";
120
+ } from "../chunk-ED4ZXQVO.js";
119
121
  import {
120
122
  GLOBAL_WORKSPACE_ID,
121
123
  isCloudCoordinatorThread
@@ -222,11 +224,30 @@ function clipMcpToolResult(result, cwd) {
222
224
  };
223
225
  }
224
226
 
227
+ // src/agents/cursor-tool-guard.ts
228
+ var CURSOR_TOOL_RECOVERY_HINT = "Continue with a smaller request. If you were reading a large file or API payload, pass offset and limit or write the output to .context/cli/ and read a slice. Do not retry the same call.";
229
+ function cursorToolErrorText(err) {
230
+ const raw = formatUnknownDetail(err).replace(/\s+/g, " ").trim();
231
+ const message = looksLikeHugeToolResultDump(raw) ? HUGE_TOOL_RESULT_SUMMARY : (raw || "unknown tool error").slice(0, 500);
232
+ return `Error: ${message}
233
+ ${CURSOR_TOOL_RECOVERY_HINT}`;
234
+ }
235
+
225
236
  // src/mcp/wrap-mcp-tools.ts
226
237
  function wrapToolCallback(fn, cwd) {
227
238
  return async (...args) => {
228
- const result = await fn(...args);
229
- return clipMcpToolResult(result, cwd());
239
+ try {
240
+ const result = await fn(...args);
241
+ return clipMcpToolResult(
242
+ result,
243
+ cwd()
244
+ );
245
+ } catch (err) {
246
+ return {
247
+ isError: true,
248
+ content: [{ type: "text", text: cursorToolErrorText(err) }]
249
+ };
250
+ }
230
251
  };
231
252
  }
232
253
  function wrapRegistrar(orig, cwd) {
@@ -9,12 +9,12 @@ import {
9
9
  resolveSendFollowUp,
10
10
  startOrchestration,
11
11
  waitForPidExit
12
- } from "./chunk-BYAFYLLZ.js";
12
+ } from "./chunk-XXT3C2EF.js";
13
13
  import "./chunk-PGPSIEMW.js";
14
- import "./chunk-JEYJGQ33.js";
14
+ import "./chunk-RWIYYFID.js";
15
15
  import "./chunk-VGNLMGBK.js";
16
- import "./chunk-YKO6HG74.js";
17
- import "./chunk-YSLCWCMJ.js";
16
+ import "./chunk-KCP6IVRI.js";
17
+ import "./chunk-Q3DPZ4DE.js";
18
18
  import "./chunk-7H655NEW.js";
19
19
  import "./chunk-QDDTVIWE.js";
20
20
  import "./chunk-B42H6GJR.js";
@@ -25,8 +25,8 @@ import "./chunk-2P4XKWV2.js";
25
25
  import "./chunk-33KDPEK4.js";
26
26
  import "./chunk-JAT3JFOS.js";
27
27
  import "./chunk-AXQ4ZWHK.js";
28
- import "./chunk-7UUILVMV.js";
29
- import "./chunk-MIVX7QKI.js";
28
+ import "./chunk-IOY2LF3Y.js";
29
+ import "./chunk-HO5R3ZRH.js";
30
30
  import "./chunk-6K64FJDD.js";
31
31
  import "./chunk-UWQ6UCIB.js";
32
32
  import "./chunk-QVN2WOKJ.js";
@@ -11,18 +11,18 @@ import {
11
11
  resolveSendFollowUp,
12
12
  startOrchestration,
13
13
  waitForPidExit
14
- } from "./chunk-CECZUHA5.js";
14
+ } from "./chunk-YFKAC4LB.js";
15
15
  import "./chunk-LX5R5JOR.js";
16
16
  import "./chunk-XCXUVX7I.js";
17
17
  import "./chunk-4GK32AYX.js";
18
18
  import "./chunk-5DZUWGKV.js";
19
- import "./chunk-SVQTKVXH.js";
19
+ import "./chunk-ABLHTRRG.js";
20
20
  import "./chunk-WZCPZVUC.js";
21
21
  import "./chunk-7IAMHN2N.js";
22
22
  import "./chunk-PXMLMBMI.js";
23
23
  import "./chunk-2GPQZZLY.js";
24
- import "./chunk-BJUHZSZQ.js";
25
- import "./chunk-AFLNFGGB.js";
24
+ import "./chunk-HWIIRVYE.js";
25
+ import "./chunk-ED4ZXQVO.js";
26
26
  import "./chunk-E7G7RY6T.js";
27
27
  import "./chunk-6SGYGYH7.js";
28
28
  import "./chunk-N2WW62LF.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.294",
3
+ "version": "0.1.295",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",