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
package/dist/index.js CHANGED
@@ -450,6 +450,7 @@ __export(config_exports, {
450
450
  setApiKey: () => setApiKey,
451
451
  setMcpServers: () => setMcpServers,
452
452
  setPublicUrl: () => setPublicUrl,
453
+ setSkillsAdditionalDirectories: () => setSkillsAdditionalDirectories,
453
454
  setSlackConfig: () => setSlackConfig,
454
455
  setWebhookToken: () => setWebhookToken
455
456
  });
@@ -739,6 +740,40 @@ function setWebhookToken(token) {
739
740
  console.warn("[config] failed to persist webhook token:", err?.message || err);
740
741
  }
741
742
  }
743
+ function setSkillsAdditionalDirectories(directories) {
744
+ if (cachedConfig) {
745
+ const cur = cachedConfig.skills || {};
746
+ cachedConfig.skills = { ...cur, additionalDirectories: directories };
747
+ try {
748
+ const discovered = discoverSkillDirectories(cachedConfig.resolvedWorkingDirectory);
749
+ const additionalAbs = directories.map((d) => resolve(cachedConfig.resolvedWorkingDirectory, d)).filter((d) => existsSync(d));
750
+ cachedConfig.discoveredSkills = discovered;
751
+ cachedConfig.resolvedSkillsDirectories = [
752
+ ...discovered.allDirectories,
753
+ ...additionalAbs
754
+ ];
755
+ } catch {
756
+ }
757
+ }
758
+ try {
759
+ const cwdPath = resolve(process.cwd(), "sparkecoder.config.json");
760
+ const target = existsSync(cwdPath) ? cwdPath : join(ensureAppDataDirectory(), "sparkecoder.config.json");
761
+ let raw = {};
762
+ if (existsSync(target)) {
763
+ try {
764
+ raw = JSON.parse(readFileSync(target, "utf-8"));
765
+ } catch {
766
+ raw = {};
767
+ }
768
+ } else {
769
+ raw = createDefaultConfig();
770
+ }
771
+ raw.skills = { ...raw.skills || {}, additionalDirectories: directories };
772
+ writeFileSync(target, JSON.stringify(raw, null, 2));
773
+ } catch (err) {
774
+ console.warn("[config] failed to persist skill directories:", err?.message || err);
775
+ }
776
+ }
742
777
  function setPublicUrl(publicUrl) {
743
778
  if (cachedConfig) {
744
779
  cachedConfig.server = { ...cachedConfig.server ?? {}, publicUrl };
@@ -3030,7 +3065,7 @@ async function createClient(serverId, handle, root) {
3030
3065
  },
3031
3066
  async waitForDiagnostics(filePath, timeoutMs = 5e3) {
3032
3067
  const normalized = normalizePath(filePath);
3033
- return new Promise((resolve12) => {
3068
+ return new Promise((resolve13) => {
3034
3069
  const startTime = Date.now();
3035
3070
  let debounceTimer;
3036
3071
  let resolved = false;
@@ -3049,7 +3084,7 @@ async function createClient(serverId, handle, root) {
3049
3084
  if (resolved) return;
3050
3085
  resolved = true;
3051
3086
  cleanup2();
3052
- resolve12(diagnostics.get(normalized) || []);
3087
+ resolve13(diagnostics.get(normalized) || []);
3053
3088
  };
3054
3089
  const onDiagnostic = () => {
3055
3090
  if (debounceTimer) clearTimeout(debounceTimer);
@@ -3424,7 +3459,7 @@ Working directory: ${options.workingDirectory}`,
3424
3459
  isChunked: true
3425
3460
  });
3426
3461
  if (chunkCount > 1) {
3427
- await new Promise((resolve12) => setTimeout(resolve12, 0));
3462
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
3428
3463
  }
3429
3464
  }
3430
3465
  }
@@ -4043,7 +4078,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
4043
4078
  if (!existsSync10(directory)) {
4044
4079
  return [];
4045
4080
  }
4046
- const skills = [];
4081
+ const skills2 = [];
4047
4082
  const entries = await readdir(directory, { withFileTypes: true });
4048
4083
  for (const entry2 of entries) {
4049
4084
  let filePath;
@@ -4067,7 +4102,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
4067
4102
  if (parsed) {
4068
4103
  const alwaysApply = forceAlwaysApply || parsed.metadata.alwaysApply;
4069
4104
  const loadType = alwaysApply ? "always" : defaultLoadType;
4070
- skills.push({
4105
+ skills2.push({
4071
4106
  name: parsed.metadata.name,
4072
4107
  description: parsed.metadata.description,
4073
4108
  filePath,
@@ -4081,7 +4116,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
4081
4116
  } else {
4082
4117
  const name = getSkillNameFromPath(filePath);
4083
4118
  const firstParagraph = content.split("\n\n")[0]?.slice(0, 200) || "No description";
4084
- skills.push({
4119
+ skills2.push({
4085
4120
  name,
4086
4121
  description: firstParagraph.replace(/^#\s*/, "").trim(),
4087
4122
  filePath,
@@ -4094,7 +4129,7 @@ async function loadSkillsFromDirectory(directory, options = {}) {
4094
4129
  });
4095
4130
  }
4096
4131
  }
4097
- return skills.filter(
4132
+ return skills2.filter(
4098
4133
  (s) => s.platforms.length === 0 || s.platforms.includes(process.platform)
4099
4134
  );
4100
4135
  }
@@ -4102,8 +4137,8 @@ async function loadAllSkills(directories) {
4102
4137
  const allSkills = [];
4103
4138
  const seenNames = /* @__PURE__ */ new Set();
4104
4139
  for (const dir of directories) {
4105
- const skills = await loadSkillsFromDirectory(dir);
4106
- for (const skill of skills) {
4140
+ const skills2 = await loadSkillsFromDirectory(dir);
4141
+ for (const skill of skills2) {
4107
4142
  if (!seenNames.has(skill.name.toLowerCase())) {
4108
4143
  seenNames.add(skill.name.toLowerCase());
4109
4144
  allSkills.push(skill);
@@ -4116,12 +4151,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
4116
4151
  const allSkills = [];
4117
4152
  const seenNames = /* @__PURE__ */ new Set();
4118
4153
  for (const { path, priority } of discovered.alwaysLoadedDirs) {
4119
- const skills = await loadSkillsFromDirectory(path, {
4154
+ const skills2 = await loadSkillsFromDirectory(path, {
4120
4155
  priority,
4121
4156
  defaultLoadType: "always",
4122
4157
  forceAlwaysApply: true
4123
4158
  });
4124
- for (const skill of skills) {
4159
+ for (const skill of skills2) {
4125
4160
  if (!seenNames.has(skill.name.toLowerCase())) {
4126
4161
  seenNames.add(skill.name.toLowerCase());
4127
4162
  allSkills.push(skill);
@@ -4129,12 +4164,12 @@ async function loadAllSkillsFromDiscovered(discovered) {
4129
4164
  }
4130
4165
  }
4131
4166
  for (const { path, priority } of discovered.onDemandDirs) {
4132
- const skills = await loadSkillsFromDirectory(path, {
4167
+ const skills2 = await loadSkillsFromDirectory(path, {
4133
4168
  priority,
4134
4169
  defaultLoadType: "on_demand",
4135
4170
  forceAlwaysApply: false
4136
4171
  });
4137
- for (const skill of skills) {
4172
+ for (const skill of skills2) {
4138
4173
  if (!seenNames.has(skill.name.toLowerCase())) {
4139
4174
  seenNames.add(skill.name.toLowerCase());
4140
4175
  allSkills.push(skill);
@@ -4159,7 +4194,7 @@ async function loadAllSkillsFromDiscovered(discovered) {
4159
4194
  all: allSkills
4160
4195
  };
4161
4196
  }
4162
- async function getGlobMatchedSkills(skills, activeFiles, workingDirectory) {
4197
+ async function getGlobMatchedSkills(skills2, activeFiles, workingDirectory) {
4163
4198
  if (activeFiles.length === 0) {
4164
4199
  return [];
4165
4200
  }
@@ -4169,7 +4204,7 @@ async function getGlobMatchedSkills(skills, activeFiles, workingDirectory) {
4169
4204
  }
4170
4205
  return f;
4171
4206
  });
4172
- const matchedSkills = skills.filter((skill) => {
4207
+ const matchedSkills = skills2.filter((skill) => {
4173
4208
  if (skill.alwaysApply || skill.loadType === "always") {
4174
4209
  return false;
4175
4210
  }
@@ -4215,8 +4250,8 @@ async function loadSkillContent(skillName, directories) {
4215
4250
  content: parsed ? parsed.body : content
4216
4251
  };
4217
4252
  }
4218
- function formatSkillsForContext(skills) {
4219
- const onDemandSkills = skills.filter((s) => !s.alwaysApply && s.loadType !== "always");
4253
+ function formatSkillsForContext(skills2) {
4254
+ const onDemandSkills = skills2.filter((s) => !s.alwaysApply && s.loadType !== "always");
4220
4255
  if (onDemandSkills.length === 0) {
4221
4256
  return "No on-demand skills available.";
4222
4257
  }
@@ -4227,12 +4262,12 @@ function formatSkillsForContext(skills) {
4227
4262
  }
4228
4263
  return lines.join("\n");
4229
4264
  }
4230
- function formatAlwaysLoadedSkills(skills) {
4231
- if (skills.length === 0) {
4265
+ function formatAlwaysLoadedSkills(skills2) {
4266
+ if (skills2.length === 0) {
4232
4267
  return "";
4233
4268
  }
4234
4269
  const sections = [];
4235
- for (const skill of skills) {
4270
+ for (const skill of skills2) {
4236
4271
  sections.push(`### ${skill.name}
4237
4272
 
4238
4273
  ${skill.content}`);
@@ -4241,12 +4276,12 @@ ${skill.content}`);
4241
4276
 
4242
4277
  ${sections.join("\n\n---\n\n")}`;
4243
4278
  }
4244
- function formatGlobMatchedSkills(skills) {
4245
- if (skills.length === 0) {
4279
+ function formatGlobMatchedSkills(skills2) {
4280
+ if (skills2.length === 0) {
4246
4281
  return "";
4247
4282
  }
4248
4283
  const sections = [];
4249
- for (const skill of skills) {
4284
+ for (const skill of skills2) {
4250
4285
  sections.push(`### ${skill.name}
4251
4286
 
4252
4287
  ${skill.content}`);
@@ -4288,16 +4323,16 @@ Once loaded, a skill's content will be available in the conversation context.`,
4288
4323
  try {
4289
4324
  switch (action) {
4290
4325
  case "list": {
4291
- const skills = await loadAllSkills(options.skillsDirectories);
4326
+ const skills2 = await loadAllSkills(options.skillsDirectories);
4292
4327
  return {
4293
4328
  success: true,
4294
4329
  action: "list",
4295
- skillCount: skills.length,
4296
- skills: skills.map((s) => ({
4330
+ skillCount: skills2.length,
4331
+ skills: skills2.map((s) => ({
4297
4332
  name: s.name,
4298
4333
  description: s.description
4299
4334
  })),
4300
- formatted: formatSkillsForContext(skills)
4335
+ formatted: formatSkillsForContext(skills2)
4301
4336
  };
4302
4337
  }
4303
4338
  case "load": {
@@ -4735,8 +4770,8 @@ var init_subagent = __esm({
4735
4770
  if (eventQueue.length > 0) {
4736
4771
  yield eventQueue.shift();
4737
4772
  } else if (!done) {
4738
- const event = await new Promise((resolve12) => {
4739
- resolveNext = resolve12;
4773
+ const event = await new Promise((resolve13) => {
4774
+ resolveNext = resolve13;
4740
4775
  });
4741
4776
  if (event) {
4742
4777
  yield event;
@@ -6512,8 +6547,8 @@ async function buildSystemPrompt(options) {
6512
6547
  }
6513
6548
  } else {
6514
6549
  const { loadAllSkills: loadAllSkills2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
6515
- const skills = await loadAllSkills2(skillsDirectories);
6516
- onDemandSkillsContext = formatSkillsForContext(skills);
6550
+ const skills2 = await loadAllSkills2(skillsDirectories);
6551
+ onDemandSkillsContext = formatSkillsForContext(skills2);
6517
6552
  }
6518
6553
  const todos = await todoQueries.getBySession(sessionId);
6519
6554
  const todosContext = formatTodosForContext(todos);
@@ -8981,11 +9016,11 @@ function waitForTaskQuestionAnswer(question) {
8981
9016
  if (pendingQuestions.has(k)) {
8982
9017
  return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
8983
9018
  }
8984
- return new Promise((resolve12, reject) => {
9019
+ return new Promise((resolve13, reject) => {
8985
9020
  pendingQuestions.set(k, {
8986
9021
  ...question,
8987
9022
  createdAt: /* @__PURE__ */ new Date(),
8988
- resolve: resolve12,
9023
+ resolve: resolve13,
8989
9024
  reject
8990
9025
  });
8991
9026
  });
@@ -10134,14 +10169,14 @@ ${p.text}` : p.text;
10134
10169
  const result = await recorder.encode();
10135
10170
  recorder.clear();
10136
10171
  if (!result) return [];
10137
- const { readFile: readFile12, unlink: unlink3 } = await import("fs/promises");
10172
+ const { readFile: readFile13, unlink: unlink4 } = await import("fs/promises");
10138
10173
  const uploadInfo = await storageQueries2.getUploadUrl(
10139
10174
  this.session.id,
10140
10175
  `browser-recording-${Date.now()}.mp4`,
10141
10176
  "video/mp4",
10142
10177
  "browser-recording"
10143
10178
  );
10144
- const fileData = await readFile12(result.path);
10179
+ const fileData = await readFile13(result.path);
10145
10180
  await fetch(uploadInfo.uploadUrl, {
10146
10181
  method: "PUT",
10147
10182
  headers: { "Content-Type": "video/mp4" },
@@ -10149,7 +10184,7 @@ ${p.text}` : p.text;
10149
10184
  });
10150
10185
  await storageQueries2.updateFile(uploadInfo.fileId, { sizeBytes: result.sizeBytes });
10151
10186
  const dlInfo = await storageQueries2.getDownloadUrl(uploadInfo.fileId);
10152
- await unlink3(result.path).catch(() => {
10187
+ await unlink4(result.path).catch(() => {
10153
10188
  });
10154
10189
  console.log(`[TASK] Browser recording uploaded (${result.sizeBytes} bytes)`);
10155
10190
  return [dlInfo.downloadUrl];
@@ -10167,13 +10202,13 @@ ${p.text}` : p.text;
10167
10202
  try {
10168
10203
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10169
10204
  if (!isRemoteConfigured2()) return [];
10170
- const { readFile: readFile12 } = await import("fs/promises");
10171
- const { join: join16, basename: basename6 } = await import("path");
10205
+ const { readFile: readFile13 } = await import("fs/promises");
10206
+ const { join: join17, basename: basename7 } = await import("path");
10172
10207
  const urls = [];
10173
10208
  for (const filePath of filePaths) {
10174
10209
  try {
10175
- const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10176
- const fileName = basename6(fullPath);
10210
+ const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10211
+ const fileName = basename7(fullPath);
10177
10212
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10178
10213
  const mimeMap = {
10179
10214
  pdf: "application/pdf",
@@ -10197,7 +10232,7 @@ ${p.text}` : p.text;
10197
10232
  contentType,
10198
10233
  "task-output"
10199
10234
  );
10200
- const fileData = await readFile12(fullPath);
10235
+ const fileData = await readFile13(fullPath);
10201
10236
  await fetch(uploadInfo.uploadUrl, {
10202
10237
  method: "PUT",
10203
10238
  headers: { "Content-Type": contentType },
@@ -10246,8 +10281,8 @@ ${p.text}` : p.text;
10246
10281
  this.pendingApprovals.set(toolCallId, await execution);
10247
10282
  options.onApprovalRequired?.(await execution);
10248
10283
  await sessionQueries.updateStatus(this.session.id, "waiting");
10249
- const approved = await new Promise((resolve12) => {
10250
- approvalResolvers.set(toolCallId, { resolve: resolve12, sessionId: this.session.id });
10284
+ const approved = await new Promise((resolve13) => {
10285
+ approvalResolvers.set(toolCallId, { resolve: resolve13, sessionId: this.session.id });
10251
10286
  });
10252
10287
  const resolverData = approvalResolvers.get(toolCallId);
10253
10288
  approvalResolvers.delete(toolCallId);
@@ -10353,8 +10388,8 @@ async function withSessionLock(sessionId, fn) {
10353
10388
  state2.pending++;
10354
10389
  const prev = state2.tail;
10355
10390
  let release;
10356
- const next = new Promise((resolve12) => {
10357
- release = resolve12;
10391
+ const next = new Promise((resolve13) => {
10392
+ release = resolve13;
10358
10393
  });
10359
10394
  state2.tail = prev.then(() => next);
10360
10395
  await prev;
@@ -10747,12 +10782,12 @@ init_agent();
10747
10782
 
10748
10783
  // src/server/index.ts
10749
10784
  import "dotenv/config";
10750
- import { Hono as Hono9 } from "hono";
10785
+ import { Hono as Hono10 } from "hono";
10751
10786
  import { serve } from "@hono/node-server";
10752
10787
  import { cors } from "hono/cors";
10753
10788
  import { logger } from "hono/logger";
10754
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10755
- import { resolve as resolve11, dirname as dirname8, join as join15 } from "path";
10789
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10790
+ import { resolve as resolve12, dirname as dirname9, join as join16 } from "path";
10756
10791
  import { spawn as spawn2 } from "child_process";
10757
10792
  import { createServer as createNetServer } from "net";
10758
10793
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11927,7 +11962,7 @@ async function emitSyntheticToolStreaming(writeSSE, toolCallStarts, toolCallId,
11927
11962
  toolCallId,
11928
11963
  argsTextDelta: chunk
11929
11964
  }));
11930
- await new Promise((resolve12) => setTimeout(resolve12, 0));
11965
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
11931
11966
  }
11932
11967
  }
11933
11968
  function buildDevtoolsContextXml(sessionId) {
@@ -12182,7 +12217,7 @@ ${prompt}` });
12182
12217
  chunkIndex,
12183
12218
  chunkCount
12184
12219
  }));
12185
- await new Promise((resolve12) => setTimeout(resolve12, 0));
12220
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
12186
12221
  }
12187
12222
  const browserPort = progress.data?.browserStreamPort;
12188
12223
  const browserClosed = progress.data?.browserClosed;
@@ -12729,7 +12764,7 @@ agents.post(
12729
12764
  chunkIndex,
12730
12765
  chunkCount
12731
12766
  }));
12732
- await new Promise((resolve12) => setTimeout(resolve12, 0));
12767
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
12733
12768
  }
12734
12769
  const browserPort = progress.data?.browserStreamPort;
12735
12770
  const browserClosed = progress.data?.browserClosed;
@@ -14237,6 +14272,224 @@ mcpRouter.post("/:id/test", async (c) => {
14237
14272
  return c.json(result);
14238
14273
  });
14239
14274
 
14275
+ // src/server/routes/skills.ts
14276
+ init_config();
14277
+ init_skills();
14278
+ import { Hono as Hono9 } from "hono";
14279
+ import { zValidator as zValidator7 } from "@hono/zod-validator";
14280
+ import { z as z22 } from "zod";
14281
+ import { existsSync as existsSync20, statSync as statSync3 } from "fs";
14282
+ import { readFile as readFile12, writeFile as writeFile6, unlink as unlink3, mkdir as mkdir5 } from "fs/promises";
14283
+ import { resolve as resolve11, join as join15, basename as basename6, dirname as dirname8, extname as extname9 } from "path";
14284
+ var skills = new Hono9();
14285
+ function encodeId(filePath) {
14286
+ return Buffer.from(filePath, "utf-8").toString("base64url");
14287
+ }
14288
+ function decodeId(id) {
14289
+ try {
14290
+ const decoded = Buffer.from(id, "base64url").toString("utf-8");
14291
+ return decoded || null;
14292
+ } catch {
14293
+ return null;
14294
+ }
14295
+ }
14296
+ function listAllDirectories() {
14297
+ const cfg = getConfig();
14298
+ const discovered = discoverSkillDirectories(cfg.resolvedWorkingDirectory);
14299
+ const out = [];
14300
+ for (const { path, priority } of discovered.alwaysLoadedDirs) {
14301
+ out.push({
14302
+ path,
14303
+ source: pathToSource(path),
14304
+ label: pathToLabel(path),
14305
+ priority,
14306
+ alwaysApply: true
14307
+ });
14308
+ }
14309
+ for (const { path, priority } of discovered.onDemandDirs) {
14310
+ out.push({
14311
+ path,
14312
+ source: pathToSource(path),
14313
+ label: pathToLabel(path),
14314
+ priority,
14315
+ alwaysApply: false
14316
+ });
14317
+ }
14318
+ const additional = cfg.skills?.additionalDirectories || [];
14319
+ for (const dir of additional) {
14320
+ const abs = resolve11(cfg.resolvedWorkingDirectory, dir);
14321
+ if (out.some((d) => d.path === abs)) continue;
14322
+ out.push({
14323
+ path: abs,
14324
+ source: "additional",
14325
+ label: pathToLabel(abs),
14326
+ priority: 50,
14327
+ alwaysApply: false
14328
+ });
14329
+ }
14330
+ return out;
14331
+ }
14332
+ function pathToSource(path) {
14333
+ if (path.includes("/skills/default") || path.endsWith("/skills/default")) return "builtin";
14334
+ return "project";
14335
+ }
14336
+ function pathToLabel(path) {
14337
+ if (path.includes("/skills/default")) return "Built-in (default)";
14338
+ if (path.includes("/.sparkecoder/rules")) return ".sparkecoder/rules";
14339
+ if (path.includes("/.sparkecoder/skills")) return ".sparkecoder/skills";
14340
+ if (path.includes("/.cursor/rules")) return ".cursor/rules";
14341
+ if (path.includes("/.claude/skills")) return ".claude/skills";
14342
+ return basename6(dirname8(path)) + "/" + basename6(path);
14343
+ }
14344
+ skills.get("/", async (c) => {
14345
+ const dirs = listAllDirectories();
14346
+ const allSkills = [];
14347
+ for (const dir of dirs) {
14348
+ if (!existsSync20(dir.path)) continue;
14349
+ try {
14350
+ const list = await loadSkillsFromDirectory(dir.path, {
14351
+ priority: dir.priority,
14352
+ defaultLoadType: dir.alwaysApply ? "always" : "on_demand",
14353
+ forceAlwaysApply: dir.alwaysApply
14354
+ });
14355
+ for (const s of list) {
14356
+ let size = 0;
14357
+ try {
14358
+ size = statSync3(s.filePath).size;
14359
+ } catch {
14360
+ }
14361
+ allSkills.push({
14362
+ id: encodeId(s.filePath),
14363
+ name: s.name,
14364
+ description: s.description,
14365
+ filePath: s.filePath,
14366
+ fileName: basename6(s.filePath),
14367
+ sourceDir: dir.path,
14368
+ sourceLabel: dir.label,
14369
+ sourceType: dir.source,
14370
+ alwaysApply: s.alwaysApply,
14371
+ globs: s.globs,
14372
+ sizeBytes: size
14373
+ });
14374
+ }
14375
+ } catch (err) {
14376
+ console.warn("[skills] failed to read", dir.path, err?.message || err);
14377
+ }
14378
+ }
14379
+ return c.json({
14380
+ directories: dirs.map((d) => ({
14381
+ path: d.path,
14382
+ label: d.label,
14383
+ source: d.source,
14384
+ alwaysApply: d.alwaysApply,
14385
+ exists: existsSync20(d.path),
14386
+ writable: isWritable(d.path)
14387
+ })),
14388
+ skills: allSkills
14389
+ });
14390
+ });
14391
+ function isWritable(dir) {
14392
+ try {
14393
+ if (!existsSync20(dir)) return false;
14394
+ if (dir.includes("/skills/default")) return false;
14395
+ return true;
14396
+ } catch {
14397
+ return false;
14398
+ }
14399
+ }
14400
+ skills.get("/:id", async (c) => {
14401
+ const filePath = decodeId(c.req.param("id"));
14402
+ if (!filePath || !existsSync20(filePath)) {
14403
+ return c.json({ error: "skill not found" }, 404);
14404
+ }
14405
+ const content = await readFile12(filePath, "utf-8");
14406
+ return c.json({
14407
+ id: c.req.param("id"),
14408
+ filePath,
14409
+ fileName: basename6(filePath),
14410
+ content,
14411
+ writable: !filePath.includes("/skills/default")
14412
+ });
14413
+ });
14414
+ skills.post(
14415
+ "/",
14416
+ zValidator7("json", z22.object({
14417
+ directory: z22.string().min(1),
14418
+ fileName: z22.string().min(1),
14419
+ content: z22.string()
14420
+ })),
14421
+ async (c) => {
14422
+ const { directory, fileName, content } = c.req.valid("json");
14423
+ const cfg = getConfig();
14424
+ const targetDir = resolve11(cfg.resolvedWorkingDirectory, directory);
14425
+ if (targetDir.includes("/skills/default")) {
14426
+ return c.json({ error: "cannot write into built-in skills directory" }, 400);
14427
+ }
14428
+ const safeName = basename6(fileName).replace(/[^A-Za-z0-9._-]/g, "-");
14429
+ const ext = extname9(safeName).toLowerCase();
14430
+ const finalName = ext === ".md" || ext === ".mdc" ? safeName : `${safeName}.md`;
14431
+ const filePath = join15(targetDir, finalName);
14432
+ if (existsSync20(filePath)) {
14433
+ return c.json({ error: `file already exists: ${finalName}` }, 409);
14434
+ }
14435
+ try {
14436
+ await mkdir5(targetDir, { recursive: true });
14437
+ await writeFile6(filePath, content, "utf-8");
14438
+ } catch (err) {
14439
+ return c.json({ error: err?.message || "write failed" }, 500);
14440
+ }
14441
+ return c.json({ id: encodeId(filePath), filePath, fileName: finalName }, 201);
14442
+ }
14443
+ );
14444
+ skills.put(
14445
+ "/:id",
14446
+ zValidator7("json", z22.object({ content: z22.string() })),
14447
+ async (c) => {
14448
+ const filePath = decodeId(c.req.param("id"));
14449
+ if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
14450
+ if (filePath.includes("/skills/default")) {
14451
+ return c.json({ error: "built-in skills are read-only" }, 400);
14452
+ }
14453
+ await writeFile6(filePath, c.req.valid("json").content, "utf-8");
14454
+ return c.json({ ok: true });
14455
+ }
14456
+ );
14457
+ skills.delete("/:id", async (c) => {
14458
+ const filePath = decodeId(c.req.param("id"));
14459
+ if (!filePath || !existsSync20(filePath)) return c.json({ error: "skill not found" }, 404);
14460
+ if (filePath.includes("/skills/default")) {
14461
+ return c.json({ error: "built-in skills are read-only" }, 400);
14462
+ }
14463
+ await unlink3(filePath);
14464
+ return c.json({ ok: true });
14465
+ });
14466
+ skills.post(
14467
+ "/directories",
14468
+ zValidator7("json", z22.object({ path: z22.string().min(1) })),
14469
+ (c) => {
14470
+ const cfg = getConfig();
14471
+ const inputPath = c.req.valid("json").path.trim();
14472
+ const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
14473
+ const current = cfg.skills?.additionalDirectories || [];
14474
+ if (current.some((d) => resolve11(cfg.resolvedWorkingDirectory, d) === abs)) {
14475
+ return c.json({ error: "directory already added" }, 409);
14476
+ }
14477
+ const next = [...current, abs];
14478
+ setSkillsAdditionalDirectories(next);
14479
+ return c.json({ ok: true, path: abs, exists: existsSync20(abs) }, 201);
14480
+ }
14481
+ );
14482
+ skills.delete("/directories", (c) => {
14483
+ const inputPath = c.req.query("path");
14484
+ if (!inputPath) return c.json({ error: "path query param required" }, 400);
14485
+ const cfg = getConfig();
14486
+ const abs = resolve11(cfg.resolvedWorkingDirectory, inputPath);
14487
+ const current = cfg.skills?.additionalDirectories || [];
14488
+ const next = current.filter((d) => resolve11(cfg.resolvedWorkingDirectory, d) !== abs);
14489
+ setSkillsAdditionalDirectories(next);
14490
+ return c.json({ ok: true });
14491
+ });
14492
+
14240
14493
  // src/server/auth/cf-access.ts
14241
14494
  init_config();
14242
14495
  import { createRemoteJWKSet, jwtVerify } from "jose";
@@ -14397,13 +14650,13 @@ var DEFAULT_WEB_PORT = 6969;
14397
14650
  var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
14398
14651
  function getWebDirectory() {
14399
14652
  try {
14400
- const currentDir = dirname8(fileURLToPath4(import.meta.url));
14401
- const webDir = resolve11(currentDir, "..", "web");
14402
- if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14653
+ const currentDir = dirname9(fileURLToPath4(import.meta.url));
14654
+ const webDir = resolve12(currentDir, "..", "web");
14655
+ if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14403
14656
  return webDir;
14404
14657
  }
14405
- const altWebDir = resolve11(currentDir, "..", "..", "web");
14406
- if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14658
+ const altWebDir = resolve12(currentDir, "..", "..", "web");
14659
+ if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14407
14660
  return altWebDir;
14408
14661
  }
14409
14662
  return null;
@@ -14426,18 +14679,18 @@ async function isSparkcoderWebRunning(port) {
14426
14679
  }
14427
14680
  }
14428
14681
  function isPortInUse(port) {
14429
- return new Promise((resolve12) => {
14682
+ return new Promise((resolve13) => {
14430
14683
  const server = createNetServer();
14431
14684
  server.once("error", (err) => {
14432
14685
  if (err.code === "EADDRINUSE") {
14433
- resolve12(true);
14686
+ resolve13(true);
14434
14687
  } else {
14435
- resolve12(false);
14688
+ resolve13(false);
14436
14689
  }
14437
14690
  });
14438
14691
  server.once("listening", () => {
14439
14692
  server.close();
14440
- resolve12(false);
14693
+ resolve13(false);
14441
14694
  });
14442
14695
  server.listen(port, "0.0.0.0");
14443
14696
  });
@@ -14461,30 +14714,30 @@ async function findWebPort(preferredPort) {
14461
14714
  return { port: preferredPort, alreadyRunning: false };
14462
14715
  }
14463
14716
  function hasProductionBuild(webDir) {
14464
- const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14465
- return existsSync20(buildIdPath);
14717
+ const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14718
+ return existsSync21(buildIdPath);
14466
14719
  }
14467
14720
  function hasSourceFiles(webDir) {
14468
- const appDir = join15(webDir, "src", "app");
14469
- const pagesDir = join15(webDir, "src", "pages");
14470
- const rootAppDir = join15(webDir, "app");
14471
- const rootPagesDir = join15(webDir, "pages");
14472
- return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14721
+ const appDir = join16(webDir, "src", "app");
14722
+ const pagesDir = join16(webDir, "src", "pages");
14723
+ const rootAppDir = join16(webDir, "app");
14724
+ const rootPagesDir = join16(webDir, "pages");
14725
+ return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
14473
14726
  }
14474
14727
  function getStandaloneServerPath(webDir) {
14475
14728
  const possiblePaths2 = [
14476
- join15(webDir, ".next", "standalone", "server.js"),
14477
- join15(webDir, ".next", "standalone", "web", "server.js")
14729
+ join16(webDir, ".next", "standalone", "server.js"),
14730
+ join16(webDir, ".next", "standalone", "web", "server.js")
14478
14731
  ];
14479
14732
  for (const serverPath of possiblePaths2) {
14480
- if (existsSync20(serverPath)) {
14733
+ if (existsSync21(serverPath)) {
14481
14734
  return serverPath;
14482
14735
  }
14483
14736
  }
14484
14737
  return null;
14485
14738
  }
14486
14739
  function runCommand(command, args, cwd, env) {
14487
- return new Promise((resolve12) => {
14740
+ return new Promise((resolve13) => {
14488
14741
  const child = spawn2(command, args, {
14489
14742
  cwd,
14490
14743
  stdio: ["ignore", "pipe", "pipe"],
@@ -14499,10 +14752,10 @@ function runCommand(command, args, cwd, env) {
14499
14752
  output += data.toString();
14500
14753
  });
14501
14754
  child.on("close", (code) => {
14502
- resolve12({ success: code === 0, output });
14755
+ resolve13({ success: code === 0, output });
14503
14756
  });
14504
14757
  child.on("error", (err) => {
14505
- resolve12({ success: false, output: err.message });
14758
+ resolve13({ success: false, output: err.message });
14506
14759
  });
14507
14760
  });
14508
14761
  }
@@ -14517,13 +14770,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14517
14770
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14518
14771
  return { process: null, port: actualPort };
14519
14772
  }
14520
- const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14521
- const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14773
+ const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14774
+ const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14522
14775
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14523
14776
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14524
14777
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14525
14778
  const runtimeConfig = { apiBaseUrl: apiUrl };
14526
- const runtimeConfigPath = join15(webDir, "runtime-config.json");
14779
+ const runtimeConfigPath = join16(webDir, "runtime-config.json");
14527
14780
  try {
14528
14781
  writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14529
14782
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
@@ -14545,7 +14798,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14545
14798
  if (standaloneServerPath) {
14546
14799
  command = "node";
14547
14800
  args = ["server.js"];
14548
- cwd = dirname8(standaloneServerPath);
14801
+ cwd = dirname9(standaloneServerPath);
14549
14802
  webEnv.PORT = String(actualPort);
14550
14803
  webEnv.HOSTNAME = "0.0.0.0";
14551
14804
  if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
@@ -14586,10 +14839,10 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14586
14839
  let started = false;
14587
14840
  let exited = false;
14588
14841
  let exitCode = null;
14589
- const startedPromise = new Promise((resolve12) => {
14842
+ const startedPromise = new Promise((resolve13) => {
14590
14843
  const timeout = setTimeout(() => {
14591
14844
  if (!started && !exited) {
14592
- resolve12(false);
14845
+ resolve13(false);
14593
14846
  }
14594
14847
  }, startupTimeout);
14595
14848
  child.stdout?.on("data", (data) => {
@@ -14603,7 +14856,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14603
14856
  if (!started && (output.includes("Ready") || output.includes("started") || output.includes("localhost"))) {
14604
14857
  started = true;
14605
14858
  clearTimeout(timeout);
14606
- resolve12(true);
14859
+ resolve13(true);
14607
14860
  }
14608
14861
  });
14609
14862
  child.stderr?.on("data", (data) => {
@@ -14615,14 +14868,14 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14615
14868
  child.on("error", (err) => {
14616
14869
  if (!quiet) console.error(` \u274C Web UI spawn error: ${err.message}`);
14617
14870
  clearTimeout(timeout);
14618
- resolve12(false);
14871
+ resolve13(false);
14619
14872
  });
14620
14873
  child.on("exit", (code) => {
14621
14874
  exited = true;
14622
14875
  exitCode = code;
14623
14876
  if (!started) {
14624
14877
  clearTimeout(timeout);
14625
- resolve12(false);
14878
+ resolve13(false);
14626
14879
  }
14627
14880
  webUIProcess = null;
14628
14881
  });
@@ -14645,7 +14898,7 @@ function stopWebUI() {
14645
14898
  }
14646
14899
  }
14647
14900
  async function createApp(options = {}) {
14648
- const app = new Hono9();
14901
+ const app = new Hono10();
14649
14902
  app.use("*", cors({
14650
14903
  origin: "*",
14651
14904
  // Allow all origins
@@ -14673,6 +14926,7 @@ async function createApp(options = {}) {
14673
14926
  app.route("/api/schedules", schedulesRouter);
14674
14927
  app.route("/api/orchestrator", orchestratorRouter);
14675
14928
  app.route("/api/mcp", mcpRouter);
14929
+ app.route("/api/skills", skills);
14676
14930
  app.route("/api/webhooks", webhooksRouter);
14677
14931
  const config = getConfig();
14678
14932
  const webhookToken = config?.webhooks?.token;
@@ -14738,7 +14992,7 @@ async function startServer(options = {}) {
14738
14992
  if (options.workingDirectory) {
14739
14993
  config.resolvedWorkingDirectory = options.workingDirectory;
14740
14994
  }
14741
- if (!existsSync20(config.resolvedWorkingDirectory)) {
14995
+ if (!existsSync21(config.resolvedWorkingDirectory)) {
14742
14996
  mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
14743
14997
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
14744
14998
  }