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.
Files changed (147) hide show
  1. package/dist/agent/index.js.map +1 -1
  2. package/dist/cli.js +379 -125
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +338 -84
  5. package/dist/index.js.map +1 -1
  6. package/dist/server/index.js +338 -84
  7. package/dist/server/index.js.map +1 -1
  8. package/dist/tools/index.js.map +1 -1
  9. package/package.json +1 -1
  10. package/web/.next/BUILD_ID +1 -1
  11. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  12. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  13. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  14. package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
  15. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  16. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  17. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  18. package/web/.next/standalone/web/.next/server/app/(main)/settings/page.js.nft.json +1 -1
  19. package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  21. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  36. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.rsc +2 -2
  38. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +2 -2
  42. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +2 -2
  44. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
  45. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  77. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  82. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  85. package/web/.next/standalone/web/.next/server/app/index.rsc +2 -2
  86. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +2 -2
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  91. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  92. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
  94. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
  95. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  97. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  98. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  100. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  101. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_6ab1f7b7._.js +3 -0
  102. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__f3e6443f._.js → [root-of-the-server]__4de426bd._.js} +2 -2
  103. package/web/.next/standalone/web/.next/server/chunks/ssr/web_62ca4286._.js +3 -0
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_settings_page_tsx_eb320e07._.js +3 -1
  105. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  106. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  107. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  108. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  109. package/web/.next/standalone/web/.next/static/chunks/74ae1f17d607b2fc.js +7 -0
  110. package/web/.next/standalone/web/.next/static/chunks/883ea0d08f88e366.js +1 -0
  111. package/web/.next/standalone/web/.next/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
  112. package/web/.next/standalone/web/.next/static/chunks/9b88f148788e4504.js +3 -0
  113. package/web/.next/standalone/web/.next/static/chunks/acb0fc66f5414af6.css +1 -0
  114. package/web/.next/standalone/web/.next/static/static/chunks/74ae1f17d607b2fc.js +7 -0
  115. package/web/.next/standalone/web/.next/static/static/chunks/883ea0d08f88e366.js +1 -0
  116. package/web/.next/standalone/web/.next/static/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
  117. package/web/.next/standalone/web/.next/static/static/chunks/9b88f148788e4504.js +3 -0
  118. package/web/.next/standalone/web/.next/static/static/chunks/acb0fc66f5414af6.css +1 -0
  119. package/web/.next/standalone/web/src/app/(main)/settings/page.tsx +464 -1
  120. package/web/.next/static/chunks/74ae1f17d607b2fc.js +7 -0
  121. package/web/.next/static/chunks/883ea0d08f88e366.js +1 -0
  122. package/web/.next/static/chunks/{44c575e006ddb992.js → 91988e253d5fa420.js} +4 -4
  123. package/web/.next/static/chunks/9b88f148788e4504.js +3 -0
  124. package/web/.next/static/chunks/acb0fc66f5414af6.css +1 -0
  125. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_7340c8b3._.js +0 -3
  126. package/web/.next/standalone/web/.next/server/chunks/ssr/web_41927ef5._.js +0 -3
  127. package/web/.next/standalone/web/.next/static/chunks/2c3c1d478808e4e4.js +0 -1
  128. package/web/.next/standalone/web/.next/static/chunks/3b0501ec3249235f.js +0 -7
  129. package/web/.next/standalone/web/.next/static/chunks/9a3afb48c245fb2a.js +0 -1
  130. package/web/.next/standalone/web/.next/static/chunks/b3bc7244f3477729.css +0 -1
  131. package/web/.next/standalone/web/.next/static/static/chunks/2c3c1d478808e4e4.js +0 -1
  132. package/web/.next/standalone/web/.next/static/static/chunks/3b0501ec3249235f.js +0 -7
  133. package/web/.next/standalone/web/.next/static/static/chunks/9a3afb48c245fb2a.js +0 -1
  134. package/web/.next/standalone/web/.next/static/static/chunks/b3bc7244f3477729.css +0 -1
  135. package/web/.next/static/chunks/2c3c1d478808e4e4.js +0 -1
  136. package/web/.next/static/chunks/3b0501ec3249235f.js +0 -7
  137. package/web/.next/static/chunks/9a3afb48c245fb2a.js +0 -1
  138. package/web/.next/static/chunks/b3bc7244f3477729.css +0 -1
  139. /package/web/.next/standalone/web/.next/static/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
  140. /package/web/.next/standalone/web/.next/static/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
  141. /package/web/.next/standalone/web/.next/static/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
  142. /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
  143. /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
  144. /package/web/.next/standalone/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
  145. /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_buildManifest.js +0 -0
  146. /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_clientMiddlewareManifest.json +0 -0
  147. /package/web/.next/static/{uy1OnyxIm3QeGGgKEmxAj → wP9z41wtqT4k-O6AlEXqw}/_ssgManifest.js +0 -0
@@ -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((resolve12) => {
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
- resolve12(diagnostics.get(normalized) || []);
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((resolve12) => setTimeout(resolve12, 0));
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 skills = [];
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
- skills.push({
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
- skills.push({
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 skills.filter(
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 skills = await loadSkillsFromDirectory(dir);
4089
- for (const skill of skills) {
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 skills = await loadSkillsFromDirectory(path, {
4137
+ const skills2 = await loadSkillsFromDirectory(path, {
4103
4138
  priority,
4104
4139
  defaultLoadType: "always",
4105
4140
  forceAlwaysApply: true
4106
4141
  });
4107
- for (const skill of skills) {
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 skills = await loadSkillsFromDirectory(path, {
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 skills) {
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(skills, activeFiles, workingDirectory) {
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 = skills.filter((skill) => {
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(skills) {
4202
- const onDemandSkills = skills.filter((s) => !s.alwaysApply && s.loadType !== "always");
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(skills) {
4214
- if (skills.length === 0) {
4248
+ function formatAlwaysLoadedSkills(skills2) {
4249
+ if (skills2.length === 0) {
4215
4250
  return "";
4216
4251
  }
4217
4252
  const sections = [];
4218
- for (const skill of skills) {
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(skills) {
4228
- if (skills.length === 0) {
4262
+ function formatGlobMatchedSkills(skills2) {
4263
+ if (skills2.length === 0) {
4229
4264
  return "";
4230
4265
  }
4231
4266
  const sections = [];
4232
- for (const skill of skills) {
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 skills = await loadAllSkills(options.skillsDirectories);
4309
+ const skills2 = await loadAllSkills(options.skillsDirectories);
4275
4310
  return {
4276
4311
  success: true,
4277
4312
  action: "list",
4278
- skillCount: skills.length,
4279
- skills: skills.map((s) => ({
4313
+ skillCount: skills2.length,
4314
+ skills: skills2.map((s) => ({
4280
4315
  name: s.name,
4281
4316
  description: s.description
4282
4317
  })),
4283
- formatted: formatSkillsForContext(skills)
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((resolve12) => {
4722
- resolveNext = resolve12;
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 skills = await loadAllSkills2(skillsDirectories);
6499
- onDemandSkillsContext = formatSkillsForContext(skills);
6533
+ const skills2 = await loadAllSkills2(skillsDirectories);
6534
+ onDemandSkillsContext = formatSkillsForContext(skills2);
6500
6535
  }
6501
6536
  const todos = await todoQueries.getBySession(sessionId);
6502
6537
  const todosContext = formatTodosForContext(todos);
@@ -8964,11 +8999,11 @@ function waitForTaskQuestionAnswer(question) {
8964
8999
  if (pendingQuestions.has(k)) {
8965
9000
  return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
8966
9001
  }
8967
- return new Promise((resolve12, reject) => {
9002
+ return new Promise((resolve13, reject) => {
8968
9003
  pendingQuestions.set(k, {
8969
9004
  ...question,
8970
9005
  createdAt: /* @__PURE__ */ new Date(),
8971
- resolve: resolve12,
9006
+ resolve: resolve13,
8972
9007
  reject
8973
9008
  });
8974
9009
  });
@@ -10117,14 +10152,14 @@ ${p.text}` : p.text;
10117
10152
  const result = await recorder.encode();
10118
10153
  recorder.clear();
10119
10154
  if (!result) return [];
10120
- const { readFile: readFile12, unlink: unlink3 } = await import("fs/promises");
10155
+ const { readFile: readFile13, unlink: unlink4 } = await import("fs/promises");
10121
10156
  const uploadInfo = await storageQueries2.getUploadUrl(
10122
10157
  this.session.id,
10123
10158
  `browser-recording-${Date.now()}.mp4`,
10124
10159
  "video/mp4",
10125
10160
  "browser-recording"
10126
10161
  );
10127
- const fileData = await readFile12(result.path);
10162
+ const fileData = await readFile13(result.path);
10128
10163
  await fetch(uploadInfo.uploadUrl, {
10129
10164
  method: "PUT",
10130
10165
  headers: { "Content-Type": "video/mp4" },
@@ -10132,7 +10167,7 @@ ${p.text}` : p.text;
10132
10167
  });
10133
10168
  await storageQueries2.updateFile(uploadInfo.fileId, { sizeBytes: result.sizeBytes });
10134
10169
  const dlInfo = await storageQueries2.getDownloadUrl(uploadInfo.fileId);
10135
- await unlink3(result.path).catch(() => {
10170
+ await unlink4(result.path).catch(() => {
10136
10171
  });
10137
10172
  console.log(`[TASK] Browser recording uploaded (${result.sizeBytes} bytes)`);
10138
10173
  return [dlInfo.downloadUrl];
@@ -10150,13 +10185,13 @@ ${p.text}` : p.text;
10150
10185
  try {
10151
10186
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10152
10187
  if (!isRemoteConfigured2()) return [];
10153
- const { readFile: readFile12 } = await import("fs/promises");
10154
- const { join: join16, basename: basename6 } = await import("path");
10188
+ const { readFile: readFile13 } = await import("fs/promises");
10189
+ const { join: join17, basename: basename7 } = await import("path");
10155
10190
  const urls = [];
10156
10191
  for (const filePath of filePaths) {
10157
10192
  try {
10158
- const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10159
- const fileName = basename6(fullPath);
10193
+ const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10194
+ const fileName = basename7(fullPath);
10160
10195
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10161
10196
  const mimeMap = {
10162
10197
  pdf: "application/pdf",
@@ -10180,7 +10215,7 @@ ${p.text}` : p.text;
10180
10215
  contentType,
10181
10216
  "task-output"
10182
10217
  );
10183
- const fileData = await readFile12(fullPath);
10218
+ const fileData = await readFile13(fullPath);
10184
10219
  await fetch(uploadInfo.uploadUrl, {
10185
10220
  method: "PUT",
10186
10221
  headers: { "Content-Type": contentType },
@@ -10229,8 +10264,8 @@ ${p.text}` : p.text;
10229
10264
  this.pendingApprovals.set(toolCallId, await execution);
10230
10265
  options.onApprovalRequired?.(await execution);
10231
10266
  await sessionQueries.updateStatus(this.session.id, "waiting");
10232
- const approved = await new Promise((resolve12) => {
10233
- approvalResolvers.set(toolCallId, { resolve: resolve12, sessionId: this.session.id });
10267
+ const approved = await new Promise((resolve13) => {
10268
+ approvalResolvers.set(toolCallId, { resolve: resolve13, sessionId: this.session.id });
10234
10269
  });
10235
10270
  const resolverData = approvalResolvers.get(toolCallId);
10236
10271
  approvalResolvers.delete(toolCallId);
@@ -10336,8 +10371,8 @@ async function withSessionLock(sessionId, fn) {
10336
10371
  state2.pending++;
10337
10372
  const prev = state2.tail;
10338
10373
  let release;
10339
- const next = new Promise((resolve12) => {
10340
- release = resolve12;
10374
+ const next = new Promise((resolve13) => {
10375
+ release = resolve13;
10341
10376
  });
10342
10377
  state2.tail = prev.then(() => next);
10343
10378
  await prev;
@@ -10727,12 +10762,12 @@ var init_scheduler = __esm({
10727
10762
 
10728
10763
  // src/server/index.ts
10729
10764
  import "dotenv/config";
10730
- import { Hono as Hono9 } from "hono";
10765
+ import { Hono as Hono10 } from "hono";
10731
10766
  import { serve } from "@hono/node-server";
10732
10767
  import { cors } from "hono/cors";
10733
10768
  import { logger } from "hono/logger";
10734
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10735
- import { resolve as resolve11, dirname as dirname8, join as join15 } from "path";
10769
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10770
+ import { resolve as resolve12, dirname as dirname9, join as join16 } from "path";
10736
10771
  import { spawn as spawn2 } from "child_process";
10737
10772
  import { createServer as createNetServer } from "net";
10738
10773
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11907,7 +11942,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
11907
11942
  toolCallId,
11908
11943
  argsTextDelta: chunk
11909
11944
  }));
11910
- await new Promise((resolve12) => setTimeout(resolve12, 0));
11945
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
11911
11946
  }
11912
11947
  }
11913
11948
  function buildDevtoolsContextXml(sessionId) {
@@ -12162,7 +12197,7 @@ ${prompt}` });
12162
12197
  chunkIndex,
12163
12198
  chunkCount
12164
12199
  }));
12165
- await new Promise((resolve12) => setTimeout(resolve12, 0));
12200
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
12166
12201
  }
12167
12202
  const browserPort = progress.data?.browserStreamPort;
12168
12203
  const browserClosed = progress.data?.browserClosed;
@@ -12709,7 +12744,7 @@ agents.post(
12709
12744
  chunkIndex,
12710
12745
  chunkCount
12711
12746
  }));
12712
- await new Promise((resolve12) => setTimeout(resolve12, 0));
12747
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
12713
12748
  }
12714
12749
  const browserPort = progress.data?.browserStreamPort;
12715
12750
  const browserClosed = progress.data?.browserClosed;
@@ -14217,6 +14252,224 @@ mcpRouter.post("/:id/test", async (c) => {
14217
14252
  return c.json(result);
14218
14253
  });
14219
14254
 
14255
+ // src/server/routes/skills.ts
14256
+ init_config();
14257
+ init_skills();
14258
+ import { Hono as Hono9 } from "hono";
14259
+ import { zValidator as zValidator7 } from "@hono/zod-validator";
14260
+ import { z as z22 } from "zod";
14261
+ import { existsSync as existsSync20, statSync as statSync3 } from "fs";
14262
+ import { readFile as readFile12, writeFile as writeFile6, unlink as unlink3, mkdir as mkdir5 } from "fs/promises";
14263
+ import { resolve as resolve11, join as join15, basename as basename6, dirname as dirname8, extname as extname9 } from "path";
14264
+ var skills = new Hono9();
14265
+ function encodeId(filePath) {
14266
+ return Buffer.from(filePath, "utf-8").toString("base64url");
14267
+ }
14268
+ function decodeId(id) {
14269
+ try {
14270
+ const decoded = Buffer.from(id, "base64url").toString("utf-8");
14271
+ return decoded || null;
14272
+ } catch {
14273
+ return null;
14274
+ }
14275
+ }
14276
+ function listAllDirectories() {
14277
+ const cfg = getConfig();
14278
+ const discovered = discoverSkillDirectories(cfg.resolvedWorkingDirectory);
14279
+ const out = [];
14280
+ for (const { path, priority } of discovered.alwaysLoadedDirs) {
14281
+ out.push({
14282
+ path,
14283
+ source: pathToSource(path),
14284
+ label: pathToLabel(path),
14285
+ priority,
14286
+ alwaysApply: true
14287
+ });
14288
+ }
14289
+ for (const { path, priority } of discovered.onDemandDirs) {
14290
+ out.push({
14291
+ path,
14292
+ source: pathToSource(path),
14293
+ label: pathToLabel(path),
14294
+ priority,
14295
+ alwaysApply: false
14296
+ });
14297
+ }
14298
+ const additional = cfg.skills?.additionalDirectories || [];
14299
+ for (const dir of additional) {
14300
+ const abs = resolve11(cfg.resolvedWorkingDirectory, dir);
14301
+ if (out.some((d) => d.path === abs)) continue;
14302
+ out.push({
14303
+ path: abs,
14304
+ source: "additional",
14305
+ label: pathToLabel(abs),
14306
+ priority: 50,
14307
+ alwaysApply: false
14308
+ });
14309
+ }
14310
+ return out;
14311
+ }
14312
+ function pathToSource(path) {
14313
+ if (path.includes("/skills/default") || path.endsWith("/skills/default")) return "builtin";
14314
+ return "project";
14315
+ }
14316
+ function pathToLabel(path) {
14317
+ if (path.includes("/skills/default")) return "Built-in (default)";
14318
+ if (path.includes("/.sparkecoder/rules")) return ".sparkecoder/rules";
14319
+ if (path.includes("/.sparkecoder/skills")) return ".sparkecoder/skills";
14320
+ if (path.includes("/.cursor/rules")) return ".cursor/rules";
14321
+ if (path.includes("/.claude/skills")) return ".claude/skills";
14322
+ return basename6(dirname8(path)) + "/" + basename6(path);
14323
+ }
14324
+ skills.get("/", async (c) => {
14325
+ const dirs = listAllDirectories();
14326
+ const allSkills = [];
14327
+ for (const dir of dirs) {
14328
+ if (!existsSync20(dir.path)) continue;
14329
+ try {
14330
+ const list = await loadSkillsFromDirectory(dir.path, {
14331
+ priority: dir.priority,
14332
+ defaultLoadType: dir.alwaysApply ? "always" : "on_demand",
14333
+ forceAlwaysApply: dir.alwaysApply
14334
+ });
14335
+ for (const s of list) {
14336
+ let size = 0;
14337
+ try {
14338
+ size = statSync3(s.filePath).size;
14339
+ } catch {
14340
+ }
14341
+ allSkills.push({
14342
+ id: encodeId(s.filePath),
14343
+ name: s.name,
14344
+ description: s.description,
14345
+ filePath: s.filePath,
14346
+ fileName: basename6(s.filePath),
14347
+ sourceDir: dir.path,
14348
+ sourceLabel: dir.label,
14349
+ sourceType: dir.source,
14350
+ alwaysApply: s.alwaysApply,
14351
+ globs: s.globs,
14352
+ sizeBytes: size
14353
+ });
14354
+ }
14355
+ } catch (err) {
14356
+ console.warn("[skills] failed to read", dir.path, err?.message || err);
14357
+ }
14358
+ }
14359
+ return c.json({
14360
+ directories: dirs.map((d) => ({
14361
+ path: d.path,
14362
+ label: d.label,
14363
+ source: d.source,
14364
+ alwaysApply: d.alwaysApply,
14365
+ exists: existsSync20(d.path),
14366
+ writable: isWritable(d.path)
14367
+ })),
14368
+ skills: allSkills
14369
+ });
14370
+ });
14371
+ function isWritable(dir) {
14372
+ try {
14373
+ if (!existsSync20(dir)) return false;
14374
+ if (dir.includes("/skills/default")) return false;
14375
+ return true;
14376
+ } catch {
14377
+ return false;
14378
+ }
14379
+ }
14380
+ skills.get("/:id", async (c) => {
14381
+ const filePath = decodeId(c.req.param("id"));
14382
+ if (!filePath || !existsSync20(filePath)) {
14383
+ return c.json({ error: "skill not found" }, 404);
14384
+ }
14385
+ const content = await readFile12(filePath, "utf-8");
14386
+ return c.json({
14387
+ id: c.req.param("id"),
14388
+ filePath,
14389
+ fileName: basename6(filePath),
14390
+ content,
14391
+ writable: !filePath.includes("/skills/default")
14392
+ });
14393
+ });
14394
+ skills.post(
14395
+ "/",
14396
+ zValidator7("json", z22.object({
14397
+ directory: z22.string().min(1),
14398
+ fileName: z22.string().min(1),
14399
+ content: z22.string()
14400
+ })),
14401
+ async (c) => {
14402
+ const { directory, fileName, content } = c.req.valid("json");
14403
+ const cfg = getConfig();
14404
+ const targetDir = resolve11(cfg.resolvedWorkingDirectory, directory);
14405
+ if (targetDir.includes("/skills/default")) {
14406
+ return c.json({ error: "cannot write into built-in skills directory" }, 400);
14407
+ }
14408
+ const safeName = basename6(fileName).replace(/[^A-Za-z0-9._-]/g, "-");
14409
+ const ext = extname9(safeName).toLowerCase();
14410
+ const finalName = ext === ".md" || ext === ".mdc" ? safeName : `${safeName}.md`;
14411
+ const filePath = join15(targetDir, finalName);
14412
+ if (existsSync20(filePath)) {
14413
+ return c.json({ error: `file already exists: ${finalName}` }, 409);
14414
+ }
14415
+ try {
14416
+ await mkdir5(targetDir, { recursive: true });
14417
+ await writeFile6(filePath, content, "utf-8");
14418
+ } catch (err) {
14419
+ return c.json({ error: err?.message || "write failed" }, 500);
14420
+ }
14421
+ return c.json({ id: encodeId(filePath), filePath, fileName: finalName }, 201);
14422
+ }
14423
+ );
14424
+ skills.put(
14425
+ "/:id",
14426
+ zValidator7("json", z22.object({ content: z22.string() })),
14427
+ async (c) => {
14428
+ const filePath = decodeId(c.req.param("id"));
14429
+ if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
14430
+ if (filePath.includes("/skills/default")) {
14431
+ return c.json({ error: "built-in skills are read-only" }, 400);
14432
+ }
14433
+ await writeFile6(filePath, c.req.valid("json").content, "utf-8");
14434
+ return c.json({ ok: true });
14435
+ }
14436
+ );
14437
+ skills.delete("/:id", async (c) => {
14438
+ const filePath = decodeId(c.req.param("id"));
14439
+ if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
14440
+ if (filePath.includes("/skills/default")) {
14441
+ return c.json({ error: "built-in skills are read-only" }, 400);
14442
+ }
14443
+ await unlink3(filePath);
14444
+ return c.json({ ok: true });
14445
+ });
14446
+ skills.post(
14447
+ "/directories",
14448
+ zValidator7("json", z22.object({ path: z22.string().min(1) })),
14449
+ (c) => {
14450
+ const cfg = getConfig();
14451
+ const inputPath = c.req.valid("json").path.trim();
14452
+ const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
14453
+ const current = cfg.skills?.additionalDirectories || [];
14454
+ if (current.some((d) => resolve11(cfg.resolvedWorkingDirectory, d) === abs)) {
14455
+ return c.json({ error: "directory already added" }, 409);
14456
+ }
14457
+ const next = [...current, abs];
14458
+ setSkillsAdditionalDirectories(next);
14459
+ return c.json({ ok: true, path: abs, exists: existsSync20(abs) }, 201);
14460
+ }
14461
+ );
14462
+ skills.delete("/directories", (c) => {
14463
+ const inputPath = c.req.query("path");
14464
+ if (!inputPath) return c.json({ error: "path query param required" }, 400);
14465
+ const cfg = getConfig();
14466
+ const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
14467
+ const current = cfg.skills?.additionalDirectories || [];
14468
+ const next = current.filter((d) => resolve11(cfg.resolvedWorkingDirectory, d) !== abs);
14469
+ setSkillsAdditionalDirectories(next);
14470
+ return c.json({ ok: true });
14471
+ });
14472
+
14220
14473
  // src/server/auth/cf-access.ts
14221
14474
  init_config();
14222
14475
  import { createRemoteJWKSet, jwtVerify } from "jose";
@@ -14377,13 +14630,13 @@ var DEFAULT_WEB_PORT = 6969;
14377
14630
  var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
14378
14631
  function getWebDirectory() {
14379
14632
  try {
14380
- const currentDir = dirname8(fileURLToPath4(import.meta.url));
14381
- const webDir = resolve11(currentDir, "..", "web");
14382
- if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14633
+ const currentDir = dirname9(fileURLToPath4(import.meta.url));
14634
+ const webDir = resolve12(currentDir, "..", "web");
14635
+ if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14383
14636
  return webDir;
14384
14637
  }
14385
- const altWebDir = resolve11(currentDir, "..", "..", "web");
14386
- if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14638
+ const altWebDir = resolve12(currentDir, "..", "..", "web");
14639
+ if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14387
14640
  return altWebDir;
14388
14641
  }
14389
14642
  return null;
@@ -14406,18 +14659,18 @@ async function isSparkcoderWebRunning(port) {
14406
14659
  }
14407
14660
  }
14408
14661
  function isPortInUse(port) {
14409
- return new Promise((resolve12) => {
14662
+ return new Promise((resolve13) => {
14410
14663
  const server = createNetServer();
14411
14664
  server.once("error", (err) => {
14412
14665
  if (err.code === "EADDRINUSE") {
14413
- resolve12(true);
14666
+ resolve13(true);
14414
14667
  } else {
14415
- resolve12(false);
14668
+ resolve13(false);
14416
14669
  }
14417
14670
  });
14418
14671
  server.once("listening", () => {
14419
14672
  server.close();
14420
- resolve12(false);
14673
+ resolve13(false);
14421
14674
  });
14422
14675
  server.listen(port, "0.0.0.0");
14423
14676
  });
@@ -14441,30 +14694,30 @@ async function findWebPort(preferredPort) {
14441
14694
  return { port: preferredPort, alreadyRunning: false };
14442
14695
  }
14443
14696
  function hasProductionBuild(webDir) {
14444
- const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14445
- return existsSync20(buildIdPath);
14697
+ const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14698
+ return existsSync21(buildIdPath);
14446
14699
  }
14447
14700
  function hasSourceFiles(webDir) {
14448
- const appDir = join15(webDir, "src", "app");
14449
- const pagesDir = join15(webDir, "src", "pages");
14450
- const rootAppDir = join15(webDir, "app");
14451
- const rootPagesDir = join15(webDir, "pages");
14452
- return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14701
+ const appDir = join16(webDir, "src", "app");
14702
+ const pagesDir = join16(webDir, "src", "pages");
14703
+ const rootAppDir = join16(webDir, "app");
14704
+ const rootPagesDir = join16(webDir, "pages");
14705
+ return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
14453
14706
  }
14454
14707
  function getStandaloneServerPath(webDir) {
14455
14708
  const possiblePaths2 = [
14456
- join15(webDir, ".next", "standalone", "server.js"),
14457
- join15(webDir, ".next", "standalone", "web", "server.js")
14709
+ join16(webDir, ".next", "standalone", "server.js"),
14710
+ join16(webDir, ".next", "standalone", "web", "server.js")
14458
14711
  ];
14459
14712
  for (const serverPath of possiblePaths2) {
14460
- if (existsSync20(serverPath)) {
14713
+ if (existsSync21(serverPath)) {
14461
14714
  return serverPath;
14462
14715
  }
14463
14716
  }
14464
14717
  return null;
14465
14718
  }
14466
14719
  function runCommand(command, args, cwd, env) {
14467
- return new Promise((resolve12) => {
14720
+ return new Promise((resolve13) => {
14468
14721
  const child = spawn2(command, args, {
14469
14722
  cwd,
14470
14723
  stdio: ["ignore", "pipe", "pipe"],
@@ -14479,10 +14732,10 @@ function runCommand(command, args, cwd, env) {
14479
14732
  output += data.toString();
14480
14733
  });
14481
14734
  child.on("close", (code) => {
14482
- resolve12({ success: code === 0, output });
14735
+ resolve13({ success: code === 0, output });
14483
14736
  });
14484
14737
  child.on("error", (err) => {
14485
- resolve12({ success: false, output: err.message });
14738
+ resolve13({ success: false, output: err.message });
14486
14739
  });
14487
14740
  });
14488
14741
  }
@@ -14497,13 +14750,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14497
14750
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14498
14751
  return { process: null, port: actualPort };
14499
14752
  }
14500
- const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14501
- const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14753
+ const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14754
+ const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14502
14755
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14503
14756
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14504
14757
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14505
14758
  const runtimeConfig = { apiBaseUrl: apiUrl };
14506
- const runtimeConfigPath = join15(webDir, "runtime-config.json");
14759
+ const runtimeConfigPath = join16(webDir, "runtime-config.json");
14507
14760
  try {
14508
14761
  writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14509
14762
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
@@ -14525,7 +14778,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14525
14778
  if (standaloneServerPath) {
14526
14779
  command = "node";
14527
14780
  args = ["server.js"];
14528
- cwd = dirname8(standaloneServerPath);
14781
+ cwd = dirname9(standaloneServerPath);
14529
14782
  webEnv.PORT = String(actualPort);
14530
14783
  webEnv.HOSTNAME = "0.0.0.0";
14531
14784
  if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
@@ -14566,10 +14819,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14566
14819
  let started = false;
14567
14820
  let exited = false;
14568
14821
  let exitCode = null;
14569
- const startedPromise = new Promise((resolve12) => {
14822
+ const startedPromise = new Promise((resolve13) => {
14570
14823
  const timeout = setTimeout(() => {
14571
14824
  if (!started && !exited) {
14572
- resolve12(false);
14825
+ resolve13(false);
14573
14826
  }
14574
14827
  }, startupTimeout);
14575
14828
  child.stdout?.on("data", (data) => {
@@ -14583,7 +14836,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14583
14836
  if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
14584
14837
  started = true;
14585
14838
  clearTimeout(timeout);
14586
- resolve12(true);
14839
+ resolve13(true);
14587
14840
  }
14588
14841
  });
14589
14842
  child.stderr?.on("data", (data) => {
@@ -14595,14 +14848,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14595
14848
  child.on("error", (err) => {
14596
14849
  if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
14597
14850
  clearTimeout(timeout);
14598
- resolve12(false);
14851
+ resolve13(false);
14599
14852
  });
14600
14853
  child.on("exit", (code) => {
14601
14854
  exited = true;
14602
14855
  exitCode = code;
14603
14856
  if (!started) {
14604
14857
  clearTimeout(timeout);
14605
- resolve12(false);
14858
+ resolve13(false);
14606
14859
  }
14607
14860
  webUIProcess = null;
14608
14861
  });
@@ -14625,7 +14878,7 @@ function stopWebUI() {
14625
14878
  }
14626
14879
  }
14627
14880
  async function createApp(options = {}) {
14628
- const app = new Hono9();
14881
+ const app = new Hono10();
14629
14882
  app.use("*", cors({
14630
14883
  origin: "*",
14631
14884
  // Allow all origins
@@ -14653,6 +14906,7 @@ async function createApp(options = {}) {
14653
14906
  app.route("/api/schedules", schedulesRouter);
14654
14907
  app.route("/api/orchestrator", orchestratorRouter);
14655
14908
  app.route("/api/mcp", mcpRouter);
14909
+ app.route("/api/skills", skills);
14656
14910
  app.route("/api/webhooks", webhooksRouter);
14657
14911
  const config = getConfig();
14658
14912
  const webhookToken = config?.webhooks?.token;
@@ -14718,7 +14972,7 @@ async function startServer(options = {}) {
14718
14972
  if (options.workingDirectory) {
14719
14973
  config.resolvedWorkingDirectory = options.workingDirectory;
14720
14974
  }
14721
- if (!existsSync20(config.resolvedWorkingDirectory)) {
14975
+ if (!existsSync21(config.resolvedWorkingDirectory)) {
14722
14976
  mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
14723
14977
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
14724
14978
  }