crewswarm 0.9.2 → 0.9.3

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 (207) hide show
  1. package/README.md +22 -9
  2. package/apps/dashboard/dist/assets/{chat-core-Cx4sTxDd.js → chat-core-3KirthZA.js} +1 -1
  3. package/apps/dashboard/dist/assets/index-GSWxxEPO.js +2 -0
  4. package/apps/dashboard/dist/assets/{tab-pm-loop-tab-Bfd449B4.js → tab-pm-loop-tab-DiAPTJXu.js} +1 -1
  5. package/apps/dashboard/dist/assets/{tab-projects-tab-DhNWnlzt.js → tab-projects-tab-SFH4E--a.js} +1 -1
  6. package/apps/dashboard/dist/assets/tab-settings-tab-BselH1c0.js +1 -0
  7. package/apps/dashboard/dist/index.html +82 -11
  8. package/apps/vibe/README.md +2 -2
  9. package/apps/vibe/package.json +1 -1
  10. package/apps/vibe/server.mjs +3 -3
  11. package/crew-lead.mjs +34 -4
  12. package/lib/bridges/gateway-ws.mjs +4 -0
  13. package/lib/crew-lead/chat-handler.mjs +34 -0
  14. package/lib/crew-lead/http-server.mjs +55 -14
  15. package/lib/crew-lead/llm-caller.mjs +24 -8
  16. package/lib/crew-lead/prompts.mjs +7 -0
  17. package/lib/crew-lead/wave-dispatcher.mjs +15 -3
  18. package/lib/crew-lead/ws-router.mjs +219 -27
  19. package/lib/engines/engine-registry.mjs +9 -0
  20. package/lib/engines/rt-envelope.mjs +1 -0
  21. package/lib/engines/runners.mjs +5 -2
  22. package/lib/runtime/paths.mjs +12 -8
  23. package/package.json +35 -15
  24. package/scripts/capture-build-flow.mjs +118 -0
  25. package/scripts/coverage-report.mjs +209 -0
  26. package/scripts/coverage-summary.mjs +47 -0
  27. package/scripts/dashboard-validation.mjs +74 -0
  28. package/scripts/dashboard.mjs +560 -70
  29. package/scripts/live-bridge-matrix.mjs +79 -0
  30. package/scripts/live-cli-matrix.mjs +166 -0
  31. package/scripts/live-crewchat-check.mjs +42 -0
  32. package/scripts/live-engine-matrix.mjs +50 -0
  33. package/scripts/live-provider-failover-matrix.mjs +107 -0
  34. package/scripts/live-provider-matrix.mjs +228 -0
  35. package/scripts/restart-all-from-repo.sh +4 -4
  36. package/scripts/smoke-dispatch.mjs +4 -1
  37. package/scripts/test-blast-radius.mjs +204 -0
  38. package/scripts/test-report-summary.mjs +88 -0
  39. package/scripts/test-reporter.mjs +651 -0
  40. package/scripts/test-rerun.mjs +136 -0
  41. package/scripts/tmux-bridge +130 -0
  42. package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
  43. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  44. package/apps/dashboard/dist/assets/components-BS9fQjE_.js.br +0 -0
  45. package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js.br +0 -0
  46. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  47. package/apps/dashboard/dist/assets/index-DnClJ1ee.js +0 -2
  48. package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
  49. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  50. package/apps/dashboard/dist/assets/setup-wizard-CA0Or47w.js.br +0 -0
  51. package/apps/dashboard/dist/assets/tab-agents-tab-BgpIsjkw.js.br +0 -0
  52. package/apps/dashboard/dist/assets/tab-comms-tab-kguqTIzD.js.br +0 -0
  53. package/apps/dashboard/dist/assets/tab-contacts-tab-DiOyMYth.js.br +0 -0
  54. package/apps/dashboard/dist/assets/tab-engines-tab-BsdZVvU0.js.br +0 -0
  55. package/apps/dashboard/dist/assets/tab-memory-tab-Cu6u13EQ.js.br +0 -0
  56. package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
  57. package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
  58. package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
  59. package/apps/dashboard/dist/assets/tab-prompts-tab-DVkUNaJd.js.br +0 -0
  60. package/apps/dashboard/dist/assets/tab-services-tab-DU_LH3uG.js.br +0 -0
  61. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js +0 -1
  62. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
  63. package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
  64. package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js.br +0 -0
  65. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BNrd88-r.js.br +0 -0
  66. package/apps/dashboard/dist/assets/tab-swarm-tab-B1AcjL1W.js.br +0 -0
  67. package/apps/dashboard/dist/assets/tab-usage-tab-BIOOnB-Y.js.br +0 -0
  68. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  69. package/apps/dashboard/dist/assets/tab-workflows-tab-B-soSy1k.js.br +0 -0
  70. package/apps/dashboard/dist/index.html.br +0 -0
  71. package/apps/dashboard/dist/index.html.gz +0 -0
  72. package/apps/dashboard/index.html +0 -6529
  73. package/apps/dashboard/package.json +0 -15
  74. package/apps/dashboard/src/app.js +0 -2828
  75. package/apps/dashboard/src/app.js.br +0 -0
  76. package/apps/dashboard/src/app.js.gz +0 -0
  77. package/apps/dashboard/src/chat/chat-actions.js +0 -1847
  78. package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
  79. package/apps/dashboard/src/chat/unified-messages.js +0 -327
  80. package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
  81. package/apps/dashboard/src/cli-process.js +0 -208
  82. package/apps/dashboard/src/cli-process.js.br +0 -0
  83. package/apps/dashboard/src/cli-process.js.gz +0 -0
  84. package/apps/dashboard/src/components/active-tasks-panel.js +0 -175
  85. package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
  86. package/apps/dashboard/src/core/api.js +0 -18
  87. package/apps/dashboard/src/core/api.js.br +0 -0
  88. package/apps/dashboard/src/core/dom.js +0 -228
  89. package/apps/dashboard/src/core/dom.js.br +0 -0
  90. package/apps/dashboard/src/core/state.js +0 -91
  91. package/apps/dashboard/src/core/state.js.br +0 -0
  92. package/apps/dashboard/src/core/task-manager.js +0 -134
  93. package/apps/dashboard/src/core/task-manager.js.br +0 -0
  94. package/apps/dashboard/src/orchestration-status.js +0 -127
  95. package/apps/dashboard/src/orchestration-status.js.br +0 -0
  96. package/apps/dashboard/src/setup-wizard.js +0 -562
  97. package/apps/dashboard/src/setup-wizard.js.br +0 -0
  98. package/apps/dashboard/src/styles.css +0 -2085
  99. package/apps/dashboard/src/styles.css.br +0 -0
  100. package/apps/dashboard/src/styles.css.gz +0 -0
  101. package/apps/dashboard/src/tabs/agents-tab.js +0 -2237
  102. package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
  103. package/apps/dashboard/src/tabs/benchmarks-tab.js +0 -229
  104. package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
  105. package/apps/dashboard/src/tabs/comms-tab.js +0 -955
  106. package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
  107. package/apps/dashboard/src/tabs/contacts-tab.js +0 -654
  108. package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
  109. package/apps/dashboard/src/tabs/engines-tab.js +0 -175
  110. package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
  111. package/apps/dashboard/src/tabs/memory-tab.js +0 -182
  112. package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
  113. package/apps/dashboard/src/tabs/models-tab.js +0 -450
  114. package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
  115. package/apps/dashboard/src/tabs/pm-loop-tab.js +0 -185
  116. package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
  117. package/apps/dashboard/src/tabs/projects-tab.js +0 -663
  118. package/apps/dashboard/src/tabs/projects-tab.js.br +0 -0
  119. package/apps/dashboard/src/tabs/projects-tab.js.gz +0 -0
  120. package/apps/dashboard/src/tabs/prompts-tab.js +0 -160
  121. package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
  122. package/apps/dashboard/src/tabs/services-tab.js +0 -202
  123. package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
  124. package/apps/dashboard/src/tabs/settings-tab.js +0 -861
  125. package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
  126. package/apps/dashboard/src/tabs/skills-tab.js +0 -284
  127. package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
  128. package/apps/dashboard/src/tabs/spending-tab.js +0 -173
  129. package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
  130. package/apps/dashboard/src/tabs/swarm-chat-tab.js +0 -660
  131. package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
  132. package/apps/dashboard/src/tabs/swarm-tab.js +0 -538
  133. package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
  134. package/apps/dashboard/src/tabs/usage-tab.js +0 -390
  135. package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
  136. package/apps/dashboard/src/tabs/waves-tab.js +0 -238
  137. package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
  138. package/apps/dashboard/src/tabs/workflows-tab.js +0 -747
  139. package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
  140. package/apps/vibe/.crew/agent-memory/pipeline.json +0 -304
  141. package/apps/vibe/.crew/cost.json +0 -17
  142. package/apps/vibe/.crew/json-parse-metrics.jsonl +0 -27
  143. package/apps/vibe/.crew/pipeline-metrics.jsonl +0 -27
  144. package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +0 -5
  145. package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +0 -5
  146. package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +0 -5
  147. package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +0 -5
  148. package/apps/vibe/.crew/pipeline-runs/pipeline-3da23550-22ed-4904-9a0a-8e79c1f3024c.jsonl +0 -5
  149. package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +0 -5
  150. package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +0 -5
  151. package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +0 -5
  152. package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +0 -5
  153. package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +0 -5
  154. package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +0 -5
  155. package/apps/vibe/.crew/pipeline-runs/pipeline-6413fa33-a802-4b57-a8c0-a9056ad67842.jsonl +0 -5
  156. package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +0 -5
  157. package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +0 -5
  158. package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +0 -5
  159. package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +0 -5
  160. package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +0 -5
  161. package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +0 -5
  162. package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +0 -5
  163. package/apps/vibe/.crew/pipeline-runs/pipeline-9bef2dd2-6122-42e5-b3d9-19f4d80f9e40.jsonl +0 -5
  164. package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +0 -5
  165. package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +0 -2
  166. package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +0 -5
  167. package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +0 -5
  168. package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +0 -5
  169. package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +0 -5
  170. package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +0 -5
  171. package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +0 -5
  172. package/apps/vibe/.crew/sandbox.json +0 -7
  173. package/apps/vibe/.crew/session.json +0 -330
  174. package/apps/vibe/.crew/training-data.jsonl +0 -0
  175. package/apps/vibe/.github/workflows/studio-quality.yml +0 -37
  176. package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +0 -18
  177. package/apps/vibe/.studio-data/project-messages/general.jsonl +0 -81
  178. package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +0 -18
  179. package/apps/vibe/ARCHITECTURE.md +0 -3393
  180. package/apps/vibe/QUICK-REFERENCE.md +0 -211
  181. package/apps/vibe/ROADMAP.md +0 -41
  182. package/apps/vibe/STUDIO-SETUP-COMPLETE.md +0 -35
  183. package/apps/vibe/VISUAL-GUIDE.md +0 -378
  184. package/apps/vibe/capture-demo.mjs +0 -160
  185. package/apps/vibe/capture-full-demo.mjs +0 -255
  186. package/apps/vibe/capture-quickstart.mjs +0 -256
  187. package/apps/vibe/capture-vibe-assets.mjs +0 -71
  188. package/apps/vibe/capture-vibe-video.mjs +0 -260
  189. package/apps/vibe/check-buttons.js +0 -41
  190. package/apps/vibe/diagnose.html +0 -106
  191. package/apps/vibe/fix-buttons.js +0 -103
  192. package/apps/vibe/index.html +0 -3404
  193. package/apps/vibe/package-lock.json +0 -920
  194. package/apps/vibe/scripts/studio-pty-host.py +0 -117
  195. package/apps/vibe/src/main.js +0 -2940
  196. package/apps/vibe/src/register-all-languages.js +0 -98
  197. package/apps/vibe/start-studio.sh +0 -11
  198. package/apps/vibe/test/accessibility-tests.js +0 -77
  199. package/apps/vibe/test/browser-performance-audit.mjs +0 -205
  200. package/apps/vibe/test/performance-tests.js +0 -120
  201. package/apps/vibe/test/security-tests.js +0 -213
  202. package/apps/vibe/tests/e2e.local.mjs +0 -54
  203. package/apps/vibe/tests/server.smoke.mjs +0 -106
  204. package/apps/vibe/update_website.mjs +0 -74
  205. package/apps/vibe/vite.config.js +0 -19
  206. package/lib/crew-lead/chat-handler.mjs.bak +0 -1274
  207. package/lib/engines/rt-envelope.mjs.backup-current +0 -870
@@ -1612,6 +1612,7 @@ export async function handleRealtimeEnvelope(envelope, client, bridge) {
1612
1612
  payload: {
1613
1613
  source: CREWSWARM_RT_AGENT,
1614
1614
  error: message,
1615
+ engineUsed: typeof engineUsed !== "undefined" ? engineUsed : null,
1615
1616
  idempotencyKey: dispatchKey,
1616
1617
  attempt: dispatchAttempt,
1617
1618
  },
@@ -1181,6 +1181,7 @@ export async function runClaudeCodeTask(prompt, payload = {}) {
1181
1181
  const agentPrefix = agentId ? `[${agentId}]` : "";
1182
1182
  const titledPrompt = agentPrefix ? `${agentPrefix} ${String(prompt)}` : String(prompt);
1183
1183
 
1184
+ const emptyMcpCfg = path.join(os.homedir(), ".crewswarm", "config", "empty-mcp.json");
1184
1185
  const args = [
1185
1186
  "-p",
1186
1187
  "--dangerously-skip-permissions",
@@ -1205,8 +1206,10 @@ export async function runClaudeCodeTask(prompt, payload = {}) {
1205
1206
  }
1206
1207
  }
1207
1208
 
1208
- // CRITICAL: Claude Code expects the prompt as a command-line argument, NOT via stdin
1209
- args.push(titledPrompt);
1209
+ // Skip user MCP servers to avoid 30s+ init hangs
1210
+ args.push("--strict-mcp-config", "--mcp-config", emptyMcpCfg);
1211
+ // -- separates flags from prompt (--mcp-config is variadic and eats positional args)
1212
+ args.push("--", titledPrompt);
1210
1213
 
1211
1214
  if (!which(CLAUDE_CODE_BIN)) {
1212
1215
  throw new Error(`Claude Code CLI not found: "${CLAUDE_CODE_BIN}". Install with: npm i -g @anthropic-ai/claude-code`);
@@ -21,14 +21,16 @@ let _stateDir = null;
21
21
  */
22
22
  export function getConfigDir() {
23
23
  if (_configDir) return _configDir;
24
-
25
- if (process.env.CREWSWARM_TEST_MODE === "true") {
24
+
25
+ if (process.env.CREWSWARM_CONFIG_DIR) {
26
+ _configDir = process.env.CREWSWARM_CONFIG_DIR;
27
+ } else if (process.env.CREWSWARM_TEST_MODE === "true") {
26
28
  // Use a consistent temp dir for the entire test process (not per-call)
27
29
  _configDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
28
30
  } else {
29
- _configDir = process.env.CREWSWARM_CONFIG_DIR || path.join(os.homedir(), ".crewswarm");
31
+ _configDir = path.join(os.homedir(), ".crewswarm");
30
32
  }
31
-
33
+
32
34
  fs.mkdirSync(_configDir, { recursive: true });
33
35
  return _configDir;
34
36
  }
@@ -39,14 +41,16 @@ export function getConfigDir() {
39
41
  */
40
42
  export function getStateDir() {
41
43
  if (_stateDir) return _stateDir;
42
-
43
- if (process.env.CREWSWARM_TEST_MODE === "true") {
44
+
45
+ if (process.env.CREWSWARM_STATE_DIR) {
46
+ _stateDir = process.env.CREWSWARM_STATE_DIR;
47
+ } else if (process.env.CREWSWARM_TEST_MODE === "true") {
44
48
  // Use a consistent temp dir for the entire test process (not per-call)
45
49
  _stateDir = path.join(os.tmpdir(), `crewswarm-test-${process.pid}`);
46
50
  } else {
47
- _stateDir = process.env.CREWSWARM_STATE_DIR || path.join(os.homedir(), ".crewswarm");
51
+ _stateDir = path.join(os.homedir(), ".crewswarm");
48
52
  }
49
-
53
+
50
54
  fs.mkdirSync(_stateDir, { recursive: true });
51
55
  return _stateDir;
52
56
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "crewswarm",
3
- "version": "0.9.2",
4
- "description": "Local-first multi-agent orchestration platform coordinate AI coding agents, LLMs, and tools from a single dashboard",
3
+ "version": "0.9.3",
4
+ "description": "Local-first multi-agent orchestration platform \u2014 coordinate AI coding agents, LLMs, and tools from a single dashboard",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -29,10 +29,11 @@
29
29
  "engines/",
30
30
  "prompts/",
31
31
  "apps/dashboard/dist/",
32
- "apps/dashboard/src/",
33
- "apps/dashboard/index.html",
34
- "apps/dashboard/package.json",
35
- "apps/vibe/",
32
+ "apps/vibe/dist/",
33
+ "apps/vibe/package.json",
34
+ "apps/vibe/public/",
35
+ "apps/vibe/server.mjs",
36
+ "apps/vibe/watch-server.mjs",
36
37
  "contrib/openclaw-plugin/",
37
38
  "crew-lead.mjs",
38
39
  "gateway-bridge.mjs",
@@ -61,14 +62,25 @@
61
62
  "@whiskeysockets/baileys": "^7.0.0-rc.9"
62
63
  },
63
64
  "scripts": {
64
- "postinstall": "node -e \"try{require('child_process').execSync('git --version',{stdio:'pipe'})}catch{console.log('\\n⚠️ git not found. Install git for full functionality (WhatsApp bridge, crew-cli git tools).\\n macOS: xcode-select --install\\n Ubuntu: sudo apt install git\\n Alpine: apk add git\\n')}\"",
65
+ "postinstall": "node -e \"try{require('child_process').execSync('git --version',{stdio:'pipe'})}catch{console.log('\\n\u26a0\ufe0f git not found. Install git for full functionality (WhatsApp bridge, crew-cli git tools).\\n macOS: xcode-select --install\\n Ubuntu: sudo apt install git\\n Alpine: apk add git\\n')}\"",
65
66
  "start": "node scripts/start.mjs",
66
- "test": "node --test test/unit/*.test.mjs test/mention-participants.test.mjs test/project-messages-chat-protocol.test.mjs && npm --prefix crew-cli test",
67
- "test:unit": "node --test test/unit/*.test.mjs",
68
- "test:integration": "PM_LOOP_TEST_MODE=1 node --test test/integration/*.test.mjs",
67
+ "test": "node --test --test-reporter=./scripts/test-reporter.mjs test/unit/*.test.mjs test/mention-participants.test.mjs test/project-messages-chat-protocol.test.mjs && npm --prefix crew-cli test",
68
+ "test:unit": "node --test --test-reporter=./scripts/test-reporter.mjs test/unit/*.test.mjs",
69
+ "test:integration": "PM_LOOP_TEST_MODE=1 node --test --test-reporter=./scripts/test-reporter.mjs test/integration/*.test.mjs",
69
70
  "test:integration:bounded": "node scripts/run-integration-bounded.mjs",
70
- "test:e2e": "node --test test/e2e/*.test.mjs",
71
- "test:all": "PM_LOOP_TEST_MODE=1 node --test test/unit/*.test.mjs test/integration/*.test.mjs test/e2e/*.test.mjs",
71
+ "test:e2e": "node --test --test-reporter=./scripts/test-reporter.mjs test/e2e/*.test.mjs",
72
+ "test:all": "PM_LOOP_TEST_MODE=1 node --test --test-reporter=./scripts/test-reporter.mjs test/unit/*.test.mjs test/integration/*.test.mjs test/e2e/*.test.mjs",
73
+ "test:coverage:root": "node --test --experimental-test-coverage test/unit/*.test.mjs",
74
+ "test:coverage": "node scripts/coverage-report.mjs",
75
+ "test:coverage:summary": "node scripts/coverage-summary.mjs",
76
+ "test:live:providers": "node scripts/live-provider-failover-matrix.mjs",
77
+ "test:live:providers:matrix": "node scripts/live-provider-matrix.mjs",
78
+ "test:live:providers:smoke": "node scripts/live-provider-matrix.mjs --smoke",
79
+ "test:live:clis": "node scripts/live-cli-matrix.mjs",
80
+ "test:live:clis:smoke": "node scripts/live-cli-matrix.mjs --smoke",
81
+ "test:live:bridges": "node scripts/live-bridge-matrix.mjs",
82
+ "test:live:crewchat": "node scripts/live-crewchat-check.mjs",
83
+ "test:live": "node scripts/live-provider-failover-matrix.mjs && node scripts/live-bridge-matrix.mjs && node scripts/live-crewchat-check.mjs",
72
84
  "docs:api": "node scripts/generate-api-docs.mjs",
73
85
  "changelog:generate": "node scripts/generate-changelog.mjs",
74
86
  "changelog:release": "node scripts/generate-changelog.mjs --release",
@@ -86,7 +98,12 @@
86
98
  "stop-crew": "node scripts/start-crew.mjs --stop",
87
99
  "dashboard": "node scripts/dashboard.mjs",
88
100
  "vibe": "node apps/vibe/server.mjs",
89
- "vibe:watch": "node apps/vibe/watch-server.mjs",
101
+ "vibe:build": "cd apps/vibe && npm run build",
102
+ "vibe:start": "cd apps/vibe && NODE_DISABLE_COMPILE_CACHE=1 npm start",
103
+ "vibe:watch": "NODE_DISABLE_COMPILE_CACHE=1 node apps/vibe/watch-server.mjs",
104
+ "vibe:full": "bash scripts/start-studio-full.sh",
105
+ "test:e2e:vibe": "node node_modules/playwright/cli.js test --config=playwright.config.js",
106
+ "test:e2e:vibe:headed": "node node_modules/playwright/cli.js test --config=playwright.config.js --headed",
90
107
  "crew-lead": "node crew-lead.mjs",
91
108
  "mcp": "node scripts/mcp-server.mjs",
92
109
  "studio": "cd apps/vibe && npm run dev",
@@ -100,10 +117,13 @@
100
117
  "smoke:static": "bash scripts/smoke.sh",
101
118
  "health": "node scripts/health-check.mjs",
102
119
  "doctor": "node scripts/doctor.mjs",
103
- "release:check": "bash scripts/release-check.sh"
120
+ "release:check": "bash scripts/release-check.sh",
121
+ "test:report": "node scripts/test-report-summary.mjs",
122
+ "test:rerun": "node scripts/test-rerun.mjs",
123
+ "test:stale": "node scripts/test-rerun.mjs --stale"
104
124
  },
105
125
  "devDependencies": {
106
126
  "@playwright/test": "^1.58.2",
107
127
  "puppeteer-core": "^24.40.0"
108
128
  }
109
- }
129
+ }
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * capture-build-flow.mjs — Puppeteer script that captures dashboard
4
+ * screenshots during a build flow for documentation / demo purposes.
5
+ *
6
+ * Usage: node scripts/capture-build-flow.mjs
7
+ * Requires: dashboard running at http://127.0.0.1:4319
8
+ */
9
+
10
+ import { mkdir } from "node:fs/promises";
11
+ import { fileURLToPath } from "node:url";
12
+ import { dirname, resolve } from "node:path";
13
+ import puppeteer from "puppeteer-core";
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const ROOT = resolve(__dirname, "..");
17
+ const OUT_DIR = resolve(ROOT, "website/screenshots/flow");
18
+ const BASE_URL = "http://127.0.0.1:4319";
19
+
20
+ const STEPS = [
21
+ { name: "step1-build-tab", hash: "build", waitMs: 2000 },
22
+ { name: "step2-requirement", action: "type" },
23
+ { name: "step3-plan", action: "plan", waitMs: 20000 },
24
+ { name: "step4-chat", hash: "chat", waitMs: 3000 },
25
+ { name: "step5-agents", hash: "swarm", waitMs: 2000 },
26
+ { name: "step6-rt-messages", hash: "rt", waitMs: 2000 },
27
+ ];
28
+
29
+ async function screenshot(page, name) {
30
+ const path = resolve(OUT_DIR, `${name}.webp`);
31
+ await page.screenshot({ path, type: "webp", quality: 85 });
32
+ }
33
+
34
+ async function sleep(ms) {
35
+ return new Promise((r) => setTimeout(r, ms));
36
+ }
37
+
38
+ async function main() {
39
+ await mkdir(OUT_DIR, { recursive: true });
40
+
41
+ const browser = await puppeteer.launch({
42
+ headless: true,
43
+ executablePath:
44
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
45
+ args: ["--no-sandbox"],
46
+ defaultViewport: { width: 1440, height: 960 },
47
+ });
48
+
49
+ const page = await browser.newPage();
50
+
51
+ // Step 1 — navigate to #build
52
+ await page.goto(`${BASE_URL}/#build`, { waitUntil: "domcontentloaded" });
53
+ await sleep(2000);
54
+ await screenshot(page, "step1-build-tab");
55
+
56
+ // Step 2 — type requirement
57
+ const REQUIREMENT = "Create a simple hello world HTML page";
58
+ // Try a few selectors for the requirement input
59
+ const textareaSelector = await page
60
+ .waitForSelector("textarea, #requirement, .requirement-input", {
61
+ timeout: 5000,
62
+ })
63
+ .catch(() => null);
64
+
65
+ if (textareaSelector) {
66
+ await textareaSelector.click();
67
+ await textareaSelector.type(REQUIREMENT, { delay: 30 });
68
+ }
69
+ await screenshot(page, "step2-requirement");
70
+
71
+ // Step 3 — click Plan and wait for result
72
+ await page.evaluate(() => {
73
+ const buttons = [...document.querySelectorAll("button")];
74
+ const planBtn = buttons.find((b) => /plan/i.test(b.textContent));
75
+ if (planBtn) planBtn.click();
76
+ });
77
+ await sleep(20000);
78
+ await screenshot(page, "step3-plan");
79
+
80
+ // Step 4 — Chat tab
81
+ await page.goto(`${BASE_URL}/#chat`, { waitUntil: "domcontentloaded" });
82
+ await sleep(3000);
83
+ await screenshot(page, "step4-chat");
84
+
85
+ // Step 5 — Swarm / agents tab
86
+ await page.goto(`${BASE_URL}/#swarm`, { waitUntil: "domcontentloaded" });
87
+ await sleep(2000);
88
+ await screenshot(page, "step5-agents");
89
+
90
+ // Step 6 — RT messages tab
91
+ await page.goto(`${BASE_URL}/#rt`, { waitUntil: "domcontentloaded" });
92
+ await sleep(2000);
93
+ await screenshot(page, "step6-rt-messages");
94
+
95
+ await browser.close();
96
+
97
+ const files = [
98
+ "step1-build-tab.webp",
99
+ "step2-requirement.webp",
100
+ "step3-plan.webp",
101
+ "step4-chat.webp",
102
+ "step5-agents.webp",
103
+ "step6-rt-messages.webp",
104
+ ];
105
+
106
+ console.log(`\nCaptured ${files.length} build flow frames:`);
107
+ for (const f of files) {
108
+ console.log(` website/screenshots/flow/${f}`);
109
+ }
110
+ console.log(
111
+ `\nTo create animated webp: convert -delay 200 website/screenshots/flow/*.webp website/screenshots/build-flow.webp`,
112
+ );
113
+ }
114
+
115
+ main().catch((err) => {
116
+ console.error("Build flow capture failed:", err.message);
117
+ process.exit(1);
118
+ });
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+
7
+ const ROOT = process.cwd();
8
+ const OUT_DIR = path.join(ROOT, "coverage");
9
+ fs.mkdirSync(OUT_DIR, { recursive: true });
10
+
11
+ function runStep(name, command, cwd = ROOT, allowFailure = false) {
12
+ console.log(`\n== ${name} ==`);
13
+ const result = spawnSync(command, {
14
+ cwd,
15
+ shell: true,
16
+ encoding: "utf8",
17
+ env: process.env,
18
+ maxBuffer: 20 * 1024 * 1024,
19
+ });
20
+ const combined = `${result.stdout || ""}${result.stderr || ""}`;
21
+ fs.writeFileSync(path.join(OUT_DIR, `${name}.log`), combined);
22
+ if (combined.trim()) process.stdout.write(combined);
23
+ if (result.status !== 0 && !allowFailure) {
24
+ throw new Error(`${name} failed with exit code ${result.status}`);
25
+ }
26
+ return { output: combined, status: result.status ?? 0 };
27
+ }
28
+
29
+ function extractCoverageTail(output) {
30
+ const lines = output.split("\n");
31
+ const start = lines.findIndex((line) => /^\s*file\s*\|/i.test(line) || /^\s*all files\s*\|/i.test(line));
32
+ if (start === -1) return "Coverage summary not found in command output.";
33
+ return lines.slice(start).join("\n").trim();
34
+ }
35
+
36
+ /**
37
+ * Parse the "all files" summary line from Node's --experimental-test-coverage output.
38
+ * Format: `ℹ all files | <line%> | <branch%> | <funcs%> |`
39
+ * Returns { lines, branches, functions } or null if not found.
40
+ */
41
+ function parseCoverageSummary(output) {
42
+ const lines = output.split("\n");
43
+ for (const line of lines) {
44
+ const match = line.match(/all files\s*\|\s*([\d.]+)\s*\|\s*([\d.]+)\s*\|\s*([\d.]+)/);
45
+ if (match) {
46
+ return {
47
+ lines: parseFloat(match[1]),
48
+ branches: parseFloat(match[2]),
49
+ functions: parseFloat(match[3]),
50
+ // Node's built-in coverage reports line% (which is effectively statements)
51
+ statements: parseFloat(match[1]),
52
+ };
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+
58
+ /**
59
+ * Compute a weighted average of two metric objects.
60
+ * Uses a simple average (equal weight) since we don't have file counts per suite.
61
+ */
62
+ function averageMetrics(a, b) {
63
+ if (!a && !b) return { statements: 0, branches: 0, functions: 0, lines: 0 };
64
+ if (!a) return b;
65
+ if (!b) return a;
66
+ const round1 = (n) => Math.round(n * 10) / 10;
67
+ return {
68
+ statements: round1((a.statements + b.statements) / 2),
69
+ branches: round1((a.branches + b.branches) / 2),
70
+ functions: round1((a.functions + b.functions) / 2),
71
+ lines: round1((a.lines + b.lines) / 2),
72
+ };
73
+ }
74
+
75
+ try {
76
+ const rootCoverage = runStep(
77
+ "root-unit-coverage",
78
+ "node --test --experimental-test-coverage test/unit/*.test.mjs"
79
+ );
80
+ const rootIntegration = runStep(
81
+ "root-integration-bounded",
82
+ "node scripts/run-integration-bounded.mjs",
83
+ ROOT,
84
+ true
85
+ );
86
+ const crewCliCoverage = runStep(
87
+ "crew-cli-coverage",
88
+ "npm run test:coverage",
89
+ path.join(ROOT, "crew-cli")
90
+ );
91
+
92
+ // Parse metrics from each suite
93
+ const rootMetrics = parseCoverageSummary(rootCoverage.output);
94
+ const crewCliMetrics = parseCoverageSummary(crewCliCoverage.output);
95
+ const overallMetrics = averageMetrics(rootMetrics, crewCliMetrics);
96
+
97
+ // Build machine-readable summary JSON
98
+ const summaryJson = {
99
+ timestamp: new Date().toISOString(),
100
+ root: rootMetrics
101
+ ? { statements: rootMetrics.statements, branches: rootMetrics.branches, functions: rootMetrics.functions, lines: rootMetrics.lines }
102
+ : null,
103
+ crewCli: crewCliMetrics
104
+ ? { statements: crewCliMetrics.statements, branches: crewCliMetrics.branches, functions: crewCliMetrics.functions, lines: crewCliMetrics.lines }
105
+ : null,
106
+ overall: overallMetrics
107
+ ? { statements: overallMetrics.statements, branches: overallMetrics.branches, functions: overallMetrics.functions, lines: overallMetrics.lines }
108
+ : null,
109
+ };
110
+
111
+ const summaryPath = path.join(OUT_DIR, "coverage-summary.json");
112
+ fs.writeFileSync(summaryPath, JSON.stringify(summaryJson, null, 2) + "\n");
113
+
114
+ // Build markdown report
115
+ function metricsTable(metrics) {
116
+ if (!metrics) return "Coverage metrics could not be parsed.";
117
+ return `| Metric | Value |
118
+ |------------|---------|
119
+ | Statements | ${metrics.statements.toFixed(1)}% |
120
+ | Branches | ${metrics.branches.toFixed(1)}% |
121
+ | Functions | ${metrics.functions.toFixed(1)}% |
122
+ | Lines | ${metrics.lines.toFixed(1)}% |`;
123
+ }
124
+
125
+ const report = `# Repo Coverage Report
126
+
127
+ Generated: ${summaryJson.timestamp}
128
+
129
+ ## Root unit coverage
130
+
131
+ ${metricsTable(rootMetrics)}
132
+
133
+ <details><summary>Full file-by-file report</summary>
134
+
135
+ \`\`\`
136
+ ${extractCoverageTail(rootCoverage.output)}
137
+ \`\`\`
138
+
139
+ </details>
140
+
141
+ ## Root integration verification
142
+
143
+ Exit code: ${rootIntegration.status}
144
+
145
+ <details><summary>Output</summary>
146
+
147
+ \`\`\`
148
+ ${rootIntegration.output.trim() || "No output."}
149
+ \`\`\`
150
+
151
+ </details>
152
+
153
+ ## crew-cli coverage
154
+
155
+ ${metricsTable(crewCliMetrics)}
156
+
157
+ <details><summary>Full file-by-file report</summary>
158
+
159
+ \`\`\`
160
+ ${extractCoverageTail(crewCliCoverage.output)}
161
+ \`\`\`
162
+
163
+ </details>
164
+
165
+ ## Overall (average across suites)
166
+
167
+ ${metricsTable(overallMetrics)}
168
+
169
+ ## Notes
170
+
171
+ - Root coverage currently reports hermetic unit coverage only.
172
+ - Integration and E2E surfaces are reported separately because many depend on running services or external credentials.
173
+ - Use \`docs/CANONICAL/COVERAGE-MATRIX.md\` for feature-by-feature status.
174
+ - Machine-readable metrics: \`coverage/coverage-summary.json\`
175
+
176
+ ## Logs
177
+
178
+ - coverage/root-unit-coverage.log
179
+ - coverage/root-integration-bounded.log
180
+ - coverage/crew-cli-coverage.log
181
+ `;
182
+
183
+ const reportPath = path.join(OUT_DIR, "coverage-report.md");
184
+ fs.writeFileSync(reportPath, report);
185
+
186
+ // Print summary to stdout
187
+ console.log("\n========================================");
188
+ console.log(" Coverage Summary");
189
+ console.log("========================================");
190
+ if (rootMetrics) {
191
+ console.log(` Root: ${rootMetrics.lines.toFixed(1)}% lines | ${rootMetrics.branches.toFixed(1)}% branches | ${rootMetrics.functions.toFixed(1)}% funcs`);
192
+ } else {
193
+ console.log(" Root: (metrics not available)");
194
+ }
195
+ if (crewCliMetrics) {
196
+ console.log(` crew-cli: ${crewCliMetrics.lines.toFixed(1)}% lines | ${crewCliMetrics.branches.toFixed(1)}% branches | ${crewCliMetrics.functions.toFixed(1)}% funcs`);
197
+ } else {
198
+ console.log(" crew-cli: (metrics not available)");
199
+ }
200
+ if (overallMetrics) {
201
+ console.log(` Overall: ${overallMetrics.lines.toFixed(1)}% lines | ${overallMetrics.branches.toFixed(1)}% branches | ${overallMetrics.functions.toFixed(1)}% funcs`);
202
+ }
203
+ console.log("========================================");
204
+ console.log(`\nWrote ${path.relative(ROOT, reportPath)}`);
205
+ console.log(`Wrote ${path.relative(ROOT, summaryPath)}`);
206
+ } catch (error) {
207
+ console.error(`\nCoverage report failed: ${error.message}`);
208
+ process.exit(1);
209
+ }
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Prints the most recent coverage summary from coverage/coverage-summary.json
5
+ * without re-running any tests.
6
+ *
7
+ * Usage: node scripts/coverage-summary.mjs
8
+ * or: npm run test:coverage:summary
9
+ */
10
+
11
+ import fs from "node:fs";
12
+ import path from "node:path";
13
+
14
+ const ROOT = process.cwd();
15
+ const summaryPath = path.join(ROOT, "coverage", "coverage-summary.json");
16
+
17
+ if (!fs.existsSync(summaryPath)) {
18
+ console.error(
19
+ `No coverage summary found at ${summaryPath}\n` +
20
+ `Run "npm run test:coverage" first to generate coverage data.`
21
+ );
22
+ process.exit(1);
23
+ }
24
+
25
+ let data;
26
+ try {
27
+ data = JSON.parse(fs.readFileSync(summaryPath, "utf8"));
28
+ } catch (err) {
29
+ console.error(`Failed to parse ${summaryPath}: ${err.message}`);
30
+ process.exit(1);
31
+ }
32
+
33
+ function fmtRow(label, metrics) {
34
+ if (!metrics) return ` ${label.padEnd(12)} (no data)`;
35
+ return ` ${label.padEnd(12)} ${String(metrics.lines.toFixed(1) + "%").padStart(7)} lines | ${String(metrics.branches.toFixed(1) + "%").padStart(7)} branches | ${String(metrics.functions.toFixed(1) + "%").padStart(7)} funcs`;
36
+ }
37
+
38
+ console.log("========================================");
39
+ console.log(" Coverage Summary");
40
+ console.log(` Generated: ${data.timestamp}`);
41
+ console.log("========================================");
42
+ console.log(fmtRow("Root", data.root));
43
+ console.log(fmtRow("crew-cli", data.crewCli));
44
+ console.log(fmtRow("Overall", data.overall));
45
+ console.log("========================================");
46
+ console.log(`\nFull report: coverage/coverage-report.md`);
47
+ console.log(`JSON data: coverage/coverage-summary.json`);
@@ -88,6 +88,13 @@ export const StartBuildSchema = z.object({
88
88
  projectId: ProjectIdSchema.optional(),
89
89
  });
90
90
 
91
+ export const EnhancePromptSchema = z.object({
92
+ text: z.string().min(1).max(10000),
93
+ projectId: ProjectIdSchema.optional(),
94
+ engine: z.enum(['claude', 'codex', 'cursor', 'gemini', 'gemini-cli', 'opencode', 'crew-cli']).optional(),
95
+ model: z.string().max(200).optional(),
96
+ });
97
+
91
98
  export const StopBuildSchema = z.object({
92
99
  projectId: ProjectIdSchema.optional(),
93
100
  });
@@ -187,6 +194,73 @@ export const UpdateConfigSchema = z.object({
187
194
  geminiCliModel: z.string().optional(),
188
195
  });
189
196
 
197
+ // ── Agent Config (create / delete / reset) ───────────────────────────────
198
+ export const AgentConfigCreateSchema = z.object({
199
+ id: z.string().min(1).max(50),
200
+ model: ModelNameSchema.optional(),
201
+ name: z.string().max(100).optional(),
202
+ emoji: z.string().max(10).optional(),
203
+ theme: z.string().max(200).optional(),
204
+ systemPrompt: z.string().max(50000).optional(),
205
+ alsoAllow: z.array(z.string()).optional(),
206
+ });
207
+
208
+ export const AgentConfigDeleteSchema = z.object({
209
+ agentId: z.string().min(1).max(50),
210
+ });
211
+
212
+ export const AgentResetSessionSchema = z.object({
213
+ agentId: z.string().min(1).max(50),
214
+ });
215
+
216
+ // ── Providers ────────────────────────────────────────────────────────────
217
+ export const ProviderAddSchema = z.object({
218
+ id: z.string().min(1).max(100),
219
+ baseUrl: z.string().min(1).max(1000),
220
+ apiKey: z.string().optional(),
221
+ api: z.string().max(100).optional(),
222
+ });
223
+
224
+ export const ProviderSaveSchema = z.object({
225
+ providerId: z.string().min(1).max(100),
226
+ apiKey: z.string().min(1),
227
+ });
228
+
229
+ export const ProviderTestSchema = z.object({
230
+ providerId: z.string().min(1).max(100),
231
+ });
232
+
233
+ export const ProviderBuiltinTestSchema = z.object({
234
+ providerId: z.string().min(1).max(100),
235
+ });
236
+
237
+ // ── Continuous Build ─────────────────────────────────────────────────────
238
+ export const ContinuousBuildSchema = z.object({
239
+ requirement: z.string().min(1).max(10000),
240
+ projectId: ProjectIdSchema.optional(),
241
+ });
242
+
243
+ // ── Roadmap ──────────────────────────────────────────────────────────────
244
+ export const RoadmapWriteSchema = z.object({
245
+ roadmapFile: z.string().min(1).max(500),
246
+ content: z.string(),
247
+ });
248
+
249
+ export const RoadmapRetryFailedSchema = z.object({
250
+ roadmapFile: z.string().min(1).max(500),
251
+ });
252
+
253
+ // ── Contacts ─────────────────────────────────────────────────────────────
254
+ export const ContactDeleteSchema = z.object({
255
+ contactId: z.string().min(1).max(200),
256
+ });
257
+
258
+ export const ContactSendSchema = z.object({
259
+ contactId: z.string().min(1).max(200),
260
+ message: z.string().min(1).max(10000),
261
+ platform: z.string().max(50).optional(),
262
+ });
263
+
190
264
  // ── Validation Helper ─────────────────────────────────────────────────────
191
265
  export function validate(schema, data) {
192
266
  try {