sparkecoder 0.1.120 → 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.
- package/dist/agent/index.js +182 -21
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +800 -220
- package/dist/cli.js.map +1 -1
- package/dist/index.js +748 -168
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +748 -168
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_6ab1f7b7._.js +3 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__f3e6443f._.js → [root-of-the-server]__4de426bd._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_62ca4286._.js +3 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_settings_page_tsx_eb320e07._.js +3 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/74ae1f17d607b2fc.js +7 -0
- package/web/.next/standalone/web/.next/static/chunks/883ea0d08f88e366.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
- package/web/.next/standalone/web/.next/static/chunks/9b88f148788e4504.js +3 -0
- package/web/.next/standalone/web/.next/static/chunks/acb0fc66f5414af6.css +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/74ae1f17d607b2fc.js +7 -0
- package/web/.next/standalone/web/.next/static/static/chunks/883ea0d08f88e366.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
- package/web/.next/standalone/web/.next/static/static/chunks/9b88f148788e4504.js +3 -0
- package/web/.next/standalone/web/.next/static/static/chunks/acb0fc66f5414af6.css +1 -0
- package/web/.next/standalone/web/src/app/(main)/settings/page.tsx +464 -1
- package/web/.next/static/chunks/74ae1f17d607b2fc.js +7 -0
- package/web/.next/static/chunks/883ea0d08f88e366.js +1 -0
- package/web/.next/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
- package/web/.next/static/chunks/9b88f148788e4504.js +3 -0
- package/web/.next/static/chunks/acb0fc66f5414af6.css +1 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_7340c8b3._.js +0 -3
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_41927ef5._.js +0 -3
- package/web/.next/standalone/web/.next/static/chunks/2c3c1d478808e4e4.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/3b0501ec3249235f.js +0 -7
- package/web/.next/standalone/web/.next/static/chunks/9a3afb48c245fb2a.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/b3bc7244f3477729.css +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/2c3c1d478808e4e4.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/3b0501ec3249235f.js +0 -7
- package/web/.next/standalone/web/.next/static/static/chunks/9a3afb48c245fb2a.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/b3bc7244f3477729.css +0 -1
- package/web/.next/static/chunks/2c3c1d478808e4e4.js +0 -1
- package/web/.next/static/chunks/3b0501ec3249235f.js +0 -7
- package/web/.next/static/chunks/9a3afb48c245fb2a.js +0 -1
- package/web/.next/static/chunks/b3bc7244f3477729.css +0 -1
- /package/web/.next/standalone/web/.next/static/{static/uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → static/BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → static/BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → static/BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_buildManifest.js +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → BEIBC9-dP0_AWGmRy97hJ}/_ssgManifest.js +0 -0
package/dist/agent/index.js
CHANGED
|
@@ -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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 "${
|
|
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(
|
|
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
|
|
2839
|
-
if (existsSync3(
|
|
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(
|
|
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(
|
|
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
|
|
7765
|
-
import { resolve as resolve10, join as
|
|
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
|
-
|
|
7913
|
+
join10(ensureAppDataDirectory(), "sparkecoder.config.json")
|
|
7778
7914
|
];
|
|
7779
7915
|
for (const path of candidates) {
|
|
7780
|
-
if (!
|
|
7916
|
+
if (!existsSync17(path)) continue;
|
|
7781
7917
|
try {
|
|
7782
|
-
const raw = JSON.parse(
|
|
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
|
|
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:
|
|
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 :
|
|
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 = {
|