sparkecoder 0.1.122 → 0.1.124

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 (136) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +67 -14
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +201 -66
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-DczYH89U.d.ts → index-Bcz0aCAR.d.ts} +104 -104
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +124 -24
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-DxrKyetI.d.ts → schema-BWbWmfDQ.d.ts} +3 -3
  12. package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
  13. package/dist/server/index.js +124 -24
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/skills/default/recording.md +2 -2
  16. package/dist/tools/index.d.ts +3 -3
  17. package/package.json +1 -1
  18. package/src/skills/default/recording.md +2 -2
  19. package/web/.next/BUILD_ID +1 -1
  20. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  21. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  22. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  23. package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
  24. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  25. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  26. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  27. package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  29. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  44. package/web/.next/standalone/web/.next/server/app/agents.rsc +3 -3
  45. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +2 -2
  46. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +3 -3
  49. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  80. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
  89. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  90. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  91. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  92. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
  97. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
  98. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +2 -2
  100. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  101. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  102. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  103. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_c87abaf4._.js → 2374f_12d55e68._.js} +1 -1
  105. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1f3f2d00._.js → 2374f_1c0639c2._.js} +1 -1
  106. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_a0d5caeb._.js → 2374f_28cd6777._.js} +1 -1
  107. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_570c34dc._.js → 2374f_5f47a9b7._.js} +1 -1
  108. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8122230._.js → 2374f_aa218457._.js} +1 -1
  109. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_9c560f3a._.js → 2374f_f678a96f._.js} +1 -1
  110. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_38945fd9._.js → 2374f_fac4000d._.js} +1 -1
  111. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__4de426bd._.js → [root-of-the-server]__e5911ea8._.js} +4 -4
  112. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_62ca4286._.js → web_2966b3a3._.js} +2 -2
  113. package/web/.next/standalone/web/.next/server/chunks/ssr/web_4fe3c244._.js +1 -1
  114. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  115. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  116. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  117. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  118. package/web/.next/standalone/web/.next/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
  119. package/web/.next/standalone/web/.next/static/chunks/780c93257fac7d43.js +1 -0
  120. package/web/.next/standalone/web/.next/static/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
  121. package/web/.next/standalone/web/.next/static/static/chunks/780c93257fac7d43.js +1 -0
  122. package/web/.next/standalone/web/src/components/chat-interface.tsx +112 -1
  123. package/web/.next/static/chunks/{91988e253d5fa420.js → 4d95c15f712c9e06.js} +5 -5
  124. package/web/.next/static/chunks/780c93257fac7d43.js +1 -0
  125. package/web/.next/standalone/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
  126. package/web/.next/standalone/web/.next/static/static/chunks/f0f19357f3fb7cf8.js +0 -1
  127. package/web/.next/static/chunks/f0f19357f3fb7cf8.js +0 -1
  128. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
  129. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
  130. /package/web/.next/standalone/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
  131. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
  132. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
  133. /package/web/.next/standalone/web/.next/static/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
  134. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_buildManifest.js +0 -0
  135. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_clientMiddlewareManifest.json +0 -0
  136. /package/web/.next/static/{BEIBC9-dP0_AWGmRy97hJ → cYXZ7UzGc5TttFIXRRcSC}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -8202,6 +8202,55 @@ function wrapToolsNeverThrow(tools) {
8202
8202
  }
8203
8203
  return wrapped;
8204
8204
  }
8205
+ function ensureToolResultsFollowCalls(messages) {
8206
+ if (!Array.isArray(messages) || messages.length < 3) return messages;
8207
+ let mutated = false;
8208
+ const result = messages.slice();
8209
+ let i = 0;
8210
+ while (i < result.length) {
8211
+ const msg = result[i];
8212
+ if (msg?.role !== "assistant" || !Array.isArray(msg.content)) {
8213
+ i++;
8214
+ continue;
8215
+ }
8216
+ const callIds = /* @__PURE__ */ new Set();
8217
+ for (const part of msg.content) {
8218
+ if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
8219
+ callIds.add(part.toolCallId);
8220
+ }
8221
+ }
8222
+ if (callIds.size === 0) {
8223
+ i++;
8224
+ continue;
8225
+ }
8226
+ let toolIdx = -1;
8227
+ for (let j = i + 1; j < result.length; j++) {
8228
+ const m = result[j];
8229
+ if (m?.role === "assistant" && Array.isArray(m.content) && m.content.some((p) => p?.type === "tool-call")) {
8230
+ break;
8231
+ }
8232
+ if (m?.role === "tool" && Array.isArray(m.content)) {
8233
+ const answersOne = m.content.some(
8234
+ (p) => p?.type === "tool-result" && typeof p.toolCallId === "string" && callIds.has(p.toolCallId)
8235
+ );
8236
+ if (answersOne) {
8237
+ toolIdx = j;
8238
+ break;
8239
+ }
8240
+ }
8241
+ }
8242
+ if (toolIdx > i + 1) {
8243
+ const [toolMsg] = result.splice(toolIdx, 1);
8244
+ result.splice(i + 1, 0, toolMsg);
8245
+ mutated = true;
8246
+ console.warn(
8247
+ `[tool-repair] Reordered tool-result message from index ${toolIdx} to ${i + 1} to immediately follow assistant tool-call(s) (${[...callIds].join(", ")}). ${toolIdx - i - 1} message(s) were wedged between them.`
8248
+ );
8249
+ }
8250
+ i++;
8251
+ }
8252
+ return mutated ? result : messages;
8253
+ }
8205
8254
  function repairToolPairing(messages) {
8206
8255
  const toolCallIds = /* @__PURE__ */ new Set();
8207
8256
  const toolResultIds = /* @__PURE__ */ new Set();
@@ -8321,6 +8370,7 @@ ${summaryContent}`
8321
8370
  ];
8322
8371
  }
8323
8372
  messages = repairToolPairing(messages);
8373
+ messages = ensureToolResultsFollowCalls(messages);
8324
8374
  messages = ensureEndsWithUserOrTool(messages);
8325
8375
  return messages;
8326
8376
  }
@@ -8515,7 +8565,7 @@ ${summaryContent}`
8515
8565
  }
8516
8566
  }
8517
8567
  async addResponseMessages(messages) {
8518
- const safe = repairToolPairing(messages);
8568
+ const safe = ensureToolResultsFollowCalls(repairToolPairing(messages));
8519
8569
  await messageQueries.addMany(this.sessionId, safe);
8520
8570
  try {
8521
8571
  const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
@@ -10626,7 +10676,7 @@ ${prompt}` });
10626
10676
  const config = getConfig();
10627
10677
  const userContent = this.buildUserMessageContent(options.prompt, options.attachments);
10628
10678
  if (!options.skipSaveUserMessage) {
10629
- this.context.addUserMessage(userContent);
10679
+ await this.context.addUserMessage(userContent);
10630
10680
  }
10631
10681
  await sessionQueries.updateStatus(this.session.id, "active");
10632
10682
  let systemPrompt = await buildSystemPrompt({
@@ -10674,9 +10724,10 @@ ${personality.trim()}`;
10674
10724
  // aborted mid-tool). Repairing in `prepareStep` guarantees no orphan
10675
10725
  // ever reaches the model and we never hit AI_MissingToolResultsError.
10676
10726
  prepareStep: async ({ messages: stepMessages }) => {
10677
- const repaired = repairToolPairing(stepMessages);
10678
- if (repaired === stepMessages) return {};
10679
- return { messages: repaired };
10727
+ const paired = repairToolPairing(stepMessages);
10728
+ const ordered = ensureToolResultsFollowCalls(paired);
10729
+ if (ordered === stepMessages) return {};
10730
+ return { messages: ordered };
10680
10731
  },
10681
10732
  onStepFinish: async (step) => {
10682
10733
  options.onStepFinish?.(step);
@@ -10689,7 +10740,7 @@ ${personality.trim()}`;
10689
10740
  const result = await stream;
10690
10741
  const response = await result.response;
10691
10742
  const responseMessages = response.messages;
10692
- this.context.addResponseMessages(responseMessages);
10743
+ await this.context.addResponseMessages(responseMessages);
10693
10744
  };
10694
10745
  return {
10695
10746
  sessionId: this.session.id,
@@ -10703,7 +10754,7 @@ ${personality.trim()}`;
10703
10754
  */
10704
10755
  async run(options) {
10705
10756
  const config = getConfig();
10706
- this.context.addUserMessage(options.prompt);
10757
+ await this.context.addUserMessage(options.prompt);
10707
10758
  const systemPrompt = await buildSystemPrompt({
10708
10759
  workingDirectory: this.session.workingDirectory,
10709
10760
  skillsDirectories: config.resolvedSkillsDirectories,
@@ -10727,13 +10778,14 @@ ${personality.trim()}`;
10727
10778
  } : void 0,
10728
10779
  // Repair tool pairing before every step (see `stream()` for full rationale).
10729
10780
  prepareStep: async ({ messages: stepMessages }) => {
10730
- const repaired = repairToolPairing(stepMessages);
10731
- if (repaired === stepMessages) return {};
10732
- return { messages: repaired };
10781
+ const paired = repairToolPairing(stepMessages);
10782
+ const ordered = ensureToolResultsFollowCalls(paired);
10783
+ if (ordered === stepMessages) return {};
10784
+ return { messages: ordered };
10733
10785
  }
10734
10786
  });
10735
10787
  const responseMessages = result.response.messages;
10736
- this.context.addResponseMessages(responseMessages);
10788
+ await this.context.addResponseMessages(responseMessages);
10737
10789
  return {
10738
10790
  text: result.text,
10739
10791
  steps: result.steps
@@ -10916,9 +10968,10 @@ ${p.text}` : p.text;
10916
10968
  // See the matching note in `stream()` — repair tool pairing before
10917
10969
  // every step so we never feed the model an orphan tool-call.
10918
10970
  prepareStep: async ({ messages: stepMessages }) => {
10919
- const repaired = repairToolPairing(stepMessages);
10920
- if (repaired === stepMessages) return {};
10921
- return { messages: repaired };
10971
+ const paired = repairToolPairing(stepMessages);
10972
+ const ordered = ensureToolResultsFollowCalls(paired);
10973
+ if (ordered === stepMessages) return {};
10974
+ return { messages: ordered };
10922
10975
  },
10923
10976
  onStepFinish: async (step) => {
10924
10977
  options.onStepFinish?.(step);
@@ -13014,31 +13067,44 @@ async function recoverFromMissingToolResults(sessionId, error) {
13014
13067
  } catch (err) {
13015
13068
  console.warn("[missing-tool-recovery] could not load messages:", err?.message || err);
13016
13069
  }
13017
- const toolNameByCallId = /* @__PURE__ */ new Map();
13070
+ const toolInfoByCallId = /* @__PURE__ */ new Map();
13071
+ const resultMessageIndexByCallId = /* @__PURE__ */ new Map();
13018
13072
  const existingResultIds = /* @__PURE__ */ new Set();
13019
- for (const msg of history) {
13073
+ for (let idx = 0; idx < history.length; idx++) {
13074
+ const msg = history[idx];
13020
13075
  if (!Array.isArray(msg.content)) continue;
13021
13076
  for (const part of msg.content) {
13022
13077
  if (part?.type === "tool-call" && typeof part.toolCallId === "string") {
13023
- if (typeof part.toolName === "string") toolNameByCallId.set(part.toolCallId, part.toolName);
13078
+ if (typeof part.toolName === "string") {
13079
+ toolInfoByCallId.set(part.toolCallId, { toolName: part.toolName, callMessageIndex: idx });
13080
+ }
13024
13081
  }
13025
13082
  if (part?.type === "tool-result" && typeof part.toolCallId === "string") {
13026
13083
  existingResultIds.add(part.toolCallId);
13084
+ resultMessageIndexByCallId.set(part.toolCallId, idx);
13027
13085
  }
13028
13086
  }
13029
13087
  }
13030
- const resolved = toolCallIds.map((id) => ({
13031
- toolCallId: id,
13032
- toolName: toolNameByCallId.get(id) ?? "unknown",
13033
- foundInAssistantMessage: toolNameByCallId.has(id)
13034
- }));
13088
+ const resolved = toolCallIds.map((id) => {
13089
+ const info = toolInfoByCallId.get(id);
13090
+ const resultIdx = resultMessageIndexByCallId.get(id);
13091
+ const wedgedRoles = info && typeof resultIdx === "number" && resultIdx > info.callMessageIndex + 1 ? history.slice(info.callMessageIndex + 1, resultIdx).map((m) => m.role) : void 0;
13092
+ return {
13093
+ toolCallId: id,
13094
+ toolName: info?.toolName ?? "unknown",
13095
+ foundInAssistantMessage: !!info,
13096
+ callMessageIndex: info?.callMessageIndex,
13097
+ resultMessageIndex: resultIdx,
13098
+ wedgedMessageRoles: wedgedRoles
13099
+ };
13100
+ });
13035
13101
  const stillOrphaned = toolCallIds.filter((id) => !existingResultIds.has(id));
13036
13102
  let syntheticToolMessageSaved = false;
13037
13103
  if (stillOrphaned.length > 0) {
13038
13104
  const syntheticParts = stillOrphaned.map((id) => ({
13039
13105
  type: "tool-result",
13040
13106
  toolCallId: id,
13041
- toolName: toolNameByCallId.get(id) ?? "unknown",
13107
+ toolName: toolInfoByCallId.get(id)?.toolName ?? "unknown",
13042
13108
  output: {
13043
13109
  type: "text",
13044
13110
  value: "[Auto-recovered: the original tool execution never produced a result (crash, timeout, or message stripped during context compaction). This synthetic placeholder lets the conversation continue.]"
@@ -13055,15 +13121,49 @@ async function recoverFromMissingToolResults(sessionId, error) {
13055
13121
  }
13056
13122
  }
13057
13123
  const lastFewMessageRoles = history.slice(-6).map((m) => m.role);
13124
+ const first = resolved.find((r) => r.callMessageIndex !== void 0);
13125
+ let contextSnapshot;
13126
+ if (first?.callMessageIndex !== void 0) {
13127
+ const start = Math.max(0, first.callMessageIndex - 1);
13128
+ const end = Math.min(
13129
+ history.length,
13130
+ Math.max(first.callMessageIndex, first.resultMessageIndex ?? first.callMessageIndex) + 2
13131
+ );
13132
+ contextSnapshot = history.slice(start, end).map((m, offset) => ({
13133
+ index: start + offset,
13134
+ role: m.role,
13135
+ summary: summarizeContent(m.content)
13136
+ }));
13137
+ }
13138
+ const anyWedged = resolved.some((r) => r.wedgedMessageRoles && r.wedgedMessageRoles.length > 0);
13058
13139
  return {
13059
13140
  kind: "missing_tool_results",
13060
13141
  toolCallIds,
13061
13142
  resolved,
13062
13143
  syntheticToolMessageSaved,
13063
13144
  lastFewMessageRoles,
13064
- hint: syntheticToolMessageSaved ? "Synthetic tool-result(s) saved. Re-send your message to continue." : "Could not auto-recover; please reset the session or revert to the previous checkpoint."
13145
+ contextSnapshot,
13146
+ hint: anyWedged ? "A non-tool message was wedged between the assistant tool-call and its tool-result (likely a Slack/system inbox event that arrived mid-turn). " + (syntheticToolMessageSaved ? "Synthetic tool-result was added as a fallback, but the proper fix (now in place) is the reordering pass that moves tool-results to immediately follow their tool-calls." : "The reordering pass should fix this on the next turn; if not, revert to the previous checkpoint.") : syntheticToolMessageSaved ? "Synthetic tool-result(s) saved. Re-send your message to continue." : "Could not auto-recover; please reset the session or revert to the previous checkpoint."
13065
13147
  };
13066
13148
  }
13149
+ function summarizeContent(content) {
13150
+ if (typeof content === "string") {
13151
+ return content.length > 160 ? content.slice(0, 160) + "\u2026" : content;
13152
+ }
13153
+ if (!Array.isArray(content)) return String(content);
13154
+ const parts = content.map((p) => {
13155
+ if (!p || typeof p !== "object") return String(p);
13156
+ if (p.type === "text") {
13157
+ const t = String(p.text ?? "");
13158
+ return `text(${t.length > 80 ? t.slice(0, 80) + "\u2026" : t})`;
13159
+ }
13160
+ if (p.type === "tool-call") return `tool-call(${p.toolName}:${p.toolCallId})`;
13161
+ if (p.type === "tool-result") return `tool-result(${p.toolName ?? "?"}:${p.toolCallId})`;
13162
+ if (p.type === "reasoning") return "reasoning";
13163
+ return p.type ?? "unknown";
13164
+ });
13165
+ return parts.join(", ");
13166
+ }
13067
13167
 
13068
13168
  // src/server/routes/agents.ts
13069
13169
  init_agent();
@@ -16924,7 +17024,7 @@ function generateOpenAPISpec() {
16924
17024
  init_config();
16925
17025
  init_semantic();
16926
17026
  init_db();
16927
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync8, readFileSync as readFileSync11, existsSync as existsSync23, statSync as statSync4 } from "fs";
17027
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync8, readFileSync as readFileSync11, existsSync as existsSync23, statSync as statSync4, unlinkSync as unlinkSync3 } from "fs";
16928
17028
  import { resolve as resolve13, join as join18 } from "path";
16929
17029
  function getCliVersion() {
16930
17030
  const here = dirname11(fileURLToPath5(import.meta.url));
@@ -18534,7 +18634,9 @@ program.command("request-permissions").description("Open System Settings to the
18534
18634
  console.log();
18535
18635
  });
18536
18636
  {
18537
- let stateFilePath = function() {
18637
+ let shellEscape2 = function(str) {
18638
+ return `'${str.replace(/'/g, "'\\''")}'`;
18639
+ }, stateFilePath = function() {
18538
18640
  return join18(ensureAppDataDirectory(), "recordings.json");
18539
18641
  }, readState = function() {
18540
18642
  const p = stateFilePath();
@@ -18556,21 +18658,81 @@ program.command("request-permissions").description("Open System Settings to the
18556
18658
  }, pruneDead = function(rows) {
18557
18659
  return rows.filter((r) => isAlive(r.pid));
18558
18660
  };
18559
- stateFilePath2 = stateFilePath, readState2 = readState, writeState2 = writeState, isAlive2 = isAlive, pruneDead2 = pruneDead;
18661
+ shellEscape3 = shellEscape2, stateFilePath2 = stateFilePath, readState2 = readState, writeState2 = writeState, isAlive2 = isAlive, pruneDead2 = pruneDead;
18662
+ async function stopRecorderPid(pid) {
18663
+ if (!isAlive(pid)) return;
18664
+ try {
18665
+ process.kill(pid, "SIGINT");
18666
+ } catch {
18667
+ return;
18668
+ }
18669
+ for (let i = 0; i < 40; i++) {
18670
+ if (!isAlive(pid)) break;
18671
+ await new Promise((r) => setTimeout(r, 200));
18672
+ }
18673
+ if (isAlive(pid)) {
18674
+ try {
18675
+ process.kill(pid, "SIGTERM");
18676
+ } catch {
18677
+ }
18678
+ }
18679
+ }
18680
+ async function convertCaptureToMp4(capturePath, mp4Path) {
18681
+ try {
18682
+ const { exec: exec8 } = await import("child_process");
18683
+ const { promisify: promisify8 } = await import("util");
18684
+ const execAsync8 = promisify8(exec8);
18685
+ await execAsync8(
18686
+ `ffmpeg -y -i ${shellEscape2(capturePath)} -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 -movflags +faststart ${shellEscape2(mp4Path)}`,
18687
+ { timeout: 12e4, maxBuffer: 10 * 1024 * 1024 }
18688
+ );
18689
+ return existsSync23(mp4Path) && statSync4(mp4Path).size > 0;
18690
+ } catch {
18691
+ return false;
18692
+ }
18693
+ }
18694
+ async function finalizeRecording(row) {
18695
+ await stopRecorderPid(row.pid);
18696
+ let finalPath = row.path;
18697
+ let warning;
18698
+ if (row.capturePath) {
18699
+ for (let i = 0; i < 20; i++) {
18700
+ if (existsSync23(row.capturePath) && statSync4(row.capturePath).size > 0) break;
18701
+ await new Promise((r) => setTimeout(r, 200));
18702
+ }
18703
+ if (existsSync23(row.capturePath)) {
18704
+ const converted = await convertCaptureToMp4(row.capturePath, row.path);
18705
+ if (converted) {
18706
+ try {
18707
+ unlinkSync3(row.capturePath);
18708
+ } catch {
18709
+ }
18710
+ } else {
18711
+ finalPath = row.capturePath;
18712
+ warning = "ffmpeg conversion to mp4 failed; kept .mov capture file";
18713
+ }
18714
+ }
18715
+ }
18716
+ const ok = existsSync23(finalPath);
18717
+ const sizeMb = ok ? Math.round(statSync4(finalPath).size / (1024 * 1024) * 10) / 10 : 0;
18718
+ return { path: finalPath, ok, sizeMb, warning };
18719
+ }
18560
18720
  const record = program.command("record").description("Start/stop screen recordings");
18561
18721
  record.command("start").description("Start a screen recording (returns id, path, pid as JSON)").option("--name <slug>", "Optional human-readable label for the recording").option("--dir <path>", "Output directory (default: ~/recordings)").action(async (opts) => {
18562
18722
  const { homedir: homedir2, platform: osPlatform } = await import("os");
18563
18723
  const outDir = opts.dir ? resolve13(opts.dir.replace(/^~/, homedir2())) : join18(homedir2(), "recordings");
18564
18724
  mkdirSync11(outDir, { recursive: true });
18565
18725
  const id = `rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
18566
- const ext = osPlatform() === "darwin" ? "mov" : "mp4";
18726
+ const ext = "mp4";
18567
18727
  const filename = `${id}${opts.name ? `-${String(opts.name).replace(/[^a-z0-9-]+/gi, "-").toLowerCase()}` : ""}.${ext}`;
18568
18728
  const path = join18(outDir, filename);
18569
18729
  let cmd;
18570
18730
  let args;
18731
+ let capturePath;
18571
18732
  if (osPlatform() === "darwin") {
18733
+ capturePath = path.replace(/\.mp4$/i, ".mov");
18572
18734
  cmd = existsSync23("/usr/sbin/screencapture") ? "/usr/sbin/screencapture" : "screencapture";
18573
- args = ["-v", "-C", "-k", path];
18735
+ args = ["-v", "-C", "-k", capturePath];
18574
18736
  } else if (osPlatform() === "linux") {
18575
18737
  const display = process.env.DISPLAY || ":0.0";
18576
18738
  const size = process.env.SPARKECODER_RECORD_SIZE || "1920x1080";
@@ -18615,6 +18777,7 @@ program.command("request-permissions").description("Open System Settings to the
18615
18777
  });
18616
18778
  await new Promise((r) => setTimeout(r, 600));
18617
18779
  if (spawnError || exited || !child.pid) {
18780
+ child.stderr?.destroy();
18618
18781
  const diagnosis = [
18619
18782
  spawnError && `spawn error: ${spawnError}`,
18620
18783
  exited && `recorder exited code=${exitCode} within 600ms`,
@@ -18633,11 +18796,13 @@ program.command("request-permissions").description("Open System Settings to the
18633
18796
  }));
18634
18797
  process.exit(1);
18635
18798
  }
18799
+ child.stderr?.destroy();
18636
18800
  child.unref();
18637
18801
  const row = {
18638
18802
  id,
18639
18803
  name: opts.name,
18640
18804
  path,
18805
+ capturePath,
18641
18806
  pid: child.pid,
18642
18807
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
18643
18808
  platform: osPlatform()
@@ -18655,31 +18820,15 @@ program.command("request-permissions").description("Open System Settings to the
18655
18820
  process.exit(1);
18656
18821
  }
18657
18822
  const startedAt = new Date(row.startedAt).getTime();
18658
- if (isAlive(row.pid)) {
18659
- try {
18660
- process.kill(row.pid, "SIGINT");
18661
- } catch {
18662
- }
18663
- for (let i = 0; i < 40; i++) {
18664
- if (!isAlive(row.pid)) break;
18665
- await new Promise((r) => setTimeout(r, 200));
18666
- }
18667
- if (isAlive(row.pid)) {
18668
- try {
18669
- process.kill(row.pid, "SIGTERM");
18670
- } catch {
18671
- }
18672
- }
18673
- }
18823
+ const { path: finalPath, ok, sizeMb, warning } = await finalizeRecording(row);
18674
18824
  writeState(rows.filter((r) => r.id !== id));
18675
- const fileExists = existsSync23(row.path);
18676
- const sizeMb = fileExists ? Math.round(statSync4(row.path).size / (1024 * 1024) * 10) / 10 : 0;
18677
18825
  console.log(JSON.stringify({
18678
18826
  id,
18679
- path: row.path,
18827
+ path: finalPath,
18680
18828
  durationSec: Math.round((Date.now() - startedAt) / 1e3),
18681
18829
  sizeMb,
18682
- ok: fileExists
18830
+ ok,
18831
+ ...warning ? { warning } : {}
18683
18832
  }));
18684
18833
  });
18685
18834
  record.command("list").description("List active recordings").action(() => {
@@ -18691,28 +18840,14 @@ program.command("request-permissions").description("Open System Settings to the
18691
18840
  const rows = readState();
18692
18841
  const stopped = [];
18693
18842
  for (const r of rows) {
18694
- if (isAlive(r.pid)) {
18695
- try {
18696
- process.kill(r.pid, "SIGINT");
18697
- } catch {
18698
- }
18699
- for (let i = 0; i < 30; i++) {
18700
- if (!isAlive(r.pid)) break;
18701
- await new Promise((res) => setTimeout(res, 200));
18702
- }
18703
- if (isAlive(r.pid)) {
18704
- try {
18705
- process.kill(r.pid, "SIGTERM");
18706
- } catch {
18707
- }
18708
- }
18709
- }
18710
- stopped.push({ id: r.id, path: r.path, ok: existsSync23(r.path) });
18843
+ const { path: finalPath, ok, warning } = await finalizeRecording(r);
18844
+ stopped.push({ id: r.id, path: finalPath, ok, ...warning ? { warning } : {} });
18711
18845
  }
18712
18846
  writeState([]);
18713
18847
  console.log(JSON.stringify({ stopped }));
18714
18848
  });
18715
18849
  }
18850
+ var shellEscape3;
18716
18851
  var stateFilePath2;
18717
18852
  var readState2;
18718
18853
  var writeState2;