sparkecoder 0.1.119 → 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.d.ts +3 -3
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +470 -135
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-Bcz0aCAR.d.ts → index-DczYH89U.d.ts} +104 -104
- package/dist/index.d.ts +5 -5
- package/dist/index.js +429 -94
- package/dist/index.js.map +1 -1
- package/dist/{schema-BWbWmfDQ.d.ts → schema-DxrKyetI.d.ts} +3 -3
- package/dist/{search-DOzC4ojH.d.ts → search-CVVfuBPZ.d.ts} +4 -4
- package/dist/server/index.js +429 -94
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +3 -3
- 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/{Bt00m8W4k5F79ALhN700F → static/wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{Bt00m8W4k5F79ALhN700F → static/wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{Bt00m8W4k5F79ALhN700F → static/wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Bt00m8W4k5F79ALhN700F → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Bt00m8W4k5F79ALhN700F → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Bt00m8W4k5F79ALhN700F → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
- /package/web/.next/static/{Bt00m8W4k5F79ALhN700F → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
- /package/web/.next/static/{Bt00m8W4k5F79ALhN700F → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{Bt00m8W4k5F79ALhN700F → 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);
|
|
@@ -7802,6 +7837,9 @@ function isSlackConfigured() {
|
|
|
7802
7837
|
function getSlackSigningSecret() {
|
|
7803
7838
|
return readSlackConfig()?.signingSecret ?? null;
|
|
7804
7839
|
}
|
|
7840
|
+
function getSlackBotToken() {
|
|
7841
|
+
return readSlackConfig()?.botToken ?? null;
|
|
7842
|
+
}
|
|
7805
7843
|
function getDefaultOrchestratorName() {
|
|
7806
7844
|
return readSlackConfig()?.defaultOrchestratorName ?? null;
|
|
7807
7845
|
}
|
|
@@ -7856,6 +7894,62 @@ function getSlackAllowlistPolicy() {
|
|
|
7856
7894
|
return { allowedUsers: [], allowedChannels: [], allowDmsFromAnyone: true };
|
|
7857
7895
|
}
|
|
7858
7896
|
}
|
|
7897
|
+
async function fetchSlackUserName(userId) {
|
|
7898
|
+
const token = getSlackBotToken();
|
|
7899
|
+
if (!token) return null;
|
|
7900
|
+
try {
|
|
7901
|
+
const res = await fetch(`https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`, {
|
|
7902
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
7903
|
+
});
|
|
7904
|
+
const data = await res.json().catch(() => ({}));
|
|
7905
|
+
if (!data?.ok) {
|
|
7906
|
+
console.warn(`[slack] users.info(${userId}) failed: ${data?.error || `HTTP ${res.status}`}`);
|
|
7907
|
+
return null;
|
|
7908
|
+
}
|
|
7909
|
+
const profile = data.user?.profile || {};
|
|
7910
|
+
const name = profile.display_name_normalized || profile.display_name || profile.real_name_normalized || profile.real_name || data.user?.real_name || data.user?.name || null;
|
|
7911
|
+
return name ? String(name) : null;
|
|
7912
|
+
} catch (err) {
|
|
7913
|
+
console.warn(`[slack] users.info(${userId}) error:`, err?.message || err);
|
|
7914
|
+
return null;
|
|
7915
|
+
}
|
|
7916
|
+
}
|
|
7917
|
+
async function resolveSlackUserName(userId) {
|
|
7918
|
+
if (!userId) return null;
|
|
7919
|
+
const now = Date.now();
|
|
7920
|
+
const hit = userNameCache.get(userId);
|
|
7921
|
+
if (hit && hit.expiresAt > now) return hit.name;
|
|
7922
|
+
const inflight = userInflight.get(userId);
|
|
7923
|
+
if (inflight) return inflight;
|
|
7924
|
+
const p = (async () => {
|
|
7925
|
+
const name = await fetchSlackUserName(userId);
|
|
7926
|
+
userNameCache.set(userId, {
|
|
7927
|
+
name,
|
|
7928
|
+
expiresAt: now + (name ? USER_TTL_MS : USER_FAIL_TTL_MS)
|
|
7929
|
+
});
|
|
7930
|
+
userInflight.delete(userId);
|
|
7931
|
+
return name;
|
|
7932
|
+
})();
|
|
7933
|
+
userInflight.set(userId, p);
|
|
7934
|
+
return p;
|
|
7935
|
+
}
|
|
7936
|
+
async function normalizeSlackMentions(text) {
|
|
7937
|
+
if (!text) return text;
|
|
7938
|
+
const userMentionRe = /<@([UW][A-Z0-9]+)(?:\|([^>]+))?>/g;
|
|
7939
|
+
const userIds = /* @__PURE__ */ new Set();
|
|
7940
|
+
for (const m of text.matchAll(userMentionRe)) {
|
|
7941
|
+
if (!m[2]) userIds.add(m[1]);
|
|
7942
|
+
}
|
|
7943
|
+
if (userIds.size > 0) {
|
|
7944
|
+
await Promise.all([...userIds].map((id) => resolveSlackUserName(id)));
|
|
7945
|
+
}
|
|
7946
|
+
return text.replace(userMentionRe, (_full, id, label) => {
|
|
7947
|
+
if (label) return `${label} <@${id}>`;
|
|
7948
|
+
const cached = userNameCache.get(id);
|
|
7949
|
+
const name = cached?.name;
|
|
7950
|
+
return name ? `${name} <@${id}>` : `<@${id}>`;
|
|
7951
|
+
});
|
|
7952
|
+
}
|
|
7859
7953
|
function getSlackDeniedReplyPolicy() {
|
|
7860
7954
|
try {
|
|
7861
7955
|
const cfg = getConfig();
|
|
@@ -7868,13 +7962,17 @@ function getSlackDeniedReplyPolicy() {
|
|
|
7868
7962
|
return { enabled: true, template: DEFAULT_DENIED_TEMPLATE };
|
|
7869
7963
|
}
|
|
7870
7964
|
}
|
|
7871
|
-
var cachedSelf, selfInflight, DEFAULT_DENIED_TEMPLATE;
|
|
7965
|
+
var cachedSelf, selfInflight, USER_TTL_MS, USER_FAIL_TTL_MS, userNameCache, userInflight, DEFAULT_DENIED_TEMPLATE;
|
|
7872
7966
|
var init_client3 = __esm({
|
|
7873
7967
|
"src/integrations/slack/client.ts"() {
|
|
7874
7968
|
"use strict";
|
|
7875
7969
|
init_config();
|
|
7876
7970
|
cachedSelf = null;
|
|
7877
7971
|
selfInflight = null;
|
|
7972
|
+
USER_TTL_MS = 60 * 60 * 1e3;
|
|
7973
|
+
USER_FAIL_TTL_MS = 5 * 60 * 1e3;
|
|
7974
|
+
userNameCache = /* @__PURE__ */ new Map();
|
|
7975
|
+
userInflight = /* @__PURE__ */ new Map();
|
|
7878
7976
|
DEFAULT_DENIED_TEMPLATE = "Sorry, you don't have permission to use this bot. (Contact the bot owner if you think this is a mistake.)";
|
|
7879
7977
|
}
|
|
7880
7978
|
});
|
|
@@ -7889,9 +7987,6 @@ function markThreadOwned(channel, threadTs) {
|
|
|
7889
7987
|
function isThreadOwned(channel, threadTs) {
|
|
7890
7988
|
return ownedThreads.has(threadKey(channel, threadTs));
|
|
7891
7989
|
}
|
|
7892
|
-
function stripMention(text) {
|
|
7893
|
-
return String(text || "").replace(/<@[^>]+>/g, "").trim();
|
|
7894
|
-
}
|
|
7895
7990
|
function isSelfAuthored(event, self) {
|
|
7896
7991
|
if (!self) return true;
|
|
7897
7992
|
if (self.botId && event.bot_id && event.bot_id === self.botId) return true;
|
|
@@ -7906,14 +8001,22 @@ function slackEventToInboundResult(event, opts = {}) {
|
|
|
7906
8001
|
return { event: null, dropReason: "bot_message" };
|
|
7907
8002
|
}
|
|
7908
8003
|
if (event.type === "message" && event.subtype && IGNORED_MESSAGE_SUBTYPES.has(event.subtype)) {
|
|
7909
|
-
return { event: null, dropReason: "
|
|
8004
|
+
return { event: null, dropReason: "ignored_subtype" };
|
|
7910
8005
|
}
|
|
7911
8006
|
const isDm = event.type === "message" && event.channel_type === "im";
|
|
7912
8007
|
const isThreadReply = event.type === "message" && !isDm && typeof event.thread_ts === "string" && event.thread_ts !== event.ts;
|
|
8008
|
+
const isNonThreadChannelMsg = event.type === "message" && !isDm && !isThreadReply && (event.channel_type === "channel" || event.channel_type === "group" || event.channel_type === "mpim" || // Some payload shapes omit channel_type for channel messages.
|
|
8009
|
+
typeof event.channel === "string");
|
|
7913
8010
|
if (event.type !== "app_mention" && !isDm && !isThreadReply) {
|
|
8011
|
+
if (isNonThreadChannelMsg) {
|
|
8012
|
+
return { event: null, dropReason: "non_thread_channel_msg" };
|
|
8013
|
+
}
|
|
8014
|
+
if (event.type !== "message") {
|
|
8015
|
+
return { event: null, dropReason: "non_message_event" };
|
|
8016
|
+
}
|
|
7914
8017
|
return { event: null, dropReason: "unsupported_type" };
|
|
7915
8018
|
}
|
|
7916
|
-
const text =
|
|
8019
|
+
const text = (event.text ?? "").trim();
|
|
7917
8020
|
if (!text) return { event: null, dropReason: "empty_text" };
|
|
7918
8021
|
const policy = getSlackAllowlistPolicy();
|
|
7919
8022
|
const userAllowlistActive = policy.allowedUsers.length > 0;
|
|
@@ -8896,11 +8999,11 @@ function waitForTaskQuestionAnswer(question) {
|
|
|
8896
8999
|
if (pendingQuestions.has(k)) {
|
|
8897
9000
|
return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
|
|
8898
9001
|
}
|
|
8899
|
-
return new Promise((
|
|
9002
|
+
return new Promise((resolve13, reject) => {
|
|
8900
9003
|
pendingQuestions.set(k, {
|
|
8901
9004
|
...question,
|
|
8902
9005
|
createdAt: /* @__PURE__ */ new Date(),
|
|
8903
|
-
resolve:
|
|
9006
|
+
resolve: resolve13,
|
|
8904
9007
|
reject
|
|
8905
9008
|
});
|
|
8906
9009
|
});
|
|
@@ -10049,14 +10152,14 @@ ${p.text}` : p.text;
|
|
|
10049
10152
|
const result = await recorder.encode();
|
|
10050
10153
|
recorder.clear();
|
|
10051
10154
|
if (!result) return [];
|
|
10052
|
-
const { readFile:
|
|
10155
|
+
const { readFile: readFile13, unlink: unlink4 } = await import("fs/promises");
|
|
10053
10156
|
const uploadInfo = await storageQueries2.getUploadUrl(
|
|
10054
10157
|
this.session.id,
|
|
10055
10158
|
`browser-recording-${Date.now()}.mp4`,
|
|
10056
10159
|
"video/mp4",
|
|
10057
10160
|
"browser-recording"
|
|
10058
10161
|
);
|
|
10059
|
-
const fileData = await
|
|
10162
|
+
const fileData = await readFile13(result.path);
|
|
10060
10163
|
await fetch(uploadInfo.uploadUrl, {
|
|
10061
10164
|
method: "PUT",
|
|
10062
10165
|
headers: { "Content-Type": "video/mp4" },
|
|
@@ -10064,7 +10167,7 @@ ${p.text}` : p.text;
|
|
|
10064
10167
|
});
|
|
10065
10168
|
await storageQueries2.updateFile(uploadInfo.fileId, { sizeBytes: result.sizeBytes });
|
|
10066
10169
|
const dlInfo = await storageQueries2.getDownloadUrl(uploadInfo.fileId);
|
|
10067
|
-
await
|
|
10170
|
+
await unlink4(result.path).catch(() => {
|
|
10068
10171
|
});
|
|
10069
10172
|
console.log(`[TASK] Browser recording uploaded (${result.sizeBytes} bytes)`);
|
|
10070
10173
|
return [dlInfo.downloadUrl];
|
|
@@ -10082,13 +10185,13 @@ ${p.text}` : p.text;
|
|
|
10082
10185
|
try {
|
|
10083
10186
|
const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
|
|
10084
10187
|
if (!isRemoteConfigured2()) return [];
|
|
10085
|
-
const { readFile:
|
|
10086
|
-
const { join:
|
|
10188
|
+
const { readFile: readFile13 } = await import("fs/promises");
|
|
10189
|
+
const { join: join17, basename: basename7 } = await import("path");
|
|
10087
10190
|
const urls = [];
|
|
10088
10191
|
for (const filePath of filePaths) {
|
|
10089
10192
|
try {
|
|
10090
|
-
const fullPath = filePath.startsWith("/") ? filePath :
|
|
10091
|
-
const fileName =
|
|
10193
|
+
const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
|
|
10194
|
+
const fileName = basename7(fullPath);
|
|
10092
10195
|
const ext = fileName.split(".").pop()?.toLowerCase() || "";
|
|
10093
10196
|
const mimeMap = {
|
|
10094
10197
|
pdf: "application/pdf",
|
|
@@ -10112,7 +10215,7 @@ ${p.text}` : p.text;
|
|
|
10112
10215
|
contentType,
|
|
10113
10216
|
"task-output"
|
|
10114
10217
|
);
|
|
10115
|
-
const fileData = await
|
|
10218
|
+
const fileData = await readFile13(fullPath);
|
|
10116
10219
|
await fetch(uploadInfo.uploadUrl, {
|
|
10117
10220
|
method: "PUT",
|
|
10118
10221
|
headers: { "Content-Type": contentType },
|
|
@@ -10161,8 +10264,8 @@ ${p.text}` : p.text;
|
|
|
10161
10264
|
this.pendingApprovals.set(toolCallId, await execution);
|
|
10162
10265
|
options.onApprovalRequired?.(await execution);
|
|
10163
10266
|
await sessionQueries.updateStatus(this.session.id, "waiting");
|
|
10164
|
-
const approved = await new Promise((
|
|
10165
|
-
approvalResolvers.set(toolCallId, { resolve:
|
|
10267
|
+
const approved = await new Promise((resolve13) => {
|
|
10268
|
+
approvalResolvers.set(toolCallId, { resolve: resolve13, sessionId: this.session.id });
|
|
10166
10269
|
});
|
|
10167
10270
|
const resolverData = approvalResolvers.get(toolCallId);
|
|
10168
10271
|
approvalResolvers.delete(toolCallId);
|
|
@@ -10268,8 +10371,8 @@ async function withSessionLock(sessionId, fn) {
|
|
|
10268
10371
|
state2.pending++;
|
|
10269
10372
|
const prev = state2.tail;
|
|
10270
10373
|
let release;
|
|
10271
|
-
const next = new Promise((
|
|
10272
|
-
release =
|
|
10374
|
+
const next = new Promise((resolve13) => {
|
|
10375
|
+
release = resolve13;
|
|
10273
10376
|
});
|
|
10274
10377
|
state2.tail = prev.then(() => next);
|
|
10275
10378
|
await prev;
|
|
@@ -10659,12 +10762,12 @@ var init_scheduler = __esm({
|
|
|
10659
10762
|
|
|
10660
10763
|
// src/server/index.ts
|
|
10661
10764
|
import "dotenv/config";
|
|
10662
|
-
import { Hono as
|
|
10765
|
+
import { Hono as Hono10 } from "hono";
|
|
10663
10766
|
import { serve } from "@hono/node-server";
|
|
10664
10767
|
import { cors } from "hono/cors";
|
|
10665
10768
|
import { logger } from "hono/logger";
|
|
10666
|
-
import { existsSync as
|
|
10667
|
-
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";
|
|
10668
10771
|
import { spawn as spawn2 } from "child_process";
|
|
10669
10772
|
import { createServer as createNetServer } from "net";
|
|
10670
10773
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
@@ -11839,7 +11942,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
|
|
|
11839
11942
|
toolCallId,
|
|
11840
11943
|
argsTextDelta: chunk
|
|
11841
11944
|
}));
|
|
11842
|
-
await new Promise((
|
|
11945
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
11843
11946
|
}
|
|
11844
11947
|
}
|
|
11845
11948
|
function buildDevtoolsContextXml(sessionId) {
|
|
@@ -12094,7 +12197,7 @@ ${prompt}` });
|
|
|
12094
12197
|
chunkIndex,
|
|
12095
12198
|
chunkCount
|
|
12096
12199
|
}));
|
|
12097
|
-
await new Promise((
|
|
12200
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
12098
12201
|
}
|
|
12099
12202
|
const browserPort = progress.data?.browserStreamPort;
|
|
12100
12203
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -12641,7 +12744,7 @@ agents.post(
|
|
|
12641
12744
|
chunkIndex,
|
|
12642
12745
|
chunkCount
|
|
12643
12746
|
}));
|
|
12644
|
-
await new Promise((
|
|
12747
|
+
await new Promise((resolve13) => setTimeout(resolve13, 0));
|
|
12645
12748
|
}
|
|
12646
12749
|
const browserPort = progress.data?.browserStreamPort;
|
|
12647
12750
|
const browserClosed = progress.data?.browserClosed;
|
|
@@ -13654,16 +13757,18 @@ init_webhook_events();
|
|
|
13654
13757
|
init_inbox();
|
|
13655
13758
|
var recentlyHandled = /* @__PURE__ */ new Map();
|
|
13656
13759
|
var MAX_RECENT = 1e3;
|
|
13657
|
-
function
|
|
13760
|
+
function wasHandled(channel, ts) {
|
|
13658
13761
|
if (!channel || !ts) return false;
|
|
13762
|
+
return recentlyHandled.has(`${channel}\u241F${ts}`);
|
|
13763
|
+
}
|
|
13764
|
+
function markHandled(channel, ts) {
|
|
13765
|
+
if (!channel || !ts) return;
|
|
13659
13766
|
const key2 = `${channel}\u241F${ts}`;
|
|
13660
|
-
if (recentlyHandled.has(key2)) return true;
|
|
13661
13767
|
recentlyHandled.set(key2, Date.now());
|
|
13662
13768
|
if (recentlyHandled.size > MAX_RECENT) {
|
|
13663
13769
|
const oldest = recentlyHandled.keys().next().value;
|
|
13664
13770
|
if (oldest) recentlyHandled.delete(oldest);
|
|
13665
13771
|
}
|
|
13666
|
-
return false;
|
|
13667
13772
|
}
|
|
13668
13773
|
var slack = new Hono6();
|
|
13669
13774
|
slack.post("/events", async (c) => {
|
|
@@ -13700,7 +13805,7 @@ slack.post("/events", async (c) => {
|
|
|
13700
13805
|
textSnippet: typeof ev.text === "string" ? ev.text : void 0,
|
|
13701
13806
|
meta: { ts: ev.ts, thread_ts: ev.thread_ts, team: ev.team, event_subtype: ev.subtype }
|
|
13702
13807
|
});
|
|
13703
|
-
if (
|
|
13808
|
+
if (wasHandled(ev.channel, ev.ts)) {
|
|
13704
13809
|
updateEvent(auditId, { status: "dropped", dropReason: "duplicate_delivery" });
|
|
13705
13810
|
return c.json({ ok: true });
|
|
13706
13811
|
}
|
|
@@ -13724,7 +13829,18 @@ slack.post("/events", async (c) => {
|
|
|
13724
13829
|
}
|
|
13725
13830
|
const orchestratorId = await findOrCreateOrchestratorId();
|
|
13726
13831
|
if (orchestratorId) {
|
|
13832
|
+
inbound.content = await normalizeSlackMentions(inbound.content);
|
|
13833
|
+
if (ev.user) {
|
|
13834
|
+
const speakerName = await resolveSlackUserName(ev.user);
|
|
13835
|
+
if (speakerName) {
|
|
13836
|
+
inbound.content = inbound.content.replace(
|
|
13837
|
+
`user=${ev.user}`,
|
|
13838
|
+
`user=${speakerName} <@${ev.user}>`
|
|
13839
|
+
);
|
|
13840
|
+
}
|
|
13841
|
+
}
|
|
13727
13842
|
pushToInbox(orchestratorId, inbound);
|
|
13843
|
+
markHandled(ev.channel, ev.ts);
|
|
13728
13844
|
updateEvent(auditId, { status: "routed", sessionId: orchestratorId });
|
|
13729
13845
|
} else {
|
|
13730
13846
|
updateEvent(auditId, { status: "error", error: "no orchestrator session available" });
|
|
@@ -14136,6 +14252,224 @@ mcpRouter.post("/:id/test", async (c) => {
|
|
|
14136
14252
|
return c.json(result);
|
|
14137
14253
|
});
|
|
14138
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
|
+
|
|
14139
14473
|
// src/server/auth/cf-access.ts
|
|
14140
14474
|
init_config();
|
|
14141
14475
|
import { createRemoteJWKSet, jwtVerify } from "jose";
|
|
@@ -14296,13 +14630,13 @@ var DEFAULT_WEB_PORT = 6969;
|
|
|
14296
14630
|
var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
|
|
14297
14631
|
function getWebDirectory() {
|
|
14298
14632
|
try {
|
|
14299
|
-
const currentDir =
|
|
14300
|
-
const webDir =
|
|
14301
|
-
if (
|
|
14633
|
+
const currentDir = dirname9(fileURLToPath4(import.meta.url));
|
|
14634
|
+
const webDir = resolve12(currentDir, "..", "web");
|
|
14635
|
+
if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
|
|
14302
14636
|
return webDir;
|
|
14303
14637
|
}
|
|
14304
|
-
const altWebDir =
|
|
14305
|
-
if (
|
|
14638
|
+
const altWebDir = resolve12(currentDir, "..", "..", "web");
|
|
14639
|
+
if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
|
|
14306
14640
|
return altWebDir;
|
|
14307
14641
|
}
|
|
14308
14642
|
return null;
|
|
@@ -14325,18 +14659,18 @@ async function isSparkcoderWebRunning(port) {
|
|
|
14325
14659
|
}
|
|
14326
14660
|
}
|
|
14327
14661
|
function isPortInUse(port) {
|
|
14328
|
-
return new Promise((
|
|
14662
|
+
return new Promise((resolve13) => {
|
|
14329
14663
|
const server = createNetServer();
|
|
14330
14664
|
server.once("error", (err) => {
|
|
14331
14665
|
if (err.code === "EADDRINUSE") {
|
|
14332
|
-
|
|
14666
|
+
resolve13(true);
|
|
14333
14667
|
} else {
|
|
14334
|
-
|
|
14668
|
+
resolve13(false);
|
|
14335
14669
|
}
|
|
14336
14670
|
});
|
|
14337
14671
|
server.once("listening", () => {
|
|
14338
14672
|
server.close();
|
|
14339
|
-
|
|
14673
|
+
resolve13(false);
|
|
14340
14674
|
});
|
|
14341
14675
|
server.listen(port, "0.0.0.0");
|
|
14342
14676
|
});
|
|
@@ -14360,30 +14694,30 @@ async function findWebPort(preferredPort) {
|
|
|
14360
14694
|
return { port: preferredPort, alreadyRunning: false };
|
|
14361
14695
|
}
|
|
14362
14696
|
function hasProductionBuild(webDir) {
|
|
14363
|
-
const buildIdPath =
|
|
14364
|
-
return
|
|
14697
|
+
const buildIdPath = join16(webDir, ".next", "BUILD_ID");
|
|
14698
|
+
return existsSync21(buildIdPath);
|
|
14365
14699
|
}
|
|
14366
14700
|
function hasSourceFiles(webDir) {
|
|
14367
|
-
const appDir =
|
|
14368
|
-
const pagesDir =
|
|
14369
|
-
const rootAppDir =
|
|
14370
|
-
const rootPagesDir =
|
|
14371
|
-
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);
|
|
14372
14706
|
}
|
|
14373
14707
|
function getStandaloneServerPath(webDir) {
|
|
14374
14708
|
const possiblePaths2 = [
|
|
14375
|
-
|
|
14376
|
-
|
|
14709
|
+
join16(webDir, ".next", "standalone", "server.js"),
|
|
14710
|
+
join16(webDir, ".next", "standalone", "web", "server.js")
|
|
14377
14711
|
];
|
|
14378
14712
|
for (const serverPath of possiblePaths2) {
|
|
14379
|
-
if (
|
|
14713
|
+
if (existsSync21(serverPath)) {
|
|
14380
14714
|
return serverPath;
|
|
14381
14715
|
}
|
|
14382
14716
|
}
|
|
14383
14717
|
return null;
|
|
14384
14718
|
}
|
|
14385
14719
|
function runCommand(command, args, cwd, env) {
|
|
14386
|
-
return new Promise((
|
|
14720
|
+
return new Promise((resolve13) => {
|
|
14387
14721
|
const child = spawn2(command, args, {
|
|
14388
14722
|
cwd,
|
|
14389
14723
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -14398,10 +14732,10 @@ function runCommand(command, args, cwd, env) {
|
|
|
14398
14732
|
output += data.toString();
|
|
14399
14733
|
});
|
|
14400
14734
|
child.on("close", (code) => {
|
|
14401
|
-
|
|
14735
|
+
resolve13({ success: code === 0, output });
|
|
14402
14736
|
});
|
|
14403
14737
|
child.on("error", (err) => {
|
|
14404
|
-
|
|
14738
|
+
resolve13({ success: false, output: err.message });
|
|
14405
14739
|
});
|
|
14406
14740
|
});
|
|
14407
14741
|
}
|
|
@@ -14416,13 +14750,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14416
14750
|
if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
|
|
14417
14751
|
return { process: null, port: actualPort };
|
|
14418
14752
|
}
|
|
14419
|
-
const usePnpm =
|
|
14420
|
-
const useNpm = !usePnpm &&
|
|
14753
|
+
const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
|
|
14754
|
+
const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
|
|
14421
14755
|
const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
|
|
14422
14756
|
const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
|
|
14423
14757
|
const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
|
|
14424
14758
|
const runtimeConfig = { apiBaseUrl: apiUrl };
|
|
14425
|
-
const runtimeConfigPath =
|
|
14759
|
+
const runtimeConfigPath = join16(webDir, "runtime-config.json");
|
|
14426
14760
|
try {
|
|
14427
14761
|
writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
|
|
14428
14762
|
if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
|
|
@@ -14444,7 +14778,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14444
14778
|
if (standaloneServerPath) {
|
|
14445
14779
|
command = "node";
|
|
14446
14780
|
args = ["server.js"];
|
|
14447
|
-
cwd =
|
|
14781
|
+
cwd = dirname9(standaloneServerPath);
|
|
14448
14782
|
webEnv.PORT = String(actualPort);
|
|
14449
14783
|
webEnv.HOSTNAME = "0.0.0.0";
|
|
14450
14784
|
if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
|
|
@@ -14485,10 +14819,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14485
14819
|
let started = false;
|
|
14486
14820
|
let exited = false;
|
|
14487
14821
|
let exitCode = null;
|
|
14488
|
-
const startedPromise = new Promise((
|
|
14822
|
+
const startedPromise = new Promise((resolve13) => {
|
|
14489
14823
|
const timeout = setTimeout(() => {
|
|
14490
14824
|
if (!started && !exited) {
|
|
14491
|
-
|
|
14825
|
+
resolve13(false);
|
|
14492
14826
|
}
|
|
14493
14827
|
}, startupTimeout);
|
|
14494
14828
|
child.stdout?.on("data", (data) => {
|
|
@@ -14502,7 +14836,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14502
14836
|
if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
|
|
14503
14837
|
started = true;
|
|
14504
14838
|
clearTimeout(timeout);
|
|
14505
|
-
|
|
14839
|
+
resolve13(true);
|
|
14506
14840
|
}
|
|
14507
14841
|
});
|
|
14508
14842
|
child.stderr?.on("data", (data) => {
|
|
@@ -14514,14 +14848,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
|
|
|
14514
14848
|
child.on("error", (err) => {
|
|
14515
14849
|
if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
|
|
14516
14850
|
clearTimeout(timeout);
|
|
14517
|
-
|
|
14851
|
+
resolve13(false);
|
|
14518
14852
|
});
|
|
14519
14853
|
child.on("exit", (code) => {
|
|
14520
14854
|
exited = true;
|
|
14521
14855
|
exitCode = code;
|
|
14522
14856
|
if (!started) {
|
|
14523
14857
|
clearTimeout(timeout);
|
|
14524
|
-
|
|
14858
|
+
resolve13(false);
|
|
14525
14859
|
}
|
|
14526
14860
|
webUIProcess = null;
|
|
14527
14861
|
});
|
|
@@ -14544,7 +14878,7 @@ function stopWebUI() {
|
|
|
14544
14878
|
}
|
|
14545
14879
|
}
|
|
14546
14880
|
async function createApp(options = {}) {
|
|
14547
|
-
const app = new
|
|
14881
|
+
const app = new Hono10();
|
|
14548
14882
|
app.use("*", cors({
|
|
14549
14883
|
origin: "*",
|
|
14550
14884
|
// Allow all origins
|
|
@@ -14572,6 +14906,7 @@ async function createApp(options = {}) {
|
|
|
14572
14906
|
app.route("/api/schedules", schedulesRouter);
|
|
14573
14907
|
app.route("/api/orchestrator", orchestratorRouter);
|
|
14574
14908
|
app.route("/api/mcp", mcpRouter);
|
|
14909
|
+
app.route("/api/skills", skills);
|
|
14575
14910
|
app.route("/api/webhooks", webhooksRouter);
|
|
14576
14911
|
const config = getConfig();
|
|
14577
14912
|
const webhookToken = config?.webhooks?.token;
|
|
@@ -14637,7 +14972,7 @@ async function startServer(options = {}) {
|
|
|
14637
14972
|
if (options.workingDirectory) {
|
|
14638
14973
|
config.resolvedWorkingDirectory = options.workingDirectory;
|
|
14639
14974
|
}
|
|
14640
|
-
if (!
|
|
14975
|
+
if (!existsSync21(config.resolvedWorkingDirectory)) {
|
|
14641
14976
|
mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
|
|
14642
14977
|
if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
|
|
14643
14978
|
}
|