sparkecoder 0.1.120 → 0.1.121
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.map +1 -1
- package/dist/cli.js +379 -125
- package/dist/cli.js.map +1 -1
- package/dist/index.js +338 -84
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +338 -84
- 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 → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
package/dist/server/index.js
CHANGED
|
@@ -963,6 +963,7 @@ __export(config_exports, {
|
|
|
963
963
|
setApiKey: () => setApiKey,
|
|
964
964
|
setMcpServers: () => setMcpServers,
|
|
965
965
|
setPublicUrl: () => setPublicUrl,
|
|
966
|
+
setSkillsAdditionalDirectories: () => setSkillsAdditionalDirectories,
|
|
966
967
|
setSlackConfig: () => setSlackConfig,
|
|
967
968
|
setWebhookToken: () => setWebhookToken
|
|
968
969
|
});
|
|
@@ -1252,6 +1253,40 @@ function setWebhookToken(token) {
|
|
|
1252
1253
|
console.warn("[config] failed to persist webhook token:", err?.message || err);
|
|
1253
1254
|
}
|
|
1254
1255
|
}
|
|
1256
|
+
function setSkillsAdditionalDirectories(directories) {
|
|
1257
|
+
if (cachedConfig) {
|
|
1258
|
+
const cur = cachedConfig.skills || {};
|
|
1259
|
+
cachedConfig.skills = { ...cur, additionalDirectories: directories };
|
|
1260
|
+
try {
|
|
1261
|
+
const discovered = discoverSkillDirectories(cachedConfig.resolvedWorkingDirectory);
|
|
1262
|
+
const additionalAbs = directories.map((d) => resolve(cachedConfig.resolvedWorkingDirectory, d)).filter((d) => existsSync(d));
|
|
1263
|
+
cachedConfig.discoveredSkills = discovered;
|
|
1264
|
+
cachedConfig.resolvedSkillsDirectories = [
|
|
1265
|
+
...discovered.allDirectories,
|
|
1266
|
+
...additionalAbs
|
|
1267
|
+
];
|
|
1268
|
+
} catch {
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
try {
|
|
1272
|
+
const cwdPath = resolve(process.cwd(), "sparkecoder.config.json");
|
|
1273
|
+
const target = existsSync(cwdPath) ? cwdPath : join(ensureAppDataDirectory(), "sparkecoder.config.json");
|
|
1274
|
+
let raw = {};
|
|
1275
|
+
if (existsSync(target)) {
|
|
1276
|
+
try {
|
|
1277
|
+
raw = JSON.parse(readFileSync(target, "utf-8"));
|
|
1278
|
+
} catch {
|
|
1279
|
+
raw = {};
|
|
1280
|
+
}
|
|
1281
|
+
} else {
|
|
1282
|
+
raw = createDefaultConfig();
|
|
1283
|
+
}
|
|
1284
|
+
raw.skills = { ...raw.skills || {}, additionalDirectories: directories };
|
|
1285
|
+
writeFileSync(target, JSON.stringify(raw, null, 2));
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
console.warn("[config] failed to persist skill directories:", err?.message || err);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1255
1290
|
function setPublicUrl(publicUrl) {
|
|
1256
1291
|
if (cachedConfig) {
|
|
1257
1292
|
cachedConfig.server = { ...cachedConfig.server ?? {}, publicUrl };
|
|
@@ -3013,7 +3048,7 @@ async function createClient(serverId, handle, root) {
|
|
|
3013
3048
|
},
|
|
3014
3049
|
async waitForDiagnostics(filePath, timeoutMs = 5e3) {
|
|
3015
3050
|
const normalized = normalizePath(filePath);
|
|
3016
|
-
return new Promise((
|
|
3051
|
+
return new Promise((resolve13) => {
|
|
3017
3052
|
const startTime = Date.now();
|
|
3018
3053
|
let debounceTimer;
|
|
3019
3054
|
let resolved = false;
|
|
@@ -3032,7 +3067,7 @@ async function createClient(serverId, handle, root) {
|
|
|
3032
3067
|
if (resolved) return;
|
|
3033
3068
|
resolved = true;
|
|
3034
3069
|
cleanup2();
|
|
3035
|
-
|
|
3070
|
+
resolve13(diagnostics.get(normalized) || []);
|
|
3036
3071
|
};
|
|
3037
3072
|
const onDiagnostic = () => {
|
|
3038
3073
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
@@ -3407,7 +3442,7 @@ Working directory: ${options.workingDirectory}`,
|
|
|
3407
3442
|
isChunked: true
|
|
3408
3443
|
});
|
|
3409
3444
|
if (chunkCount > 1) {
|
|
3410
|
-
await new Promise((
|
|
3445
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
3411
3446
|
}
|
|
3412
3447
|
}
|
|
3413
3448
|
}
|
|
@@ -4026,7 +4061,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4026
4061
|
if (!existsSync10(directory)) {
|
|
4027
4062
|
return [];
|
|
4028
4063
|
}
|
|
4029
|
-
const
|
|
4064
|
+
const skills2 = [];
|
|
4030
4065
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
4031
4066
|
for (const entry2 of entries) {
|
|
4032
4067
|
let filePath;
|
|
@@ -4050,7 +4085,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4050
4085
|
if (parsed) {
|
|
4051
4086
|
const alwaysApply = forceAlwaysApply || parsed.metadata.alwaysApply;
|
|
4052
4087
|
const loadType = alwaysApply ? "always" : defaultLoadType;
|
|
4053
|
-
|
|
4088
|
+
skills2.push({
|
|
4054
4089
|
name: parsed.metadata.name,
|
|
4055
4090
|
description: parsed.metadata.description,
|
|
4056
4091
|
filePath,
|
|
@@ -4064,7 +4099,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4064
4099
|
} else {
|
|
4065
4100
|
const name = getSkillNameFromPath(filePath);
|
|
4066
4101
|
const firstParagraph = content.split("\n\n")[0]?.slice(0, 200) || "No description";
|
|
4067
|
-
|
|
4102
|
+
skills2.push({
|
|
4068
4103
|
name,
|
|
4069
4104
|
description: firstParagraph.replace(/^#\s*/, "").trim(),
|
|
4070
4105
|
filePath,
|
|
@@ -4077,7 +4112,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4077
4112
|
});
|
|
4078
4113
|
}
|
|
4079
4114
|
}
|
|
4080
|
-
return
|
|
4115
|
+
return skills2.filter(
|
|
4081
4116
|
(s) => s.platforms.length === 0 || s.platforms.includes(process.platform)
|
|
4082
4117
|
);
|
|
4083
4118
|
}
|
|
@@ -4085,8 +4120,8 @@ async function loadAllSkills(directories) {
|
|
|
4085
4120
|
const allSkills = [];
|
|
4086
4121
|
const seenNames = /* @__PURE__ */ new Set();
|
|
4087
4122
|
for (const dir of directories) {
|
|
4088
|
-
const
|
|
4089
|
-
for (const skill of
|
|
4123
|
+
const skills2 = await loadSkillsFromDirectory(dir);
|
|
4124
|
+
for (const skill of skills2) {
|
|
4090
4125
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4091
4126
|
seenNames.add(skill.name.toLowerCase());
|
|
4092
4127
|
allSkills.push(skill);
|
|
@@ -4099,12 +4134,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4099
4134
|
const allSkills = [];
|
|
4100
4135
|
const seenNames = /* @__PURE__ */ new Set();
|
|
4101
4136
|
for (const { path, priority } of discovered.alwaysLoadedDirs) {
|
|
4102
|
-
const
|
|
4137
|
+
const skills2 = await loadSkillsFromDirectory(path, {
|
|
4103
4138
|
priority,
|
|
4104
4139
|
defaultLoadType: "always",
|
|
4105
4140
|
forceAlwaysApply: true
|
|
4106
4141
|
});
|
|
4107
|
-
for (const skill of
|
|
4142
|
+
for (const skill of skills2) {
|
|
4108
4143
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4109
4144
|
seenNames.add(skill.name.toLowerCase());
|
|
4110
4145
|
allSkills.push(skill);
|
|
@@ -4112,12 +4147,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4112
4147
|
}
|
|
4113
4148
|
}
|
|
4114
4149
|
for (const { path, priority } of discovered.onDemandDirs) {
|
|
4115
|
-
const
|
|
4150
|
+
const skills2 = await loadSkillsFromDirectory(path, {
|
|
4116
4151
|
priority,
|
|
4117
4152
|
defaultLoadType: "on_demand",
|
|
4118
4153
|
forceAlwaysApply: false
|
|
4119
4154
|
});
|
|
4120
|
-
for (const skill of
|
|
4155
|
+
for (const skill of skills2) {
|
|
4121
4156
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4122
4157
|
seenNames.add(skill.name.toLowerCase());
|
|
4123
4158
|
allSkills.push(skill);
|
|
@@ -4142,7 +4177,7 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4142
4177
|
all: allSkills
|
|
4143
4178
|
};
|
|
4144
4179
|
}
|
|
4145
|
-
async function getGlobMatchedSkills(
|
|
4180
|
+
async function getGlobMatchedSkills(skills2, activeFiles, workingDirectory) {
|
|
4146
4181
|
if (activeFiles.length === 0) {
|
|
4147
4182
|
return [];
|
|
4148
4183
|
}
|
|
@@ -4152,7 +4187,7 @@ async function getGlobMatchedSkills(skills, activeFiles, workingDirectory) {
|
|
|
4152
4187
|
}
|
|
4153
4188
|
return f;
|
|
4154
4189
|
});
|
|
4155
|
-
const matchedSkills =
|
|
4190
|
+
const matchedSkills = skills2.filter((skill) => {
|
|
4156
4191
|
if (skill.alwaysApply || skill.loadType === "always") {
|
|
4157
4192
|
return false;
|
|
4158
4193
|
}
|
|
@@ -4198,8 +4233,8 @@ async function loadSkillContent(skillName, directories) {
|
|
|
4198
4233
|
content: parsed ? parsed.body : content
|
|
4199
4234
|
};
|
|
4200
4235
|
}
|
|
4201
|
-
function formatSkillsForContext(
|
|
4202
|
-
const onDemandSkills =
|
|
4236
|
+
function formatSkillsForContext(skills2) {
|
|
4237
|
+
const onDemandSkills = skills2.filter((s) => !s.alwaysApply && s.loadType !== "always");
|
|
4203
4238
|
if (onDemandSkills.length === 0) {
|
|
4204
4239
|
return "No on-demand skills available.";
|
|
4205
4240
|
}
|
|
@@ -4210,12 +4245,12 @@ function formatSkillsForContext(skills) {
|
|
|
4210
4245
|
}
|
|
4211
4246
|
return lines.join("\n");
|
|
4212
4247
|
}
|
|
4213
|
-
function formatAlwaysLoadedSkills(
|
|
4214
|
-
if (
|
|
4248
|
+
function formatAlwaysLoadedSkills(skills2) {
|
|
4249
|
+
if (skills2.length === 0) {
|
|
4215
4250
|
return "";
|
|
4216
4251
|
}
|
|
4217
4252
|
const sections = [];
|
|
4218
|
-
for (const skill of
|
|
4253
|
+
for (const skill of skills2) {
|
|
4219
4254
|
sections.push(`### ${skill.name}
|
|
4220
4255
|
|
|
4221
4256
|
${skill.content}`);
|
|
@@ -4224,12 +4259,12 @@ ${skill.content}`);
|
|
|
4224
4259
|
|
|
4225
4260
|
${sections.join("\n\n---\n\n")}`;
|
|
4226
4261
|
}
|
|
4227
|
-
function formatGlobMatchedSkills(
|
|
4228
|
-
if (
|
|
4262
|
+
function formatGlobMatchedSkills(skills2) {
|
|
4263
|
+
if (skills2.length === 0) {
|
|
4229
4264
|
return "";
|
|
4230
4265
|
}
|
|
4231
4266
|
const sections = [];
|
|
4232
|
-
for (const skill of
|
|
4267
|
+
for (const skill of skills2) {
|
|
4233
4268
|
sections.push(`### ${skill.name}
|
|
4234
4269
|
|
|
4235
4270
|
${skill.content}`);
|
|
@@ -4271,16 +4306,16 @@ Once loaded, a skill's content will be available in the conversation context.`,
|
|
|
4271
4306
|
try {
|
|
4272
4307
|
switch (action) {
|
|
4273
4308
|
case "list": {
|
|
4274
|
-
const
|
|
4309
|
+
const skills2 = await loadAllSkills(options.skillsDirectories);
|
|
4275
4310
|
return {
|
|
4276
4311
|
success: true,
|
|
4277
4312
|
action: "list",
|
|
4278
|
-
skillCount:
|
|
4279
|
-
skills:
|
|
4313
|
+
skillCount: skills2.length,
|
|
4314
|
+
skills: skills2.map((s) => ({
|
|
4280
4315
|
name: s.name,
|
|
4281
4316
|
description: s.description
|
|
4282
4317
|
})),
|
|
4283
|
-
formatted: formatSkillsForContext(
|
|
4318
|
+
formatted: formatSkillsForContext(skills2)
|
|
4284
4319
|
};
|
|
4285
4320
|
}
|
|
4286
4321
|
case "load": {
|
|
@@ -4718,8 +4753,8 @@ var init_subagent = __esm({
|
|
|
4718
4753
|
if (eventQueue.length > 0) {
|
|
4719
4754
|
yield eventQueue.shift();
|
|
4720
4755
|
} else if (!done) {
|
|
4721
|
-
const event = await new Promise((
|
|
4722
|
-
resolveNext =
|
|
4756
|
+
const event = await new Promise((resolve13) => {
|
|
4757
|
+
resolveNext = resolve13;
|
|
4723
4758
|
});
|
|
4724
4759
|
if (event) {
|
|
4725
4760
|
yield event;
|
|
@@ -6495,8 +6530,8 @@ async function buildSystemPrompt(options) {
|
|
|
6495
6530
|
}
|
|
6496
6531
|
} else {
|
|
6497
6532
|
const { loadAllSkills: loadAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
6498
|
-
const
|
|
6499
|
-
onDemandSkillsContext = formatSkillsForContext(
|
|
6533
|
+
const skills2 = await loadAllSkills2(skillsDirectories);
|
|
6534
|
+
onDemandSkillsContext = formatSkillsForContext(skills2);
|
|
6500
6535
|
}
|
|
6501
6536
|
const todos = await todoQueries.getBySession(sessionId);
|
|
6502
6537
|
const todosContext = formatTodosForContext(todos);
|
|
@@ -8964,11 +8999,11 @@ function waitForTaskQuestionAnswer(question) {
|
|
|
8964
8999
|
if (pendingQuestions.has(k)) {
|
|
8965
9000
|
return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
|
|
8966
9001
|
}
|
|
8967
|
-
return new Promise((
|
|
9002
|
+
return new Promise((resolve13, reject) => {
|
|
8968
9003
|
pendingQuestions.set(k, {
|
|
8969
9004
|
...question,
|
|
8970
9005
|
createdAt: /* @__PURE__ */ new Date(),
|
|
8971
|
-
resolve:
|
|
9006
|
+
resolve: resolve13,
|
|
8972
9007
|
reject
|
|
8973
9008
|
});
|
|
8974
9009
|
});
|
|
@@ -10117,14 +10152,14 @@ ${p.text}` : p.text;
|
|
|
10117
10152
|
const result = await recorder.encode();
|
|
10118
10153
|
recorder.clear();
|
|
10119
10154
|
if (!result) return [];
|
|
10120
|
-
const { readFile:
|
|
10155
|
+
const { readFile: readFile13, unlink: unlink4 } = await import("fs/promises");
|
|
10121
10156
|
const uploadInfo = await storageQueries2.getUploadUrl(
|
|
10122
10157
|
this.session.id,
|
|
10123
10158
|
`browser-recording-${Date.now()}.mp4`,
|
|
10124
10159
|
"video/mp4",
|
|
10125
10160
|
"browser-recording"
|
|
10126
10161
|
);
|
|
10127
|
-
const fileData = await
|
|
10162
|
+
const fileData = await readFile13(result.path);
|
|
10128
10163
|
await fetch(uploadInfo.uploadUrl, {
|
|
10129
10164
|
method: "PUT",
|
|
10130
10165
|
headers: { "Content-Type": "video/mp4" },
|
|
@@ -10132,7 +10167,7 @@ ${p.text}` : p.text;
|
|
|
10132
10167
|
});
|
|
10133
10168
|
await storageQueries2.updateFile(uploadInfo.fileId, { sizeBytes: result.sizeBytes });
|
|
10134
10169
|
const dlInfo = await storageQueries2.getDownloadUrl(uploadInfo.fileId);
|
|
10135
|
-
await
|
|
10170
|
+
await unlink4(result.path).catch(() => {
|
|
10136
10171
|
});
|
|
10137
10172
|
console.log(`[TASK] Browser recording uploaded (${result.sizeBytes} bytes)`);
|
|
10138
10173
|
return [dlInfo.downloadUrl];
|
|
@@ -10150,13 +10185,13 @@ ${p.text}` : p.text;
|
|
|
10150
10185
|
try {
|
|
10151
10186
|
const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
|
|
10152
10187
|
if (!isRemoteConfigured2()) return [];
|
|
10153
|
-
const { readFile:
|
|
10154
|
-
const { join:
|
|
10188
|
+
const { readFile: readFile13 } = await import("fs/promises");
|
|
10189
|
+
const { join: join17, basename: basename7 } = await import("path");
|
|
10155
10190
|
const urls = [];
|
|
10156
10191
|
for (const filePath of filePaths) {
|
|
10157
10192
|
try {
|
|
10158
|
-
const fullPath = filePath.startsWith("/") ? filePath :
|
|
10159
|
-
const fileName =
|
|
10193
|
+
const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
|
|
10194
|
+
const fileName = basename7(fullPath);
|
|
10160
10195
|
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
|
10161
10196
|
const mimeMap = {
|
|
10162
10197
|
pdf: "application/pdf",
|
|
@@ -10180,7 +10215,7 @@ ${p.text}` : p.text;
|
|
|
10180
10215
|
contentType,
|
|
10181
10216
|
"task-output"
|
|
10182
10217
|
);
|
|
10183
|
-
const fileData = await
|
|
10218
|
+
const fileData = await readFile13(fullPath);
|
|
10184
10219
|
await fetch(uploadInfo.uploadUrl, {
|
|
10185
10220
|
method: "PUT",
|
|
10186
10221
|
headers: { "Content-Type": contentType },
|
|
@@ -10229,8 +10264,8 @@ ${p.text}` : p.text;
|
|
|
10229
10264
|
this.pendingApprovals.set(toolCallId, await execution);
|
|
10230
10265
|
options.onApprovalRequired?.(await execution);
|
|
10231
10266
|
await sessionQueries.updateStatus(this.session.id, "waiting");
|
|
10232
|
-
const approved = await new Promise((
|
|
10233
|
-
approvalResolvers.set(toolCallId, { resolve:
|
|
10267
|
+
const approved = await new Promise((resolve13) => {
|
|
10268
|
+
approvalResolvers.set(toolCallId, { resolve: resolve13, sessionId: this.session.id });
|
|
10234
10269
|
});
|
|
10235
10270
|
const resolverData = approvalResolvers.get(toolCallId);
|
|
10236
10271
|
approvalResolvers.delete(toolCallId);
|
|
@@ -10336,8 +10371,8 @@ async function withSessionLock(sessionId, fn) {
|
|
|
10336
10371
|
state2.pending++;
|
|
10337
10372
|
const prev = state2.tail;
|
|
10338
10373
|
let release;
|
|
10339
|
-
const next = new Promise((
|
|
10340
|
-
release =
|
|
10374
|
+
const next = new Promise((resolve13) => {
|
|
10375
|
+
release = resolve13;
|
|
10341
10376
|
});
|
|
10342
10377
|
state2.tail = prev.then(() => next);
|
|
10343
10378
|
await prev;
|
|
@@ -10727,12 +10762,12 @@ var init_scheduler = __esm({
|
|
|
10727
10762
|
|
|
10728
10763
|
// src/server/index.ts
|
|
10729
10764
|
import "dotenv/config";
|
|
10730
|
-
import { Hono as
|
|
10765
|
+
import { Hono as Hono10 } from "hono";
|
|
10731
10766
|
import { serve } from "@hono/node-server";
|
|
10732
10767
|
import { cors } from "hono/cors";
|
|
10733
10768
|
import { logger } from "hono/logger";
|
|
10734
|
-
import { existsSync as
|
|
10735
|
-
import { resolve as
|
|
10769
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
10770
|
+
import { resolve as resolve12, dirname as dirname9, join as join16 } from "path";
|
|
10736
10771
|
import { spawn as spawn2 } from "child_process";
|
|
10737
10772
|
import { createServer as createNetServer } from "net";
|
|
10738
10773
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -11907,7 +11942,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
|
|
|
11907
11942
|
toolCallId,
|
|
11908
11943
|
argsTextDelta: chunk
|
|
11909
11944
|
}));
|
|
11910
|
-
await new Promise((
|
|
11945
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
11911
11946
|
}
|
|
11912
11947
|
}
|
|
11913
11948
|
function buildDevtoolsContextXml(sessionId) {
|
|
@@ -12162,7 +12197,7 @@ ${prompt}` });
|
|
|
12162
12197
|
chunkIndex,
|
|
12163
12198
|
chunkCount
|
|
12164
12199
|
}));
|
|
12165
|
-
await new Promise((
|
|
12200
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
12166
12201
|
}
|
|
12167
12202
|
const browserPort = progress.data?.browserStreamPort;
|
|
12168
12203
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -12709,7 +12744,7 @@ agents.post(
|
|
|
12709
12744
|
chunkIndex,
|
|
12710
12745
|
chunkCount
|
|
12711
12746
|
}));
|
|
12712
|
-
await new Promise((
|
|
12747
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
12713
12748
|
}
|
|
12714
12749
|
const browserPort = progress.data?.browserStreamPort;
|
|
12715
12750
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -14217,6 +14252,224 @@ mcpRouter.post("/:id/test", async (c) => {
|
|
|
14217
14252
|
return c.json(result);
|
|
14218
14253
|
});
|
|
14219
14254
|
|
|
14255
|
+
// src/server/routes/skills.ts
|
|
14256
|
+
init_config();
|
|
14257
|
+
init_skills();
|
|
14258
|
+
import { Hono as Hono9 } from "hono";
|
|
14259
|
+
import { zValidator as zValidator7 } from "@hono/zod-validator";
|
|
14260
|
+
import { z as z22 } from "zod";
|
|
14261
|
+
import { existsSync as existsSync20, statSync as statSync3 } from "fs";
|
|
14262
|
+
import { readFile as readFile12, writeFile as writeFile6, unlink as unlink3, mkdir as mkdir5 } from "fs/promises";
|
|
14263
|
+
import { resolve as resolve11, join as join15, basename as basename6, dirname as dirname8, extname as extname9 } from "path";
|
|
14264
|
+
var skills = new Hono9();
|
|
14265
|
+
function encodeId(filePath) {
|
|
14266
|
+
return Buffer.from(filePath, "utf-8").toString("base64url");
|
|
14267
|
+
}
|
|
14268
|
+
function decodeId(id) {
|
|
14269
|
+
try {
|
|
14270
|
+
const decoded = Buffer.from(id, "base64url").toString("utf-8");
|
|
14271
|
+
return decoded || null;
|
|
14272
|
+
} catch {
|
|
14273
|
+
return null;
|
|
14274
|
+
}
|
|
14275
|
+
}
|
|
14276
|
+
function listAllDirectories() {
|
|
14277
|
+
const cfg = getConfig();
|
|
14278
|
+
const discovered = discoverSkillDirectories(cfg.resolvedWorkingDirectory);
|
|
14279
|
+
const out = [];
|
|
14280
|
+
for (const { path, priority } of discovered.alwaysLoadedDirs) {
|
|
14281
|
+
out.push({
|
|
14282
|
+
path,
|
|
14283
|
+
source: pathToSource(path),
|
|
14284
|
+
label: pathToLabel(path),
|
|
14285
|
+
priority,
|
|
14286
|
+
alwaysApply: true
|
|
14287
|
+
});
|
|
14288
|
+
}
|
|
14289
|
+
for (const { path, priority } of discovered.onDemandDirs) {
|
|
14290
|
+
out.push({
|
|
14291
|
+
path,
|
|
14292
|
+
source: pathToSource(path),
|
|
14293
|
+
label: pathToLabel(path),
|
|
14294
|
+
priority,
|
|
14295
|
+
alwaysApply: false
|
|
14296
|
+
});
|
|
14297
|
+
}
|
|
14298
|
+
const additional = cfg.skills?.additionalDirectories || [];
|
|
14299
|
+
for (const dir of additional) {
|
|
14300
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, dir);
|
|
14301
|
+
if (out.some((d) => d.path === abs)) continue;
|
|
14302
|
+
out.push({
|
|
14303
|
+
path: abs,
|
|
14304
|
+
source: "additional",
|
|
14305
|
+
label: pathToLabel(abs),
|
|
14306
|
+
priority: 50,
|
|
14307
|
+
alwaysApply: false
|
|
14308
|
+
});
|
|
14309
|
+
}
|
|
14310
|
+
return out;
|
|
14311
|
+
}
|
|
14312
|
+
function pathToSource(path) {
|
|
14313
|
+
if (path.includes("/skills/default") || path.endsWith("/skills/default")) return "builtin";
|
|
14314
|
+
return "project";
|
|
14315
|
+
}
|
|
14316
|
+
function pathToLabel(path) {
|
|
14317
|
+
if (path.includes("/skills/default")) return "Built-in (default)";
|
|
14318
|
+
if (path.includes("/.sparkecoder/rules")) return ".sparkecoder/rules";
|
|
14319
|
+
if (path.includes("/.sparkecoder/skills")) return ".sparkecoder/skills";
|
|
14320
|
+
if (path.includes("/.cursor/rules")) return ".cursor/rules";
|
|
14321
|
+
if (path.includes("/.claude/skills")) return ".claude/skills";
|
|
14322
|
+
return basename6(dirname8(path)) + "/" + basename6(path);
|
|
14323
|
+
}
|
|
14324
|
+
skills.get("/", async (c) => {
|
|
14325
|
+
const dirs = listAllDirectories();
|
|
14326
|
+
const allSkills = [];
|
|
14327
|
+
for (const dir of dirs) {
|
|
14328
|
+
if (!existsSync20(dir.path)) continue;
|
|
14329
|
+
try {
|
|
14330
|
+
const list = await loadSkillsFromDirectory(dir.path, {
|
|
14331
|
+
priority: dir.priority,
|
|
14332
|
+
defaultLoadType: dir.alwaysApply ? "always" : "on_demand",
|
|
14333
|
+
forceAlwaysApply: dir.alwaysApply
|
|
14334
|
+
});
|
|
14335
|
+
for (const s of list) {
|
|
14336
|
+
let size = 0;
|
|
14337
|
+
try {
|
|
14338
|
+
size = statSync3(s.filePath).size;
|
|
14339
|
+
} catch {
|
|
14340
|
+
}
|
|
14341
|
+
allSkills.push({
|
|
14342
|
+
id: encodeId(s.filePath),
|
|
14343
|
+
name: s.name,
|
|
14344
|
+
description: s.description,
|
|
14345
|
+
filePath: s.filePath,
|
|
14346
|
+
fileName: basename6(s.filePath),
|
|
14347
|
+
sourceDir: dir.path,
|
|
14348
|
+
sourceLabel: dir.label,
|
|
14349
|
+
sourceType: dir.source,
|
|
14350
|
+
alwaysApply: s.alwaysApply,
|
|
14351
|
+
globs: s.globs,
|
|
14352
|
+
sizeBytes: size
|
|
14353
|
+
});
|
|
14354
|
+
}
|
|
14355
|
+
} catch (err) {
|
|
14356
|
+
console.warn("[skills] failed to read", dir.path, err?.message || err);
|
|
14357
|
+
}
|
|
14358
|
+
}
|
|
14359
|
+
return c.json({
|
|
14360
|
+
directories: dirs.map((d) => ({
|
|
14361
|
+
path: d.path,
|
|
14362
|
+
label: d.label,
|
|
14363
|
+
source: d.source,
|
|
14364
|
+
alwaysApply: d.alwaysApply,
|
|
14365
|
+
exists: existsSync20(d.path),
|
|
14366
|
+
writable: isWritable(d.path)
|
|
14367
|
+
})),
|
|
14368
|
+
skills: allSkills
|
|
14369
|
+
});
|
|
14370
|
+
});
|
|
14371
|
+
function isWritable(dir) {
|
|
14372
|
+
try {
|
|
14373
|
+
if (!existsSync20(dir)) return false;
|
|
14374
|
+
if (dir.includes("/skills/default")) return false;
|
|
14375
|
+
return true;
|
|
14376
|
+
} catch {
|
|
14377
|
+
return false;
|
|
14378
|
+
}
|
|
14379
|
+
}
|
|
14380
|
+
skills.get("/:id", async (c) => {
|
|
14381
|
+
const filePath = decodeId(c.req.param("id"));
|
|
14382
|
+
if (!filePath || !existsSync20(filePath)) {
|
|
14383
|
+
return c.json({ error: "skill not found" }, 404);
|
|
14384
|
+
}
|
|
14385
|
+
const content = await readFile12(filePath, "utf-8");
|
|
14386
|
+
return c.json({
|
|
14387
|
+
id: c.req.param("id"),
|
|
14388
|
+
filePath,
|
|
14389
|
+
fileName: basename6(filePath),
|
|
14390
|
+
content,
|
|
14391
|
+
writable: !filePath.includes("/skills/default")
|
|
14392
|
+
});
|
|
14393
|
+
});
|
|
14394
|
+
skills.post(
|
|
14395
|
+
"/",
|
|
14396
|
+
zValidator7("json", z22.object({
|
|
14397
|
+
directory: z22.string().min(1),
|
|
14398
|
+
fileName: z22.string().min(1),
|
|
14399
|
+
content: z22.string()
|
|
14400
|
+
})),
|
|
14401
|
+
async (c) => {
|
|
14402
|
+
const { directory, fileName, content } = c.req.valid("json");
|
|
14403
|
+
const cfg = getConfig();
|
|
14404
|
+
const targetDir = resolve11(cfg.resolvedWorkingDirectory, directory);
|
|
14405
|
+
if (targetDir.includes("/skills/default")) {
|
|
14406
|
+
return c.json({ error: "cannot write into built-in skills directory" }, 400);
|
|
14407
|
+
}
|
|
14408
|
+
const safeName = basename6(fileName).replace(/[^A-Za-z0-9._-]/g, "-");
|
|
14409
|
+
const ext = extname9(safeName).toLowerCase();
|
|
14410
|
+
const finalName = ext === ".md" || ext === ".mdc" ? safeName : `${safeName}.md`;
|
|
14411
|
+
const filePath = join15(targetDir, finalName);
|
|
14412
|
+
if (existsSync20(filePath)) {
|
|
14413
|
+
return c.json({ error: `file already exists: ${finalName}` }, 409);
|
|
14414
|
+
}
|
|
14415
|
+
try {
|
|
14416
|
+
await mkdir5(targetDir, { recursive: true });
|
|
14417
|
+
await writeFile6(filePath, content, "utf-8");
|
|
14418
|
+
} catch (err) {
|
|
14419
|
+
return c.json({ error: err?.message || "write failed" }, 500);
|
|
14420
|
+
}
|
|
14421
|
+
return c.json({ id: encodeId(filePath), filePath, fileName: finalName }, 201);
|
|
14422
|
+
}
|
|
14423
|
+
);
|
|
14424
|
+
skills.put(
|
|
14425
|
+
"/:id",
|
|
14426
|
+
zValidator7("json", z22.object({ content: z22.string() })),
|
|
14427
|
+
async (c) => {
|
|
14428
|
+
const filePath = decodeId(c.req.param("id"));
|
|
14429
|
+
if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
|
|
14430
|
+
if (filePath.includes("/skills/default")) {
|
|
14431
|
+
return c.json({ error: "built-in skills are read-only" }, 400);
|
|
14432
|
+
}
|
|
14433
|
+
await writeFile6(filePath, c.req.valid("json").content, "utf-8");
|
|
14434
|
+
return c.json({ ok: true });
|
|
14435
|
+
}
|
|
14436
|
+
);
|
|
14437
|
+
skills.delete("/:id", async (c) => {
|
|
14438
|
+
const filePath = decodeId(c.req.param("id"));
|
|
14439
|
+
if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
|
|
14440
|
+
if (filePath.includes("/skills/default")) {
|
|
14441
|
+
return c.json({ error: "built-in skills are read-only" }, 400);
|
|
14442
|
+
}
|
|
14443
|
+
await unlink3(filePath);
|
|
14444
|
+
return c.json({ ok: true });
|
|
14445
|
+
});
|
|
14446
|
+
skills.post(
|
|
14447
|
+
"/directories",
|
|
14448
|
+
zValidator7("json", z22.object({ path: z22.string().min(1) })),
|
|
14449
|
+
(c) => {
|
|
14450
|
+
const cfg = getConfig();
|
|
14451
|
+
const inputPath = c.req.valid("json").path.trim();
|
|
14452
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
|
|
14453
|
+
const current = cfg.skills?.additionalDirectories || [];
|
|
14454
|
+
if (current.some((d) => resolve11(cfg.resolvedWorkingDirectory, d) === abs)) {
|
|
14455
|
+
return c.json({ error: "directory already added" }, 409);
|
|
14456
|
+
}
|
|
14457
|
+
const next = [...current, abs];
|
|
14458
|
+
setSkillsAdditionalDirectories(next);
|
|
14459
|
+
return c.json({ ok: true, path: abs, exists: existsSync20(abs) }, 201);
|
|
14460
|
+
}
|
|
14461
|
+
);
|
|
14462
|
+
skills.delete("/directories", (c) => {
|
|
14463
|
+
const inputPath = c.req.query("path");
|
|
14464
|
+
if (!inputPath) return c.json({ error: "path query param required" }, 400);
|
|
14465
|
+
const cfg = getConfig();
|
|
14466
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
|
|
14467
|
+
const current = cfg.skills?.additionalDirectories || [];
|
|
14468
|
+
const next = current.filter((d) => resolve11(cfg.resolvedWorkingDirectory, d) !== abs);
|
|
14469
|
+
setSkillsAdditionalDirectories(next);
|
|
14470
|
+
return c.json({ ok: true });
|
|
14471
|
+
});
|
|
14472
|
+
|
|
14220
14473
|
// src/server/auth/cf-access.ts
|
|
14221
14474
|
init_config();
|
|
14222
14475
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
@@ -14377,13 +14630,13 @@ var DEFAULT_WEB_PORT = 6969;
|
|
|
14377
14630
|
var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
|
|
14378
14631
|
function getWebDirectory() {
|
|
14379
14632
|
try {
|
|
14380
|
-
const currentDir =
|
|
14381
|
-
const webDir =
|
|
14382
|
-
if (
|
|
14633
|
+
const currentDir = dirname9(fileURLToPath4(import.meta.url));
|
|
14634
|
+
const webDir = resolve12(currentDir, "..", "web");
|
|
14635
|
+
if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
|
|
14383
14636
|
return webDir;
|
|
14384
14637
|
}
|
|
14385
|
-
const altWebDir =
|
|
14386
|
-
if (
|
|
14638
|
+
const altWebDir = resolve12(currentDir, "..", "..", "web");
|
|
14639
|
+
if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
|
|
14387
14640
|
return altWebDir;
|
|
14388
14641
|
}
|
|
14389
14642
|
return null;
|
|
@@ -14406,18 +14659,18 @@ async function isSparkcoderWebRunning(port) {
|
|
|
14406
14659
|
}
|
|
14407
14660
|
}
|
|
14408
14661
|
function isPortInUse(port) {
|
|
14409
|
-
return new Promise((
|
|
14662
|
+
return new Promise((resolve13) => {
|
|
14410
14663
|
const server = createNetServer();
|
|
14411
14664
|
server.once("error", (err) => {
|
|
14412
14665
|
if (err.code === "EADDRINUSE") {
|
|
14413
|
-
|
|
14666
|
+
resolve13(true);
|
|
14414
14667
|
} else {
|
|
14415
|
-
|
|
14668
|
+
resolve13(false);
|
|
14416
14669
|
}
|
|
14417
14670
|
});
|
|
14418
14671
|
server.once("listening", () => {
|
|
14419
14672
|
server.close();
|
|
14420
|
-
|
|
14673
|
+
resolve13(false);
|
|
14421
14674
|
});
|
|
14422
14675
|
server.listen(port, "0.0.0.0");
|
|
14423
14676
|
});
|
|
@@ -14441,30 +14694,30 @@ async function findWebPort(preferredPort) {
|
|
|
14441
14694
|
return { port: preferredPort, alreadyRunning: false };
|
|
14442
14695
|
}
|
|
14443
14696
|
function hasProductionBuild(webDir) {
|
|
14444
|
-
const buildIdPath =
|
|
14445
|
-
return
|
|
14697
|
+
const buildIdPath = join16(webDir, ".next", "BUILD_ID");
|
|
14698
|
+
return existsSync21(buildIdPath);
|
|
14446
14699
|
}
|
|
14447
14700
|
function hasSourceFiles(webDir) {
|
|
14448
|
-
const appDir =
|
|
14449
|
-
const pagesDir =
|
|
14450
|
-
const rootAppDir =
|
|
14451
|
-
const rootPagesDir =
|
|
14452
|
-
return
|
|
14701
|
+
const appDir = join16(webDir, "src", "app");
|
|
14702
|
+
const pagesDir = join16(webDir, "src", "pages");
|
|
14703
|
+
const rootAppDir = join16(webDir, "app");
|
|
14704
|
+
const rootPagesDir = join16(webDir, "pages");
|
|
14705
|
+
return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
|
|
14453
14706
|
}
|
|
14454
14707
|
function getStandaloneServerPath(webDir) {
|
|
14455
14708
|
const possiblePaths2 = [
|
|
14456
|
-
|
|
14457
|
-
|
|
14709
|
+
join16(webDir, ".next", "standalone", "server.js"),
|
|
14710
|
+
join16(webDir, ".next", "standalone", "web", "server.js")
|
|
14458
14711
|
];
|
|
14459
14712
|
for (const serverPath of possiblePaths2) {
|
|
14460
|
-
if (
|
|
14713
|
+
if (existsSync21(serverPath)) {
|
|
14461
14714
|
return serverPath;
|
|
14462
14715
|
}
|
|
14463
14716
|
}
|
|
14464
14717
|
return null;
|
|
14465
14718
|
}
|
|
14466
14719
|
function runCommand(command, args, cwd, env) {
|
|
14467
|
-
return new Promise((
|
|
14720
|
+
return new Promise((resolve13) => {
|
|
14468
14721
|
const child = spawn2(command, args, {
|
|
14469
14722
|
cwd,
|
|
14470
14723
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -14479,10 +14732,10 @@ function runCommand(command, args, cwd, env) {
|
|
|
14479
14732
|
output += data.toString();
|
|
14480
14733
|
});
|
|
14481
14734
|
child.on("close", (code) => {
|
|
14482
|
-
|
|
14735
|
+
resolve13({ success: code === 0, output });
|
|
14483
14736
|
});
|
|
14484
14737
|
child.on("error", (err) => {
|
|
14485
|
-
|
|
14738
|
+
resolve13({ success: false, output: err.message });
|
|
14486
14739
|
});
|
|
14487
14740
|
});
|
|
14488
14741
|
}
|
|
@@ -14497,13 +14750,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14497
14750
|
if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
|
|
14498
14751
|
return { process: null, port: actualPort };
|
|
14499
14752
|
}
|
|
14500
|
-
const usePnpm =
|
|
14501
|
-
const useNpm = !usePnpm &&
|
|
14753
|
+
const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
|
|
14754
|
+
const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
|
|
14502
14755
|
const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
|
|
14503
14756
|
const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
|
|
14504
14757
|
const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
|
|
14505
14758
|
const runtimeConfig = { apiBaseUrl: apiUrl };
|
|
14506
|
-
const runtimeConfigPath =
|
|
14759
|
+
const runtimeConfigPath = join16(webDir, "runtime-config.json");
|
|
14507
14760
|
try {
|
|
14508
14761
|
writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
|
|
14509
14762
|
if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
|
|
@@ -14525,7 +14778,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14525
14778
|
if (standaloneServerPath) {
|
|
14526
14779
|
command = "node";
|
|
14527
14780
|
args = ["server.js"];
|
|
14528
|
-
cwd =
|
|
14781
|
+
cwd = dirname9(standaloneServerPath);
|
|
14529
14782
|
webEnv.PORT = String(actualPort);
|
|
14530
14783
|
webEnv.HOSTNAME = "0.0.0.0";
|
|
14531
14784
|
if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
|
|
@@ -14566,10 +14819,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14566
14819
|
let started = false;
|
|
14567
14820
|
let exited = false;
|
|
14568
14821
|
let exitCode = null;
|
|
14569
|
-
const startedPromise = new Promise((
|
|
14822
|
+
const startedPromise = new Promise((resolve13) => {
|
|
14570
14823
|
const timeout = setTimeout(() => {
|
|
14571
14824
|
if (!started && !exited) {
|
|
14572
|
-
|
|
14825
|
+
resolve13(false);
|
|
14573
14826
|
}
|
|
14574
14827
|
}, startupTimeout);
|
|
14575
14828
|
child.stdout?.on("data", (data) => {
|
|
@@ -14583,7 +14836,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14583
14836
|
if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
|
|
14584
14837
|
started = true;
|
|
14585
14838
|
clearTimeout(timeout);
|
|
14586
|
-
|
|
14839
|
+
resolve13(true);
|
|
14587
14840
|
}
|
|
14588
14841
|
});
|
|
14589
14842
|
child.stderr?.on("data", (data) => {
|
|
@@ -14595,14 +14848,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14595
14848
|
child.on("error", (err) => {
|
|
14596
14849
|
if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
|
|
14597
14850
|
clearTimeout(timeout);
|
|
14598
|
-
|
|
14851
|
+
resolve13(false);
|
|
14599
14852
|
});
|
|
14600
14853
|
child.on("exit", (code) => {
|
|
14601
14854
|
exited = true;
|
|
14602
14855
|
exitCode = code;
|
|
14603
14856
|
if (!started) {
|
|
14604
14857
|
clearTimeout(timeout);
|
|
14605
|
-
|
|
14858
|
+
resolve13(false);
|
|
14606
14859
|
}
|
|
14607
14860
|
webUIProcess = null;
|
|
14608
14861
|
});
|
|
@@ -14625,7 +14878,7 @@ function stopWebUI() {
|
|
|
14625
14878
|
}
|
|
14626
14879
|
}
|
|
14627
14880
|
async function createApp(options = {}) {
|
|
14628
|
-
const app = new
|
|
14881
|
+
const app = new Hono10();
|
|
14629
14882
|
app.use("*", cors({
|
|
14630
14883
|
origin: "*",
|
|
14631
14884
|
// Allow all origins
|
|
@@ -14653,6 +14906,7 @@ async function createApp(options = {}) {
|
|
|
14653
14906
|
app.route("/api/schedules", schedulesRouter);
|
|
14654
14907
|
app.route("/api/orchestrator", orchestratorRouter);
|
|
14655
14908
|
app.route("/api/mcp", mcpRouter);
|
|
14909
|
+
app.route("/api/skills", skills);
|
|
14656
14910
|
app.route("/api/webhooks", webhooksRouter);
|
|
14657
14911
|
const config = getConfig();
|
|
14658
14912
|
const webhookToken = config?.webhooks?.token;
|
|
@@ -14718,7 +14972,7 @@ async function startServer(options = {}) {
|
|
|
14718
14972
|
if (options.workingDirectory) {
|
|
14719
14973
|
config.resolvedWorkingDirectory = options.workingDirectory;
|
|
14720
14974
|
}
|
|
14721
|
-
if (!
|
|
14975
|
+
if (!existsSync21(config.resolvedWorkingDirectory)) {
|
|
14722
14976
|
mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
|
|
14723
14977
|
if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
|
|
14724
14978
|
}
|