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/cli.js
CHANGED
|
@@ -964,6 +964,7 @@ __export(config_exports, {
|
|
|
964
964
|
setApiKey: () => setApiKey,
|
|
965
965
|
setMcpServers: () => setMcpServers,
|
|
966
966
|
setPublicUrl: () => setPublicUrl,
|
|
967
|
+
setSkillsAdditionalDirectories: () => setSkillsAdditionalDirectories,
|
|
967
968
|
setSlackConfig: () => setSlackConfig,
|
|
968
969
|
setWebhookToken: () => setWebhookToken
|
|
969
970
|
});
|
|
@@ -1253,6 +1254,40 @@ function setWebhookToken(token) {
|
|
|
1253
1254
|
console.warn("[config] failed to persist webhook token:", err?.message || err);
|
|
1254
1255
|
}
|
|
1255
1256
|
}
|
|
1257
|
+
function setSkillsAdditionalDirectories(directories) {
|
|
1258
|
+
if (cachedConfig) {
|
|
1259
|
+
const cur = cachedConfig.skills || {};
|
|
1260
|
+
cachedConfig.skills = { ...cur, additionalDirectories: directories };
|
|
1261
|
+
try {
|
|
1262
|
+
const discovered = discoverSkillDirectories(cachedConfig.resolvedWorkingDirectory);
|
|
1263
|
+
const additionalAbs = directories.map((d) => resolve(cachedConfig.resolvedWorkingDirectory, d)).filter((d) => existsSync(d));
|
|
1264
|
+
cachedConfig.discoveredSkills = discovered;
|
|
1265
|
+
cachedConfig.resolvedSkillsDirectories = [
|
|
1266
|
+
...discovered.allDirectories,
|
|
1267
|
+
...additionalAbs
|
|
1268
|
+
];
|
|
1269
|
+
} catch {
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
try {
|
|
1273
|
+
const cwdPath = resolve(process.cwd(), "sparkecoder.config.json");
|
|
1274
|
+
const target = existsSync(cwdPath) ? cwdPath : join(ensureAppDataDirectory(), "sparkecoder.config.json");
|
|
1275
|
+
let raw = {};
|
|
1276
|
+
if (existsSync(target)) {
|
|
1277
|
+
try {
|
|
1278
|
+
raw = JSON.parse(readFileSync(target, "utf-8"));
|
|
1279
|
+
} catch {
|
|
1280
|
+
raw = {};
|
|
1281
|
+
}
|
|
1282
|
+
} else {
|
|
1283
|
+
raw = createDefaultConfig();
|
|
1284
|
+
}
|
|
1285
|
+
raw.skills = { ...raw.skills || {}, additionalDirectories: directories };
|
|
1286
|
+
writeFileSync(target, JSON.stringify(raw, null, 2));
|
|
1287
|
+
} catch (err) {
|
|
1288
|
+
console.warn("[config] failed to persist skill directories:", err?.message || err);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1256
1291
|
function setPublicUrl(publicUrl) {
|
|
1257
1292
|
if (cachedConfig) {
|
|
1258
1293
|
cachedConfig.server = { ...cachedConfig.server ?? {}, publicUrl };
|
|
@@ -3014,7 +3049,7 @@ async function createClient(serverId, handle, root) {
|
|
|
3014
3049
|
},
|
|
3015
3050
|
async waitForDiagnostics(filePath, timeoutMs = 5e3) {
|
|
3016
3051
|
const normalized = normalizePath(filePath);
|
|
3017
|
-
return new Promise((
|
|
3052
|
+
return new Promise((resolve14) => {
|
|
3018
3053
|
const startTime = Date.now();
|
|
3019
3054
|
let debounceTimer;
|
|
3020
3055
|
let resolved = false;
|
|
@@ -3033,7 +3068,7 @@ async function createClient(serverId, handle, root) {
|
|
|
3033
3068
|
if (resolved) return;
|
|
3034
3069
|
resolved = true;
|
|
3035
3070
|
cleanup2();
|
|
3036
|
-
|
|
3071
|
+
resolve14(diagnostics.get(normalized) || []);
|
|
3037
3072
|
};
|
|
3038
3073
|
const onDiagnostic = () => {
|
|
3039
3074
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
@@ -3408,7 +3443,7 @@ Working directory: ${options.workingDirectory}`,
|
|
|
3408
3443
|
isChunked: true
|
|
3409
3444
|
});
|
|
3410
3445
|
if (chunkCount > 1) {
|
|
3411
|
-
await new Promise((
|
|
3446
|
+
await new Promise((resolve14) => setTimeout(resolve14, 0));
|
|
3412
3447
|
}
|
|
3413
3448
|
}
|
|
3414
3449
|
}
|
|
@@ -4027,7 +4062,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4027
4062
|
if (!existsSync10(directory)) {
|
|
4028
4063
|
return [];
|
|
4029
4064
|
}
|
|
4030
|
-
const
|
|
4065
|
+
const skills2 = [];
|
|
4031
4066
|
const entries = await readdir(directory, { withFileTypes: true });
|
|
4032
4067
|
for (const entry2 of entries) {
|
|
4033
4068
|
let filePath;
|
|
@@ -4051,7 +4086,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4051
4086
|
if (parsed) {
|
|
4052
4087
|
const alwaysApply = forceAlwaysApply || parsed.metadata.alwaysApply;
|
|
4053
4088
|
const loadType = alwaysApply ? "always" : defaultLoadType;
|
|
4054
|
-
|
|
4089
|
+
skills2.push({
|
|
4055
4090
|
name: parsed.metadata.name,
|
|
4056
4091
|
description: parsed.metadata.description,
|
|
4057
4092
|
filePath,
|
|
@@ -4065,7 +4100,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4065
4100
|
} else {
|
|
4066
4101
|
const name = getSkillNameFromPath(filePath);
|
|
4067
4102
|
const firstParagraph = content.split("\n\n")[0]?.slice(0, 200) || "No description";
|
|
4068
|
-
|
|
4103
|
+
skills2.push({
|
|
4069
4104
|
name,
|
|
4070
4105
|
description: firstParagraph.replace(/^#\s*/, "").trim(),
|
|
4071
4106
|
filePath,
|
|
@@ -4078,7 +4113,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
|
|
|
4078
4113
|
});
|
|
4079
4114
|
}
|
|
4080
4115
|
}
|
|
4081
|
-
return
|
|
4116
|
+
return skills2.filter(
|
|
4082
4117
|
(s) => s.platforms.length === 0 || s.platforms.includes(process.platform)
|
|
4083
4118
|
);
|
|
4084
4119
|
}
|
|
@@ -4086,8 +4121,8 @@ async function loadAllSkills(directories) {
|
|
|
4086
4121
|
const allSkills = [];
|
|
4087
4122
|
const seenNames = /* @__PURE__ */ new Set();
|
|
4088
4123
|
for (const dir of directories) {
|
|
4089
|
-
const
|
|
4090
|
-
for (const skill of
|
|
4124
|
+
const skills2 = await loadSkillsFromDirectory(dir);
|
|
4125
|
+
for (const skill of skills2) {
|
|
4091
4126
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4092
4127
|
seenNames.add(skill.name.toLowerCase());
|
|
4093
4128
|
allSkills.push(skill);
|
|
@@ -4100,12 +4135,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4100
4135
|
const allSkills = [];
|
|
4101
4136
|
const seenNames = /* @__PURE__ */ new Set();
|
|
4102
4137
|
for (const { path, priority } of discovered.alwaysLoadedDirs) {
|
|
4103
|
-
const
|
|
4138
|
+
const skills2 = await loadSkillsFromDirectory(path, {
|
|
4104
4139
|
priority,
|
|
4105
4140
|
defaultLoadType: "always",
|
|
4106
4141
|
forceAlwaysApply: true
|
|
4107
4142
|
});
|
|
4108
|
-
for (const skill of
|
|
4143
|
+
for (const skill of skills2) {
|
|
4109
4144
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4110
4145
|
seenNames.add(skill.name.toLowerCase());
|
|
4111
4146
|
allSkills.push(skill);
|
|
@@ -4113,12 +4148,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4113
4148
|
}
|
|
4114
4149
|
}
|
|
4115
4150
|
for (const { path, priority } of discovered.onDemandDirs) {
|
|
4116
|
-
const
|
|
4151
|
+
const skills2 = await loadSkillsFromDirectory(path, {
|
|
4117
4152
|
priority,
|
|
4118
4153
|
defaultLoadType: "on_demand",
|
|
4119
4154
|
forceAlwaysApply: false
|
|
4120
4155
|
});
|
|
4121
|
-
for (const skill of
|
|
4156
|
+
for (const skill of skills2) {
|
|
4122
4157
|
if (!seenNames.has(skill.name.toLowerCase())) {
|
|
4123
4158
|
seenNames.add(skill.name.toLowerCase());
|
|
4124
4159
|
allSkills.push(skill);
|
|
@@ -4143,7 +4178,7 @@ async function loadAllSkillsFromDiscovered(discovered) {
|
|
|
4143
4178
|
all: allSkills
|
|
4144
4179
|
};
|
|
4145
4180
|
}
|
|
4146
|
-
async function getGlobMatchedSkills(
|
|
4181
|
+
async function getGlobMatchedSkills(skills2, activeFiles, workingDirectory) {
|
|
4147
4182
|
if (activeFiles.length === 0) {
|
|
4148
4183
|
return [];
|
|
4149
4184
|
}
|
|
@@ -4153,7 +4188,7 @@ async function getGlobMatchedSkills(skills, activeFiles, workingDirectory) {
|
|
|
4153
4188
|
}
|
|
4154
4189
|
return f;
|
|
4155
4190
|
});
|
|
4156
|
-
const matchedSkills =
|
|
4191
|
+
const matchedSkills = skills2.filter((skill) => {
|
|
4157
4192
|
if (skill.alwaysApply || skill.loadType === "always") {
|
|
4158
4193
|
return false;
|
|
4159
4194
|
}
|
|
@@ -4199,8 +4234,8 @@ async function loadSkillContent(skillName, directories) {
|
|
|
4199
4234
|
content: parsed ? parsed.body : content
|
|
4200
4235
|
};
|
|
4201
4236
|
}
|
|
4202
|
-
function formatSkillsForContext(
|
|
4203
|
-
const onDemandSkills =
|
|
4237
|
+
function formatSkillsForContext(skills2) {
|
|
4238
|
+
const onDemandSkills = skills2.filter((s) => !s.alwaysApply && s.loadType !== "always");
|
|
4204
4239
|
if (onDemandSkills.length === 0) {
|
|
4205
4240
|
return "No on-demand skills available.";
|
|
4206
4241
|
}
|
|
@@ -4211,12 +4246,12 @@ function formatSkillsForContext(skills) {
|
|
|
4211
4246
|
}
|
|
4212
4247
|
return lines.join("\n");
|
|
4213
4248
|
}
|
|
4214
|
-
function formatAlwaysLoadedSkills(
|
|
4215
|
-
if (
|
|
4249
|
+
function formatAlwaysLoadedSkills(skills2) {
|
|
4250
|
+
if (skills2.length === 0) {
|
|
4216
4251
|
return "";
|
|
4217
4252
|
}
|
|
4218
4253
|
const sections = [];
|
|
4219
|
-
for (const skill of
|
|
4254
|
+
for (const skill of skills2) {
|
|
4220
4255
|
sections.push(`### ${skill.name}
|
|
4221
4256
|
|
|
4222
4257
|
${skill.content}`);
|
|
@@ -4225,12 +4260,12 @@ ${skill.content}`);
|
|
|
4225
4260
|
|
|
4226
4261
|
${sections.join("\n\n---\n\n")}`;
|
|
4227
4262
|
}
|
|
4228
|
-
function formatGlobMatchedSkills(
|
|
4229
|
-
if (
|
|
4263
|
+
function formatGlobMatchedSkills(skills2) {
|
|
4264
|
+
if (skills2.length === 0) {
|
|
4230
4265
|
return "";
|
|
4231
4266
|
}
|
|
4232
4267
|
const sections = [];
|
|
4233
|
-
for (const skill of
|
|
4268
|
+
for (const skill of skills2) {
|
|
4234
4269
|
sections.push(`### ${skill.name}
|
|
4235
4270
|
|
|
4236
4271
|
${skill.content}`);
|
|
@@ -4272,16 +4307,16 @@ Once loaded, a skill's content will be available in the conversation context.`,
|
|
|
4272
4307
|
try {
|
|
4273
4308
|
switch (action) {
|
|
4274
4309
|
case "list": {
|
|
4275
|
-
const
|
|
4310
|
+
const skills2 = await loadAllSkills(options.skillsDirectories);
|
|
4276
4311
|
return {
|
|
4277
4312
|
success: true,
|
|
4278
4313
|
action: "list",
|
|
4279
|
-
skillCount:
|
|
4280
|
-
skills:
|
|
4314
|
+
skillCount: skills2.length,
|
|
4315
|
+
skills: skills2.map((s) => ({
|
|
4281
4316
|
name: s.name,
|
|
4282
4317
|
description: s.description
|
|
4283
4318
|
})),
|
|
4284
|
-
formatted: formatSkillsForContext(
|
|
4319
|
+
formatted: formatSkillsForContext(skills2)
|
|
4285
4320
|
};
|
|
4286
4321
|
}
|
|
4287
4322
|
case "load": {
|
|
@@ -4719,8 +4754,8 @@ var init_subagent = __esm({
|
|
|
4719
4754
|
if (eventQueue.length > 0) {
|
|
4720
4755
|
yield eventQueue.shift();
|
|
4721
4756
|
} else if (!done) {
|
|
4722
|
-
const event = await new Promise((
|
|
4723
|
-
resolveNext =
|
|
4757
|
+
const event = await new Promise((resolve14) => {
|
|
4758
|
+
resolveNext = resolve14;
|
|
4724
4759
|
});
|
|
4725
4760
|
if (event) {
|
|
4726
4761
|
yield event;
|
|
@@ -5362,7 +5397,7 @@ function formatError(error) {
|
|
|
5362
5397
|
}
|
|
5363
5398
|
}
|
|
5364
5399
|
function sleep(ms) {
|
|
5365
|
-
return new Promise((
|
|
5400
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
5366
5401
|
}
|
|
5367
5402
|
function isPathExcluded(relativePath, exclude) {
|
|
5368
5403
|
return exclude.some((pattern) => {
|
|
@@ -5380,7 +5415,7 @@ function isPathExcluded(relativePath, exclude) {
|
|
|
5380
5415
|
}
|
|
5381
5416
|
async function walkDirectory(dir, include, exclude, baseDir) {
|
|
5382
5417
|
const { readdirSync: readdirSync4 } = await import("fs");
|
|
5383
|
-
const { join:
|
|
5418
|
+
const { join: join18, relative: relative10 } = await import("path");
|
|
5384
5419
|
const files = [];
|
|
5385
5420
|
function walk(currentDir) {
|
|
5386
5421
|
let entries;
|
|
@@ -5390,7 +5425,7 @@ async function walkDirectory(dir, include, exclude, baseDir) {
|
|
|
5390
5425
|
return;
|
|
5391
5426
|
}
|
|
5392
5427
|
for (const entry2 of entries) {
|
|
5393
|
-
const fullPath =
|
|
5428
|
+
const fullPath = join18(currentDir, entry2.name);
|
|
5394
5429
|
const relativePath = relative10(baseDir, fullPath);
|
|
5395
5430
|
if (isPathExcluded(relativePath, exclude)) {
|
|
5396
5431
|
continue;
|
|
@@ -7238,8 +7273,8 @@ async function buildSystemPrompt(options) {
|
|
|
7238
7273
|
}
|
|
7239
7274
|
} else {
|
|
7240
7275
|
const { loadAllSkills: loadAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
7241
|
-
const
|
|
7242
|
-
onDemandSkillsContext = formatSkillsForContext(
|
|
7276
|
+
const skills2 = await loadAllSkills2(skillsDirectories);
|
|
7277
|
+
onDemandSkillsContext = formatSkillsForContext(skills2);
|
|
7243
7278
|
}
|
|
7244
7279
|
const todos = await todoQueries.getBySession(sessionId);
|
|
7245
7280
|
const todosContext = formatTodosForContext(todos);
|
|
@@ -9707,11 +9742,11 @@ function waitForTaskQuestionAnswer(question) {
|
|
|
9707
9742
|
if (pendingQuestions.has(k)) {
|
|
9708
9743
|
return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
|
|
9709
9744
|
}
|
|
9710
|
-
return new Promise((
|
|
9745
|
+
return new Promise((resolve14, reject) => {
|
|
9711
9746
|
pendingQuestions.set(k, {
|
|
9712
9747
|
...question,
|
|
9713
9748
|
createdAt: /* @__PURE__ */ new Date(),
|
|
9714
|
-
resolve:
|
|
9749
|
+
resolve: resolve14,
|
|
9715
9750
|
reject
|
|
9716
9751
|
});
|
|
9717
9752
|
});
|
|
@@ -10860,14 +10895,14 @@ ${p.text}` : p.text;
|
|
|
10860
10895
|
const result = await recorder.encode();
|
|
10861
10896
|
recorder.clear();
|
|
10862
10897
|
if (!result) return [];
|
|
10863
|
-
const { readFile:
|
|
10898
|
+
const { readFile: readFile13, unlink: unlink4 } = await import("fs/promises");
|
|
10864
10899
|
const uploadInfo = await storageQueries2.getUploadUrl(
|
|
10865
10900
|
this.session.id,
|
|
10866
10901
|
`browser-recording-${Date.now()}.mp4`,
|
|
10867
10902
|
"video/mp4",
|
|
10868
10903
|
"browser-recording"
|
|
10869
10904
|
);
|
|
10870
|
-
const fileData = await
|
|
10905
|
+
const fileData = await readFile13(result.path);
|
|
10871
10906
|
await fetch(uploadInfo.uploadUrl, {
|
|
10872
10907
|
method: "PUT",
|
|
10873
10908
|
headers: { "Content-Type": "video/mp4" },
|
|
@@ -10875,7 +10910,7 @@ ${p.text}` : p.text;
|
|
|
10875
10910
|
});
|
|
10876
10911
|
await storageQueries2.updateFile(uploadInfo.fileId, { sizeBytes: result.sizeBytes });
|
|
10877
10912
|
const dlInfo = await storageQueries2.getDownloadUrl(uploadInfo.fileId);
|
|
10878
|
-
await
|
|
10913
|
+
await unlink4(result.path).catch(() => {
|
|
10879
10914
|
});
|
|
10880
10915
|
console.log(`[TASK] Browser recording uploaded (${result.sizeBytes} bytes)`);
|
|
10881
10916
|
return [dlInfo.downloadUrl];
|
|
@@ -10893,13 +10928,13 @@ ${p.text}` : p.text;
|
|
|
10893
10928
|
try {
|
|
10894
10929
|
const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
|
|
10895
10930
|
if (!isRemoteConfigured2()) return [];
|
|
10896
|
-
const { readFile:
|
|
10897
|
-
const { join:
|
|
10931
|
+
const { readFile: readFile13 } = await import("fs/promises");
|
|
10932
|
+
const { join: join18, basename: basename7 } = await import("path");
|
|
10898
10933
|
const urls = [];
|
|
10899
10934
|
for (const filePath of filePaths) {
|
|
10900
10935
|
try {
|
|
10901
|
-
const fullPath = filePath.startsWith("/") ? filePath :
|
|
10902
|
-
const fileName =
|
|
10936
|
+
const fullPath = filePath.startsWith("/") ? filePath : join18(this.session.workingDirectory, filePath);
|
|
10937
|
+
const fileName = basename7(fullPath);
|
|
10903
10938
|
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
|
10904
10939
|
const mimeMap = {
|
|
10905
10940
|
pdf: "application/pdf",
|
|
@@ -10923,7 +10958,7 @@ ${p.text}` : p.text;
|
|
|
10923
10958
|
contentType,
|
|
10924
10959
|
"task-output"
|
|
10925
10960
|
);
|
|
10926
|
-
const fileData = await
|
|
10961
|
+
const fileData = await readFile13(fullPath);
|
|
10927
10962
|
await fetch(uploadInfo.uploadUrl, {
|
|
10928
10963
|
method: "PUT",
|
|
10929
10964
|
headers: { "Content-Type": contentType },
|
|
@@ -10972,8 +11007,8 @@ ${p.text}` : p.text;
|
|
|
10972
11007
|
this.pendingApprovals.set(toolCallId, await execution);
|
|
10973
11008
|
options.onApprovalRequired?.(await execution);
|
|
10974
11009
|
await sessionQueries.updateStatus(this.session.id, "waiting");
|
|
10975
|
-
const approved = await new Promise((
|
|
10976
|
-
approvalResolvers.set(toolCallId, { resolve:
|
|
11010
|
+
const approved = await new Promise((resolve14) => {
|
|
11011
|
+
approvalResolvers.set(toolCallId, { resolve: resolve14, sessionId: this.session.id });
|
|
10977
11012
|
});
|
|
10978
11013
|
const resolverData = approvalResolvers.get(toolCallId);
|
|
10979
11014
|
approvalResolvers.delete(toolCallId);
|
|
@@ -11079,8 +11114,8 @@ async function withSessionLock(sessionId, fn) {
|
|
|
11079
11114
|
state2.pending++;
|
|
11080
11115
|
const prev = state2.tail;
|
|
11081
11116
|
let release;
|
|
11082
|
-
const next = new Promise((
|
|
11083
|
-
release =
|
|
11117
|
+
const next = new Promise((resolve14) => {
|
|
11118
|
+
release = resolve14;
|
|
11084
11119
|
});
|
|
11085
11120
|
state2.tail = prev.then(() => next);
|
|
11086
11121
|
await prev;
|
|
@@ -11693,17 +11728,17 @@ import chalk from "chalk";
|
|
|
11693
11728
|
import ora from "ora";
|
|
11694
11729
|
import "dotenv/config";
|
|
11695
11730
|
import { createInterface } from "readline";
|
|
11696
|
-
import { dirname as
|
|
11731
|
+
import { dirname as dirname10 } from "path";
|
|
11697
11732
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
11698
11733
|
|
|
11699
11734
|
// src/server/index.ts
|
|
11700
11735
|
import "dotenv/config";
|
|
11701
|
-
import { Hono as
|
|
11736
|
+
import { Hono as Hono10 } from "hono";
|
|
11702
11737
|
import { serve } from "@hono/node-server";
|
|
11703
11738
|
import { cors } from "hono/cors";
|
|
11704
11739
|
import { logger } from "hono/logger";
|
|
11705
|
-
import { existsSync as
|
|
11706
|
-
import { resolve as
|
|
11740
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
11741
|
+
import { resolve as resolve12, dirname as dirname9, join as join16 } from "path";
|
|
11707
11742
|
import { spawn as spawn2 } from "child_process";
|
|
11708
11743
|
import { createServer as createNetServer } from "net";
|
|
11709
11744
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -12878,7 +12913,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
|
|
|
12878
12913
|
toolCallId,
|
|
12879
12914
|
argsTextDelta: chunk
|
|
12880
12915
|
}));
|
|
12881
|
-
await new Promise((
|
|
12916
|
+
await new Promise((resolve14) => setTimeout(resolve14, 0));
|
|
12882
12917
|
}
|
|
12883
12918
|
}
|
|
12884
12919
|
function buildDevtoolsContextXml(sessionId) {
|
|
@@ -13133,7 +13168,7 @@ ${prompt}` });
|
|
|
13133
13168
|
chunkIndex,
|
|
13134
13169
|
chunkCount
|
|
13135
13170
|
}));
|
|
13136
|
-
await new Promise((
|
|
13171
|
+
await new Promise((resolve14) => setTimeout(resolve14, 0));
|
|
13137
13172
|
}
|
|
13138
13173
|
const browserPort = progress.data?.browserStreamPort;
|
|
13139
13174
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -13680,7 +13715,7 @@ agents.post(
|
|
|
13680
13715
|
chunkIndex,
|
|
13681
13716
|
chunkCount
|
|
13682
13717
|
}));
|
|
13683
|
-
await new Promise((
|
|
13718
|
+
await new Promise((resolve14) => setTimeout(resolve14, 0));
|
|
13684
13719
|
}
|
|
13685
13720
|
const browserPort = progress.data?.browserStreamPort;
|
|
13686
13721
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -15188,6 +15223,224 @@ mcpRouter.post("/:id/test", async (c) => {
|
|
|
15188
15223
|
return c.json(result);
|
|
15189
15224
|
});
|
|
15190
15225
|
|
|
15226
|
+
// src/server/routes/skills.ts
|
|
15227
|
+
init_config();
|
|
15228
|
+
init_skills();
|
|
15229
|
+
import { Hono as Hono9 } from "hono";
|
|
15230
|
+
import { zValidator as zValidator7 } from "@hono/zod-validator";
|
|
15231
|
+
import { z as z22 } from "zod";
|
|
15232
|
+
import { existsSync as existsSync20, statSync as statSync3 } from "fs";
|
|
15233
|
+
import { readFile as readFile12, writeFile as writeFile6, unlink as unlink3, mkdir as mkdir5 } from "fs/promises";
|
|
15234
|
+
import { resolve as resolve11, join as join15, basename as basename6, dirname as dirname8, extname as extname9 } from "path";
|
|
15235
|
+
var skills = new Hono9();
|
|
15236
|
+
function encodeId(filePath) {
|
|
15237
|
+
return Buffer.from(filePath, "utf-8").toString("base64url");
|
|
15238
|
+
}
|
|
15239
|
+
function decodeId(id) {
|
|
15240
|
+
try {
|
|
15241
|
+
const decoded = Buffer.from(id, "base64url").toString("utf-8");
|
|
15242
|
+
return decoded || null;
|
|
15243
|
+
} catch {
|
|
15244
|
+
return null;
|
|
15245
|
+
}
|
|
15246
|
+
}
|
|
15247
|
+
function listAllDirectories() {
|
|
15248
|
+
const cfg = getConfig();
|
|
15249
|
+
const discovered = discoverSkillDirectories(cfg.resolvedWorkingDirectory);
|
|
15250
|
+
const out = [];
|
|
15251
|
+
for (const { path, priority } of discovered.alwaysLoadedDirs) {
|
|
15252
|
+
out.push({
|
|
15253
|
+
path,
|
|
15254
|
+
source: pathToSource(path),
|
|
15255
|
+
label: pathToLabel(path),
|
|
15256
|
+
priority,
|
|
15257
|
+
alwaysApply: true
|
|
15258
|
+
});
|
|
15259
|
+
}
|
|
15260
|
+
for (const { path, priority } of discovered.onDemandDirs) {
|
|
15261
|
+
out.push({
|
|
15262
|
+
path,
|
|
15263
|
+
source: pathToSource(path),
|
|
15264
|
+
label: pathToLabel(path),
|
|
15265
|
+
priority,
|
|
15266
|
+
alwaysApply: false
|
|
15267
|
+
});
|
|
15268
|
+
}
|
|
15269
|
+
const additional = cfg.skills?.additionalDirectories || [];
|
|
15270
|
+
for (const dir of additional) {
|
|
15271
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, dir);
|
|
15272
|
+
if (out.some((d) => d.path === abs)) continue;
|
|
15273
|
+
out.push({
|
|
15274
|
+
path: abs,
|
|
15275
|
+
source: "additional",
|
|
15276
|
+
label: pathToLabel(abs),
|
|
15277
|
+
priority: 50,
|
|
15278
|
+
alwaysApply: false
|
|
15279
|
+
});
|
|
15280
|
+
}
|
|
15281
|
+
return out;
|
|
15282
|
+
}
|
|
15283
|
+
function pathToSource(path) {
|
|
15284
|
+
if (path.includes("/skills/default") || path.endsWith("/skills/default")) return "builtin";
|
|
15285
|
+
return "project";
|
|
15286
|
+
}
|
|
15287
|
+
function pathToLabel(path) {
|
|
15288
|
+
if (path.includes("/skills/default")) return "Built-in (default)";
|
|
15289
|
+
if (path.includes("/.sparkecoder/rules")) return ".sparkecoder/rules";
|
|
15290
|
+
if (path.includes("/.sparkecoder/skills")) return ".sparkecoder/skills";
|
|
15291
|
+
if (path.includes("/.cursor/rules")) return ".cursor/rules";
|
|
15292
|
+
if (path.includes("/.claude/skills")) return ".claude/skills";
|
|
15293
|
+
return basename6(dirname8(path)) + "/" + basename6(path);
|
|
15294
|
+
}
|
|
15295
|
+
skills.get("/", async (c) => {
|
|
15296
|
+
const dirs = listAllDirectories();
|
|
15297
|
+
const allSkills = [];
|
|
15298
|
+
for (const dir of dirs) {
|
|
15299
|
+
if (!existsSync20(dir.path)) continue;
|
|
15300
|
+
try {
|
|
15301
|
+
const list = await loadSkillsFromDirectory(dir.path, {
|
|
15302
|
+
priority: dir.priority,
|
|
15303
|
+
defaultLoadType: dir.alwaysApply ? "always" : "on_demand",
|
|
15304
|
+
forceAlwaysApply: dir.alwaysApply
|
|
15305
|
+
});
|
|
15306
|
+
for (const s of list) {
|
|
15307
|
+
let size = 0;
|
|
15308
|
+
try {
|
|
15309
|
+
size = statSync3(s.filePath).size;
|
|
15310
|
+
} catch {
|
|
15311
|
+
}
|
|
15312
|
+
allSkills.push({
|
|
15313
|
+
id: encodeId(s.filePath),
|
|
15314
|
+
name: s.name,
|
|
15315
|
+
description: s.description,
|
|
15316
|
+
filePath: s.filePath,
|
|
15317
|
+
fileName: basename6(s.filePath),
|
|
15318
|
+
sourceDir: dir.path,
|
|
15319
|
+
sourceLabel: dir.label,
|
|
15320
|
+
sourceType: dir.source,
|
|
15321
|
+
alwaysApply: s.alwaysApply,
|
|
15322
|
+
globs: s.globs,
|
|
15323
|
+
sizeBytes: size
|
|
15324
|
+
});
|
|
15325
|
+
}
|
|
15326
|
+
} catch (err) {
|
|
15327
|
+
console.warn("[skills] failed to read", dir.path, err?.message || err);
|
|
15328
|
+
}
|
|
15329
|
+
}
|
|
15330
|
+
return c.json({
|
|
15331
|
+
directories: dirs.map((d) => ({
|
|
15332
|
+
path: d.path,
|
|
15333
|
+
label: d.label,
|
|
15334
|
+
source: d.source,
|
|
15335
|
+
alwaysApply: d.alwaysApply,
|
|
15336
|
+
exists: existsSync20(d.path),
|
|
15337
|
+
writable: isWritable(d.path)
|
|
15338
|
+
})),
|
|
15339
|
+
skills: allSkills
|
|
15340
|
+
});
|
|
15341
|
+
});
|
|
15342
|
+
function isWritable(dir) {
|
|
15343
|
+
try {
|
|
15344
|
+
if (!existsSync20(dir)) return false;
|
|
15345
|
+
if (dir.includes("/skills/default")) return false;
|
|
15346
|
+
return true;
|
|
15347
|
+
} catch {
|
|
15348
|
+
return false;
|
|
15349
|
+
}
|
|
15350
|
+
}
|
|
15351
|
+
skills.get("/:id", async (c) => {
|
|
15352
|
+
const filePath = decodeId(c.req.param("id"));
|
|
15353
|
+
if (!filePath || !existsSync20(filePath)) {
|
|
15354
|
+
return c.json({ error: "skill not found" }, 404);
|
|
15355
|
+
}
|
|
15356
|
+
const content = await readFile12(filePath, "utf-8");
|
|
15357
|
+
return c.json({
|
|
15358
|
+
id: c.req.param("id"),
|
|
15359
|
+
filePath,
|
|
15360
|
+
fileName: basename6(filePath),
|
|
15361
|
+
content,
|
|
15362
|
+
writable: !filePath.includes("/skills/default")
|
|
15363
|
+
});
|
|
15364
|
+
});
|
|
15365
|
+
skills.post(
|
|
15366
|
+
"/",
|
|
15367
|
+
zValidator7("json", z22.object({
|
|
15368
|
+
directory: z22.string().min(1),
|
|
15369
|
+
fileName: z22.string().min(1),
|
|
15370
|
+
content: z22.string()
|
|
15371
|
+
})),
|
|
15372
|
+
async (c) => {
|
|
15373
|
+
const { directory, fileName, content } = c.req.valid("json");
|
|
15374
|
+
const cfg = getConfig();
|
|
15375
|
+
const targetDir = resolve11(cfg.resolvedWorkingDirectory, directory);
|
|
15376
|
+
if (targetDir.includes("/skills/default")) {
|
|
15377
|
+
return c.json({ error: "cannot write into built-in skills directory" }, 400);
|
|
15378
|
+
}
|
|
15379
|
+
const safeName = basename6(fileName).replace(/[^A-Za-z0-9._-]/g, "-");
|
|
15380
|
+
const ext = extname9(safeName).toLowerCase();
|
|
15381
|
+
const finalName = ext === ".md" || ext === ".mdc" ? safeName : `${safeName}.md`;
|
|
15382
|
+
const filePath = join15(targetDir, finalName);
|
|
15383
|
+
if (existsSync20(filePath)) {
|
|
15384
|
+
return c.json({ error: `file already exists: ${finalName}` }, 409);
|
|
15385
|
+
}
|
|
15386
|
+
try {
|
|
15387
|
+
await mkdir5(targetDir, { recursive: true });
|
|
15388
|
+
await writeFile6(filePath, content, "utf-8");
|
|
15389
|
+
} catch (err) {
|
|
15390
|
+
return c.json({ error: err?.message || "write failed" }, 500);
|
|
15391
|
+
}
|
|
15392
|
+
return c.json({ id: encodeId(filePath), filePath, fileName: finalName }, 201);
|
|
15393
|
+
}
|
|
15394
|
+
);
|
|
15395
|
+
skills.put(
|
|
15396
|
+
"/:id",
|
|
15397
|
+
zValidator7("json", z22.object({ content: z22.string() })),
|
|
15398
|
+
async (c) => {
|
|
15399
|
+
const filePath = decodeId(c.req.param("id"));
|
|
15400
|
+
if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
|
|
15401
|
+
if (filePath.includes("/skills/default")) {
|
|
15402
|
+
return c.json({ error: "built-in skills are read-only" }, 400);
|
|
15403
|
+
}
|
|
15404
|
+
await writeFile6(filePath, c.req.valid("json").content, "utf-8");
|
|
15405
|
+
return c.json({ ok: true });
|
|
15406
|
+
}
|
|
15407
|
+
);
|
|
15408
|
+
skills.delete("/:id", async (c) => {
|
|
15409
|
+
const filePath = decodeId(c.req.param("id"));
|
|
15410
|
+
if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
|
|
15411
|
+
if (filePath.includes("/skills/default")) {
|
|
15412
|
+
return c.json({ error: "built-in skills are read-only" }, 400);
|
|
15413
|
+
}
|
|
15414
|
+
await unlink3(filePath);
|
|
15415
|
+
return c.json({ ok: true });
|
|
15416
|
+
});
|
|
15417
|
+
skills.post(
|
|
15418
|
+
"/directories",
|
|
15419
|
+
zValidator7("json", z22.object({ path: z22.string().min(1) })),
|
|
15420
|
+
(c) => {
|
|
15421
|
+
const cfg = getConfig();
|
|
15422
|
+
const inputPath = c.req.valid("json").path.trim();
|
|
15423
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
|
|
15424
|
+
const current = cfg.skills?.additionalDirectories || [];
|
|
15425
|
+
if (current.some((d) => resolve11(cfg.resolvedWorkingDirectory, d) === abs)) {
|
|
15426
|
+
return c.json({ error: "directory already added" }, 409);
|
|
15427
|
+
}
|
|
15428
|
+
const next = [...current, abs];
|
|
15429
|
+
setSkillsAdditionalDirectories(next);
|
|
15430
|
+
return c.json({ ok: true, path: abs, exists: existsSync20(abs) }, 201);
|
|
15431
|
+
}
|
|
15432
|
+
);
|
|
15433
|
+
skills.delete("/directories", (c) => {
|
|
15434
|
+
const inputPath = c.req.query("path");
|
|
15435
|
+
if (!inputPath) return c.json({ error: "path query param required" }, 400);
|
|
15436
|
+
const cfg = getConfig();
|
|
15437
|
+
const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
|
|
15438
|
+
const current = cfg.skills?.additionalDirectories || [];
|
|
15439
|
+
const next = current.filter((d) => resolve11(cfg.resolvedWorkingDirectory, d) !== abs);
|
|
15440
|
+
setSkillsAdditionalDirectories(next);
|
|
15441
|
+
return c.json({ ok: true });
|
|
15442
|
+
});
|
|
15443
|
+
|
|
15191
15444
|
// src/server/auth/cf-access.ts
|
|
15192
15445
|
init_config();
|
|
15193
15446
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
@@ -15444,13 +15697,13 @@ var DEFAULT_WEB_PORT = 6969;
|
|
|
15444
15697
|
var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
|
|
15445
15698
|
function getWebDirectory() {
|
|
15446
15699
|
try {
|
|
15447
|
-
const currentDir =
|
|
15448
|
-
const webDir =
|
|
15449
|
-
if (
|
|
15700
|
+
const currentDir = dirname9(fileURLToPath4(import.meta.url));
|
|
15701
|
+
const webDir = resolve12(currentDir, "..", "web");
|
|
15702
|
+
if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
|
|
15450
15703
|
return webDir;
|
|
15451
15704
|
}
|
|
15452
|
-
const altWebDir =
|
|
15453
|
-
if (
|
|
15705
|
+
const altWebDir = resolve12(currentDir, "..", "..", "web");
|
|
15706
|
+
if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
|
|
15454
15707
|
return altWebDir;
|
|
15455
15708
|
}
|
|
15456
15709
|
return null;
|
|
@@ -15473,18 +15726,18 @@ async function isSparkcoderWebRunning(port) {
|
|
|
15473
15726
|
}
|
|
15474
15727
|
}
|
|
15475
15728
|
function isPortInUse(port) {
|
|
15476
|
-
return new Promise((
|
|
15729
|
+
return new Promise((resolve14) => {
|
|
15477
15730
|
const server = createNetServer();
|
|
15478
15731
|
server.once("error", (err) => {
|
|
15479
15732
|
if (err.code === "EADDRINUSE") {
|
|
15480
|
-
|
|
15733
|
+
resolve14(true);
|
|
15481
15734
|
} else {
|
|
15482
|
-
|
|
15735
|
+
resolve14(false);
|
|
15483
15736
|
}
|
|
15484
15737
|
});
|
|
15485
15738
|
server.once("listening", () => {
|
|
15486
15739
|
server.close();
|
|
15487
|
-
|
|
15740
|
+
resolve14(false);
|
|
15488
15741
|
});
|
|
15489
15742
|
server.listen(port, "0.0.0.0");
|
|
15490
15743
|
});
|
|
@@ -15508,30 +15761,30 @@ async function findWebPort(preferredPort) {
|
|
|
15508
15761
|
return { port: preferredPort, alreadyRunning: false };
|
|
15509
15762
|
}
|
|
15510
15763
|
function hasProductionBuild(webDir) {
|
|
15511
|
-
const buildIdPath =
|
|
15512
|
-
return
|
|
15764
|
+
const buildIdPath = join16(webDir, ".next", "BUILD_ID");
|
|
15765
|
+
return existsSync21(buildIdPath);
|
|
15513
15766
|
}
|
|
15514
15767
|
function hasSourceFiles(webDir) {
|
|
15515
|
-
const appDir =
|
|
15516
|
-
const pagesDir =
|
|
15517
|
-
const rootAppDir =
|
|
15518
|
-
const rootPagesDir =
|
|
15519
|
-
return
|
|
15768
|
+
const appDir = join16(webDir, "src", "app");
|
|
15769
|
+
const pagesDir = join16(webDir, "src", "pages");
|
|
15770
|
+
const rootAppDir = join16(webDir, "app");
|
|
15771
|
+
const rootPagesDir = join16(webDir, "pages");
|
|
15772
|
+
return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
|
|
15520
15773
|
}
|
|
15521
15774
|
function getStandaloneServerPath(webDir) {
|
|
15522
15775
|
const possiblePaths2 = [
|
|
15523
|
-
|
|
15524
|
-
|
|
15776
|
+
join16(webDir, ".next", "standalone", "server.js"),
|
|
15777
|
+
join16(webDir, ".next", "standalone", "web", "server.js")
|
|
15525
15778
|
];
|
|
15526
15779
|
for (const serverPath of possiblePaths2) {
|
|
15527
|
-
if (
|
|
15780
|
+
if (existsSync21(serverPath)) {
|
|
15528
15781
|
return serverPath;
|
|
15529
15782
|
}
|
|
15530
15783
|
}
|
|
15531
15784
|
return null;
|
|
15532
15785
|
}
|
|
15533
15786
|
function runCommand(command, args, cwd, env) {
|
|
15534
|
-
return new Promise((
|
|
15787
|
+
return new Promise((resolve14) => {
|
|
15535
15788
|
const child = spawn2(command, args, {
|
|
15536
15789
|
cwd,
|
|
15537
15790
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -15546,10 +15799,10 @@ function runCommand(command, args, cwd, env) {
|
|
|
15546
15799
|
output += data.toString();
|
|
15547
15800
|
});
|
|
15548
15801
|
child.on("close", (code) => {
|
|
15549
|
-
|
|
15802
|
+
resolve14({ success: code === 0, output });
|
|
15550
15803
|
});
|
|
15551
15804
|
child.on("error", (err) => {
|
|
15552
|
-
|
|
15805
|
+
resolve14({ success: false, output: err.message });
|
|
15553
15806
|
});
|
|
15554
15807
|
});
|
|
15555
15808
|
}
|
|
@@ -15564,13 +15817,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
15564
15817
|
if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
|
|
15565
15818
|
return { process: null, port: actualPort };
|
|
15566
15819
|
}
|
|
15567
|
-
const usePnpm =
|
|
15568
|
-
const useNpm = !usePnpm &&
|
|
15820
|
+
const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
|
|
15821
|
+
const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
|
|
15569
15822
|
const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
|
|
15570
15823
|
const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
|
|
15571
15824
|
const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
|
|
15572
15825
|
const runtimeConfig = { apiBaseUrl: apiUrl };
|
|
15573
|
-
const runtimeConfigPath =
|
|
15826
|
+
const runtimeConfigPath = join16(webDir, "runtime-config.json");
|
|
15574
15827
|
try {
|
|
15575
15828
|
writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
|
|
15576
15829
|
if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
|
|
@@ -15592,7 +15845,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
15592
15845
|
if (standaloneServerPath) {
|
|
15593
15846
|
command = "node";
|
|
15594
15847
|
args = ["server.js"];
|
|
15595
|
-
cwd =
|
|
15848
|
+
cwd = dirname9(standaloneServerPath);
|
|
15596
15849
|
webEnv.PORT = String(actualPort);
|
|
15597
15850
|
webEnv.HOSTNAME = "0.0.0.0";
|
|
15598
15851
|
if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
|
|
@@ -15633,10 +15886,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
15633
15886
|
let started = false;
|
|
15634
15887
|
let exited = false;
|
|
15635
15888
|
let exitCode = null;
|
|
15636
|
-
const startedPromise = new Promise((
|
|
15889
|
+
const startedPromise = new Promise((resolve14) => {
|
|
15637
15890
|
const timeout = setTimeout(() => {
|
|
15638
15891
|
if (!started && !exited) {
|
|
15639
|
-
|
|
15892
|
+
resolve14(false);
|
|
15640
15893
|
}
|
|
15641
15894
|
}, startupTimeout);
|
|
15642
15895
|
child.stdout?.on("data", (data) => {
|
|
@@ -15650,7 +15903,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
15650
15903
|
if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
|
|
15651
15904
|
started = true;
|
|
15652
15905
|
clearTimeout(timeout);
|
|
15653
|
-
|
|
15906
|
+
resolve14(true);
|
|
15654
15907
|
}
|
|
15655
15908
|
});
|
|
15656
15909
|
child.stderr?.on("data", (data) => {
|
|
@@ -15662,14 +15915,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
15662
15915
|
child.on("error", (err) => {
|
|
15663
15916
|
if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
|
|
15664
15917
|
clearTimeout(timeout);
|
|
15665
|
-
|
|
15918
|
+
resolve14(false);
|
|
15666
15919
|
});
|
|
15667
15920
|
child.on("exit", (code) => {
|
|
15668
15921
|
exited = true;
|
|
15669
15922
|
exitCode = code;
|
|
15670
15923
|
if (!started) {
|
|
15671
15924
|
clearTimeout(timeout);
|
|
15672
|
-
|
|
15925
|
+
resolve14(false);
|
|
15673
15926
|
}
|
|
15674
15927
|
webUIProcess = null;
|
|
15675
15928
|
});
|
|
@@ -15692,7 +15945,7 @@ function stopWebUI() {
|
|
|
15692
15945
|
}
|
|
15693
15946
|
}
|
|
15694
15947
|
async function createApp(options = {}) {
|
|
15695
|
-
const app = new
|
|
15948
|
+
const app = new Hono10();
|
|
15696
15949
|
app.use("*", cors({
|
|
15697
15950
|
origin: "*",
|
|
15698
15951
|
// Allow all origins
|
|
@@ -15720,6 +15973,7 @@ async function createApp(options = {}) {
|
|
|
15720
15973
|
app.route("/api/schedules", schedulesRouter);
|
|
15721
15974
|
app.route("/api/orchestrator", orchestratorRouter);
|
|
15722
15975
|
app.route("/api/mcp", mcpRouter);
|
|
15976
|
+
app.route("/api/skills", skills);
|
|
15723
15977
|
app.route("/api/webhooks", webhooksRouter);
|
|
15724
15978
|
const config = getConfig();
|
|
15725
15979
|
const webhookToken = config?.webhooks?.token;
|
|
@@ -15785,7 +16039,7 @@ async function startServer(options = {}) {
|
|
|
15785
16039
|
if (options.workingDirectory) {
|
|
15786
16040
|
config.resolvedWorkingDirectory = options.workingDirectory;
|
|
15787
16041
|
}
|
|
15788
|
-
if (!
|
|
16042
|
+
if (!existsSync21(config.resolvedWorkingDirectory)) {
|
|
15789
16043
|
mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
|
|
15790
16044
|
if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
|
|
15791
16045
|
}
|
|
@@ -16344,14 +16598,14 @@ function generateOpenAPISpec() {
|
|
|
16344
16598
|
init_config();
|
|
16345
16599
|
init_semantic();
|
|
16346
16600
|
init_db();
|
|
16347
|
-
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync7, readFileSync as readFileSync10, existsSync as
|
|
16348
|
-
import { resolve as
|
|
16601
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync7, readFileSync as readFileSync10, existsSync as existsSync22, statSync as statSync4 } from "fs";
|
|
16602
|
+
import { resolve as resolve13, join as join17 } from "path";
|
|
16349
16603
|
function getCliVersion() {
|
|
16350
|
-
const here =
|
|
16604
|
+
const here = dirname10(fileURLToPath5(import.meta.url));
|
|
16351
16605
|
const candidates = [
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16606
|
+
join17(here, "..", "package.json"),
|
|
16607
|
+
join17(here, "..", "..", "package.json"),
|
|
16608
|
+
join17(process.cwd(), "package.json")
|
|
16355
16609
|
];
|
|
16356
16610
|
for (const p of candidates) {
|
|
16357
16611
|
try {
|
|
@@ -16396,18 +16650,18 @@ async function getActiveStream(baseUrl, sessionId) {
|
|
|
16396
16650
|
return { hasActiveStream: false };
|
|
16397
16651
|
}
|
|
16398
16652
|
function promptApproval(rl, toolName, input) {
|
|
16399
|
-
return new Promise((
|
|
16653
|
+
return new Promise((resolve14) => {
|
|
16400
16654
|
const inputStr = JSON.stringify(input);
|
|
16401
16655
|
const truncatedInput = inputStr.length > 100 ? inputStr.slice(0, 100) + "..." : inputStr;
|
|
16402
16656
|
console.log(chalk.dim(` Command: ${truncatedInput}`));
|
|
16403
16657
|
rl.question(chalk.yellow(` Approve? [y/n/a(lways)]: `), (answer) => {
|
|
16404
16658
|
const lower = answer.toLowerCase().trim();
|
|
16405
16659
|
if (lower === "a" || lower === "always") {
|
|
16406
|
-
|
|
16660
|
+
resolve14("always");
|
|
16407
16661
|
} else if (lower.startsWith("y")) {
|
|
16408
|
-
|
|
16662
|
+
resolve14("approve");
|
|
16409
16663
|
} else {
|
|
16410
|
-
|
|
16664
|
+
resolve14("reject");
|
|
16411
16665
|
}
|
|
16412
16666
|
});
|
|
16413
16667
|
});
|
|
@@ -16604,9 +16858,9 @@ async function runChat(options) {
|
|
|
16604
16858
|
input: process.stdin,
|
|
16605
16859
|
output: process.stdout
|
|
16606
16860
|
});
|
|
16607
|
-
const apiKey = await new Promise((
|
|
16861
|
+
const apiKey = await new Promise((resolve14) => {
|
|
16608
16862
|
keyRl.question(chalk.cyan("Enter your AI Gateway API key: "), (answer) => {
|
|
16609
|
-
|
|
16863
|
+
resolve14(answer.trim());
|
|
16610
16864
|
});
|
|
16611
16865
|
});
|
|
16612
16866
|
keyRl.close();
|
|
@@ -17002,7 +17256,7 @@ program.command("task").description("Run an autonomous task that completes witho
|
|
|
17002
17256
|
let outputSchema;
|
|
17003
17257
|
try {
|
|
17004
17258
|
const schemaStr = options.schema;
|
|
17005
|
-
if (
|
|
17259
|
+
if (existsSync22(schemaStr)) {
|
|
17006
17260
|
outputSchema = JSON.parse(readFileSync10(schemaStr, "utf-8"));
|
|
17007
17261
|
} else {
|
|
17008
17262
|
outputSchema = JSON.parse(schemaStr);
|
|
@@ -17070,13 +17324,13 @@ program.command("init").description("Create a sparkecoder.config.json file").opt
|
|
|
17070
17324
|
let configLocation;
|
|
17071
17325
|
if (options.global) {
|
|
17072
17326
|
const appDataDir = ensureAppDataDirectory();
|
|
17073
|
-
configPath =
|
|
17327
|
+
configPath = join17(appDataDir, "sparkecoder.config.json");
|
|
17074
17328
|
configLocation = "global";
|
|
17075
17329
|
} else {
|
|
17076
|
-
configPath =
|
|
17330
|
+
configPath = resolve13(process.cwd(), "sparkecoder.config.json");
|
|
17077
17331
|
configLocation = "local";
|
|
17078
17332
|
}
|
|
17079
|
-
if (
|
|
17333
|
+
if (existsSync22(configPath) && !options.force) {
|
|
17080
17334
|
console.log(chalk.yellow("Config file already exists. Use --force to overwrite."));
|
|
17081
17335
|
console.log(chalk.dim(` ${configPath}`));
|
|
17082
17336
|
return;
|
|
@@ -17089,9 +17343,9 @@ program.command("init").description("Create a sparkecoder.config.json file").opt
|
|
|
17089
17343
|
});
|
|
17090
17344
|
program.command("slack-setup").description("Interactively configure Slack integration (bot token + signing secret)").option("--bot-token <token>", "Slack bot token (xoxb-...)").option("--signing-secret <secret>", "Slack app signing secret").option("-g, --global", "Write to global config (~/.sparkecoder/sparkecoder.config.json)").action(async (options) => {
|
|
17091
17345
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
17092
|
-
const ask = (label, fallback = "") => new Promise((
|
|
17346
|
+
const ask = (label, fallback = "") => new Promise((resolve14) => {
|
|
17093
17347
|
const suffix = fallback ? ` (${fallback})` : "";
|
|
17094
|
-
rl.question(`${label}${suffix}: `, (answer) =>
|
|
17348
|
+
rl.question(`${label}${suffix}: `, (answer) => resolve14(answer.trim() || fallback));
|
|
17095
17349
|
});
|
|
17096
17350
|
try {
|
|
17097
17351
|
const botToken = options.botToken || await ask("Slack bot token (xoxb-...)");
|
|
@@ -17101,9 +17355,9 @@ program.command("slack-setup").description("Interactively configure Slack integr
|
|
|
17101
17355
|
console.error(chalk.red("Both bot token and signing secret are required."));
|
|
17102
17356
|
process.exit(1);
|
|
17103
17357
|
}
|
|
17104
|
-
const configPath = options.global ?
|
|
17358
|
+
const configPath = options.global ? join17(ensureAppDataDirectory(), "sparkecoder.config.json") : resolve13(process.cwd(), "sparkecoder.config.json");
|
|
17105
17359
|
let existing = {};
|
|
17106
|
-
if (
|
|
17360
|
+
if (existsSync22(configPath)) {
|
|
17107
17361
|
try {
|
|
17108
17362
|
existing = JSON.parse(readFileSync10(configPath, "utf-8"));
|
|
17109
17363
|
} catch {
|
|
@@ -17369,9 +17623,9 @@ program.command("cloudflared-setup").description("Auto-detect cloudflared + set
|
|
|
17369
17623
|
}
|
|
17370
17624
|
const verOut = run("cloudflared", ["--version"]).stdout?.toString().split("\n")[0] || "installed";
|
|
17371
17625
|
console.log(chalk.green("\u2713"), "cloudflared:", chalk.dim(verOut));
|
|
17372
|
-
const cfDir =
|
|
17373
|
-
const certPath =
|
|
17374
|
-
if (!
|
|
17626
|
+
const cfDir = join17(homedir2(), ".cloudflared");
|
|
17627
|
+
const certPath = join17(cfDir, "cert.pem");
|
|
17628
|
+
if (!existsSync22(certPath)) {
|
|
17375
17629
|
console.log(chalk.yellow("No Cloudflare login cert found."));
|
|
17376
17630
|
if (await confirm("Run `cloudflared tunnel login` now (opens a browser)?", true)) {
|
|
17377
17631
|
run("cloudflared", ["tunnel", "login"], { inheritIO: true, check: true });
|
|
@@ -17415,8 +17669,8 @@ program.command("cloudflared-setup").description("Auto-detect cloudflared + set
|
|
|
17415
17669
|
return;
|
|
17416
17670
|
}
|
|
17417
17671
|
}
|
|
17418
|
-
const credsFile = tunnel.credentials_file ||
|
|
17419
|
-
if (!
|
|
17672
|
+
const credsFile = tunnel.credentials_file || join17(cfDir, `${tunnel.id}.json`);
|
|
17673
|
+
if (!existsSync22(credsFile)) {
|
|
17420
17674
|
console.log(chalk.yellow(`Credentials file not found at ${credsFile}. The tunnel may still work via cert.pem.`));
|
|
17421
17675
|
}
|
|
17422
17676
|
let hostname = options.hostname;
|
|
@@ -17439,7 +17693,7 @@ program.command("cloudflared-setup").description("Auto-detect cloudflared + set
|
|
|
17439
17693
|
console.log(chalk.yellow("DNS route warning:"), err.trim().split("\n").slice(-2).join(" "));
|
|
17440
17694
|
}
|
|
17441
17695
|
}
|
|
17442
|
-
const configPath =
|
|
17696
|
+
const configPath = join17(cfDir, "config.yml");
|
|
17443
17697
|
const configBody = `tunnel: ${tunnel.id}
|
|
17444
17698
|
credentials-file: ${credsFile}
|
|
17445
17699
|
ingress:
|
|
@@ -17450,7 +17704,7 @@ ingress:
|
|
|
17450
17704
|
- service: http_status:404
|
|
17451
17705
|
`;
|
|
17452
17706
|
let wroteConfig = false;
|
|
17453
|
-
if (
|
|
17707
|
+
if (existsSync22(configPath)) {
|
|
17454
17708
|
const existing = readFileSync10(configPath, "utf8");
|
|
17455
17709
|
if (existing.trim() === configBody.trim()) {
|
|
17456
17710
|
console.log(chalk.green("\u2713"), `config.yml already up to date: ${configPath}`);
|
|
@@ -17566,7 +17820,7 @@ program.command("config").description("Show current configuration").option("-c,
|
|
|
17566
17820
|
});
|
|
17567
17821
|
program.command("index").description("Index repository for semantic search").option("--status", "Show index status instead of indexing").option("--full", "Force full re-index (ignore existing embeddings)").option("-w, --working-dir <path>", "Working directory (defaults to current directory)").option("-c, --config <path>", "Path to config file").option("-v, --verbose", "Show detailed progress").action(async (options) => {
|
|
17568
17822
|
try {
|
|
17569
|
-
const workingDir = options.workingDir ?
|
|
17823
|
+
const workingDir = options.workingDir ? resolve13(options.workingDir) : process.cwd();
|
|
17570
17824
|
let config = loadConfig(options.config, workingDir);
|
|
17571
17825
|
const remoteUrl = config.resolvedRemoteServer.url;
|
|
17572
17826
|
if (!remoteUrl) {
|
|
@@ -17700,7 +17954,7 @@ Indexing ${chalk.cyan(namespace)}...
|
|
|
17700
17954
|
});
|
|
17701
17955
|
program.command("search").description("Search indexed repository using semantic search").argument("<query>", "Search query").option("-n, --num <count>", "Number of results to show", "5").option("-w, --working-dir <path>", "Working directory (defaults to current directory)").option("-c, --config <path>", "Path to config file").action(async (query, options) => {
|
|
17702
17956
|
try {
|
|
17703
|
-
const workingDir = options.workingDir ?
|
|
17957
|
+
const workingDir = options.workingDir ? resolve13(options.workingDir) : process.cwd();
|
|
17704
17958
|
const config = loadConfig(options.config, workingDir);
|
|
17705
17959
|
const remoteUrl = config.resolvedRemoteServer.url;
|
|
17706
17960
|
if (!remoteUrl) {
|
|
@@ -17955,10 +18209,10 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
17955
18209
|
});
|
|
17956
18210
|
{
|
|
17957
18211
|
let stateFilePath = function() {
|
|
17958
|
-
return
|
|
18212
|
+
return join17(ensureAppDataDirectory(), "recordings.json");
|
|
17959
18213
|
}, readState = function() {
|
|
17960
18214
|
const p = stateFilePath();
|
|
17961
|
-
if (!
|
|
18215
|
+
if (!existsSync22(p)) return [];
|
|
17962
18216
|
try {
|
|
17963
18217
|
return JSON.parse(readFileSync10(p, "utf-8"));
|
|
17964
18218
|
} catch {
|
|
@@ -17980,16 +18234,16 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
17980
18234
|
const record = program.command("record").description("Start/stop screen recordings");
|
|
17981
18235
|
record.command("start").description("Start a screen recording (returns id, path, pid as JSON)").option("--name <slug>", "Optional human-readable label for the recording").option("--dir <path>", "Output directory (default: ~/recordings)").action(async (opts) => {
|
|
17982
18236
|
const { homedir: homedir2, platform: osPlatform } = await import("os");
|
|
17983
|
-
const outDir = opts.dir ?
|
|
18237
|
+
const outDir = opts.dir ? resolve13(opts.dir.replace(/^~/, homedir2())) : join17(homedir2(), "recordings");
|
|
17984
18238
|
mkdirSync10(outDir, { recursive: true });
|
|
17985
18239
|
const id = `rec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
|
|
17986
18240
|
const ext = osPlatform() === "darwin" ? "mov" : "mp4";
|
|
17987
18241
|
const filename = `${id}${opts.name ? `-${String(opts.name).replace(/[^a-z0-9-]+/gi, "-").toLowerCase()}` : ""}.${ext}`;
|
|
17988
|
-
const path =
|
|
18242
|
+
const path = join17(outDir, filename);
|
|
17989
18243
|
let cmd;
|
|
17990
18244
|
let args;
|
|
17991
18245
|
if (osPlatform() === "darwin") {
|
|
17992
|
-
cmd =
|
|
18246
|
+
cmd = existsSync22("/usr/sbin/screencapture") ? "/usr/sbin/screencapture" : "screencapture";
|
|
17993
18247
|
args = ["-v", "-C", "-k", path];
|
|
17994
18248
|
} else if (osPlatform() === "linux") {
|
|
17995
18249
|
const display = process.env.DISPLAY || ":0.0";
|
|
@@ -18092,8 +18346,8 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18092
18346
|
}
|
|
18093
18347
|
}
|
|
18094
18348
|
writeState(rows.filter((r) => r.id !== id));
|
|
18095
|
-
const fileExists =
|
|
18096
|
-
const sizeMb = fileExists ? Math.round(
|
|
18349
|
+
const fileExists = existsSync22(row.path);
|
|
18350
|
+
const sizeMb = fileExists ? Math.round(statSync4(row.path).size / (1024 * 1024) * 10) / 10 : 0;
|
|
18097
18351
|
console.log(JSON.stringify({
|
|
18098
18352
|
id,
|
|
18099
18353
|
path: row.path,
|
|
@@ -18127,7 +18381,7 @@ program.command("request-permissions").description("Open System Settings to the
|
|
|
18127
18381
|
}
|
|
18128
18382
|
}
|
|
18129
18383
|
}
|
|
18130
|
-
stopped.push({ id: r.id, path: r.path, ok:
|
|
18384
|
+
stopped.push({ id: r.id, path: r.path, ok: existsSync22(r.path) });
|
|
18131
18385
|
}
|
|
18132
18386
|
writeState([]);
|
|
18133
18387
|
console.log(JSON.stringify({ stopped }));
|