@sideboard-ai/core 0.1.187 → 0.1.189

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.
@@ -12,7 +12,7 @@ import {
12
12
  ensureCursorRipgrepPath,
13
13
  fetchCursorTurnCostUsd,
14
14
  formatUnknownDetail
15
- } from "../chunk-NQTKRAUF.js";
15
+ } from "../chunk-ZSFQLR7Y.js";
16
16
  import {
17
17
  dropNestedElectronEnvFromProcess
18
18
  } from "../chunk-4TR3HZFT.js";
@@ -38,7 +38,7 @@ import {
38
38
  resolveQuotaFallbackAgent,
39
39
  turnCostUsdFromCursorUsage,
40
40
  whichOnPath
41
- } from "./chunk-7DBYKEYF.js";
41
+ } from "./chunk-QU663NPO.js";
42
42
  import "./chunk-HVIEYTUK.js";
43
43
  import "./chunk-Y4MIXGPA.js";
44
44
  import "./chunk-VKQGAWHY.js";
@@ -32,7 +32,7 @@ import {
32
32
  resolveLoginCommand,
33
33
  resolveQuotaFallbackAgent,
34
34
  whichOnPath
35
- } from "./chunk-6XOSOIDJ.js";
35
+ } from "./chunk-ISOCLQEX.js";
36
36
  import "./chunk-VIODP5PT.js";
37
37
  import "./chunk-WXKXSZN4.js";
38
38
  import "./chunk-6K64FJDD.js";
@@ -44,7 +44,7 @@ import {
44
44
  parseCursorRunnerLine,
45
45
  preferredCursorCostCents,
46
46
  turnCostUsdFromCursorUsage
47
- } from "./chunk-NQTKRAUF.js";
47
+ } from "./chunk-ZSFQLR7Y.js";
48
48
  import {
49
49
  ORCHESTRATOR_AGENT_KINDS,
50
50
  assertOrchestratorCapableAgent,
@@ -29,7 +29,7 @@ import {
29
29
  packagedMcpStdioPath,
30
30
  parseCursorRunnerLine,
31
31
  resolveNodeLaunch
32
- } from "./chunk-NQTKRAUF.js";
32
+ } from "./chunk-ZSFQLR7Y.js";
33
33
  import {
34
34
  claudeChromeEnabled,
35
35
  isAbleTimeConnected,
@@ -33,7 +33,7 @@ import {
33
33
  summarizeTurnStderr,
34
34
  toolDescription,
35
35
  turnFailChatText
36
- } from "./chunk-7DBYKEYF.js";
36
+ } from "./chunk-QU663NPO.js";
37
37
  import {
38
38
  extractPresentedPlan,
39
39
  readPlanFile,
@@ -402,7 +402,7 @@ async function continueSourceThread(threadId, prompt) {
402
402
  await continueOnReply(threadId, prompt);
403
403
  return;
404
404
  }
405
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6PZQ7DZS.js");
405
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-EVDOHS2S.js");
406
406
  await getOrchestrator2().send(threadId, prompt);
407
407
  } catch {
408
408
  }
@@ -2675,6 +2675,10 @@ function mcpWaitFinishedHint(status) {
2675
2675
 
2676
2676
  // src/mcp/wait-for-job.ts
2677
2677
  var MAX_JOB_CONTINUES = 8;
2678
+ var MAX_JOB_DELTA_LINES = 80;
2679
+ var MAX_JOB_DELTA_CHARS = 4e3;
2680
+ var DEFERRED_DONE_MAX_CHARS = 480;
2681
+ var GH_WATCH_REFRESH = "Refreshing run status every 3 seconds.";
2678
2682
  var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
2679
2683
  var MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
2680
2684
  var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
@@ -2748,8 +2752,37 @@ function listRunningDetachedJobs(worktreePath) {
2748
2752
  }
2749
2753
  function looksLikeDeferredDonePromise(text) {
2750
2754
  const t = (text ?? "").trim();
2751
- if (!t) return false;
2752
- return /\b(i['’]?ll|i will)\s+let you know\b/i.test(t) || /\blet you know when\b/i.test(t) || /\b(check back|ping me)\s+when\b/i.test(t) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(t);
2755
+ if (!t || t.length > DEFERRED_DONE_MAX_CHARS) return false;
2756
+ const unquoted = t.replace(/`[^`]*`/g, " ").replace(/["“”][^"“”]*["“”]/g, " ").replace(/\s+/g, " ").trim();
2757
+ if (!unquoted) return false;
2758
+ return /\b(i['’]?ll|i will)\s+let you know\b/i.test(unquoted) || /\blet you know when\b/i.test(unquoted) || /\b(check back|ping me)\s+when\b/i.test(unquoted) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(unquoted);
2759
+ }
2760
+ function isJobContinuePrompt(text) {
2761
+ const t = text.trim();
2762
+ return t.startsWith("Detached job still running:") || t.startsWith("You ended the turn after promising to report later");
2763
+ }
2764
+ function collapseGhRunWatchLog(text) {
2765
+ if (!text.includes(GH_WATCH_REFRESH)) return text;
2766
+ const frames = text.split(/(?=Refreshing run status every 3 seconds\.)/);
2767
+ const watchFrames = frames.filter((f) => f.includes(GH_WATCH_REFRESH));
2768
+ if (watchFrames.length <= 1) return text;
2769
+ const prefix = frames[0]?.includes(GH_WATCH_REFRESH) ? "" : frames[0] ?? "";
2770
+ const last = watchFrames[watchFrames.length - 1] ?? "";
2771
+ const omitted = watchFrames.length - 1;
2772
+ const note = `(${omitted} identical gh run watch refresh${omitted === 1 ? "" : "es"} omitted)
2773
+ `;
2774
+ return [prefix.trimEnd(), note, last.trimStart()].filter(Boolean).join("\n");
2775
+ }
2776
+ function capJobLogDelta(text) {
2777
+ const collapsed = collapseGhRunWatchLog(text);
2778
+ const lines = collapsed.split("\n");
2779
+ let out = lines.length > MAX_JOB_DELTA_LINES ? `\u2026(${lines.length - MAX_JOB_DELTA_LINES} earlier lines omitted)
2780
+ ${lines.slice(-MAX_JOB_DELTA_LINES).join("\n")}` : collapsed;
2781
+ if (out.length > MAX_JOB_DELTA_CHARS) {
2782
+ out = `\u2026(truncated ${out.length} chars)
2783
+ ${out.slice(-MAX_JOB_DELTA_CHARS)}`;
2784
+ }
2785
+ return out;
2753
2786
  }
2754
2787
  function formatJobStillRunningContinuePrompt(jobIds) {
2755
2788
  const ids = jobIds.join(", ");
@@ -2812,7 +2845,7 @@ function takeDelta(logFile, cursorFile) {
2812
2845
  const lines = readLogLines(logFile);
2813
2846
  const cursor = readIntFile(cursorFile) ?? 0;
2814
2847
  const start = Math.min(Math.max(0, cursor), lines.length);
2815
- return { delta: lines.slice(start).join("\n"), nextCursor: lines.length };
2848
+ return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
2816
2849
  }
2817
2850
  function snapshotJob(dir) {
2818
2851
  const pid = readIntFile(join11(dir, "pid"));
@@ -5939,7 +5972,7 @@ function formatIssueToolsDirective(opts) {
5939
5972
  ];
5940
5973
  if (opts.linear) {
5941
5974
  lines.push(
5942
- "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
5975
+ "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
5943
5976
  );
5944
5977
  }
5945
5978
  if (github) {
@@ -6425,7 +6458,7 @@ function formatScheduledPrompt(name, prompt) {
6425
6458
  ${prompt}`;
6426
6459
  }
6427
6460
  async function defaultDeps() {
6428
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-6PZQ7DZS.js");
6461
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-EVDOHS2S.js");
6429
6462
  const orch = getOrchestrator2();
6430
6463
  return {
6431
6464
  findThread: (id) => findThreadByRef(id),
@@ -7214,11 +7247,13 @@ var Orchestrator = class {
7214
7247
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
7215
7248
  thread = this.requireThread(threadId);
7216
7249
  }
7217
- const sentAttachments = thread.attachments.length > 0 ? [...thread.attachments] : void 0;
7250
+ const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
7251
+ const sentAttachments = !autoContinue && thread.attachments.length > 0 ? [...thread.attachments] : void 0;
7218
7252
  appendMessage(threadId, {
7219
7253
  role: "user",
7220
7254
  text: prompt,
7221
7255
  ...sentAttachments ? { attachments: sentAttachments } : {},
7256
+ ...autoContinue ? { origin: "continue" } : {},
7222
7257
  ts: (/* @__PURE__ */ new Date()).toISOString()
7223
7258
  });
7224
7259
  thread = this.requireThread(threadId);
@@ -7227,7 +7262,7 @@ var Orchestrator = class {
7227
7262
  thread.worktreePath,
7228
7263
  gitPrompt,
7229
7264
  {
7230
- attachments: sentAttachments ?? thread.attachments
7265
+ attachments: autoContinue ? [] : sentAttachments ?? thread.attachments
7231
7266
  }
7232
7267
  );
7233
7268
  const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
@@ -7280,7 +7315,7 @@ var Orchestrator = class {
7280
7315
  slackReplyContext,
7281
7316
  expandedPrompt
7282
7317
  ].filter(Boolean).join("\n\n");
7283
- if (thread.attachments.length > 0) {
7318
+ if (!autoContinue && thread.attachments.length > 0) {
7284
7319
  updateThread(threadId, { attachments: [] });
7285
7320
  }
7286
7321
  const adapter = getAdapter(thread.agent);
@@ -229,11 +229,45 @@ function looksLikeHugeToolResultDump(text) {
229
229
  if (t.length < 4e3) return false;
230
230
  return looksLikeMinifiedJsDump(t);
231
231
  }
232
+ function clipJobWaitResultJson(content) {
233
+ const trimmed = content.trim();
234
+ if (!trimmed.startsWith("{")) return void 0;
235
+ try {
236
+ const rec = JSON.parse(trimmed);
237
+ const isJob = typeof rec.stillRunning === "boolean" || typeof rec.stopped === "boolean" || typeof rec.delta === "string" && typeof rec.status === "string";
238
+ if (!isJob) return void 0;
239
+ if (typeof rec.delta === "string" && rec.delta.length > 3500) {
240
+ rec.delta = `\u2026(truncated ${rec.delta.length} chars)
241
+ ${rec.delta.slice(-3500)}`;
242
+ }
243
+ if (typeof rec.progress === "string" && rec.progress.length > 800) {
244
+ rec.progress = rec.progress.slice(-800);
245
+ }
246
+ if (typeof rec.hint === "string" && rec.hint.length > 240) {
247
+ rec.hint = rec.hint.slice(0, 240);
248
+ }
249
+ let out = JSON.stringify(rec);
250
+ if (out.length <= TOOL_RESULT_STORE_MAX_CHARS) return out;
251
+ return JSON.stringify({
252
+ stillRunning: rec.stillRunning,
253
+ ok: rec.ok,
254
+ failed: rec.failed,
255
+ status: rec.status,
256
+ id: rec.id,
257
+ phase: rec.phase,
258
+ delta: typeof rec.delta === "string" ? rec.delta.slice(-2500) : ""
259
+ });
260
+ } catch {
261
+ return void 0;
262
+ }
263
+ }
232
264
  function clipToolResultForStore(content) {
233
265
  if (content == null) return void 0;
234
266
  if (looksLikeCursorSdkSourceDump(content) || looksLikeMinifiedJsDump(content)) {
235
267
  return `${HUGE_TOOL_RESULT_SUMMARY} (${content.length} chars omitted)`;
236
268
  }
269
+ const jobClipped = clipJobWaitResultJson(content);
270
+ if (jobClipped) return jobClipped;
237
271
  if (content.length <= TOOL_RESULT_STORE_MAX_CHARS) return content;
238
272
  const head = 5e3;
239
273
  const tail = 2e3;
@@ -24,7 +24,7 @@ import {
24
24
  stripBrightsyNdjsonNoise,
25
25
  sumUsageList,
26
26
  toolDescription
27
- } from "./chunk-6XOSOIDJ.js";
27
+ } from "./chunk-ISOCLQEX.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -124,7 +124,7 @@ import {
124
124
  shouldRetryFailedAgentTurn,
125
125
  summarizeTurnStderr,
126
126
  turnFailChatText
127
- } from "./chunk-NQTKRAUF.js";
127
+ } from "./chunk-ZSFQLR7Y.js";
128
128
  import {
129
129
  assertOrchestratorCapableAgent,
130
130
  childEnvWithAppSettings,
@@ -467,7 +467,7 @@ async function continueSourceThread(threadId, prompt) {
467
467
  await continueOnReply(threadId, prompt);
468
468
  return;
469
469
  }
470
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-5CFTLN7B.js");
470
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-CWBYGHAT.js");
471
471
  await getOrchestrator2().send(threadId, prompt);
472
472
  } catch {
473
473
  }
@@ -2762,6 +2762,10 @@ function mcpWaitFinishedHint(status) {
2762
2762
 
2763
2763
  // src/mcp/wait-for-job.ts
2764
2764
  var MAX_JOB_CONTINUES = 8;
2765
+ var MAX_JOB_DELTA_LINES = 80;
2766
+ var MAX_JOB_DELTA_CHARS = 4e3;
2767
+ var DEFERRED_DONE_MAX_CHARS = 480;
2768
+ var GH_WATCH_REFRESH = "Refreshing run status every 3 seconds.";
2765
2769
  var MCP_WAIT_JOB_STILL_RUNNING_HINT = "Job is still running. The type=log pane already appended this delta. Call wait_for_job again. If it is hanging, producing no useful output, or doing the wrong thing, call stop_job (same id) instead of looping forever. Do not end the turn or tell the user you will let them know later.";
2766
2770
  var MCP_STOP_JOB_HINT = "Stopped. The type=log pane is status=failed with the last delta. Do not wait again unless you start a new command.";
2767
2771
  var JOB_ID_RE = /^[a-zA-Z0-9._-]{1,64}$/;
@@ -2835,8 +2839,37 @@ function listRunningDetachedJobs(worktreePath) {
2835
2839
  }
2836
2840
  function looksLikeDeferredDonePromise(text) {
2837
2841
  const t = (text ?? "").trim();
2838
- if (!t) return false;
2839
- return /\b(i['’]?ll|i will)\s+let you know\b/i.test(t) || /\blet you know when\b/i.test(t) || /\b(check back|ping me)\s+when\b/i.test(t) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(t);
2842
+ if (!t || t.length > DEFERRED_DONE_MAX_CHARS) return false;
2843
+ const unquoted = t.replace(/`[^`]*`/g, " ").replace(/["“”][^"“”]*["“”]/g, " ").replace(/\s+/g, " ").trim();
2844
+ if (!unquoted) return false;
2845
+ return /\b(i['’]?ll|i will)\s+let you know\b/i.test(unquoted) || /\blet you know when\b/i.test(unquoted) || /\b(check back|ping me)\s+when\b/i.test(unquoted) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(unquoted);
2846
+ }
2847
+ function isJobContinuePrompt(text) {
2848
+ const t = text.trim();
2849
+ return t.startsWith("Detached job still running:") || t.startsWith("You ended the turn after promising to report later");
2850
+ }
2851
+ function collapseGhRunWatchLog(text) {
2852
+ if (!text.includes(GH_WATCH_REFRESH)) return text;
2853
+ const frames = text.split(/(?=Refreshing run status every 3 seconds\.)/);
2854
+ const watchFrames = frames.filter((f) => f.includes(GH_WATCH_REFRESH));
2855
+ if (watchFrames.length <= 1) return text;
2856
+ const prefix = frames[0]?.includes(GH_WATCH_REFRESH) ? "" : frames[0] ?? "";
2857
+ const last = watchFrames[watchFrames.length - 1] ?? "";
2858
+ const omitted = watchFrames.length - 1;
2859
+ const note = `(${omitted} identical gh run watch refresh${omitted === 1 ? "" : "es"} omitted)
2860
+ `;
2861
+ return [prefix.trimEnd(), note, last.trimStart()].filter(Boolean).join("\n");
2862
+ }
2863
+ function capJobLogDelta(text) {
2864
+ const collapsed = collapseGhRunWatchLog(text);
2865
+ const lines = collapsed.split("\n");
2866
+ let out = lines.length > MAX_JOB_DELTA_LINES ? `\u2026(${lines.length - MAX_JOB_DELTA_LINES} earlier lines omitted)
2867
+ ${lines.slice(-MAX_JOB_DELTA_LINES).join("\n")}` : collapsed;
2868
+ if (out.length > MAX_JOB_DELTA_CHARS) {
2869
+ out = `\u2026(truncated ${out.length} chars)
2870
+ ${out.slice(-MAX_JOB_DELTA_CHARS)}`;
2871
+ }
2872
+ return out;
2840
2873
  }
2841
2874
  function formatJobStillRunningContinuePrompt(jobIds) {
2842
2875
  const ids = jobIds.join(", ");
@@ -2899,7 +2932,7 @@ function takeDelta(logFile, cursorFile) {
2899
2932
  const lines = readLogLines(logFile);
2900
2933
  const cursor = readIntFile(cursorFile) ?? 0;
2901
2934
  const start = Math.min(Math.max(0, cursor), lines.length);
2902
- return { delta: lines.slice(start).join("\n"), nextCursor: lines.length };
2935
+ return { delta: capJobLogDelta(lines.slice(start).join("\n")), nextCursor: lines.length };
2903
2936
  }
2904
2937
  function snapshotJob(dir) {
2905
2938
  const pid = readIntFile(join11(dir, "pid"));
@@ -3841,7 +3874,7 @@ async function createThread(input, _onSetupLine) {
3841
3874
  return readThread(thread.id) ?? thread;
3842
3875
  }
3843
3876
  async function listLinearIssues(agent, repoPath) {
3844
- const { getAdapter: getAdapter2 } = await import("./agents-W3JQANEC.js");
3877
+ const { getAdapter: getAdapter2 } = await import("./agents-XPWKGOVT.js");
3845
3878
  await requireAgent(agent, { requireLinear: true });
3846
3879
  const adapter = getAdapter2(agent);
3847
3880
  if (!adapter.listLinearIssues) {
@@ -6097,7 +6130,7 @@ function formatIssueToolsDirective(opts) {
6097
6130
  ];
6098
6131
  if (opts.linear) {
6099
6132
  lines.push(
6100
- "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
6133
+ "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
6101
6134
  );
6102
6135
  }
6103
6136
  if (github) {
@@ -6772,7 +6805,7 @@ function formatScheduledPrompt(name, prompt) {
6772
6805
  ${prompt}`;
6773
6806
  }
6774
6807
  async function defaultDeps() {
6775
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5CFTLN7B.js");
6808
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-CWBYGHAT.js");
6776
6809
  const orch = getOrchestrator2();
6777
6810
  return {
6778
6811
  findThread: (id) => findThreadByRef(id),
@@ -7561,11 +7594,13 @@ var Orchestrator = class {
7561
7594
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
7562
7595
  thread = this.requireThread(threadId);
7563
7596
  }
7564
- const sentAttachments = thread.attachments.length > 0 ? [...thread.attachments] : void 0;
7597
+ const autoContinue = isJobContinuePrompt(prompt) || prompt.trim().startsWith("The previous agent process ended before it finished.");
7598
+ const sentAttachments = !autoContinue && thread.attachments.length > 0 ? [...thread.attachments] : void 0;
7565
7599
  appendMessage(threadId, {
7566
7600
  role: "user",
7567
7601
  text: prompt,
7568
7602
  ...sentAttachments ? { attachments: sentAttachments } : {},
7603
+ ...autoContinue ? { origin: "continue" } : {},
7569
7604
  ts: (/* @__PURE__ */ new Date()).toISOString()
7570
7605
  });
7571
7606
  thread = this.requireThread(threadId);
@@ -7574,7 +7609,7 @@ var Orchestrator = class {
7574
7609
  thread.worktreePath,
7575
7610
  gitPrompt,
7576
7611
  {
7577
- attachments: sentAttachments ?? thread.attachments
7612
+ attachments: autoContinue ? [] : sentAttachments ?? thread.attachments
7578
7613
  }
7579
7614
  );
7580
7615
  const slackInbound = /^(Slack DM|Slack @mention)(?:\n|$)/.test(
@@ -7627,7 +7662,7 @@ var Orchestrator = class {
7627
7662
  slackReplyContext,
7628
7663
  expandedPrompt
7629
7664
  ].filter(Boolean).join("\n\n");
7630
- if (thread.attachments.length > 0) {
7665
+ if (!autoContinue && thread.attachments.length > 0) {
7631
7666
  updateThread(threadId, { attachments: [] });
7632
7667
  }
7633
7668
  const adapter = getAdapter(thread.agent);
@@ -86,11 +86,45 @@ function looksLikeHugeToolResultDump(text) {
86
86
  if (t.length < 4e3) return false;
87
87
  return looksLikeMinifiedJsDump(t);
88
88
  }
89
+ function clipJobWaitResultJson(content) {
90
+ const trimmed = content.trim();
91
+ if (!trimmed.startsWith("{")) return void 0;
92
+ try {
93
+ const rec = JSON.parse(trimmed);
94
+ const isJob = typeof rec.stillRunning === "boolean" || typeof rec.stopped === "boolean" || typeof rec.delta === "string" && typeof rec.status === "string";
95
+ if (!isJob) return void 0;
96
+ if (typeof rec.delta === "string" && rec.delta.length > 3500) {
97
+ rec.delta = `\u2026(truncated ${rec.delta.length} chars)
98
+ ${rec.delta.slice(-3500)}`;
99
+ }
100
+ if (typeof rec.progress === "string" && rec.progress.length > 800) {
101
+ rec.progress = rec.progress.slice(-800);
102
+ }
103
+ if (typeof rec.hint === "string" && rec.hint.length > 240) {
104
+ rec.hint = rec.hint.slice(0, 240);
105
+ }
106
+ let out = JSON.stringify(rec);
107
+ if (out.length <= TOOL_RESULT_STORE_MAX_CHARS) return out;
108
+ return JSON.stringify({
109
+ stillRunning: rec.stillRunning,
110
+ ok: rec.ok,
111
+ failed: rec.failed,
112
+ status: rec.status,
113
+ id: rec.id,
114
+ phase: rec.phase,
115
+ delta: typeof rec.delta === "string" ? rec.delta.slice(-2500) : ""
116
+ });
117
+ } catch {
118
+ return void 0;
119
+ }
120
+ }
89
121
  function clipToolResultForStore(content) {
90
122
  if (content == null) return void 0;
91
123
  if (looksLikeCursorSdkSourceDump(content) || looksLikeMinifiedJsDump(content)) {
92
124
  return `${HUGE_TOOL_RESULT_SUMMARY} (${content.length} chars omitted)`;
93
125
  }
126
+ const jobClipped = clipJobWaitResultJson(content);
127
+ if (jobClipped) return jobClipped;
94
128
  if (content.length <= TOOL_RESULT_STORE_MAX_CHARS) return content;
95
129
  const head = 5e3;
96
130
  const tail = 2e3;