crewswarm 0.9.2 → 0.9.4

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 (228) hide show
  1. package/README.md +22 -9
  2. package/apps/dashboard/dist/assets/chat-core-uXb_C0GM.js +1 -0
  3. package/apps/dashboard/dist/assets/chat-core-uXb_C0GM.js.br +0 -0
  4. package/apps/dashboard/dist/assets/cli-process-CNZ_UBCt.js +1 -0
  5. package/apps/dashboard/dist/assets/cli-process-CNZ_UBCt.js.br +0 -0
  6. package/apps/dashboard/dist/assets/index-BeVllEj_.js +2 -0
  7. package/apps/dashboard/dist/assets/index-BeVllEj_.js.br +0 -0
  8. package/apps/dashboard/dist/assets/{index-CF0aJRtC.css → index-D-sRshvg.css} +1 -1
  9. package/apps/dashboard/dist/assets/index-D-sRshvg.css.br +0 -0
  10. package/apps/dashboard/dist/assets/tab-benchmarks-tab-BHjKCPm3.js.br +0 -0
  11. package/apps/dashboard/dist/assets/tab-models-tab-dNRgsTOO.js +1 -0
  12. package/apps/dashboard/dist/assets/tab-models-tab-dNRgsTOO.js.br +0 -0
  13. package/apps/dashboard/dist/assets/{tab-pm-loop-tab-Bfd449B4.js → tab-pm-loop-tab-DiAPTJXu.js} +1 -1
  14. package/apps/dashboard/dist/assets/tab-pm-loop-tab-DiAPTJXu.js.br +0 -0
  15. package/apps/dashboard/dist/assets/{tab-projects-tab-DhNWnlzt.js → tab-projects-tab-SFH4E--a.js} +1 -1
  16. package/apps/dashboard/dist/assets/tab-projects-tab-SFH4E--a.js.br +0 -0
  17. package/apps/dashboard/dist/assets/tab-settings-tab-CuvH_Fj_.js +1 -0
  18. package/apps/dashboard/dist/assets/tab-settings-tab-CuvH_Fj_.js.br +0 -0
  19. package/apps/dashboard/dist/assets/tab-skills-tab-DR7PJ7NB.js +1 -0
  20. package/apps/dashboard/dist/assets/tab-skills-tab-DR7PJ7NB.js.br +0 -0
  21. package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js +1 -0
  22. package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js.br +0 -0
  23. package/apps/dashboard/dist/index.html +135 -15
  24. package/apps/dashboard/dist/index.html.br +0 -0
  25. package/apps/dashboard/dist/index.html.gz +0 -0
  26. package/apps/vibe/README.md +2 -2
  27. package/apps/vibe/package.json +1 -1
  28. package/apps/vibe/server.mjs +101 -56
  29. package/crew-lead.mjs +34 -4
  30. package/lib/bridges/cli-executor.mjs +1 -1
  31. package/lib/bridges/gateway-ws.mjs +4 -0
  32. package/lib/browser/passthrough-stderr.js +1 -0
  33. package/lib/chat/project-messages.mjs +3 -5
  34. package/lib/cli-process-tracker.mjs +3 -2
  35. package/lib/contacts/identity-linker.mjs +1 -0
  36. package/lib/crew-judge/judge.mjs +19 -18
  37. package/lib/crew-lead/agent-manager.mjs +1 -1
  38. package/lib/crew-lead/background.mjs +14 -1
  39. package/lib/crew-lead/chat-handler.mjs +38 -1
  40. package/lib/crew-lead/http-server.mjs +106 -57
  41. package/lib/crew-lead/llm-caller.mjs +24 -8
  42. package/lib/crew-lead/prompts.mjs +14 -1
  43. package/lib/crew-lead/tools.mjs +3 -2
  44. package/lib/crew-lead/wave-dispatcher.mjs +19 -5
  45. package/lib/crew-lead/ws-router.mjs +219 -27
  46. package/lib/engines/crew-cli.mjs +1 -1
  47. package/lib/engines/engine-registry.mjs +14 -3
  48. package/lib/engines/rt-envelope.mjs +1 -0
  49. package/lib/engines/runners.mjs +28 -4
  50. package/lib/gemini-cli-passthrough-noise.mjs +1 -1
  51. package/lib/integrations/code-search.mjs +4 -3
  52. package/lib/memory/shared-adapter.mjs +23 -10
  53. package/lib/pipeline/manager.mjs +2 -1
  54. package/lib/runtime/config.mjs +1 -1
  55. package/lib/runtime/paths.mjs +12 -8
  56. package/lib/runtime/spending.mjs +2 -1
  57. package/package.json +42 -14
  58. package/scripts/capture-build-flow.mjs +118 -0
  59. package/scripts/coverage-report.mjs +209 -0
  60. package/scripts/coverage-summary.mjs +47 -0
  61. package/scripts/dashboard-validation.mjs +76 -0
  62. package/scripts/dashboard.mjs +1667 -551
  63. package/scripts/generate-openapi.mjs +683 -277
  64. package/scripts/live-bridge-matrix.mjs +79 -0
  65. package/scripts/live-cli-matrix.mjs +166 -0
  66. package/scripts/live-crewchat-check.mjs +42 -0
  67. package/scripts/live-engine-matrix.mjs +50 -0
  68. package/scripts/live-provider-failover-matrix.mjs +107 -0
  69. package/scripts/live-provider-matrix.mjs +228 -0
  70. package/scripts/restart-all-from-repo.sh +4 -4
  71. package/scripts/restart-service.sh +12 -9
  72. package/scripts/smoke-dispatch.mjs +4 -1
  73. package/scripts/test-blast-radius.mjs +204 -0
  74. package/scripts/test-report-summary.mjs +88 -0
  75. package/scripts/test-reporter.mjs +651 -0
  76. package/scripts/test-rerun.mjs +136 -0
  77. package/scripts/tmux-bridge +130 -0
  78. package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js +0 -1
  79. package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
  80. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js +0 -1
  81. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  82. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  83. package/apps/dashboard/dist/assets/index-DnClJ1ee.js +0 -2
  84. package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
  85. package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js +0 -1
  86. package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
  87. package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
  88. package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
  89. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js +0 -1
  90. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
  91. package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js +0 -1
  92. package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
  93. package/apps/dashboard/index.html +0 -6529
  94. package/apps/dashboard/package.json +0 -15
  95. package/apps/dashboard/src/app.js +0 -2828
  96. package/apps/dashboard/src/app.js.br +0 -0
  97. package/apps/dashboard/src/app.js.gz +0 -0
  98. package/apps/dashboard/src/chat/chat-actions.js +0 -1847
  99. package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
  100. package/apps/dashboard/src/chat/unified-messages.js +0 -327
  101. package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
  102. package/apps/dashboard/src/cli-process.js +0 -208
  103. package/apps/dashboard/src/cli-process.js.br +0 -0
  104. package/apps/dashboard/src/cli-process.js.gz +0 -0
  105. package/apps/dashboard/src/components/active-tasks-panel.js +0 -175
  106. package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
  107. package/apps/dashboard/src/core/api.js +0 -18
  108. package/apps/dashboard/src/core/api.js.br +0 -0
  109. package/apps/dashboard/src/core/dom.js +0 -228
  110. package/apps/dashboard/src/core/dom.js.br +0 -0
  111. package/apps/dashboard/src/core/state.js +0 -91
  112. package/apps/dashboard/src/core/state.js.br +0 -0
  113. package/apps/dashboard/src/core/task-manager.js +0 -134
  114. package/apps/dashboard/src/core/task-manager.js.br +0 -0
  115. package/apps/dashboard/src/orchestration-status.js +0 -127
  116. package/apps/dashboard/src/orchestration-status.js.br +0 -0
  117. package/apps/dashboard/src/setup-wizard.js +0 -562
  118. package/apps/dashboard/src/setup-wizard.js.br +0 -0
  119. package/apps/dashboard/src/styles.css +0 -2085
  120. package/apps/dashboard/src/styles.css.br +0 -0
  121. package/apps/dashboard/src/styles.css.gz +0 -0
  122. package/apps/dashboard/src/tabs/agents-tab.js +0 -2237
  123. package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
  124. package/apps/dashboard/src/tabs/benchmarks-tab.js +0 -229
  125. package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
  126. package/apps/dashboard/src/tabs/comms-tab.js +0 -955
  127. package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
  128. package/apps/dashboard/src/tabs/contacts-tab.js +0 -654
  129. package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
  130. package/apps/dashboard/src/tabs/engines-tab.js +0 -175
  131. package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
  132. package/apps/dashboard/src/tabs/memory-tab.js +0 -182
  133. package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
  134. package/apps/dashboard/src/tabs/models-tab.js +0 -450
  135. package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
  136. package/apps/dashboard/src/tabs/pm-loop-tab.js +0 -185
  137. package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
  138. package/apps/dashboard/src/tabs/projects-tab.js +0 -663
  139. package/apps/dashboard/src/tabs/projects-tab.js.br +0 -0
  140. package/apps/dashboard/src/tabs/projects-tab.js.gz +0 -0
  141. package/apps/dashboard/src/tabs/prompts-tab.js +0 -160
  142. package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
  143. package/apps/dashboard/src/tabs/services-tab.js +0 -202
  144. package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
  145. package/apps/dashboard/src/tabs/settings-tab.js +0 -861
  146. package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
  147. package/apps/dashboard/src/tabs/skills-tab.js +0 -284
  148. package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
  149. package/apps/dashboard/src/tabs/spending-tab.js +0 -173
  150. package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
  151. package/apps/dashboard/src/tabs/swarm-chat-tab.js +0 -660
  152. package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
  153. package/apps/dashboard/src/tabs/swarm-tab.js +0 -538
  154. package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
  155. package/apps/dashboard/src/tabs/usage-tab.js +0 -390
  156. package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
  157. package/apps/dashboard/src/tabs/waves-tab.js +0 -238
  158. package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
  159. package/apps/dashboard/src/tabs/workflows-tab.js +0 -747
  160. package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
  161. package/apps/vibe/.crew/agent-memory/pipeline.json +0 -304
  162. package/apps/vibe/.crew/cost.json +0 -17
  163. package/apps/vibe/.crew/json-parse-metrics.jsonl +0 -27
  164. package/apps/vibe/.crew/pipeline-metrics.jsonl +0 -27
  165. package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +0 -5
  166. package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +0 -5
  167. package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +0 -5
  168. package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +0 -5
  169. package/apps/vibe/.crew/pipeline-runs/pipeline-3da23550-22ed-4904-9a0a-8e79c1f3024c.jsonl +0 -5
  170. package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +0 -5
  171. package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +0 -5
  172. package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +0 -5
  173. package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +0 -5
  174. package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +0 -5
  175. package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +0 -5
  176. package/apps/vibe/.crew/pipeline-runs/pipeline-6413fa33-a802-4b57-a8c0-a9056ad67842.jsonl +0 -5
  177. package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +0 -5
  178. package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +0 -5
  179. package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +0 -5
  180. package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +0 -5
  181. package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +0 -5
  182. package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +0 -5
  183. package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +0 -5
  184. package/apps/vibe/.crew/pipeline-runs/pipeline-9bef2dd2-6122-42e5-b3d9-19f4d80f9e40.jsonl +0 -5
  185. package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +0 -5
  186. package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +0 -2
  187. package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +0 -5
  188. package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +0 -5
  189. package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +0 -5
  190. package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +0 -5
  191. package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +0 -5
  192. package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +0 -5
  193. package/apps/vibe/.crew/sandbox.json +0 -7
  194. package/apps/vibe/.crew/session.json +0 -330
  195. package/apps/vibe/.crew/training-data.jsonl +0 -0
  196. package/apps/vibe/.github/workflows/studio-quality.yml +0 -37
  197. package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +0 -18
  198. package/apps/vibe/.studio-data/project-messages/general.jsonl +0 -81
  199. package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +0 -18
  200. package/apps/vibe/ARCHITECTURE.md +0 -3393
  201. package/apps/vibe/QUICK-REFERENCE.md +0 -211
  202. package/apps/vibe/ROADMAP.md +0 -41
  203. package/apps/vibe/STUDIO-SETUP-COMPLETE.md +0 -35
  204. package/apps/vibe/VISUAL-GUIDE.md +0 -378
  205. package/apps/vibe/capture-demo.mjs +0 -160
  206. package/apps/vibe/capture-full-demo.mjs +0 -255
  207. package/apps/vibe/capture-quickstart.mjs +0 -256
  208. package/apps/vibe/capture-vibe-assets.mjs +0 -71
  209. package/apps/vibe/capture-vibe-video.mjs +0 -260
  210. package/apps/vibe/check-buttons.js +0 -41
  211. package/apps/vibe/diagnose.html +0 -106
  212. package/apps/vibe/fix-buttons.js +0 -103
  213. package/apps/vibe/index.html +0 -3404
  214. package/apps/vibe/package-lock.json +0 -920
  215. package/apps/vibe/scripts/studio-pty-host.py +0 -117
  216. package/apps/vibe/src/main.js +0 -2940
  217. package/apps/vibe/src/register-all-languages.js +0 -98
  218. package/apps/vibe/start-studio.sh +0 -11
  219. package/apps/vibe/test/accessibility-tests.js +0 -77
  220. package/apps/vibe/test/browser-performance-audit.mjs +0 -205
  221. package/apps/vibe/test/performance-tests.js +0 -120
  222. package/apps/vibe/test/security-tests.js +0 -213
  223. package/apps/vibe/tests/e2e.local.mjs +0 -54
  224. package/apps/vibe/tests/server.smoke.mjs +0 -106
  225. package/apps/vibe/update_website.mjs +0 -74
  226. package/apps/vibe/vite.config.js +0 -19
  227. package/lib/crew-lead/chat-handler.mjs.bak +0 -1274
  228. package/lib/engines/rt-envelope.mjs.backup-current +0 -870
@@ -1,6 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Generate complete OpenAPI spec from actual endpoint implementations
3
+ * Generate complete OpenAPI spec by dynamically scanning source files for routes.
4
+ *
5
+ * Scanning strategy (regex-based, no AST):
6
+ * - Pattern A: url.pathname === "/path" && req.method === "METHOD"
7
+ * - Pattern B: req.method === "METHOD" && url.pathname === "/path"
8
+ * - Pattern C: url.pathname === "/path" (method inferred from context)
9
+ * - Pattern D: parsedUrl.pathname === "/path" && req.method === "METHOD" (Vibe server)
10
+ * - Pattern E: req.method === 'METHOD' && path === '/path' (crew-cli server.ts)
11
+ *
12
+ * Manual entries in dashboardEndpoints / crewLeadEndpoints act as overrides for
13
+ * tag assignment. Scanned routes that match a manual entry use that tag; newly
14
+ * discovered routes get auto-tagged from their path prefix.
4
15
  */
5
16
 
6
17
  import fs from "node:fs";
@@ -10,7 +21,10 @@ import { fileURLToPath } from "node:url";
10
21
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
22
  const rootDir = path.resolve(__dirname, "..");
12
23
 
13
- // Read the old spec to preserve schemas
24
+ // ---------------------------------------------------------------------------
25
+ // Shared spec skeleton
26
+ // ---------------------------------------------------------------------------
27
+
14
28
  const oldSpecPath = path.join(rootDir, "crew-cli/docs/openapi.unified.v1.json");
15
29
  const oldSpec = JSON.parse(fs.readFileSync(oldSpecPath, "utf8"));
16
30
 
@@ -19,316 +33,708 @@ const spec = {
19
33
  info: {
20
34
  title: "crewswarm Complete API",
21
35
  version: "2.0.0",
22
- description: "Complete API specification for crewswarm Dashboard (port 4319) and crew-lead (port 5010). Includes all agent orchestration, messaging integrations, memory management, and system control endpoints."
36
+ description:
37
+ "Complete API specification for crewswarm Dashboard (port 4319), crew-lead (port 5010), Vibe Studio (port 4320), and crew-cli (variable port). " +
38
+ "Includes all agent orchestration, messaging integrations, memory management, and system control endpoints.",
23
39
  },
24
40
  servers: [
25
- {
26
- url: "http://127.0.0.1:4319",
27
- description: "Dashboard API (primary web interface)"
28
- },
29
- {
30
- url: "http://127.0.0.1:5010",
31
- description: "crew-lead API (orchestration and chat)"
32
- }
41
+ { url: "http://127.0.0.1:4319", description: "Dashboard API (primary web interface)" },
42
+ { url: "http://127.0.0.1:5010", description: "crew-lead API (orchestration and chat)" },
43
+ { url: "http://127.0.0.1:4320", description: "Vibe Studio API (editor and sessions)" },
44
+ { url: "http://127.0.0.1:4321", description: "crew-cli API (agent router and tasks)" },
33
45
  ],
34
46
  tags: [
35
- { name: "Core", description: "Essential system endpoints" },
36
- { name: "Agents", description: "Agent management and configuration" },
37
- { name: "Chat", description: "Conversational interfaces" },
38
- { name: "Dispatch", description: "Task dispatch and orchestration" },
39
- { name: "Projects", description: "Project and roadmap management" },
40
- { name: "PM Loop", description: "Project manager autonomous loop" },
41
- { name: "Build", description: "Build orchestration" },
42
- { name: "Providers", description: "LLM provider configuration" },
43
- { name: "Skills", description: "Skill plugin management" },
44
- { name: "Memory", description: "Shared memory and brain" },
45
- { name: "Messaging", description: "Telegram and WhatsApp integrations" },
46
- { name: "Contacts", description: "Contact management" },
47
- { name: "Settings", description: "System configuration" },
48
- { name: "Services", description: "Service lifecycle management" },
49
- { name: "Engines", description: "Engine passthrough and configuration" },
47
+ { name: "Core", description: "Essential system endpoints" },
48
+ { name: "Agents", description: "Agent management and configuration" },
49
+ { name: "Chat", description: "Conversational interfaces" },
50
+ { name: "Dispatch", description: "Task dispatch and orchestration" },
51
+ { name: "Projects", description: "Project and roadmap management" },
52
+ { name: "PM Loop", description: "Project manager autonomous loop" },
53
+ { name: "Build", description: "Build orchestration" },
54
+ { name: "Providers", description: "LLM provider configuration" },
55
+ { name: "Skills", description: "Skill plugin management" },
56
+ { name: "Memory", description: "Shared memory and brain" },
57
+ { name: "Messaging", description: "Telegram and WhatsApp integrations" },
58
+ { name: "Contacts", description: "Contact management" },
59
+ { name: "Settings", description: "System configuration" },
60
+ { name: "Services", description: "Service lifecycle management" },
61
+ { name: "Engines", description: "Engine passthrough and configuration" },
50
62
  { name: "Multimodal", description: "Image and audio processing" },
51
- { name: "Telemetry", description: "Usage tracking and spending" }
63
+ { name: "Telemetry", description: "Usage tracking and spending" },
64
+ { name: "OAuth", description: "OAuth and subscription provider authentication" },
65
+ { name: "Testing", description: "Test suite execution and results" },
66
+ { name: "Workflows", description: "Scheduled pipeline workflow management" },
67
+ { name: "Studio", description: "Vibe Studio editor and session management" },
68
+ { name: "RAG", description: "Retrieval-augmented generation and indexing" },
69
+ { name: "MCP", description: "Model Context Protocol endpoints" },
70
+ { name: "V1", description: "crew-cli v1 API (tasks, sandbox, traces)" },
52
71
  ],
53
72
  paths: {},
54
- components: oldSpec.components // Preserve existing schemas
73
+ components: oldSpec.components,
74
+ };
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Manual override tables (path → { method: tag, ... })
78
+ // These supply authoritative tags for known routes discovered by scanning.
79
+ // ---------------------------------------------------------------------------
80
+
81
+ const dashboardOverrides = {
82
+ "/": { get: "Core" },
83
+ "/health": { get: "Core" },
84
+ "/api/health": { get: "Core" },
85
+ "/api/agents": { get: "Agents" },
86
+ "/api/agents-config": { get: "Agents" },
87
+ "/api/agents-config/create": { post: "Agents" },
88
+ "/api/agents-config/update": { post: "Agents" },
89
+ "/api/agents-config/delete": { post: "Agents" },
90
+ "/api/agents-config/reset-session": { post: "Agents" },
91
+ "/api/agents/reset-session": { post: "Agents" },
92
+ "/api/crew-lead/chat": { post: "Chat" },
93
+ "/api/crew-lead/history": { get: "Chat" },
94
+ "/api/crew-lead/clear": { post: "Chat" },
95
+ "/api/crew-lead/status": { get: "Chat" },
96
+ "/api/crew-lead/events": { get: "Chat" },
97
+ "/api/crew-lead/confirm-project": { post: "Projects" },
98
+ "/api/crew-lead/discard-project": { post: "Projects" },
99
+ "/api/crew-lead/project-messages": { get: "Projects" },
100
+ "/api/dispatch": { post: "Dispatch" },
101
+ "/api/projects": { get: "Projects", post: "Projects" },
102
+ "/api/projects/update": { post: "Projects" },
103
+ "/api/projects/delete": { post: "Projects" },
104
+ "/api/pm-loop/start": { post: "PM Loop" },
105
+ "/api/pm-loop/stop": { post: "PM Loop" },
106
+ "/api/pm-loop/status": { get: "PM Loop" },
107
+ "/api/pm-loop/log": { get: "PM Loop" },
108
+ "/api/pm-loop/roadmap": { get: "PM Loop" },
109
+ "/api/roadmap/read": { post: "PM Loop" },
110
+ "/api/roadmap/write": { post: "PM Loop" },
111
+ "/api/roadmap/retry-failed": { post: "PM Loop" },
112
+ "/api/build": { post: "Build" },
113
+ "/api/build/stop": { post: "Build" },
114
+ "/api/continuous-build": { post: "Build" },
115
+ "/api/continuous-build/stop": { post: "Build" },
116
+ "/api/continuous-build/log": { get: "Build" },
117
+ "/api/phased-progress": { get: "Build" },
118
+ "/api/providers": { get: "Providers" },
119
+ "/api/providers/builtin": { get: "Providers" },
120
+ "/api/providers/builtin/save": { post: "Providers" },
121
+ "/api/providers/builtin/test": { post: "Providers" },
122
+ "/api/providers/add": { post: "Providers" },
123
+ "/api/providers/save": { post: "Providers" },
124
+ "/api/providers/test": { post: "Providers" },
125
+ "/api/providers/fetch-models": { post: "Providers" },
126
+ "/api/models": { get: "Providers" },
127
+ "/api/skills/import": { post: "Skills" },
128
+ "/api/memory/stats": { get: "Memory" },
129
+ "/api/memory/search": { post: "Memory" },
130
+ "/api/memory/migrate": { post: "Memory" },
131
+ "/api/memory/compact": { post: "Memory" },
132
+ "/api/telegram/config": { get: "Messaging", post: "Messaging" },
133
+ "/api/telegram/start": { post: "Messaging" },
134
+ "/api/telegram/stop": { post: "Messaging" },
135
+ "/api/telegram/status": { get: "Messaging" },
136
+ "/api/telegram/messages": { get: "Messaging" },
137
+ "/api/telegram/discover-topics": { get: "Messaging" },
138
+ "/api/telegram-sessions": { get: "Messaging" },
139
+ "/api/whatsapp/config": { get: "Messaging", post: "Messaging" },
140
+ "/api/whatsapp/start": { post: "Messaging" },
141
+ "/api/whatsapp/stop": { post: "Messaging" },
142
+ "/api/whatsapp/status": { get: "Messaging" },
143
+ "/api/whatsapp/messages": { get: "Messaging" },
144
+ "/api/contacts": { get: "Contacts" },
145
+ "/api/contacts/update": { post: "Contacts" },
146
+ "/api/contacts/delete": { post: "Contacts" },
147
+ "/api/contacts/send": { post: "Contacts" },
148
+ "/api/settings/rt-token": { get: "Settings", post: "Settings" },
149
+ "/api/settings/opencode-project": { get: "Settings", post: "Settings" },
150
+ "/api/settings/bg-consciousness": { get: "Settings", post: "Settings" },
151
+ "/api/settings/cursor-waves": { get: "Settings", post: "Settings" },
152
+ "/api/settings/claude-code": { get: "Settings", post: "Settings" },
153
+ "/api/settings/codex": { get: "Settings", post: "Settings" },
154
+ "/api/settings/gemini-cli": { get: "Settings", post: "Settings" },
155
+ "/api/settings/crew-cli": { get: "Settings", post: "Settings" },
156
+ "/api/settings/global-fallback": { get: "Settings", post: "Settings" },
157
+ "/api/settings/global-oc-loop": { get: "Settings", post: "Settings" },
158
+ "/api/settings/global-rules": { get: "Settings", post: "Settings" },
159
+ "/api/settings/loop-brain": { get: "Settings", post: "Settings" },
160
+ "/api/settings/openclaw-status": { get: "Settings" },
161
+ "/api/settings/passthrough-notify": { get: "Settings", post: "Settings" },
162
+ "/api/settings/role-defaults": { get: "Settings", post: "Settings" },
163
+ "/api/settings/spending-caps": { get: "Settings", post: "Settings" },
164
+ "/api/settings/autonomous-mentions": { get: "Settings", post: "Settings" },
165
+ "/api/settings/cli-models": { get: "Settings", post: "Settings" },
166
+ "/api/settings/opencode": { get: "Settings", post: "Settings" },
167
+ "/api/settings/tmux-bridge": { get: "Settings", post: "Settings" },
168
+ "/api/env": { get: "Settings" },
169
+ "/api/env-advanced": { get: "Settings", post: "Settings" },
170
+ "/api/config/lock-status": { get: "Settings" },
171
+ "/api/config/lock": { post: "Settings" },
172
+ "/api/config/unlock": { post: "Settings" },
173
+ "/api/services/status": { get: "Services" },
174
+ "/api/services/restart": { post: "Services" },
175
+ "/api/services/stop": { post: "Services" },
176
+ "/api/crew/start": { post: "Services" },
177
+ "/api/engines": { get: "Engines" },
178
+ "/api/engines/import": { post: "Engines" },
179
+ "/api/engines/toggle": { post: "Engines" },
180
+ "/api/engine-passthrough": { post: "Engines" },
181
+ "/api/opencode-models": { get: "Engines" },
182
+ "/api/opencode-stats": { get: "Engines" },
183
+ "/api/passthrough-sessions": { get: "Engines", delete: "Engines" },
184
+ "/api/engine-runtimes": { get: "Engines" },
185
+ "/api/engine-sessions": { get: "Engines" },
186
+ "/api/codex-sessions": { get: "Engines" },
187
+ "/api/gemini-sessions": { get: "Engines" },
188
+ "/api/crew-cli-sessions": { get: "Engines" },
189
+ "/api/first-run-engines": { get: "Engines" },
190
+ "/api/analyze-image": { post: "Multimodal" },
191
+ "/api/transcribe-audio": { post: "Multimodal" },
192
+ "/api/token-usage": { get: "Telemetry" },
193
+ "/api/oauth/status": { get: "OAuth" },
194
+ "/api/oauth/test": { post: "OAuth" },
195
+ "/api/oauth/models": { get: "OAuth" },
196
+ "/api/oauth/model": { get: "OAuth", post: "OAuth" },
197
+ "/api/tests/summary": { get: "Testing" },
198
+ "/api/tests/history": { get: "Testing" },
199
+ "/api/tests/run-detail": { get: "Testing" },
200
+ "/api/tests/run": { post: "Testing" },
201
+ "/api/tests/progress": { get: "Testing" },
202
+ "/api/workflows/list": { get: "Workflows" },
203
+ "/api/workflows/item": { get: "Workflows" },
204
+ "/api/workflows/save": { post: "Workflows" },
205
+ "/api/workflows/delete": { post: "Workflows" },
206
+ "/api/workflows/run": { post: "Workflows" },
207
+ "/api/workflows/log": { get: "Workflows" },
208
+ "/api/workflows/status": { get: "Workflows" },
209
+ "/api/dlq": { get: "Core" },
210
+ "/api/dlq/replay": { post: "Core" },
211
+ "/api/waves/config": { get: "Core", post: "Core" },
212
+ "/api/waves/config/reset": { post: "Core" },
213
+ "/api/prompts": { get: "Core", post: "Core" },
214
+ "/api/cmd-allowlist": { get: "Core", post: "Core", delete: "Core" },
215
+ "/api/cmd-approve": { post: "Core" },
216
+ "/api/cmd-reject": { post: "Core" },
217
+ "/api/enhance-prompt": { post: "Core" },
218
+ "/api/search-tools": { get: "Core" },
219
+ "/api/search-tools/save": { post: "Core" },
220
+ "/api/search-tools/test": { post: "Core" },
221
+ "/api/benchmark-tasks": { get: "Core" },
222
+ "/api/benchmark-run": { post: "Core" },
223
+ "/api/files": { get: "Core" },
224
+ "/api/file-content": { get: "Core" },
225
+ "/api/pick-folder": { get: "Core" },
226
+ "/api/sessions": { get: "Core" },
227
+ "/api/messages": { get: "Core" },
228
+ "/api/send": { post: "Core" },
229
+ "/api/rt-messages": { get: "Core" },
230
+ "/api/auth/token": { get: "Core" },
231
+ "/api/signup": { post: "Core" },
232
+ "/api/first-run-status": { get: "Core" },
233
+ "/api/cli-processes": { get: "Core" },
234
+ "/api/ui/active-project": { get: "Core", post: "Core" },
235
+ "/api/agent-chat": { post: "Chat" },
236
+ "/api/chat/unified": { post: "Chat" },
237
+ "/api/cli/chat": { post: "Chat" },
238
+ "/api/chat-participants": { get: "Chat" },
239
+ "/api/chat-agent": { post: "Chat" },
55
240
  };
56
241
 
57
- // Dashboard endpoints with methods and tags
58
- const dashboardEndpoints = {
59
- "/": { get: "Core" },
60
- "/health": { get: "Core" },
61
- "/api/health": { get: "Core" },
62
- "/api/agents": { get: "Agents" },
63
- "/api/agents-config": { get: "Agents" },
64
- "/api/agents-config/create": { post: "Agents" },
65
- "/api/agents-config/update": { post: "Agents" },
66
- "/api/agents-config/delete": { post: "Agents" },
67
- "/api/agents-config/reset-session": { post: "Agents" },
68
- "/api/agents/reset-session": { post: "Agents" },
69
- "/api/crew-lead/chat": { post: "Chat" },
70
- "/api/crew-lead/history": { get: "Chat" },
71
- "/api/crew-lead/clear": { post: "Chat" },
72
- "/api/crew-lead/status": { get: "Chat" },
73
- "/api/crew-lead/events": { get: "Chat" },
74
- "/api/crew-lead/confirm-project": { post: "Projects" },
75
- "/api/crew-lead/discard-project": { post: "Projects" },
76
- "/api/dispatch": { post: "Dispatch" },
77
- "/api/projects": { get: "Projects", post: "Projects" },
78
- "/api/projects/update": { post: "Projects" },
79
- "/api/projects/delete": { post: "Projects" },
80
- "/api/pm-loop/start": { post: "PM Loop" },
81
- "/api/pm-loop/stop": { post: "PM Loop" },
82
- "/api/pm-loop/status": { get: "PM Loop" },
83
- "/api/pm-loop/log": { get: "PM Loop" },
84
- "/api/pm-loop/roadmap": { get: "PM Loop" },
85
- "/api/roadmap/read": { post: "PM Loop" },
86
- "/api/roadmap/write": { post: "PM Loop" },
87
- "/api/roadmap/retry-failed": { post: "PM Loop" },
88
- "/api/build": { post: "Build" },
89
- "/api/build/stop": { post: "Build" },
90
- "/api/continuous-build": { post: "Build" },
91
- "/api/continuous-build/stop": { post: "Build" },
92
- "/api/continuous-build/log": { get: "Build" },
93
- "/api/phased-progress": { get: "Build" },
94
- "/api/providers": { get: "Providers" },
95
- "/api/providers/builtin": { get: "Providers" },
96
- "/api/providers/builtin/save": { post: "Providers" },
97
- "/api/providers/builtin/test": { post: "Providers" },
98
- "/api/providers/add": { post: "Providers" },
99
- "/api/providers/save": { post: "Providers" },
100
- "/api/providers/test": { post: "Providers" },
101
- "/api/providers/fetch-models": { post: "Providers" },
102
- "/api/skills/import": { post: "Skills" },
103
- "/api/memory/stats": { get: "Memory" },
104
- "/api/memory/search": { post: "Memory" },
105
- "/api/memory/migrate": { post: "Memory" },
106
- "/api/memory/compact": { post: "Memory" },
107
- "/api/telegram/config": { get: "Messaging", post: "Messaging" },
108
- "/api/telegram/start": { post: "Messaging" },
109
- "/api/telegram/stop": { post: "Messaging" },
110
- "/api/telegram/status": { get: "Messaging" },
111
- "/api/telegram/messages": { get: "Messaging" },
112
- "/api/telegram/discover-topics": { get: "Messaging" },
113
- "/api/telegram-sessions": { get: "Messaging" },
114
- "/api/whatsapp/config": { get: "Messaging", post: "Messaging" },
115
- "/api/whatsapp/start": { post: "Messaging" },
116
- "/api/whatsapp/stop": { post: "Messaging" },
117
- "/api/whatsapp/status": { get: "Messaging" },
118
- "/api/whatsapp/messages": { get: "Messaging" },
119
- "/api/contacts": { get: "Contacts" },
120
- "/api/contacts/update": { post: "Contacts" },
121
- "/api/contacts/delete": { post: "Contacts" },
122
- "/api/contacts/send": { post: "Contacts" },
123
- "/api/settings/rt-token": { get: "Settings", post: "Settings" },
124
- "/api/settings/opencode-project": { get: "Settings", post: "Settings" },
125
- "/api/settings/bg-consciousness": { get: "Settings", post: "Settings" },
126
- "/api/settings/cursor-waves": { get: "Settings", post: "Settings" },
127
- "/api/settings/claude-code": { get: "Settings", post: "Settings" },
128
- "/api/settings/codex": { get: "Settings", post: "Settings" },
129
- "/api/settings/gemini-cli": { get: "Settings", post: "Settings" },
130
- "/api/settings/crew-cli": { get: "Settings", post: "Settings" },
131
- "/api/settings/global-fallback": { get: "Settings", post: "Settings" },
132
- "/api/settings/global-oc-loop": { get: "Settings", post: "Settings" },
133
- "/api/settings/global-rules": { get: "Settings", post: "Settings" },
134
- "/api/settings/loop-brain": { get: "Settings", post: "Settings" },
135
- "/api/settings/openclaw-status": { get: "Settings" },
136
- "/api/settings/passthrough-notify": { get: "Settings", post: "Settings" },
137
- "/api/settings/role-defaults": { get: "Settings", post: "Settings" },
138
- "/api/settings/spending-caps": { get: "Settings", post: "Settings" },
139
- "/api/env": { get: "Settings" },
140
- "/api/env-advanced": { get: "Settings", post: "Settings" },
141
- "/api/services/status": { get: "Services" },
142
- "/api/services/restart": { post: "Services" },
143
- "/api/services/stop": { post: "Services" },
144
- "/api/crew/start": { post: "Services" },
145
- "/api/engines": { get: "Engines" },
146
- "/api/engines/import": { post: "Engines" },
147
- "/api/engine-passthrough": { post: "Engines" },
148
- "/api/opencode-models": { get: "Engines" },
149
- "/api/opencode-stats": { get: "Engines" },
150
- "/api/passthrough-sessions": { get: "Engines", delete: "Engines" },
151
- "/api/analyze-image": { post: "Multimodal" },
152
- "/api/transcribe-audio": { post: "Multimodal" },
153
- "/api/token-usage": { get: "Telemetry" },
154
- "/api/dlq": { get: "Core" },
155
- "/api/dlq/replay": { post: "Core" },
156
- "/api/waves/config": { get: "Core", post: "Core" },
157
- "/api/waves/config/reset": { post: "Core" },
158
- "/api/prompts": { get: "Core", post: "Core" },
159
- "/api/cmd-allowlist": { get: "Core", post: "Core", delete: "Core" },
160
- "/api/cmd-approve": { post: "Core" },
161
- "/api/cmd-reject": { post: "Core" },
162
- "/api/enhance-prompt": { post: "Core" },
163
- "/api/search-tools": { get: "Core" },
164
- "/api/search-tools/save": { post: "Core" },
165
- "/api/search-tools/test": { post: "Core" },
166
- "/api/benchmark-tasks": { get: "Core" },
167
- "/api/benchmark-run": { post: "Core" },
168
- "/api/files": { get: "Core" },
169
- "/api/file-content": { get: "Core" },
170
- "/api/pick-folder": { get: "Core" },
171
- "/api/sessions": { get: "Core" },
172
- "/api/messages": { get: "Core" },
173
- "/api/send": { post: "Core" },
174
- "/api/rt-messages": { get: "Core" }
242
+ const crewLeadOverrides = {
243
+ "/health": { get: "Core" },
244
+ "/status": { get: "Core" },
245
+ "/api/health": { get: "Core" },
246
+ "/api/background": { get: "Core" },
247
+ "/chat": { post: "Chat" },
248
+ "/chat/stream": { post: "Chat" },
249
+ "/history": { get: "Chat" },
250
+ "/clear": { post: "Chat" },
251
+ "/events": { get: "Chat" },
252
+ "/confirm-project": { post: "Projects" },
253
+ "/discard-project": { post: "Projects" },
254
+ "/api/dispatch": { post: "Dispatch" },
255
+ "/api/classify": { post: "Dispatch" },
256
+ "/api/chat-agent": { post: "Dispatch" },
257
+ "/api/pipeline": { post: "Dispatch" },
258
+ "/api/agents": { get: "Agents" },
259
+ "/api/agents/opencode": { get: "Agents" },
260
+ "/api/skills": { get: "Skills", post: "Skills" },
261
+ "/api/skills/approve": { post: "Skills" },
262
+ "/api/skills/reject": { post: "Skills" },
263
+ "/api/crew-lead/history": { get: "Chat" },
264
+ "/api/crew-lead/project-messages": { get: "Projects" },
265
+ "/api/crew-lead/search-project-messages": { get: "Projects" },
266
+ "/api/crew-lead/export-project-messages": { get: "Projects" },
267
+ "/api/crew-lead/message-threads": { get: "Projects" },
268
+ "/api/crew-lead/search-messages-semantic": { get: "Projects" },
269
+ "/api/crew-lead/index-project-messages": { post: "Projects" },
270
+ "/api/crew-lead/message-index-stats": { get: "Projects" },
271
+ "/api/engine-passthrough": { post: "Engines" },
272
+ "/api/engine-passthrough/clear-session": { post: "Engines" },
273
+ "/api/opencode-event": { post: "Engines" },
274
+ "/api/opencode-sessions": { get: "Engines" },
275
+ "/api/claude-sessions": { get: "Engines" },
276
+ "/api/codex-sessions": { get: "Engines" },
277
+ "/api/gemini-sessions": { get: "Engines" },
278
+ "/api/crew-cli-sessions": { get: "Engines" },
279
+ "/api/passthrough-sessions": { get: "Engines", delete: "Engines" },
280
+ "/api/services/health": { get: "Services" },
281
+ "/api/services/restart-opencode": { post: "Services" },
282
+ "/api/settings/bg-consciousness": { get: "Settings", post: "Settings" },
283
+ "/api/settings/claude-code": { get: "Settings", post: "Settings" },
284
+ "/api/settings/cursor-waves": { get: "Settings", post: "Settings" },
285
+ "/api/settings/global-fallback": { get: "Settings", post: "Settings" },
286
+ "/api/settings/opencode-project": { get: "Settings", post: "Settings" },
287
+ "/api/settings/autonomous-mentions": { get: "Settings", post: "Settings" },
288
+ "/api/settings/codex": { get: "Settings", post: "Settings" },
289
+ "/api/settings/gemini-cli": { get: "Settings", post: "Settings" },
290
+ "/api/settings/crew-cli": { get: "Settings", post: "Settings" },
291
+ "/api/settings/opencode": { get: "Settings", post: "Settings" },
292
+ "/api/settings/global-oc-loop": { get: "Settings", post: "Settings" },
293
+ "/api/settings/passthrough-notify": { get: "Settings", post: "Settings" },
294
+ "/api/settings/loop-brain": { get: "Settings", post: "Settings" },
295
+ "/api/settings/openclaw-status": { get: "Settings" },
296
+ "/api/settings/rt-token": { get: "Settings", post: "Settings" },
297
+ "/api/settings/tmux-bridge": { get: "Settings", post: "Settings" },
298
+ "/api/config/lock-status": { get: "Settings" },
299
+ "/api/config/lock": { post: "Settings" },
300
+ "/api/config/unlock": { post: "Settings" },
301
+ "/api/spending": { get: "Telemetry" },
302
+ "/api/spending/reset": { post: "Telemetry" },
303
+ "/api/telemetry": { get: "Telemetry" },
304
+ "/api/agent-transcripts/recent": { get: "Telemetry" },
305
+ "/allowlist-cmd": { get: "Core", post: "Core", delete: "Core" },
306
+ "/approve-cmd": { post: "Core" },
307
+ "/reject-cmd": { post: "Core" },
175
308
  };
176
309
 
177
- // crew-lead endpoints
178
- const crewLeadEndpoints = {
179
- "/health": { get: "Core" },
180
- "/status": { get: "Core" },
181
- "/chat": { post: "Chat" },
182
- "/history": { get: "Chat" },
183
- "/clear": { post: "Chat" },
184
- "/events": { get: "Chat" },
185
- "/confirm-project": { post: "Projects" },
186
- "/discard-project": { post: "Projects" },
187
- "/api/dispatch": { post: "Dispatch" },
188
- "/api/classify": { post: "Dispatch" },
189
- "/api/chat-agent": { post: "Dispatch" },
190
- "/api/agents": { get: "Agents" },
191
- "/api/agents/opencode": { get: "Agents" },
192
- "/api/skills": { get: "Skills", post: "Skills" },
193
- "/api/skills/approve": { post: "Skills" },
194
- "/api/skills/reject": { post: "Skills" },
195
- "/api/crew-lead/history": { get: "Chat" },
196
- "/api/engine-passthrough": { post: "Engines" },
197
- "/api/opencode-event": { post: "Engines" },
198
- "/api/opencode-sessions": { get: "Engines" },
199
- "/api/claude-sessions": { get: "Engines" },
200
- "/api/passthrough-sessions": { get: "Engines" },
201
- "/api/services/health": { get: "Services" },
202
- "/api/services/restart-opencode": { post: "Services" },
203
- "/api/settings/bg-consciousness": { get: "Settings", post: "Settings" },
204
- "/api/settings/claude-code": { get: "Settings", post: "Settings" },
205
- "/api/settings/cursor-waves": { get: "Settings", post: "Settings" },
206
- "/api/settings/global-fallback": { get: "Settings", post: "Settings" },
207
- "/api/settings/opencode-project": { get: "Settings", post: "Settings" },
208
- "/api/spending": { get: "Telemetry" },
209
- "/api/spending/reset": { post: "Telemetry" },
210
- "/api/telemetry": { get: "Telemetry" },
211
- "/api/agent-transcripts/recent": { get: "Telemetry" },
212
- "/api/background": { get: "Core" },
213
- "/api/health": { get: "Core" },
214
- "/allowlist-cmd": { get: "Core", post: "Core", delete: "Core" },
215
- "/approve-cmd": { post: "Core" },
216
- "/reject-cmd": { post: "Core" }
310
+ const vibeOverrides = {
311
+ "/api/version": { get: "Core" },
312
+ "/api/auth/token": { get: "Core" },
313
+ "/api/agents": { get: "Agents" },
314
+ "/api/chat/unified": { post: "Chat" },
315
+ "/api/studio/sessions": { get: "Studio", delete: "Studio" },
316
+ "/api/studio/projects": { get: "Studio", post: "Studio" },
317
+ "/api/studio/active-project": { get: "Studio", post: "Studio" },
318
+ "/api/studio/files": { get: "Studio" },
319
+ "/api/studio/file-content": { get: "Studio", post: "Studio" },
320
+ "/api/studio/project-messages": { get: "Studio" },
321
+ "/api/studio/engines": { get: "Studio" },
322
+ "/api/studio/clear-cli-session": { post: "Studio" },
323
+ "/api/studio/git-diff": { get: "Studio" },
324
+ "/api/studio/chat/unified": { post: "Studio" },
325
+ "/api/studio/terminal/start": { post: "Studio" },
326
+ "/api/studio/terminal": { delete: "Studio" },
217
327
  };
218
328
 
219
- // Generate path objects
220
- function createPathObject(path, methods, tag) {
329
+ const crewCliOverrides = {
330
+ "/health": { get: "Core" },
331
+ "/v1/chat": { post: "V1" },
332
+ "/v1/chat/completions": { post: "V1" },
333
+ "/v1/models": { get: "V1" },
334
+ "/v1/tasks": { post: "V1" },
335
+ "/v1/agents": { get: "V1" },
336
+ "/v1/status": { get: "V1" },
337
+ "/v1/sandbox": { get: "V1" },
338
+ "/v1/sandbox/apply": { post: "V1" },
339
+ "/v1/sandbox/rollback": { post: "V1" },
340
+ "/v1/index/rebuild": { post: "V1" },
341
+ "/v1/index/search": { get: "V1" },
342
+ "/api/engine-passthrough": { post: "Engines" },
343
+ "/api/passthrough-sessions": { get: "Engines", delete: "Engines" },
344
+ "/api/tool-audit": { get: "Core" },
345
+ "/api/tool-audit/replay": { post: "Core" },
346
+ "/api/rag/search": { get: "RAG" },
347
+ "/api/rag/index": { post: "RAG" },
348
+ "/api/rag/stats": { get: "RAG" },
349
+ "/mcp": { post: "MCP" },
350
+ "/mcp/health": { get: "MCP" },
351
+ };
352
+
353
+ // ---------------------------------------------------------------------------
354
+ // Auto-tag inference from path prefix
355
+ // ---------------------------------------------------------------------------
356
+
357
+ function inferTag(routePath) {
358
+ if (routePath.startsWith("/api/oauth")) return "OAuth";
359
+ if (routePath.startsWith("/api/settings")) return "Settings";
360
+ if (routePath.startsWith("/api/config")) return "Settings";
361
+ if (routePath.startsWith("/api/telegram")) return "Messaging";
362
+ if (routePath.startsWith("/api/whatsapp")) return "Messaging";
363
+ if (routePath.startsWith("/api/contacts")) return "Contacts";
364
+ if (routePath.startsWith("/api/agents")) return "Agents";
365
+ if (routePath.startsWith("/api/skills")) return "Skills";
366
+ if (routePath.startsWith("/api/memory")) return "Memory";
367
+ if (routePath.startsWith("/api/pm-loop")) return "PM Loop";
368
+ if (routePath.startsWith("/api/roadmap")) return "PM Loop";
369
+ if (routePath.startsWith("/api/build")) return "Build";
370
+ if (routePath.startsWith("/api/continuous-build")) return "Build";
371
+ if (routePath.startsWith("/api/phased")) return "Build";
372
+ if (routePath.startsWith("/api/providers")) return "Providers";
373
+ if (routePath.startsWith("/api/models")) return "Providers";
374
+ if (routePath.startsWith("/api/crew-lead")) return "Chat";
375
+ if (routePath.startsWith("/api/dispatch")) return "Dispatch";
376
+ if (routePath.startsWith("/api/classify")) return "Dispatch";
377
+ if (routePath.startsWith("/api/pipeline")) return "Dispatch";
378
+ if (routePath.startsWith("/api/projects")) return "Projects";
379
+ if (routePath.startsWith("/api/services")) return "Services";
380
+ if (routePath.startsWith("/api/engines")) return "Engines";
381
+ if (routePath.startsWith("/api/engine")) return "Engines";
382
+ if (routePath.startsWith("/api/opencode")) return "Engines";
383
+ if (routePath.startsWith("/api/passthrough")) return "Engines";
384
+ if (routePath.startsWith("/api/codex")) return "Engines";
385
+ if (routePath.startsWith("/api/gemini")) return "Engines";
386
+ if (routePath.startsWith("/api/crew-cli")) return "Engines";
387
+ if (routePath.startsWith("/api/analyze")) return "Multimodal";
388
+ if (routePath.startsWith("/api/transcribe")) return "Multimodal";
389
+ if (routePath.startsWith("/api/spending")) return "Telemetry";
390
+ if (routePath.startsWith("/api/telemetry")) return "Telemetry";
391
+ if (routePath.startsWith("/api/token-usage")) return "Telemetry";
392
+ if (routePath.startsWith("/api/agent-transcripts")) return "Telemetry";
393
+ if (routePath.startsWith("/api/tests")) return "Testing";
394
+ if (routePath.startsWith("/api/workflows")) return "Workflows";
395
+ if (routePath.startsWith("/api/studio")) return "Studio";
396
+ if (routePath.startsWith("/api/rag")) return "RAG";
397
+ if (routePath.startsWith("/mcp")) return "MCP";
398
+ if (routePath.startsWith("/v1")) return "V1";
399
+ if (routePath.startsWith("/api/agent-chat")) return "Chat";
400
+ if (routePath.startsWith("/api/chat")) return "Chat";
401
+ if (routePath.startsWith("/api/cli/chat")) return "Chat";
402
+ if (routePath.startsWith("/chat")) return "Chat";
403
+ return "Core";
404
+ }
405
+
406
+ // ---------------------------------------------------------------------------
407
+ // Source scanner — extracts (path, method) pairs via regex
408
+ // ---------------------------------------------------------------------------
409
+
410
+ /**
411
+ * Scan a source file and return Map<routePath, Set<method>>.
412
+ *
413
+ * Handles:
414
+ * A) url.pathname === "/path" && req.method === "METHOD"
415
+ * B) req.method === "METHOD" && url.pathname === "/path"
416
+ * C) parsedUrl.pathname === "/path" && req.method === "METHOD" (Vibe)
417
+ * D) req.method === 'METHOD' && path === '/path' (crew-cli TS)
418
+ * E) req.method === "METHOD" && path === "/path" (crew-cli TS alternate)
419
+ * F) Standalone pathname match without explicit method (multi-method blocks)
420
+ */
421
+ function scanSourceFile(filePath) {
422
+ const routes = new Map(); // routePath → Set<method>
423
+ const source = fs.readFileSync(filePath, "utf8");
424
+
425
+ // Skip non-route pathnames (static files, globs, etc.)
426
+ const SKIP_EXTENSIONS = /\.(html|ico|png|jpg|css|js|json|map|br|gz|txt|md)$/;
427
+ const isRoutePath = (p) =>
428
+ (p.startsWith("/api/") || p.startsWith("/v1/") || p.startsWith("/mcp") ||
429
+ p === "/health" || p === "/status" || p === "/chat" || p === "/chat/stream" ||
430
+ p === "/history" || p === "/clear" || p === "/events" ||
431
+ p === "/confirm-project" || p === "/discard-project" ||
432
+ p === "/approve-cmd" || p === "/reject-cmd" || p === "/allowlist-cmd" ||
433
+ p === "/crew-chat.html" || p === "/signup" || p === "/signup.html") &&
434
+ !SKIP_EXTENSIONS.test(p);
435
+
436
+ function addRoute(rPath, method) {
437
+ if (!isRoutePath(rPath)) return;
438
+ if (!routes.has(rPath)) routes.set(rPath, new Set());
439
+ if (method) routes.get(rPath).add(method.toLowerCase());
440
+ }
441
+
442
+ // Pattern A + C: pathname === "/path" && method === "METHOD"
443
+ // Also handles: parsedUrl.pathname === "/path" && req.method === "METHOD"
444
+ const patA = /(?:url|parsedUrl)\.pathname\s*===\s*["']([^"']+)["']\s*&&\s*req\.method\s*===\s*["'](GET|POST|DELETE|PUT|PATCH)["']/g;
445
+ let m;
446
+ while ((m = patA.exec(source)) !== null) addRoute(m[1], m[2]);
447
+
448
+ // Pattern B: method === "METHOD" && pathname === "/path"
449
+ const patB = /req\.method\s*===\s*["'](GET|POST|DELETE|PUT|PATCH)["']\s*&&\s*(?:url|parsedUrl)\.pathname\s*===\s*["']([^"']+)["']/g;
450
+ while ((m = patB.exec(source)) !== null) addRoute(m[2], m[1]);
451
+
452
+ // Pattern D/E: crew-cli style req.method === 'METHOD' && path === '/path'
453
+ const patD = /req\.method\s*===\s*['"]?(GET|POST|DELETE|PUT|PATCH)['"]?\s*&&\s*path\s*===\s*['"]([^'"]+)['"]/g;
454
+ while ((m = patD.exec(source)) !== null) addRoute(m[2], m[1]);
455
+
456
+ // Pattern E reverse: path === '/path' && req.method === 'METHOD'
457
+ const patE = /path\s*===\s*['"]([^'"]+)['"]\s*&&\s*req\.method\s*===\s*['"]?(GET|POST|DELETE|PUT|PATCH)['"]?/g;
458
+ while ((m = patE.exec(source)) !== null) addRoute(m[1], m[2]);
459
+
460
+ // Pattern F: standalone pathname match (used for multi-method blocks like passthrough-sessions)
461
+ // Only add path without method so we don't lose discovered paths.
462
+ const patF = /(?:url|parsedUrl)\.pathname\s*===\s*["']([^"']+)["']/g;
463
+ while ((m = patF.exec(source)) !== null) {
464
+ if (isRoutePath(m[1]) && !routes.has(m[1])) {
465
+ routes.set(m[1], new Set());
466
+ }
467
+ }
468
+
469
+ // Pattern G: crew-cli — plain path === '/...' blocks (standalone, no method adjacent)
470
+ const patG = /\bpath\s*===\s*['"]([^'"]+)['"]/g;
471
+ while ((m = patG.exec(source)) !== null) {
472
+ if (isRoutePath(m[1]) && !routes.has(m[1])) {
473
+ routes.set(m[1], new Set());
474
+ }
475
+ }
476
+
477
+ // Scan nearby lines to infer method for routes that had no explicit pairing
478
+ // We do a second pass: for each known path, look within ±8 lines of each
479
+ // occurrence for if (req.method === "X") blocks.
480
+ const lines = source.split("\n");
481
+ for (const [rPath, methods] of routes) {
482
+ if (methods.size > 0) continue; // already has methods from pattern matching
483
+ const escapedPath = rPath.replace(/[/.*+?^${}()|[\]\\]/g, "\\$&");
484
+ const lineRe = new RegExp(`["']${escapedPath}["']`);
485
+ for (let i = 0; i < lines.length; i++) {
486
+ if (!lineRe.test(lines[i])) continue;
487
+ for (let j = Math.max(0, i - 2); j < Math.min(lines.length, i + 12); j++) {
488
+ const methodMatch = lines[j].match(/req\.method\s*===\s*["'](GET|POST|DELETE|PUT|PATCH)["']/);
489
+ if (methodMatch) methods.add(methodMatch[1].toLowerCase());
490
+ }
491
+ }
492
+ }
493
+
494
+ return routes;
495
+ }
496
+
497
+ // ---------------------------------------------------------------------------
498
+ // Scan validate() calls to associate Zod schemas with routes
499
+ // ---------------------------------------------------------------------------
500
+
501
+ function scanValidations(filePath) {
502
+ const source = fs.readFileSync(filePath, "utf8");
503
+ const lines = source.split("\n");
504
+ const result = {}; // routePath → schemaName
505
+
506
+ for (let i = 0; i < lines.length; i++) {
507
+ const pathMatch = lines[i].match(/(?:url|parsedUrl)\.pathname\s*===\s*["']([^"']+)["']/);
508
+ if (!pathMatch) continue;
509
+ const rPath = pathMatch[1];
510
+ for (let j = i; j < Math.min(i + 15, lines.length); j++) {
511
+ const valMatch = lines[j].match(/\bvalidate\((\w+Schema)\b/);
512
+ if (valMatch) {
513
+ result[rPath] = valMatch[1];
514
+ break;
515
+ }
516
+ }
517
+ }
518
+ return result;
519
+ }
520
+
521
+ // ---------------------------------------------------------------------------
522
+ // Build a per-server route table by merging scan output with manual overrides
523
+ // ---------------------------------------------------------------------------
524
+
525
+ /**
526
+ * Merge scanned routes and manual overrides into a unified map:
527
+ * routePath → { method: tag, ... }
528
+ *
529
+ * Priority:
530
+ * 1. Manual override provides the tag for a (path, method) pair.
531
+ * 2. If path is in override table but scanned method is missing from override,
532
+ * keep the scanned method and infer the tag.
533
+ * 3. Newly scanned paths not in override table get auto-generated tags.
534
+ */
535
+ function mergeRoutes(scanned, overrides) {
536
+ const merged = {};
537
+
538
+ // Start from manual overrides (authoritative for their paths)
539
+ for (const [rPath, methodTags] of Object.entries(overrides)) {
540
+ merged[rPath] = { ...methodTags };
541
+ }
542
+
543
+ // Layer in scanned routes
544
+ for (const [rPath, methods] of scanned) {
545
+ if (!merged[rPath]) merged[rPath] = {};
546
+ for (const method of methods) {
547
+ if (!merged[rPath][method]) {
548
+ // Auto-tag
549
+ merged[rPath][method] = inferTag(rPath);
550
+ }
551
+ // If method already in override, keep the override tag (already there)
552
+ }
553
+ // If scanned path has no methods at all (only path known), and it's not in
554
+ // overrides yet, we can't add it without a method — skip.
555
+ }
556
+
557
+ return merged;
558
+ }
559
+
560
+ // ---------------------------------------------------------------------------
561
+ // Build OpenAPI path object
562
+ // ---------------------------------------------------------------------------
563
+
564
+ function buildPathEntry(routePath, methodTags, zodSchema, isAutoGenerated) {
221
565
  const pathObj = {};
222
- const methodList = typeof methods === "string" ? [methods] : methods;
223
-
224
- for (const method of methodList) {
225
- pathObj[method] = {
566
+ for (const [method, tag] of Object.entries(methodTags)) {
567
+ const entry = {
226
568
  tags: [tag],
227
- summary: `${method.toUpperCase()} ${path}`,
569
+ summary: `${method.toUpperCase()} ${routePath}`,
570
+ description: isAutoGenerated
571
+ ? `Auto-discovered endpoint. Method: ${method.toUpperCase()}.`
572
+ : undefined,
228
573
  responses: {
229
574
  "200": {
230
575
  description: "Success",
231
- content: {
232
- "application/json": {
233
- schema: { type: "object" }
234
- }
235
- }
236
- }
237
- }
576
+ content: { "application/json": { schema: { type: "object" } } },
577
+ },
578
+ },
238
579
  };
239
-
240
- // Add request body for POST/PUT/PATCH
580
+ if (zodSchema) {
581
+ entry.description = (entry.description || "") +
582
+ ` Validated with ${zodSchema}.`;
583
+ }
584
+ if (!entry.description) delete entry.description;
241
585
  if (["post", "put", "patch"].includes(method)) {
242
- pathObj[method].requestBody = {
243
- content: {
244
- "application/json": {
245
- "schema": { type: "object" }
246
- }
247
- }
586
+ entry.requestBody = {
587
+ content: { "application/json": { schema: { type: "object" } } },
248
588
  };
249
589
  }
590
+ pathObj[method] = entry;
250
591
  }
251
-
252
592
  return pathObj;
253
593
  }
254
594
 
255
- // Merge dashboard endpoints
256
- for (const [path, methodsOrObj] of Object.entries(dashboardEndpoints)) {
257
- if (typeof methodsOrObj === "object" && !Array.isArray(methodsOrObj)) {
258
- const methods = Object.keys(methodsOrObj);
259
- const tags = Object.values(methodsOrObj);
260
- spec.paths[path] = {};
261
- for (let i = 0; i < methods.length; i++) {
262
- spec.paths[path][methods[i]] = {
263
- tags: [tags[i]],
264
- summary: `${methods[i].toUpperCase()} ${path}`,
265
- responses: {
266
- "200": {
267
- description: "Success",
268
- content: {
269
- "application/json": {
270
- schema: { type: "object" }
271
- }
272
- }
273
- }
274
- }
275
- };
276
- if (["post", "put", "patch"].includes(methods[i])) {
277
- spec.paths[path][methods[i]].requestBody = {
278
- content: {
279
- "application/json": {
280
- schema: { type: "object" }
281
- }
282
- }
283
- };
284
- }
285
- }
286
- }
287
- }
595
+ // ---------------------------------------------------------------------------
596
+ // Main pipeline
597
+ // ---------------------------------------------------------------------------
598
+
599
+ const sources = [
600
+ {
601
+ label: "dashboard (scripts/dashboard.mjs)",
602
+ file: path.join(rootDir, "scripts/dashboard.mjs"),
603
+ overrides: dashboardOverrides,
604
+ },
605
+ {
606
+ label: "crew-lead (lib/crew-lead/http-server.mjs)",
607
+ file: path.join(rootDir, "lib/crew-lead/http-server.mjs"),
608
+ overrides: crewLeadOverrides,
609
+ },
610
+ {
611
+ label: "vibe (apps/vibe/server.mjs)",
612
+ file: path.join(rootDir, "apps/vibe/server.mjs"),
613
+ overrides: vibeOverrides,
614
+ },
615
+ {
616
+ label: "crew-cli (crew-cli/src/interface/server.ts)",
617
+ file: path.join(rootDir, "crew-cli/src/interface/server.ts"),
618
+ overrides: crewCliOverrides,
619
+ },
620
+ ];
621
+
622
+ const summaryRows = [];
623
+ let totalManualCount = 0;
624
+ let totalAutoCount = 0;
288
625
 
289
- // Merge crew-lead endpoints
290
- for (const [path, methodsOrObj] of Object.entries(crewLeadEndpoints)) {
291
- if (!spec.paths[path]) {
292
- spec.paths[path] = {};
626
+ for (const src of sources) {
627
+ let scanned;
628
+ try {
629
+ scanned = scanSourceFile(src.file);
630
+ } catch (err) {
631
+ console.warn(` [WARN] Could not read ${src.file}: ${err.message}`);
632
+ scanned = new Map();
293
633
  }
294
- if (typeof methodsOrObj === "object" && !Array.isArray(methodsOrObj)) {
295
- const methods = Object.keys(methodsOrObj);
296
- const tags = Object.values(methodsOrObj);
297
- for (let i = 0; i < methods.length; i++) {
298
- if (!spec.paths[path][methods[i]]) {
299
- spec.paths[path][methods[i]] = {
300
- tags: [tags[i]],
301
- summary: `${methods[i].toUpperCase()} ${path}`,
302
- responses: {
303
- "200": {
304
- description: "Success",
305
- content: {
306
- "application/json": {
307
- schema: { type: "object" }
308
- }
309
- }
310
- }
311
- }
312
- };
313
- if (["post", "put", "patch"].includes(methods[i])) {
314
- spec.paths[path][methods[i]].requestBody = {
315
- content: {
316
- "application/json": {
317
- schema: { type: "object" }
318
- }
319
- }
320
- };
634
+
635
+ const validations = (() => {
636
+ try { return scanValidations(src.file); } catch { return {}; }
637
+ })();
638
+
639
+ const merged = mergeRoutes(scanned, src.overrides);
640
+
641
+ let fileManual = 0;
642
+ let fileAuto = 0;
643
+
644
+ for (const [rPath, methodTags] of Object.entries(merged)) {
645
+ if (Object.keys(methodTags).length === 0) continue; // path-only scan, no method known
646
+
647
+ const isManual = src.overrides[rPath] !== undefined;
648
+ const zodSchema = validations[rPath];
649
+ const isAutoGenerated = !isManual;
650
+
651
+ if (isManual) fileManual++; else fileAuto++;
652
+
653
+ const pathEntry = buildPathEntry(rPath, methodTags, zodSchema, isAutoGenerated);
654
+
655
+ if (!spec.paths[rPath]) {
656
+ spec.paths[rPath] = pathEntry;
657
+ } else {
658
+ // Merge methods — don't overwrite existing ones from higher-priority sources
659
+ for (const [method, opObj] of Object.entries(pathEntry)) {
660
+ if (!spec.paths[rPath][method]) {
661
+ spec.paths[rPath][method] = opObj;
321
662
  }
322
663
  }
323
664
  }
324
665
  }
666
+
667
+ totalManualCount += fileManual;
668
+ totalAutoCount += fileAuto;
669
+ summaryRows.push({
670
+ source: src.label,
671
+ scannedPaths: scanned.size,
672
+ merged: Object.keys(merged).length,
673
+ manual: fileManual,
674
+ auto: fileAuto,
675
+ });
325
676
  }
326
677
 
678
+ // ---------------------------------------------------------------------------
327
679
  // Write output
680
+ // ---------------------------------------------------------------------------
681
+
328
682
  const outputPath = path.join(rootDir, "crew-cli/docs/openapi.complete.v2.json");
329
683
  fs.writeFileSync(outputPath, JSON.stringify(spec, null, 2), "utf8");
330
684
 
331
- console.log(`✅ Generated complete OpenAPI spec:`);
332
- console.log(` ${outputPath}`);
333
- console.log(` ${Object.keys(spec.paths).length} endpoints documented`);
334
- console.log(` ${spec.tags.length} tag categories`);
685
+ // ---------------------------------------------------------------------------
686
+ // Summary report
687
+ // ---------------------------------------------------------------------------
688
+
689
+ const totalPaths = Object.keys(spec.paths).length;
690
+ // Count individual (path, method) pairs across all paths
691
+ const totalOps = Object.values(spec.paths).reduce(
692
+ (n, pathObj) => n + Object.keys(pathObj).length, 0
693
+ );
694
+
695
+ console.log("");
696
+ console.log("crewswarm OpenAPI generator — dynamic scan + manual override merge");
697
+ console.log("=".repeat(68));
698
+ console.log("");
699
+ console.log("Source files scanned:");
700
+ console.log("-".repeat(68));
701
+
702
+ const col = (s, w) => String(s).padEnd(w);
703
+ console.log(
704
+ col("Source", 44) +
705
+ col("Scanned", 9) +
706
+ col("Manual", 8) +
707
+ col("Auto", 6)
708
+ );
709
+ console.log("-".repeat(68));
710
+ for (const r of summaryRows) {
711
+ console.log(
712
+ col(r.source, 44) +
713
+ col(r.scannedPaths, 9) +
714
+ col(r.manual, 8) +
715
+ col(r.auto, 6)
716
+ );
717
+ }
718
+ console.log("-".repeat(68));
719
+ console.log(
720
+ col("TOTAL", 44) +
721
+ col("", 9) +
722
+ col(totalManualCount, 8) +
723
+ col(totalAutoCount, 6)
724
+ );
725
+ console.log("");
726
+ console.log(`Output: ${outputPath}`);
727
+ console.log(` Unique paths : ${totalPaths}`);
728
+ console.log(` Operations : ${totalOps} (path × method pairs)`);
729
+ console.log(` Tag categories: ${spec.tags.length}`);
730
+ console.log(` Manual desc. : ${totalManualCount} paths`);
731
+ console.log(` Auto-generated: ${totalAutoCount} paths`);
732
+ console.log("");
733
+
734
+ if (totalOps < 182) {
735
+ console.warn(` [WARN] Expected >= 182 operations but only got ${totalOps}.`);
736
+ process.exitCode = 1;
737
+ } else {
738
+ console.log(` [OK] >= 182 operations confirmed.`);
739
+ }
740
+ console.log("");