sparkecoder 0.1.121 → 0.1.122

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 (102) hide show
  1. package/dist/agent/index.js +182 -21
  2. package/dist/agent/index.js.map +1 -1
  3. package/dist/cli.js +483 -157
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +444 -118
  6. package/dist/index.js.map +1 -1
  7. package/dist/server/index.js +444 -118
  8. package/dist/server/index.js.map +1 -1
  9. package/package.json +1 -1
  10. package/web/.next/BUILD_ID +1 -1
  11. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  12. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  13. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  14. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  15. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  16. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  17. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  18. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  19. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  30. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  39. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  57. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  66. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  74. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  82. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  91. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  92. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  93. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  94. /package/web/.next/standalone/web/.next/static/{static/wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
  95. /package/web/.next/standalone/web/.next/static/{static/wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
  96. /package/web/.next/standalone/web/.next/static/{static/wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
  97. /package/web/.next/standalone/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → static/BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
  98. /package/web/.next/standalone/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → static/BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
  99. /package/web/.next/standalone/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → static/BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
  100. /package/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
  101. /package/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
  102. /package/web/.next/static/{wP9z41wtqT4k-O6AlEXqw → BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
@@ -1894,7 +1894,7 @@ __export(recorder_exports, {
1894
1894
  import { exec as exec5 } from "child_process";
1895
1895
  import { promisify as promisify5 } from "util";
1896
1896
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
1897
- import { join as join10 } from "path";
1897
+ import { join as join11 } from "path";
1898
1898
  import { tmpdir } from "os";
1899
1899
  import { nanoid as nanoid7 } from "nanoid";
1900
1900
  async function checkFfmpeg() {
@@ -1951,21 +1951,21 @@ var init_recorder = __esm({
1951
1951
  */
1952
1952
  async encode() {
1953
1953
  if (this.frames.length === 0) return null;
1954
- const workDir = join10(tmpdir(), `sparkecoder-recording-${nanoid7(8)}`);
1954
+ const workDir = join11(tmpdir(), `sparkecoder-recording-${nanoid7(8)}`);
1955
1955
  await mkdir4(workDir, { recursive: true });
1956
1956
  try {
1957
1957
  for (let i = 0; i < this.frames.length; i++) {
1958
- const framePath = join10(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
1958
+ const framePath = join11(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
1959
1959
  await writeFile5(framePath, this.frames[i].data);
1960
1960
  }
1961
1961
  const duration = (this.frames[this.frames.length - 1].timestamp - this.frames[0].timestamp) / 1e3;
1962
1962
  const fps = duration > 0 ? Math.round(this.frames.length / duration) : 10;
1963
1963
  const clampedFps = Math.max(1, Math.min(fps, 30));
1964
- const outputPath = join10(workDir, `recording_${this.sessionId}.mp4`);
1964
+ const outputPath = join11(workDir, `recording_${this.sessionId}.mp4`);
1965
1965
  const hasFfmpeg = await checkFfmpeg();
1966
1966
  if (hasFfmpeg) {
1967
1967
  await execAsync5(
1968
- `ffmpeg -y -framerate ${clampedFps} -i "${join10(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
1968
+ `ffmpeg -y -framerate ${clampedFps} -i "${join11(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
1969
1969
  { timeout: 12e4 }
1970
1970
  );
1971
1971
  } else {
@@ -1977,7 +1977,7 @@ var init_recorder = __esm({
1977
1977
  const files = await readdir5(workDir);
1978
1978
  for (const f of files) {
1979
1979
  if (f.startsWith("frame_")) {
1980
- await unlink2(join10(workDir, f)).catch(() => {
1980
+ await unlink2(join11(workDir, f)).catch(() => {
1981
1981
  });
1982
1982
  }
1983
1983
  }
@@ -2835,10 +2835,10 @@ async function resizeImageIfNeeded(buffer, mediaType) {
2835
2835
  const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
2836
2836
  const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
2837
2837
  const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
2838
- const cachePath = join3(cacheDir, key2 + ext);
2839
- if (existsSync3(cachePath)) {
2838
+ const cachePath2 = join3(cacheDir, key2 + ext);
2839
+ if (existsSync3(cachePath2)) {
2840
2840
  console.log(`[image-resize] Cache hit for ${width}x${height} image`);
2841
- return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
2841
+ return { buffer: readFileSync2(cachePath2), mediaType: outputMediaType };
2842
2842
  }
2843
2843
  let pipeline = sharp(buffer);
2844
2844
  if (needsResize) {
@@ -2863,7 +2863,7 @@ async function resizeImageIfNeeded(buffer, mediaType) {
2863
2863
  }
2864
2864
  finalMediaType = "image/jpeg";
2865
2865
  }
2866
- writeFileSync2(cachePath, result);
2866
+ writeFileSync2(cachePath2, result);
2867
2867
  const resultMeta = await sharp(result).metadata();
2868
2868
  console.log(
2869
2869
  `[image-resize] ${width}x${height} -> ${resultMeta.width}x${resultMeta.height} (${(buffer.length / 1024).toFixed(0)}KB -> ${(result.length / 1024).toFixed(0)}KB, ${finalMediaType})`
@@ -7104,6 +7104,35 @@ function stripOrphanedToolResults(msg, removedIds) {
7104
7104
  if (parts.length === 0) return null;
7105
7105
  return { ...msg, content: parts };
7106
7106
  }
7107
+ function wrapToolsNeverThrow(tools) {
7108
+ if (!tools || typeof tools !== "object") return tools;
7109
+ const wrapped = {};
7110
+ for (const [name, t] of Object.entries(tools)) {
7111
+ if (!t || typeof t.execute !== "function") {
7112
+ wrapped[name] = t;
7113
+ continue;
7114
+ }
7115
+ const original = t.execute;
7116
+ wrapped[name] = {
7117
+ ...t,
7118
+ execute: async (input, opts) => {
7119
+ try {
7120
+ return await original.call(t, input, opts);
7121
+ } catch (err) {
7122
+ const message = err?.message ?? String(err);
7123
+ console.warn(`[tool:${name}] threw \u2014 converted to error result so the tool-call isn't orphaned:`, message);
7124
+ return {
7125
+ __error: true,
7126
+ tool: name,
7127
+ message,
7128
+ note: "Tool execution threw an exception. The agent should treat this as a failed tool call and decide how to recover."
7129
+ };
7130
+ }
7131
+ }
7132
+ };
7133
+ }
7134
+ return wrapped;
7135
+ }
7107
7136
  function repairToolPairing(messages) {
7108
7137
  const toolCallIds = /* @__PURE__ */ new Set();
7109
7138
  const toolResultIds = /* @__PURE__ */ new Set();
@@ -7181,6 +7210,100 @@ var webChannel = {
7181
7210
 
7182
7211
  // src/integrations/slack/client.ts
7183
7212
  init_config();
7213
+
7214
+ // src/integrations/slack/persistence.ts
7215
+ init_config();
7216
+ import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync3, renameSync } from "fs";
7217
+ import { join as join9, dirname as dirname6 } from "path";
7218
+ var FILENAME = "slack-cache.json";
7219
+ var FILE_VERSION = 1;
7220
+ var SAVE_DEBOUNCE_MS = 500;
7221
+ var MAX_THREADS = 5e3;
7222
+ var loaded = false;
7223
+ var userMap = /* @__PURE__ */ new Map();
7224
+ var threadMap = /* @__PURE__ */ new Map();
7225
+ var dirty = false;
7226
+ var saveTimer = null;
7227
+ function cachePath() {
7228
+ return join9(ensureAppDataDirectory(), FILENAME);
7229
+ }
7230
+ function load() {
7231
+ if (loaded) return;
7232
+ loaded = true;
7233
+ const path = cachePath();
7234
+ if (!existsSync16(path)) return;
7235
+ try {
7236
+ const raw = readFileSync7(path, "utf-8");
7237
+ const parsed = JSON.parse(raw);
7238
+ if (parsed?.version !== FILE_VERSION) return;
7239
+ const now = Date.now();
7240
+ for (const [id, e] of Object.entries(parsed.users || {})) {
7241
+ if (e && typeof e.expiresAt === "number" && e.expiresAt > now) {
7242
+ userMap.set(id, { name: e.name ?? null, expiresAt: e.expiresAt });
7243
+ }
7244
+ }
7245
+ for (const [key2, e] of Object.entries(parsed.threads || {})) {
7246
+ if (e && typeof e.expiresAt === "number" && e.expiresAt > now) {
7247
+ threadMap.set(key2, { owned: !!e.owned, expiresAt: e.expiresAt });
7248
+ }
7249
+ }
7250
+ } catch (err) {
7251
+ console.warn(`[slack] could not load ${FILENAME}:`, err?.message || err);
7252
+ }
7253
+ }
7254
+ function evictIfOversized(map, max) {
7255
+ if (map.size <= max) return;
7256
+ const sorted = [...map.entries()].sort((a, b) => a[1].expiresAt - b[1].expiresAt);
7257
+ const toRemove = map.size - max;
7258
+ for (let i = 0; i < toRemove; i++) map.delete(sorted[i][0]);
7259
+ }
7260
+ function scheduleSave() {
7261
+ dirty = true;
7262
+ if (saveTimer) return;
7263
+ saveTimer = setTimeout(() => {
7264
+ saveTimer = null;
7265
+ if (dirty) saveSync();
7266
+ }, SAVE_DEBOUNCE_MS);
7267
+ saveTimer.unref?.();
7268
+ }
7269
+ function saveSync() {
7270
+ dirty = false;
7271
+ try {
7272
+ const path = cachePath();
7273
+ const dir = dirname6(path);
7274
+ if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
7275
+ const payload = {
7276
+ version: FILE_VERSION,
7277
+ users: Object.fromEntries(userMap),
7278
+ threads: Object.fromEntries(threadMap)
7279
+ };
7280
+ const tmp = `${path}.tmp`;
7281
+ writeFileSync3(tmp, JSON.stringify(payload), "utf-8");
7282
+ renameSync(tmp, path);
7283
+ } catch (err) {
7284
+ console.warn(`[slack] could not persist ${FILENAME}:`, err?.message || err);
7285
+ }
7286
+ }
7287
+ var exitHooked = false;
7288
+ function hookExit() {
7289
+ if (exitHooked) return;
7290
+ exitHooked = true;
7291
+ const flush2 = () => {
7292
+ if (dirty) saveSync();
7293
+ };
7294
+ process.once("beforeExit", flush2);
7295
+ process.once("SIGINT", flush2);
7296
+ process.once("SIGTERM", flush2);
7297
+ }
7298
+ function setCachedThreadOwnership(key2, entry2) {
7299
+ load();
7300
+ hookExit();
7301
+ threadMap.set(key2, entry2);
7302
+ evictIfOversized(threadMap, MAX_THREADS);
7303
+ scheduleSave();
7304
+ }
7305
+
7306
+ // src/integrations/slack/client.ts
7184
7307
  function readSlackConfig() {
7185
7308
  try {
7186
7309
  const cfg = getConfig();
@@ -7221,6 +7344,18 @@ function isSlackConfigured() {
7221
7344
  }
7222
7345
  var USER_TTL_MS = 60 * 60 * 1e3;
7223
7346
  var USER_FAIL_TTL_MS = 5 * 60 * 1e3;
7347
+ var THREAD_OWNED_TTL_MS = 60 * 60 * 1e3;
7348
+ var THREAD_NEG_TTL_MS = 5 * 60 * 1e3;
7349
+ function threadCacheKey(channel, threadTs) {
7350
+ return `${channel}\u241F${threadTs}`;
7351
+ }
7352
+ function noteBotPostedInThread(channel, threadTs) {
7353
+ if (!channel || !threadTs) return;
7354
+ setCachedThreadOwnership(threadCacheKey(channel, threadTs), {
7355
+ owned: true,
7356
+ expiresAt: Date.now() + THREAD_OWNED_TTL_MS
7357
+ });
7358
+ }
7224
7359
 
7225
7360
  // src/integrations/channels/slack.ts
7226
7361
  var ownedThreads = /* @__PURE__ */ new Set();
@@ -7245,6 +7380,7 @@ var slackChannel = {
7245
7380
  if (!result.ok) throw new Error(`slack post failed: ${result.error}`);
7246
7381
  if (r.slackChannel && r.threadTs) {
7247
7382
  markThreadOwned(r.slackChannel, r.threadTs);
7383
+ noteBotPostedInThread(r.slackChannel, r.threadTs);
7248
7384
  }
7249
7385
  },
7250
7386
  displayLabel(ref) {
@@ -7761,8 +7897,8 @@ import { createMCPClient } from "@ai-sdk/mcp";
7761
7897
  // src/integrations/mcp/store.ts
7762
7898
  init_config();
7763
7899
  import { nanoid as nanoid6 } from "nanoid";
7764
- import { existsSync as existsSync16, readFileSync as readFileSync7 } from "fs";
7765
- import { resolve as resolve10, join as join9 } from "path";
7900
+ import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
7901
+ import { resolve as resolve10, join as join10 } from "path";
7766
7902
  function readServers() {
7767
7903
  try {
7768
7904
  const cfg = getConfig();
@@ -7774,12 +7910,12 @@ function readServers() {
7774
7910
  function refreshMcpServersFromDisk() {
7775
7911
  const candidates = [
7776
7912
  resolve10(process.cwd(), "sparkecoder.config.json"),
7777
- join9(ensureAppDataDirectory(), "sparkecoder.config.json")
7913
+ join10(ensureAppDataDirectory(), "sparkecoder.config.json")
7778
7914
  ];
7779
7915
  for (const path of candidates) {
7780
- if (!existsSync16(path)) continue;
7916
+ if (!existsSync17(path)) continue;
7781
7917
  try {
7782
- const raw = JSON.parse(readFileSync7(path, "utf-8"));
7918
+ const raw = JSON.parse(readFileSync8(path, "utf-8"));
7783
7919
  const servers2 = Array.isArray(raw?.mcp?.servers) ? raw.mcp.servers : [];
7784
7920
  setMcpServers(servers2);
7785
7921
  return servers2;
@@ -8217,7 +8353,8 @@ ${personality.trim()}`;
8217
8353
  }
8218
8354
  const messages = await this.context.getMessages();
8219
8355
  const tools = options.onToolProgress ? await this.createToolsWithCallbacks({ onToolProgress: options.onToolProgress }) : this.baseTools;
8220
- const wrappedTools = this.wrapToolsWithApproval(options, tools);
8356
+ const approvalWrapped = this.wrapToolsWithApproval(options, tools);
8357
+ const wrappedTools = wrapToolsNeverThrow(approvalWrapped);
8221
8358
  const useAnthropic = isAnthropicModel(this.session.model);
8222
8359
  const stream = streamText2({
8223
8360
  model: resolveModel(this.session.model),
@@ -8231,6 +8368,17 @@ ${personality.trim()}`;
8231
8368
  providerOptions: useAnthropic ? {
8232
8369
  anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8233
8370
  } : void 0,
8371
+ // Run repairToolPairing before EVERY step's model call, not just the
8372
+ // first one. The AI SDK's multi-step loop can otherwise feed the model
8373
+ // a prompt containing an orphan tool-call (e.g. when a previous step's
8374
+ // tool result was lost, dropped during compaction, or the stream was
8375
+ // aborted mid-tool). Repairing in `prepareStep` guarantees no orphan
8376
+ // ever reaches the model and we never hit AI_MissingToolResultsError.
8377
+ prepareStep: async ({ messages: stepMessages }) => {
8378
+ const repaired = repairToolPairing(stepMessages);
8379
+ if (repaired === stepMessages) return {};
8380
+ return { messages: repaired };
8381
+ },
8234
8382
  onStepFinish: async (step) => {
8235
8383
  options.onStepFinish?.(step);
8236
8384
  },
@@ -8266,7 +8414,7 @@ ${personality.trim()}`;
8266
8414
  });
8267
8415
  const messages = await this.context.getMessages();
8268
8416
  const tools = options.onToolProgress ? await this.createToolsWithCallbacks({ onToolProgress: options.onToolProgress }) : this.baseTools;
8269
- const wrappedTools = this.wrapToolsWithApproval(options, tools);
8417
+ const wrappedTools = wrapToolsNeverThrow(this.wrapToolsWithApproval(options, tools));
8270
8418
  const useAnthropic = isAnthropicModel(this.session.model);
8271
8419
  const result = await generateText3({
8272
8420
  model: resolveModel(this.session.model),
@@ -8277,7 +8425,13 @@ ${personality.trim()}`;
8277
8425
  // Enable extended thinking/reasoning for models that support it
8278
8426
  providerOptions: useAnthropic ? {
8279
8427
  anthropic: getAnthropicProviderOptions(this.session.model)
8280
- } : void 0
8428
+ } : void 0,
8429
+ // Repair tool pairing before every step (see `stream()` for full rationale).
8430
+ prepareStep: async ({ messages: stepMessages }) => {
8431
+ const repaired = repairToolPairing(stepMessages);
8432
+ if (repaired === stepMessages) return {};
8433
+ return { messages: repaired };
8434
+ }
8281
8435
  });
8282
8436
  const responseMessages = result.response.messages;
8283
8437
  this.context.addResponseMessages(responseMessages);
@@ -8454,12 +8608,19 @@ ${p.text}` : p.text;
8454
8608
  model: resolveModel(this.session.model),
8455
8609
  system: systemPrompt,
8456
8610
  messages,
8457
- tools: taskTools,
8611
+ tools: wrapToolsNeverThrow(taskTools),
8458
8612
  stopWhen: stepCountIs2(500),
8459
8613
  abortSignal: combinedAbort,
8460
8614
  providerOptions: useAnthropic ? {
8461
8615
  anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8462
8616
  } : void 0,
8617
+ // See the matching note in `stream()` — repair tool pairing before
8618
+ // every step so we never feed the model an orphan tool-call.
8619
+ prepareStep: async ({ messages: stepMessages }) => {
8620
+ const repaired = repairToolPairing(stepMessages);
8621
+ if (repaired === stepMessages) return {};
8622
+ return { messages: repaired };
8623
+ },
8463
8624
  onStepFinish: async (step) => {
8464
8625
  options.onStepFinish?.(step);
8465
8626
  fireWebhook("task.step_finished", { iteration, text: step.text });
@@ -8693,11 +8854,11 @@ ${p.text}` : p.text;
8693
8854
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
8694
8855
  if (!isRemoteConfigured2()) return [];
8695
8856
  const { readFile: readFile12 } = await import("fs/promises");
8696
- const { join: join11, basename: basename5 } = await import("path");
8857
+ const { join: join12, basename: basename5 } = await import("path");
8697
8858
  const urls = [];
8698
8859
  for (const filePath of filePaths) {
8699
8860
  try {
8700
- const fullPath = filePath.startsWith("/") ? filePath : join11(this.session.workingDirectory, filePath);
8861
+ const fullPath = filePath.startsWith("/") ? filePath : join12(this.session.workingDirectory, filePath);
8701
8862
  const fileName = basename5(fullPath);
8702
8863
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
8703
8864
  const mimeMap = {