@sideboard-ai/core 0.1.264 → 0.1.267

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/{abletime-6AOJI2YZ.js → abletime-4ZSDI4YP.js} +9 -6
  2. package/dist/{abletime-U75ZGDIX.js → abletime-JNQAHLHH.js} +7 -4
  3. package/dist/{abletime-oauth-TA2YDCYX.js → abletime-oauth-4RXZH2KU.js} +3 -3
  4. package/dist/{abletime-oauth-LOAHGG4X.js → abletime-oauth-DCEIINYT.js} +5 -5
  5. package/dist/{abletime-rest-CTA5WV26.js → abletime-rest-KVBJFVFD.js} +3 -3
  6. package/dist/{abletime-rest-YZPFM6IY.js → abletime-rest-VN6PZ6P2.js} +5 -5
  7. package/dist/agents/cursor-runner.js +7 -5
  8. package/dist/{agents-3TUMFSMH.js → agents-G3JTULM2.js} +7 -5
  9. package/dist/{agents-6FWDRVA2.js → agents-XRXJCAWJ.js} +11 -10
  10. package/dist/{app-settings-RKFFUIFQ.js → app-settings-L5HGYXWJ.js} +1 -3
  11. package/dist/{app-settings-MVZPM6WW.js → app-settings-RAC4PSSP.js} +3 -5
  12. package/dist/{caffeinate-hold-UAGLSGMM.js → caffeinate-hold-7JM5H5P3.js} +2 -2
  13. package/dist/{chunk-F5MFNUAA.js → chunk-27Z4MEQ5.js} +1 -1
  14. package/dist/{chunk-EK3KVT7I.js → chunk-2XIRV7FS.js} +53 -1254
  15. package/dist/{chunk-3H7O27X2.js → chunk-3VBS6MES.js} +39 -1017
  16. package/dist/chunk-4ECDIKAS.js +2273 -0
  17. package/dist/{chunk-H547WSSZ.js → chunk-4RZRHTSZ.js} +1 -1
  18. package/dist/{chunk-QN5DL2QO.js → chunk-5DZUWGKV.js} +1 -1
  19. package/dist/chunk-5N4Q46SG.js +392 -0
  20. package/dist/{chunk-YKYEHDMX.js → chunk-AGXZAMOF.js} +5 -5
  21. package/dist/{chunk-RKPBIB2U.js → chunk-DB7MVDYS.js} +33 -7
  22. package/dist/{chunk-BOMSJUXW.js → chunk-DBFAFI5A.js} +5 -5
  23. package/dist/chunk-FAGK33E2.js +994 -0
  24. package/dist/{chunk-A5SAYFJ4.js → chunk-FIBZEFKA.js} +4 -390
  25. package/dist/{chunk-5PK53SAP.js → chunk-GONPMH36.js} +5 -5
  26. package/dist/{chunk-L5WGAIL2.js → chunk-GZXKUUJO.js} +35 -9
  27. package/dist/{chunk-Z2LGMV6C.js → chunk-H5XL4KUS.js} +21 -0
  28. package/dist/{chunk-T3AYRQJZ.js → chunk-HSRN2CSL.js} +473 -2487
  29. package/dist/{chunk-TJ673EZT.js → chunk-JANCPF7Z.js} +2 -2
  30. package/dist/chunk-KZ2CDZBZ.js +828 -0
  31. package/dist/{chunk-6YY7XPPL.js → chunk-L6CYOON4.js} +5 -5
  32. package/dist/{chunk-6YOXQVJ7.js → chunk-LAIBYKZS.js} +3 -3
  33. package/dist/{chunk-4ALDX5IO.js → chunk-NWE3NOWQ.js} +3 -3
  34. package/dist/{chunk-36FOBJBF.js → chunk-OIENQEGG.js} +63 -38
  35. package/dist/{chunk-2QUQH2SZ.js → chunk-PAH7KDL2.js} +68 -24
  36. package/dist/{chunk-XAISOBBG.js → chunk-TQRSVE7D.js} +1 -1
  37. package/dist/chunk-UKSJO36E.js +1224 -0
  38. package/dist/{chunk-CEMNIGQH.js → chunk-UN5Q7POQ.js} +1 -1
  39. package/dist/{chunk-5ZPT5YAV.js → chunk-USBZ7PH4.js} +1 -1
  40. package/dist/chunk-UXI52MLJ.js +826 -0
  41. package/dist/chunk-X7RP3TQB.js +2385 -0
  42. package/dist/{chunk-QX6QUZVD.js → chunk-ZSGSVFWD.js} +424 -2611
  43. package/dist/conductor-MLM5NGTP.js +104 -0
  44. package/dist/conductor-NRKTEN5X.js +105 -0
  45. package/dist/{connected-teams-7CENZDWU.js → connected-teams-JIUOSZ6C.js} +2 -2
  46. package/dist/{coordinator-prompt-J7DKHOCH.js → coordinator-prompt-4GHKCVRH.js} +7 -7
  47. package/dist/{coordinator-prompt-HZCQZ6C5.js → coordinator-prompt-BKRQDZFT.js} +3 -3
  48. package/dist/{cursor-recover-FALSNEZN.js → cursor-recover-MB3T2K5T.js} +2 -2
  49. package/dist/{global-workspace-TI26K25J.js → global-workspace-EEWJOMED.js} +9 -3
  50. package/dist/{global-workspace-6LDUZ2NF.js → global-workspace-EWFL4HPW.js} +13 -7
  51. package/dist/index.cjs +3918 -2592
  52. package/dist/index.d.cts +363 -68
  53. package/dist/index.d.ts +363 -68
  54. package/dist/index.js +4181 -3462
  55. package/dist/{managed-accounts-4BLTJKAN.js → managed-accounts-46A4KRUE.js} +2 -2
  56. package/dist/mcp/run-stdio.cjs +1894 -2012
  57. package/dist/mcp/run-stdio.js +719 -1445
  58. package/dist/{orchestrator-5YU46YNS.js → orchestrator-6ZQ2CYS4.js} +9 -6
  59. package/dist/{orchestrator-4JSG7BWC.js → orchestrator-MA3MHYIM.js} +15 -13
  60. package/dist/{paths-IUR3ABNG.js → paths-HYT5WOOX.js} +1 -1
  61. package/dist/{thread-store-FJ5CDX2M.js → thread-store-B3ZM4QEZ.js} +3 -3
  62. package/dist/{workspaces-QJ3XIPUJ.js → workspaces-F33Z4CEY.js} +3 -3
  63. package/dist/{workspaces-WOQHJFRQ.js → workspaces-SLP24Z3S.js} +7 -7
  64. package/dist/{worktree-6U2FA5LO.js → worktree-ACW23KJ5.js} +6 -6
  65. package/dist/{worktree-KQA4ON2G.js → worktree-C7RPVHZ7.js} +2 -2
  66. package/package.json +1 -1
  67. package/dist/chunk-CEOTK5GZ.js +0 -479
  68. package/dist/chunk-K7B25HO4.js +0 -477
@@ -0,0 +1,1224 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/agents/error-detail.ts
5
+ function formatUnknownDetail(err) {
6
+ if (err == null) return "";
7
+ if (typeof err === "string") return err.trim();
8
+ if (err instanceof Error) {
9
+ const base = err.message.trim() || err.name;
10
+ const code = "code" in err && typeof err.code === "string" ? err.code.trim() : "";
11
+ return code && !base.includes(code) ? `${base} (${code})` : base;
12
+ }
13
+ if (typeof err === "object") {
14
+ const o = err;
15
+ const nested = o.error != null && typeof o.error === "object" ? formatUnknownDetail(o.error) : "";
16
+ const message = typeof o.message === "string" ? o.message.trim() : typeof o.error === "string" ? o.error.trim() : typeof o.result === "string" ? o.result.trim() : nested;
17
+ const code = typeof o.code === "string" ? o.code.trim() : "";
18
+ if (message) return code && !message.includes(code) ? `${message} (${code})` : message;
19
+ try {
20
+ const json = JSON.stringify(err);
21
+ if (json && json !== "{}" && json !== "null") return json;
22
+ } catch {
23
+ }
24
+ }
25
+ const fallback = String(err);
26
+ return fallback === "[object Object]" ? "" : fallback;
27
+ }
28
+ function extractJsonErrorMessage(obj) {
29
+ const nested = obj.error != null && typeof obj.error === "object" ? obj.error : null;
30
+ const candidates = [
31
+ typeof obj.message === "string" ? obj.message : null,
32
+ typeof obj.error === "string" ? obj.error : null,
33
+ nested && typeof nested.message === "string" ? nested.message : null,
34
+ typeof obj.result === "string" ? obj.result : null,
35
+ typeof obj.detail === "string" ? obj.detail : null
36
+ ];
37
+ for (const c of candidates) {
38
+ const t = c?.trim();
39
+ if (t) return t;
40
+ }
41
+ if (Array.isArray(obj.errors)) {
42
+ const parts = obj.errors.map((e) => formatUnknownDetail(e)).map((s) => s.trim()).filter(Boolean);
43
+ if (parts.length) return parts.join("; ");
44
+ }
45
+ return null;
46
+ }
47
+ var NODE_VERSION_FOOTER = /^Node\.js v\d+/i;
48
+ function isPinnedStderrLine(line) {
49
+ if (/^\s*at\s/.test(line)) return false;
50
+ return /cannot find (?:package|module)|ERR_MODULE_NOT_FOUND|cursor startup failed:|FATAL ERROR|heap out of memory|javascript heap|OOMErrorHandler|FatalProcessOutOfMemory/i.test(
51
+ line
52
+ );
53
+ }
54
+ function pushTurnStderr(tail, line, maxLines = 12) {
55
+ const trimmed = line.trim();
56
+ if (!trimmed) return;
57
+ if (NODE_VERSION_FOOTER.test(trimmed)) return;
58
+ if (/^reconnecting\.\.\./i.test(trimmed)) return;
59
+ tail.push(trimmed);
60
+ while (tail.length > maxLines) {
61
+ const dropIdx = tail.findIndex((l) => !isPinnedStderrLine(l));
62
+ if (dropIdx === -1) tail.shift();
63
+ else tail.splice(dropIdx, 1);
64
+ }
65
+ }
66
+ function looksLikeMinifiedJsDump(line) {
67
+ if (line.length < 200) return false;
68
+ return /yield Promise\.all/.test(line) || /\(0,[A-Za-z$]\.\w+\)/.test(line) || /CURSOR_RIPGREP_PATH/.test(line) || /findFilesWithRipgrep/.test(line) || /@cursor\/sdk\/dist\//.test(line) || looksLikeCursorSdkSourceDump(line);
69
+ }
70
+ function looksLikeCursorSdkSourceDump(text) {
71
+ const t = text.trim();
72
+ if (t.length < 120) return false;
73
+ return /cursor-runtime\/node_modules\/@cursor\/sdk/.test(t) || /importas [a-z] from"@bufbuild\/protobuf"/.test(t) || /file:\/\/[^\s]*@cursor\/sdk\/dist\/esm\/index\.js/.test(t);
74
+ }
75
+ function looksLikeHugeToolResultDump(text) {
76
+ if (looksLikeCursorSdkSourceDump(text)) return true;
77
+ const t = text.trim();
78
+ if (t.length < 4e3) return false;
79
+ return looksLikeMinifiedJsDump(t);
80
+ }
81
+ function looksLikeJobWaitResult(rec) {
82
+ if (typeof rec.delta === "string") {
83
+ return typeof rec.status === "string" || typeof rec.id === "string" || typeof rec.stillRunning === "boolean";
84
+ }
85
+ if (typeof rec.stopped === "boolean") {
86
+ return typeof rec.id === "string" || typeof rec.status === "string";
87
+ }
88
+ return rec.started === true || rec.reason === "already-running";
89
+ }
90
+ function clipJobWaitResultJson(content) {
91
+ const trimmed = content.trim();
92
+ if (!trimmed.startsWith("{")) return void 0;
93
+ try {
94
+ const rec = JSON.parse(trimmed);
95
+ if (!looksLikeJobWaitResult(rec)) 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
+ }
121
+ function clipToolResultForStore(content) {
122
+ if (content == null) return void 0;
123
+ if (looksLikeCursorSdkSourceDump(content) || looksLikeMinifiedJsDump(content)) {
124
+ return `${HUGE_TOOL_RESULT_SUMMARY} (${content.length} chars omitted)`;
125
+ }
126
+ const jobClipped = clipJobWaitResultJson(content);
127
+ if (jobClipped) return jobClipped;
128
+ if (content.length <= TOOL_RESULT_STORE_MAX_CHARS) return content;
129
+ const head = 5e3;
130
+ const tail = 2e3;
131
+ return `${content.slice(0, head)}
132
+
133
+ \u2026(truncated ${content.length} chars \u2014 write output to .context/cli/ and read a slice)
134
+
135
+ ${content.slice(-tail)}`;
136
+ }
137
+ function looksLikeNestedElectronCrash(line) {
138
+ return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
139
+ }
140
+ function looksLikeNativeEventLoopCrash(text) {
141
+ return /uv_run|uv__io_poll|SpinEventLoopInternal/i.test(text);
142
+ }
143
+ function looksLikeV8Oom(text) {
144
+ return /javascript heap|reached heap limit|OOMErrorHandler|FatalProcessOutOfMemory|Allocation failed - JavaScript heap/i.test(
145
+ text
146
+ );
147
+ }
148
+ function looksLikeHomebrewLibuvCrash(text) {
149
+ if (!looksLikeNativeEventLoopCrash(text)) return false;
150
+ return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text);
151
+ }
152
+ var NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
153
+ var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
154
+ var BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
155
+ var V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
156
+ var MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
157
+ 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.";
158
+ var TOOL_RESULT_STORE_MAX_CHARS = 8e3;
159
+ function clipStderr(text, maxChars) {
160
+ const trimmed = text.trim();
161
+ if (trimmed.length <= maxChars) return trimmed;
162
+ return trimmed.slice(0, maxChars);
163
+ }
164
+ function summarizeTurnStderr(tail, maxChars = 500) {
165
+ if (tail.length === 0) return "";
166
+ const cursorStartup = [...tail].reverse().find((line) => /cursor startup failed:/i.test(line));
167
+ if (cursorStartup) return clipStderr(cursorStartup, maxChars);
168
+ const cursorRunFailed = [...tail].reverse().find((line) => /^cursor run failed\b/i.test(line.trim()));
169
+ if (cursorRunFailed) return clipStderr(cursorRunFailed, maxChars);
170
+ if (tail.some(looksLikeNestedElectronCrash)) return NESTED_ELECTRON_SUMMARY;
171
+ const blob = tail.join("\n");
172
+ if (looksLikeV8Oom(blob)) return V8_OOM_SUMMARY;
173
+ if (looksLikeHomebrewLibuvCrash(blob)) return HOMEBREW_LIBUV_SUMMARY;
174
+ if (looksLikeNativeEventLoopCrash(blob)) {
175
+ return BUNDLED_NODE_CRASH_SUMMARY;
176
+ }
177
+ if (tail.some(
178
+ (line) => /\[resource_exhausted\]|resource_exhausted/i.test(line) || /findFilesWithRipgrep/.test(line)
179
+ )) {
180
+ return clipStderr(
181
+ "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.",
182
+ maxChars
183
+ );
184
+ }
185
+ const moduleMissing = [...tail].reverse().find((line) => /cannot find (?:package|module)/i.test(line));
186
+ if (moduleMissing) return clipStderr(moduleMissing, maxChars);
187
+ if (tail.some(looksLikeHugeToolResultDump)) {
188
+ return HUGE_TOOL_RESULT_SUMMARY;
189
+ }
190
+ const useful = tail.filter((line) => !looksLikeMinifiedJsDump(line));
191
+ if (useful.length === 0 && tail.some(looksLikeMinifiedJsDump)) {
192
+ return MINIFIED_DUMP_SUMMARY;
193
+ }
194
+ const joined = (useful.length ? useful : tail).slice(-6).join("\n").trim();
195
+ return clipStderr(joined, maxChars);
196
+ }
197
+ function looksLikeInvalidAgentSession(text) {
198
+ const lower = text.trim().toLowerCase();
199
+ if (!lower) return false;
200
+ 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
+ }
202
+ function looksLikeCursorHttp2StreamClose(text) {
203
+ return /nghttp2/i.test(text.trim());
204
+ }
205
+ function looksLikeBrightsyEmptyCompletion(text) {
206
+ const core = text.trim().replace(/^exit\s*\d+:\s*/i, "").replace(/^error:\s*/i, "").trim();
207
+ return /^i did not receive a valid model response\. please try again\.$/i.test(core);
208
+ }
209
+ function looksLikeRetryableRunnerCrash(text) {
210
+ if (looksLikeAgentFailureMessage(text)) return false;
211
+ if (looksLikeInvalidAgentSession(text)) return false;
212
+ if (looksLikeV8Oom(text)) return false;
213
+ if (looksLikeHugeToolResultDump(text)) return true;
214
+ if (looksLikeCursorHttp2StreamClose(text)) return true;
215
+ if (looksLikeBrightsyEmptyCompletion(text)) return true;
216
+ const lower = text.trim().toLowerCase();
217
+ if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
218
+ if (!lower) return true;
219
+ return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|huge tool result|cursor sdk crashed mid-turn|connection stalled|network request failed|cursor startup failed:.+\(retryable\)|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
220
+ lower
221
+ );
222
+ }
223
+ function shouldRetryFailedAgentTurn(detail, opts) {
224
+ if (looksLikeInvalidAgentSession(detail) && opts.hasSession) return true;
225
+ if (looksLikeV8Oom(detail) && opts.hasSession) return true;
226
+ return looksLikeRetryableRunnerCrash(detail);
227
+ }
228
+ function looksLikeAgentFailureMessage(text) {
229
+ const lower = text.trim().toLowerCase();
230
+ if (!lower) return false;
231
+ return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
232
+ lower
233
+ ) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text);
234
+ }
235
+ function fallbackTurnFailDetail(assistantText) {
236
+ const t = assistantText.trim();
237
+ if (!t) return "";
238
+ if (looksLikeHugeToolResultDump(t)) return HUGE_TOOL_RESULT_SUMMARY;
239
+ if (looksLikeAgentFailureMessage(t)) return t;
240
+ if (t.length <= 400 && !/\n\n/.test(t)) return t;
241
+ return "";
242
+ }
243
+ function humanizeAgentFailDetail(detail) {
244
+ const raw = detail.trim();
245
+ if (!raw) return raw;
246
+ const lower = raw.toLowerCase();
247
+ if (/credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded|billing/.test(lower)) {
248
+ return `${raw} \u2014 add credits or switch auth, then retry.`;
249
+ }
250
+ if (/hit your (session|weekly|opus) limit|usage limit|you've hit your/.test(lower)) {
251
+ return raw.includes("reset") ? raw : `${raw} \u2014 wait for the limit window to reset, then retry.`;
252
+ }
253
+ if (/\b429\b|rate.?limit|too many requests/.test(lower)) {
254
+ return `${raw} \u2014 wait a moment and retry.`;
255
+ }
256
+ if (/\[resource_exhausted\]|resource_exhausted|findfileswithripgrep/.test(lower)) {
257
+ return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
258
+ }
259
+ if (looksLikeCodexMcpError(raw)) {
260
+ return `${raw} \u2014 skip that vendor MCP and continue (PostHog: Settings \u2192 Connectors + HTTP API).`;
261
+ }
262
+ if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
263
+ lower
264
+ )) {
265
+ return `${raw} \u2014 check agent login / API key in Settings.`;
266
+ }
267
+ if (/model .{0,80}(not found|unavailable|unknown|invalid)/.test(lower)) {
268
+ return `${raw} \u2014 pick another model in the agent options.`;
269
+ }
270
+ if (/context.*(too long|exceed)|prompt is too long|conversation too long/.test(lower)) {
271
+ return `${raw} \u2014 start a new chat or compact context, then retry.`;
272
+ }
273
+ if (/hascustomhostobject|electroninitializeicuandstartnode|nested chromium/i.test(lower)) {
274
+ return `${raw} \u2014 retry the turn; if it keeps failing, pick another agent.`;
275
+ }
276
+ if (looksLikeV8Oom(raw) || /javascript heap out of memory/i.test(lower)) {
277
+ return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
278
+ }
279
+ if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
280
+ return /brew install node@(?:22|24)/i.test(raw) ? raw : `${raw} \u2014 install Node 24 LTS (\`brew install node@24\`) and retry.`;
281
+ }
282
+ if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
283
+ return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
284
+ }
285
+ if (looksLikeHugeToolResultDump(raw) || /huge tool result|cursor sdk crashed mid-turn/.test(lower)) {
286
+ return HUGE_TOOL_RESULT_SUMMARY;
287
+ }
288
+ if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
289
+ return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
290
+ }
291
+ if (/connection stalled/.test(lower) || looksLikeCursorHttp2StreamClose(raw)) {
292
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
293
+ }
294
+ if (looksLikeBrightsyEmptyCompletion(raw)) {
295
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Brightsy returned an empty model completion).`;
296
+ }
297
+ if (/network request failed|cursor startup failed:.+\(retryable\)/.test(lower)) {
298
+ return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (a transient Cursor SDK network error).`;
299
+ }
300
+ return raw;
301
+ }
302
+ function turnFailChatText(opts) {
303
+ const chat = opts.assistantText.trim();
304
+ if (opts.exitCode === 0) return chat;
305
+ if (looksLikeHugeToolResultDump(chat)) {
306
+ return HUGE_TOOL_RESULT_SUMMARY;
307
+ }
308
+ const detail = opts.detail.trim();
309
+ const fail = detail ? humanizeAgentFailDetail(detail) : formatTurnExitError(opts.exitCode ?? 1, "");
310
+ if (!chat) return fail;
311
+ const failCore = fail.replace(/^exit\s*\d+:\s*/i, "").trim();
312
+ if (looksLikeAgentFailureMessage(chat) || failCore && chat.includes(failCore) || chat.includes(fail)) {
313
+ return chat;
314
+ }
315
+ return `${chat}
316
+
317
+ ${fail}`;
318
+ }
319
+ function shouldRetryCodexPluginIsolate(detail, opts) {
320
+ if (opts?.alreadyIsolated) return false;
321
+ return looksLikeCodexMcpError(detail);
322
+ }
323
+ function looksLikeCodexMcpError(text) {
324
+ const t = text.trim().toLowerCase();
325
+ if (!t) return false;
326
+ if (/authrequired|authorization required/.test(t) && /mcp|posthog|rmcp|connector|plugin/.test(t)) {
327
+ return true;
328
+ }
329
+ if (/\bposthog\b/.test(t) && /mcp|oauth|auth|unauthorized|401|plugin|app/.test(t)) {
330
+ return true;
331
+ }
332
+ if (/\brmcp\b/.test(t) && /fatal|quit|transport|error|died|kill|auth/.test(t)) {
333
+ return true;
334
+ }
335
+ return /invalid transport in mcp_servers/.test(t);
336
+ }
337
+ function shouldFeedErrorBackToAgent(opts) {
338
+ const detail = opts.detail.trim();
339
+ const chat = (opts.assistantText ?? "").trim();
340
+ if (looksLikeCodexMcpError(detail)) return true;
341
+ if (looksLikeAgentFailureMessage(detail) || looksLikeAgentFailureMessage(chat)) {
342
+ return false;
343
+ }
344
+ if (looksLikeInvalidAgentSession(detail) || looksLikeV8Oom(detail) || looksLikeRetryableRunnerCrash(detail)) {
345
+ return true;
346
+ }
347
+ if (/without details|segfault|sig(?:segv|abrt|ill)|fatal error/i.test(detail)) {
348
+ return true;
349
+ }
350
+ return !chat && (opts.partsCount ?? 0) === 0;
351
+ }
352
+ function formatAgentErrorContinuePrompt(detail) {
353
+ const fail = humanizeAgentFailDetail(detail.trim()) || "the agent process exited without details";
354
+ return [
355
+ "The previous agent process ended before it finished. Error:",
356
+ fail,
357
+ "",
358
+ "Continue from where you left off. Use the error to recover \u2014 do not restart the whole task unless the error requires it. If you cannot continue, say why."
359
+ ].join("\n");
360
+ }
361
+ function formatTurnExitError(exitCode, stderrSummary) {
362
+ const code = exitCode ?? 1;
363
+ const raw = stderrSummary.trim();
364
+ if (/^exit\s*\d+$/i.test(raw)) {
365
+ return `exit ${code}: agent exited without details (credits, auth, rate limits, or a CLI error)`;
366
+ }
367
+ const detail = humanizeAgentFailDetail(raw);
368
+ if (!detail) {
369
+ return `exit ${code}: agent exited without details (credits, auth, rate limits, or a CLI error)`;
370
+ }
371
+ if (looksLikeAgentFailureMessage(raw)) return detail;
372
+ return `exit ${code}: ${detail}`;
373
+ }
374
+
375
+ // src/agents/message-parts.ts
376
+ function asRecord(input) {
377
+ if (input && typeof input === "object" && !Array.isArray(input)) {
378
+ return input;
379
+ }
380
+ return void 0;
381
+ }
382
+ function str(v) {
383
+ return typeof v === "string" && v.trim() ? v : void 0;
384
+ }
385
+ var CHAT_DETAIL_MAX = 72;
386
+ function clipChatLine(value, max = CHAT_DETAIL_MAX) {
387
+ const line = value.trim().split(/\r?\n/, 1)[0] ?? "";
388
+ if (line.length <= max) return line;
389
+ return `${line.slice(0, Math.max(1, max - 1))}\u2026`;
390
+ }
391
+ function isSkillToolName(name) {
392
+ const n = (name ?? "").trim();
393
+ if (/^(Skill|SlashCommand)$/i.test(n)) return true;
394
+ return /(?:^|__)Skill$/i.test(n);
395
+ }
396
+ function skillCommandFromInput(input) {
397
+ const raw = str(input?.skill) ?? str(input?.command) ?? str(input?.name) ?? str(input?.skill_name) ?? str(input?.skillName);
398
+ if (raw) return raw.replace(/^\//, "").trim() || void 0;
399
+ const path = str(input?.file_path) ?? str(input?.path);
400
+ if (path && /SKILL\.md$/i.test(path)) {
401
+ const parts = path.replace(/\\/g, "/").split("/");
402
+ const dir = parts[parts.length - 2];
403
+ if (dir && dir !== "skills") return dir;
404
+ }
405
+ return void 0;
406
+ }
407
+ function looksLikeComposerSkillExpansion(text) {
408
+ const t = text.trim();
409
+ return /^## Skill: \//m.test(t) && /Follow this skill for the request above:/i.test(t);
410
+ }
411
+ var SKILL_FRONTMATTER_NAME = /^\s*name\s*:\s*['"]?([A-Za-z0-9][A-Za-z0-9._-]*)['"]?\s*$/m;
412
+ function skillNameFromFrontmatter(text) {
413
+ const t = text.trim();
414
+ if (!t) return void 0;
415
+ let yaml = t;
416
+ if (!yaml.startsWith("---")) {
417
+ const at = t.search(/(?:^|\n)---(?:\r?\n)/);
418
+ if (at < 0 || at > 800) return void 0;
419
+ yaml = t.slice(at).replace(/^\n/, "");
420
+ }
421
+ if (!yaml.startsWith("---")) return void 0;
422
+ const close = yaml.indexOf("\n---", 3);
423
+ if (close < 0) return void 0;
424
+ return yaml.slice(3, close).match(SKILL_FRONTMATTER_NAME)?.[1];
425
+ }
426
+ function skillCommandFromBody(text) {
427
+ return skillNameFromFrontmatter(text) ?? text.match(/^## Skill: \/([A-Za-z0-9][A-Za-z0-9._-]*)/m)?.[1] ?? text.match(/^Launching skill:\s*\/?([A-Za-z0-9][A-Za-z0-9._-]*)/im)?.[1];
428
+ }
429
+ function looksLikeSkillBody(text) {
430
+ const t = text.trim();
431
+ if (!t) return false;
432
+ if (looksLikeComposerSkillExpansion(t)) return true;
433
+ if (skillNameFromFrontmatter(t) != null) return true;
434
+ return /^Launching skill:/im.test(t) && /Base directory for this skill:/i.test(t);
435
+ }
436
+ function looksLikeIncompleteSkillDump(text) {
437
+ const t = text.trim();
438
+ if (!t || looksLikeSkillBody(t)) return false;
439
+ if (/^## Skill: \//m.test(t)) return true;
440
+ if (/^Launching skill:/im.test(t)) return true;
441
+ if (/Base directory for this skill:/i.test(t)) return true;
442
+ return t.startsWith("---") && SKILL_FRONTMATTER_NAME.test(t);
443
+ }
444
+ function isCompactToolName(name) {
445
+ const short = (name ?? "").replace(/^mcp__[^_]+__/, "").trim();
446
+ return /^(Compact|ConversationCompact|summarize_context|SummarizeContext|SummarizeConversation)$/i.test(
447
+ short
448
+ );
449
+ }
450
+ function isContextCompactDone(text) {
451
+ return /\bContext compressed\b/i.test(text.trim());
452
+ }
453
+ function isContextCompactInProgress(text) {
454
+ const t = text.trim();
455
+ if (isContextCompactDone(t)) return false;
456
+ return /^Compressing context/i.test(t);
457
+ }
458
+ function isSystemStatusThinking(event) {
459
+ if (event.replace) return true;
460
+ const t = (event.data ?? "").trim();
461
+ if (!t) return true;
462
+ if (/^API retry\b/i.test(t)) return true;
463
+ if (/^MCP:/i.test(t)) return true;
464
+ if (isContextCompactInProgress(t) || isContextCompactDone(t)) return true;
465
+ return false;
466
+ }
467
+ function looksLikeConversationSummary(text) {
468
+ const t = text.trim();
469
+ if (t.length < 80) return false;
470
+ if (/<summarized_conversation\b/i.test(t) || /<conversation_summary\b/i.test(t)) {
471
+ return true;
472
+ }
473
+ if (/this session is being continued from a previous conversation/i.test(t)) {
474
+ return true;
475
+ }
476
+ if (/conversation compacted|replaced with a summary/i.test(t)) return true;
477
+ if (/^## Prior summary\b/m.test(t)) return true;
478
+ if (/_Automatic extractive summary/i.test(t)) return true;
479
+ if (/"context_summary"\s*:/.test(t)) return true;
480
+ if (/^(?:#+\s*)?(?:conversation summary|summary of (?:the )?conversation|compacted (?:conversation|context))\b/im.test(
481
+ t
482
+ )) {
483
+ return true;
484
+ }
485
+ return false;
486
+ }
487
+ function toolDetail(name, input) {
488
+ if (isSkillToolName(name) || isCompactToolName(name)) return void 0;
489
+ if (!input) return void 0;
490
+ const command = str(input.command) ?? str(input.cmd);
491
+ if (command) return clipChatLine(command);
492
+ const pattern = str(input.pattern) ?? str(input.glob) ?? str(input.glob_pattern);
493
+ const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
494
+ if (isSearch && pattern) {
495
+ return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
496
+ }
497
+ const path = str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
498
+ if (path) return path;
499
+ if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
500
+ const query = str(input.query) ?? str(input.prompt);
501
+ if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
502
+ try {
503
+ const raw = JSON.stringify(input);
504
+ return raw.length > 80 ? `${raw.slice(0, 77)}\u2026` : raw;
505
+ } catch {
506
+ return name;
507
+ }
508
+ }
509
+ function toolDescription(name, input) {
510
+ const n = name.replace(/^mcp__/, "").replace(/__/g, " \xB7 ");
511
+ if (/^get_record_types$|recordTypes/i.test(name)) return "List record types";
512
+ if (/connectedAgentRequest/i.test(name)) {
513
+ return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
514
+ }
515
+ if (/present_artifact$/i.test(name)) {
516
+ return str(input?.title) ? `Present ${str(input?.title)}` : "Present artifact";
517
+ }
518
+ if (/present_plan$/i.test(name)) {
519
+ return str(input?.title) ? `Plan ${str(input?.title)}` : "Present plan";
520
+ }
521
+ if (/present_schema$/i.test(name)) {
522
+ return str(input?.title) ? `Schema ${str(input?.title)}` : "Present schema";
523
+ }
524
+ if (/present_files$/i.test(name)) {
525
+ return str(input?.title) ? `Files ${str(input?.title)}` : "Present files";
526
+ }
527
+ if (/wait_for_job$/i.test(name)) {
528
+ return str(input?.id) ? `Wait for ${str(input?.id)}` : "Wait for job";
529
+ }
530
+ if (/stop_job$/i.test(name)) {
531
+ return str(input?.id) ? `Stop ${str(input?.id)}` : "Stop job";
532
+ }
533
+ if (/list_run_scripts$/i.test(name)) return "List run scripts";
534
+ if (/run_dev_script$/i.test(name)) {
535
+ return str(input?.name) ? `Start ${str(input?.name)}` : "Start Dev script";
536
+ }
537
+ if (/stop_dev_script$/i.test(name)) {
538
+ return str(input?.name) ? `Stop ${str(input?.name)}` : "Stop Dev script";
539
+ }
540
+ if (/get_run_log$/i.test(name)) {
541
+ return str(input?.name) ? `Read ${str(input?.name)} log` : "Read Dev log";
542
+ }
543
+ if (/notify_orchestrator$/i.test(name)) return "Notify orchestrator";
544
+ if (/list_schedules$/i.test(name)) return "List schedules";
545
+ if (/create_schedule$/i.test(name)) {
546
+ return str(input?.name) ? `Schedule ${str(input?.name)}` : "Create schedule";
547
+ }
548
+ if (/update_schedule$/i.test(name)) return "Update schedule";
549
+ if (/delete_schedule$/i.test(name)) return "Delete schedule";
550
+ if (/run_schedule$/i.test(name)) return "Run schedule";
551
+ if (isSkillToolName(name)) {
552
+ const cmd = skillCommandFromInput(input);
553
+ return cmd ? `Using /${cmd}` : "Using skill";
554
+ }
555
+ if (isCompactToolName(name)) {
556
+ const trigger = str(input?.trigger);
557
+ if (trigger && !/^auto$/i.test(trigger) && trigger !== "injected") {
558
+ return `Summarized conversation (${trigger})`;
559
+ }
560
+ return "Summarized conversation";
561
+ }
562
+ if (isSubagentToolName(name)) {
563
+ const desc = str(input?.description);
564
+ const sub = asRecord(input?.subagentType);
565
+ const kind = str(sub?.name) ?? str(sub?.kind) ?? str(input?.subagent_type) ?? str(input?.subagentType);
566
+ if (/^spawn_agent$/i.test(name)) {
567
+ return str(input?.prompt) ?? desc ?? "Subagent";
568
+ }
569
+ if (/connectedAgentRequest/i.test(name)) {
570
+ return str(input?.agent_id) ? `Ask connected agent` : "Ask connected agent";
571
+ }
572
+ if (desc && kind) return `${kind}: ${desc}${subagentLiveSuffix(input)}`;
573
+ if (desc) return `${desc}${subagentLiveSuffix(input)}`;
574
+ return `Subagent${subagentLiveSuffix(input)}`;
575
+ }
576
+ if (/^(create|update)_artifact$/i.test(name.replace(/^mcp__[^_]+__/, ""))) {
577
+ return str(input?.title) ? `Artifact ${str(input?.title)}` : "Artifact";
578
+ }
579
+ if (!input) return n;
580
+ if (/bash|shell|terminal/i.test(name) && str(input.command)) {
581
+ const cmd = str(input.command);
582
+ if (/git\s+fetch/i.test(cmd)) return "Fetch latest from origin and check status";
583
+ if (/git\s+status/i.test(cmd)) return "Check git status";
584
+ if (/git\s+log/i.test(cmd)) return "Inspect recent commits";
585
+ if (/git\s+branch/i.test(cmd)) return "List branches";
586
+ if (/grep|rg\b/i.test(cmd)) return "Search repository";
587
+ return "Run shell command";
588
+ }
589
+ if (/edit|write|apply/i.test(name)) {
590
+ const path = str(input.file_path) ?? str(input.path);
591
+ return path ? `Edit ${path.split("/").pop()}` : "Edit file";
592
+ }
593
+ if (/read/i.test(name)) {
594
+ const path = str(input.file_path) ?? str(input.path);
595
+ return path ? `Read ${path.split("/").pop()}` : "Read file";
596
+ }
597
+ if (/grep/i.test(name)) return "Search files";
598
+ if (/glob/i.test(name)) return "Find files";
599
+ const compact = n.replace(/[_-]/g, "");
600
+ if (/^taskoutput$/i.test(compact)) {
601
+ return str(input.task_id) ? `Wait for ${str(input.task_id)}` : "Wait for background task";
602
+ }
603
+ if (/^taskstop$/i.test(compact)) {
604
+ return str(input.task_id) ? `Stop ${str(input.task_id)}` : "Stop background task";
605
+ }
606
+ if (/^monitor$/i.test(compact)) {
607
+ const command = str(input.command);
608
+ return command ? `Watch ${command.length > 48 ? `${command.slice(0, 45)}\u2026` : command}` : "Watch command";
609
+ }
610
+ return n;
611
+ }
612
+ function subagentLiveSuffix(input) {
613
+ if (!input) return "";
614
+ const bits = [];
615
+ const status = str(input.live_status);
616
+ if (status && !/^runn(ing)?$|^working$/i.test(status)) bits.push(status);
617
+ if (typeof input.live_tool_uses === "number") bits.push(`${input.live_tool_uses} tools`);
618
+ if (typeof input.live_duration_ms === "number") {
619
+ bits.push(`${Math.max(0, Math.round(Number(input.live_duration_ms) / 1e3))}s`);
620
+ }
621
+ const last = str(input.live_last_tool);
622
+ if (last) bits.push(last);
623
+ return bits.length ? ` \xB7 ${bits.join(" \xB7 ")}` : "";
624
+ }
625
+ function isSubagentToolName(name) {
626
+ const n = (name ?? "").trim();
627
+ if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
628
+ return /connectedAgentRequest/i.test(n);
629
+ }
630
+ function isInternalAgentStatusText(text) {
631
+ const t = text.trim();
632
+ if (!t) return false;
633
+ if (/waiting for gate to pass/i.test(t)) return true;
634
+ if (/^agent is running\b/i.test(t) && t.length < 160) return true;
635
+ return false;
636
+ }
637
+ function isPollWrapperToolName(name) {
638
+ const n = (name ?? "").replace(/[_-]/g, "");
639
+ return /^(taskoutput|taskstop|sleep)$/i.test(n);
640
+ }
641
+ function lastTextPart(parts, type) {
642
+ for (let i = parts.length - 1; i >= 0; i--) {
643
+ const p = parts[i];
644
+ if (p.type !== type) continue;
645
+ const text = p.text.trim();
646
+ if (!text || isInternalAgentStatusText(text)) continue;
647
+ return text;
648
+ }
649
+ return "";
650
+ }
651
+ function toolLabel(tool) {
652
+ return tool.description || toolDescription(tool.name, tool.input) || tool.name;
653
+ }
654
+ function liveActivitySummary(parts, opts) {
655
+ if (opts?.queued && parts.length === 0) {
656
+ return "Queued \u2014 waiting for a slot";
657
+ }
658
+ const tools = parts.filter((p) => p.type === "tool");
659
+ const runningSubs = tools.filter(
660
+ (t) => t.status === "running" && !t.parentId && isSubagentToolName(t.name)
661
+ );
662
+ const runningNested = [...tools].reverse().find((t) => t.status === "running" && t.parentId && !isPollWrapperToolName(t.name));
663
+ const runningTop = [...tools].reverse().find(
664
+ (t) => t.status === "running" && !t.parentId && !isPollWrapperToolName(t.name) && !isSubagentToolName(t.name)
665
+ );
666
+ const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
667
+ const thinking = lastTextPart(parts, "thinking");
668
+ const text = lastTextPart(parts, "text");
669
+ if (runningSubs.length > 0) {
670
+ const heads = runningSubs.map(toolLabel);
671
+ const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
672
+ if (runningNested) return `${head} \xB7 ${toolLabel(runningNested)}`;
673
+ return head;
674
+ }
675
+ if (runningTop) return toolLabel(runningTop);
676
+ if (runningPoll) return toolLabel(runningPoll);
677
+ if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
678
+ if (text) return "Writing reply\u2026";
679
+ const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
680
+ if (last) {
681
+ const label = toolLabel(last);
682
+ return last.status === "running" ? label : `Finished ${label}`;
683
+ }
684
+ return "Working\u2026";
685
+ }
686
+ function messagePartParentId(part) {
687
+ if ("parentId" in part && typeof part.parentId === "string" && part.parentId.trim()) {
688
+ return part.parentId;
689
+ }
690
+ return void 0;
691
+ }
692
+ function sameParentId(a, b) {
693
+ return (a ?? "") === (b ?? "");
694
+ }
695
+ function withEventParentId(event, parentId) {
696
+ if (!parentId) return event;
697
+ if (event.type === "stdout" || event.type === "thinking" || event.type === "tool_use" || event.type === "tool_result") {
698
+ return { ...event, parentId: event.parentId ?? parentId };
699
+ }
700
+ return event;
701
+ }
702
+ function toolFilePath(input) {
703
+ if (!input) return void 0;
704
+ return str(input.file_path) ?? str(input.path) ?? str(input.filePath) ?? str(input.filename);
705
+ }
706
+ function countLines(text) {
707
+ if (!text) return 0;
708
+ return text.split("\n").length;
709
+ }
710
+ function diffFromInput(input) {
711
+ if (!input) return {};
712
+ const oldS = str(input.old_string) ?? str(input.oldString);
713
+ const newS = str(input.new_string) ?? str(input.newString) ?? str(input.content);
714
+ if (oldS != null || newS != null) {
715
+ return {
716
+ additions: countLines(newS),
717
+ deletions: countLines(oldS)
718
+ };
719
+ }
720
+ return {};
721
+ }
722
+ function parseDiffStat(result) {
723
+ if (!result) return {};
724
+ const paired = result.match(/\+(\d+)\s+-(\d+)/);
725
+ if (paired) {
726
+ return {
727
+ additions: Number(paired[1]),
728
+ deletions: Number(paired[2])
729
+ };
730
+ }
731
+ const verbose = result.match(
732
+ /(\d+)\s+insertions?(?:,\s*(\d+)\s+deletions?)?/i
733
+ );
734
+ if (verbose) {
735
+ return {
736
+ additions: Number(verbose[1]),
737
+ deletions: verbose[2] != null ? Number(verbose[2]) : void 0
738
+ };
739
+ }
740
+ return {};
741
+ }
742
+ var THINKING_PART_MAX_CHARS = 64e3;
743
+ function clipThinkingForStore(text, max = THINKING_PART_MAX_CHARS) {
744
+ if (text.length <= max) return text;
745
+ const marker = "\u2026(earlier thinking trimmed)\n";
746
+ return marker + text.slice(text.length - Math.max(1, max - marker.length));
747
+ }
748
+ var STDOUT_EVENT_MAX_CHARS = 16e3;
749
+ var STDERR_EVENT_MAX_CHARS = 4e3;
750
+ function clipEventTail(text, max) {
751
+ if (text.length <= max) return text;
752
+ const marker = "\u2026(truncated)\n";
753
+ return marker + text.slice(text.length - Math.max(1, max - marker.length));
754
+ }
755
+ function clipAgentEventForPaint(event) {
756
+ if (event.type === "tool_result" && event.content) {
757
+ const content = clipToolResultForStore(event.content);
758
+ if (content === event.content) return event;
759
+ return { ...event, content };
760
+ }
761
+ if (event.type === "thinking" && event.data.length > THINKING_PART_MAX_CHARS) {
762
+ return { ...event, data: clipThinkingForStore(event.data) };
763
+ }
764
+ if (event.type === "stdout" && event.data.length > STDOUT_EVENT_MAX_CHARS) {
765
+ return { ...event, data: clipEventTail(event.data, STDOUT_EVENT_MAX_CHARS) };
766
+ }
767
+ if (event.type === "stderr" && event.data.length > STDERR_EVENT_MAX_CHARS) {
768
+ return { ...event, data: clipEventTail(event.data, STDERR_EVENT_MAX_CHARS) };
769
+ }
770
+ return event;
771
+ }
772
+ function withPartTimes(next, prev) {
773
+ const now = Date.now();
774
+ const startedAt = prev && typeof prev.startedAt === "number" ? prev.startedAt : now;
775
+ return { ...next, startedAt, updatedAt: now };
776
+ }
777
+ function skillToolFromTextPart(part, id, status = "done") {
778
+ const command = skillCommandFromBody(part.text);
779
+ const input = command ? { skill: command } : void 0;
780
+ return {
781
+ type: "tool",
782
+ id: command ? `skill-${command}` : id,
783
+ name: "Skill",
784
+ input,
785
+ description: toolDescription("Skill", input),
786
+ status,
787
+ result: clipToolResultForStore(part.text),
788
+ ...part.parentId ? { parentId: part.parentId } : {},
789
+ startedAt: part.startedAt,
790
+ updatedAt: Date.now()
791
+ };
792
+ }
793
+ function lastSkillToolIndex(parts, parentId) {
794
+ for (let i = parts.length - 1; i >= 0; i--) {
795
+ const p = parts[i];
796
+ if (p.type === "tool" && isSkillToolName(p.name) && sameParentId(p.parentId, parentId)) {
797
+ return i;
798
+ }
799
+ }
800
+ return -1;
801
+ }
802
+ function lastRunningSkillIndex(parts, parentId) {
803
+ for (let i = parts.length - 1; i >= 0; i--) {
804
+ const p = parts[i];
805
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
806
+ return i;
807
+ }
808
+ }
809
+ return -1;
810
+ }
811
+ function markRunningSkillsDone(parts, parentId) {
812
+ return parts.map((p) => {
813
+ if (p.type === "tool" && isSkillToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
814
+ return withPartTimes({ ...p, status: "done" }, p);
815
+ }
816
+ return p;
817
+ });
818
+ }
819
+ function promoteOrFoldSkillText(parts, textIdx) {
820
+ const acc = parts[textIdx];
821
+ if (acc?.type !== "text") return parts;
822
+ const complete = looksLikeSkillBody(acc.text);
823
+ const incomplete = looksLikeIncompleteSkillDump(acc.text);
824
+ if (!complete && !incomplete) return parts;
825
+ const existing = lastSkillToolIndex(parts, acc.parentId);
826
+ if (existing >= 0 && existing !== textIdx) {
827
+ const prev = parts[existing];
828
+ const next2 = parts.filter((_, i) => i !== textIdx);
829
+ const existingIdx = lastSkillToolIndex(next2, acc.parentId);
830
+ if (existingIdx < 0) return parts;
831
+ next2[existingIdx] = withPartTimes(
832
+ {
833
+ ...prev,
834
+ status: complete ? "done" : prev.status,
835
+ result: clipToolResultForStore(acc.text) ?? prev.result
836
+ },
837
+ prev
838
+ );
839
+ return next2;
840
+ }
841
+ const next = [...parts];
842
+ next[textIdx] = skillToolFromTextPart(
843
+ acc,
844
+ `skill-${next.length}`,
845
+ complete ? "done" : "running"
846
+ );
847
+ return next;
848
+ }
849
+ function compactSummaryPart(text, id = "compact-summary") {
850
+ return compactToolPart(text, id, { status: "done" });
851
+ }
852
+ function compactToolPart(text, id, opts) {
853
+ const input = { trigger: opts?.trigger ?? "auto" };
854
+ return withPartTimes(
855
+ {
856
+ type: "tool",
857
+ id,
858
+ name: "Compact",
859
+ input,
860
+ description: toolDescription("Compact", input),
861
+ status: opts?.status ?? "done",
862
+ result: clipToolResultForStore(text) ?? "",
863
+ ...opts?.parentId ? { parentId: opts.parentId } : {}
864
+ },
865
+ opts?.prev
866
+ );
867
+ }
868
+ function contextCompactInProgress(parts, parentId) {
869
+ let compressing = false;
870
+ for (const p of parts) {
871
+ if (!sameParentId(p.parentId, parentId)) continue;
872
+ if (p.type === "thinking" && isContextCompactInProgress(p.text)) compressing = true;
873
+ if (p.type === "thinking" && isContextCompactDone(p.text)) compressing = false;
874
+ }
875
+ return compressing;
876
+ }
877
+ function lastRunningCompactIndex(parts, parentId) {
878
+ for (let i = parts.length - 1; i >= 0; i--) {
879
+ const p = parts[i];
880
+ if (p.type === "tool" && isCompactToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
881
+ return i;
882
+ }
883
+ }
884
+ return -1;
885
+ }
886
+ function markRunningCompactDone(parts, parentId) {
887
+ return parts.map((p) => {
888
+ if (p.type === "tool" && isCompactToolName(p.name) && p.status === "running" && sameParentId(p.parentId, parentId)) {
889
+ return withPartTimes({ ...p, status: "done" }, p);
890
+ }
891
+ return p;
892
+ });
893
+ }
894
+ function ensureCompactTool(parts, parentId) {
895
+ const hasCompact = parts.some(
896
+ (p) => p.type === "tool" && isCompactToolName(p.name) && sameParentId(p.parentId, parentId)
897
+ );
898
+ if (hasCompact) return parts;
899
+ return [
900
+ ...parts,
901
+ compactToolPart("Context compressed", `compact-${parts.length}`, {
902
+ parentId,
903
+ status: "done"
904
+ })
905
+ ];
906
+ }
907
+ function withCompactFinish(parts, thinking, parentId) {
908
+ if (!isContextCompactDone(thinking)) return parts;
909
+ return ensureCompactTool(markRunningCompactDone(parts, parentId), parentId);
910
+ }
911
+ function applyAgentEvent(parts, event) {
912
+ if (event.type === "stdout") {
913
+ const data = event.data;
914
+ if (!data) return parts;
915
+ const runningIdx = lastRunningCompactIndex(parts, event.parentId);
916
+ if (runningIdx >= 0) {
917
+ const prev = parts[runningIdx];
918
+ const next2 = [...parts];
919
+ next2[runningIdx] = withPartTimes(
920
+ {
921
+ ...prev,
922
+ result: clipToolResultForStore(`${prev.result ?? ""}${data}`)
923
+ },
924
+ prev
925
+ );
926
+ return next2;
927
+ }
928
+ const runningSkillIdx = lastRunningSkillIndex(parts, event.parentId);
929
+ if (runningSkillIdx >= 0) {
930
+ const prev = parts[runningSkillIdx];
931
+ const result = `${prev.result ?? ""}${data}`;
932
+ const next2 = [...parts];
933
+ next2[runningSkillIdx] = withPartTimes(
934
+ {
935
+ ...prev,
936
+ result: clipToolResultForStore(result),
937
+ // Stay running after the YAML `name:` fence so later content_block_delta
938
+ // tokens of SKILL.md stay on this row. thinking / tool_use / finalizeParts
939
+ // mark the row done so the real reply can be chat.
940
+ status: "running"
941
+ },
942
+ prev
943
+ );
944
+ return next2;
945
+ }
946
+ if (contextCompactInProgress(parts, event.parentId)) {
947
+ return [
948
+ ...parts,
949
+ compactToolPart(data, `compact-${parts.length}`, {
950
+ parentId: event.parentId,
951
+ status: "running"
952
+ })
953
+ ];
954
+ }
955
+ const next = [...parts];
956
+ const last = next[next.length - 1];
957
+ if (last?.type === "text" && sameParentId(last.parentId, event.parentId)) {
958
+ next[next.length - 1] = withPartTimes(
959
+ {
960
+ type: "text",
961
+ text: last.text + data,
962
+ ...event.parentId ? { parentId: event.parentId } : {}
963
+ },
964
+ last
965
+ );
966
+ } else {
967
+ next.push(
968
+ withPartTimes({
969
+ type: "text",
970
+ text: data,
971
+ ...event.parentId ? { parentId: event.parentId } : {}
972
+ })
973
+ );
974
+ }
975
+ const acc = next[next.length - 1];
976
+ if (acc?.type === "text" && (looksLikeSkillBody(acc.text) || looksLikeIncompleteSkillDump(acc.text))) {
977
+ return promoteOrFoldSkillText(next, next.length - 1);
978
+ }
979
+ if (acc?.type === "text" && looksLikeConversationSummary(acc.text)) {
980
+ next[next.length - 1] = compactToolPart(acc.text, `compact-${next.length}`, {
981
+ parentId: acc.parentId,
982
+ status: "done",
983
+ prev: acc
984
+ });
985
+ }
986
+ return next;
987
+ }
988
+ if (event.type === "thinking") {
989
+ const data = event.data;
990
+ if (!data) return parts;
991
+ if (!isSystemStatusThinking(event)) {
992
+ parts = markRunningSkillsDone(parts, event.parentId);
993
+ }
994
+ const next = [...parts];
995
+ if (event.replace) {
996
+ for (let i = next.length - 1; i >= 0; i--) {
997
+ const prev = next[i];
998
+ if (prev?.type === "thinking" && sameParentId(prev.parentId, event.parentId)) {
999
+ next[i] = withPartTimes(
1000
+ {
1001
+ type: "thinking",
1002
+ text: clipThinkingForStore(data),
1003
+ ...event.parentId ? { parentId: event.parentId } : {}
1004
+ },
1005
+ prev
1006
+ );
1007
+ return withCompactFinish(next, data, event.parentId);
1008
+ }
1009
+ }
1010
+ next.push(
1011
+ withPartTimes({
1012
+ type: "thinking",
1013
+ text: clipThinkingForStore(data),
1014
+ ...event.parentId ? { parentId: event.parentId } : {}
1015
+ })
1016
+ );
1017
+ return withCompactFinish(next, data, event.parentId);
1018
+ }
1019
+ const last = next[next.length - 1];
1020
+ if (last?.type === "thinking" && sameParentId(last.parentId, event.parentId)) {
1021
+ next[next.length - 1] = withPartTimes(
1022
+ {
1023
+ type: "thinking",
1024
+ text: clipThinkingForStore(last.text + data),
1025
+ ...event.parentId ? { parentId: event.parentId } : {}
1026
+ },
1027
+ last
1028
+ );
1029
+ } else {
1030
+ next.push(
1031
+ withPartTimes({
1032
+ type: "thinking",
1033
+ text: clipThinkingForStore(data),
1034
+ ...event.parentId ? { parentId: event.parentId } : {}
1035
+ })
1036
+ );
1037
+ }
1038
+ return withCompactFinish(next, data, event.parentId);
1039
+ }
1040
+ if (event.type === "tool_use") {
1041
+ parts = markRunningSkillsDone(parts, event.parentId);
1042
+ const input = asRecord(event.input);
1043
+ const diff = diffFromInput(input);
1044
+ const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
1045
+ if (existing >= 0) {
1046
+ const prev = parts[existing];
1047
+ const next = [...parts];
1048
+ const mergedInput = {
1049
+ ...prev.input ?? {},
1050
+ ...input ?? {}
1051
+ };
1052
+ const mergedRecord = Object.keys(mergedInput).length > 0 ? mergedInput : void 0;
1053
+ next[existing] = withPartTimes(
1054
+ {
1055
+ ...prev,
1056
+ name: event.name || prev.name,
1057
+ input: mergedRecord,
1058
+ description: toolDescription(event.name || prev.name, mergedRecord),
1059
+ detail: toolDetail(event.name || prev.name, mergedRecord) ?? prev.detail,
1060
+ filePath: toolFilePath(mergedRecord) ?? prev.filePath,
1061
+ additions: diff.additions ?? prev.additions,
1062
+ deletions: diff.deletions ?? prev.deletions,
1063
+ parentId: event.parentId ?? prev.parentId
1064
+ },
1065
+ prev
1066
+ );
1067
+ return next;
1068
+ }
1069
+ return [
1070
+ ...parts,
1071
+ withPartTimes({
1072
+ type: "tool",
1073
+ id: event.id,
1074
+ name: event.name,
1075
+ input,
1076
+ description: toolDescription(event.name, input),
1077
+ detail: toolDetail(event.name, input),
1078
+ status: "running",
1079
+ filePath: toolFilePath(input),
1080
+ ...event.parentId ? { parentId: event.parentId } : {},
1081
+ ...diff
1082
+ })
1083
+ ];
1084
+ }
1085
+ if (event.type === "tool_result") {
1086
+ const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
1087
+ const fromResult = parseDiffStat(event.content);
1088
+ if (event.partial) {
1089
+ if (existing < 0) {
1090
+ return [
1091
+ ...parts,
1092
+ withPartTimes({
1093
+ type: "tool",
1094
+ id: event.id,
1095
+ name: "tool",
1096
+ description: "tool",
1097
+ status: event.isError ? "error" : "running",
1098
+ result: clipToolResultForStore(event.content),
1099
+ ...event.parentId ? { parentId: event.parentId } : {}
1100
+ })
1101
+ ];
1102
+ }
1103
+ return parts.map((p, i) => {
1104
+ if (i !== existing || p.type !== "tool") return p;
1105
+ if (p.status === "done" || p.status === "error") return p;
1106
+ return withPartTimes(
1107
+ {
1108
+ ...p,
1109
+ result: clipToolResultForStore(event.content) ?? p.result
1110
+ },
1111
+ p
1112
+ );
1113
+ });
1114
+ }
1115
+ if (existing < 0) {
1116
+ return [
1117
+ ...parts,
1118
+ withPartTimes({
1119
+ type: "tool",
1120
+ id: event.id,
1121
+ name: "tool",
1122
+ description: "tool",
1123
+ status: event.isError ? "error" : "done",
1124
+ result: clipToolResultForStore(event.content),
1125
+ ...event.parentId ? { parentId: event.parentId } : {},
1126
+ ...fromResult.additions != null ? { additions: fromResult.additions } : {},
1127
+ ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
1128
+ })
1129
+ ];
1130
+ }
1131
+ return parts.map((p, i) => {
1132
+ if (i !== existing || p.type !== "tool") return p;
1133
+ return withPartTimes(
1134
+ {
1135
+ ...p,
1136
+ status: event.isError ? "error" : "done",
1137
+ result: clipToolResultForStore(event.content),
1138
+ ...fromResult.additions != null ? { additions: fromResult.additions } : {},
1139
+ ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
1140
+ },
1141
+ p
1142
+ );
1143
+ });
1144
+ }
1145
+ return parts;
1146
+ }
1147
+ function partsToAssistantText(parts) {
1148
+ return parts.filter(
1149
+ (p) => p.type === "text" && !messagePartParentId(p)
1150
+ ).map((p) => p.text).join("").trim();
1151
+ }
1152
+ function lastAssistantMessageText(parts) {
1153
+ if (!parts?.length) return "";
1154
+ for (let i = parts.length - 1; i >= 0; i--) {
1155
+ const p = parts[i];
1156
+ if (!p || p.type !== "text" || messagePartParentId(p)) continue;
1157
+ const text = p.text.trim();
1158
+ if (!text || isInternalAgentStatusText(text)) continue;
1159
+ return text;
1160
+ }
1161
+ return "";
1162
+ }
1163
+ function stripBrightsyNdjsonNoise(text) {
1164
+ if (!text || !text.includes('"type"')) return text;
1165
+ let out = text;
1166
+ out = out.replace(
1167
+ /\{"type":"(?:tool_use|tool_result|tool|thinking|usage|done|error)"[\s\S]*?\}\s*(?=\{"type":"|$|(?=[A-Za-z*#]))/g,
1168
+ ""
1169
+ );
1170
+ out = out.replace(/\{"type":"(?:tool_use|tool_result|tool)"[\s\S]*$/g, "");
1171
+ return out.trim();
1172
+ }
1173
+ function isBrightsyNdjsonLine(line) {
1174
+ const t = line.trim();
1175
+ if (!t.startsWith("{")) return false;
1176
+ return /"type"\s*:\s*"(tool_use|tool_result|tool|thinking|usage|done|error|text)"/.test(t);
1177
+ }
1178
+ function finalizeParts(parts) {
1179
+ return parts.map(
1180
+ (p) => p.type === "tool" && p.status === "running" ? { ...p, status: "done" } : p
1181
+ );
1182
+ }
1183
+ function normalizeParseResult(parsed) {
1184
+ if (!parsed) return [];
1185
+ return Array.isArray(parsed) ? parsed : [parsed];
1186
+ }
1187
+
1188
+ export {
1189
+ formatUnknownDetail,
1190
+ extractJsonErrorMessage,
1191
+ pushTurnStderr,
1192
+ looksLikeHugeToolResultDump,
1193
+ clipToolResultForStore,
1194
+ looksLikeV8Oom,
1195
+ summarizeTurnStderr,
1196
+ looksLikeInvalidAgentSession,
1197
+ looksLikeBrightsyEmptyCompletion,
1198
+ shouldRetryFailedAgentTurn,
1199
+ looksLikeAgentFailureMessage,
1200
+ fallbackTurnFailDetail,
1201
+ turnFailChatText,
1202
+ shouldRetryCodexPluginIsolate,
1203
+ shouldFeedErrorBackToAgent,
1204
+ formatAgentErrorContinuePrompt,
1205
+ formatTurnExitError,
1206
+ skillCommandFromBody,
1207
+ looksLikeSkillBody,
1208
+ looksLikeConversationSummary,
1209
+ toolDescription,
1210
+ isInternalAgentStatusText,
1211
+ isPollWrapperToolName,
1212
+ liveActivitySummary,
1213
+ messagePartParentId,
1214
+ withEventParentId,
1215
+ clipAgentEventForPaint,
1216
+ compactSummaryPart,
1217
+ applyAgentEvent,
1218
+ partsToAssistantText,
1219
+ lastAssistantMessageText,
1220
+ stripBrightsyNdjsonNoise,
1221
+ isBrightsyNdjsonLine,
1222
+ finalizeParts,
1223
+ normalizeParseResult
1224
+ };