crewswarm 0.9.1 → 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 (210) 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 +48 -5
  12. package/lib/bridges/gateway-ws.mjs +4 -0
  13. package/lib/bridges/tmux-bridge.mjs +200 -0
  14. package/lib/cli-process-tracker.mjs +2 -1
  15. package/lib/crew-lead/chat-handler.mjs +34 -0
  16. package/lib/crew-lead/http-server.mjs +340 -14
  17. package/lib/crew-lead/llm-caller.mjs +24 -8
  18. package/lib/crew-lead/prompts.mjs +7 -0
  19. package/lib/crew-lead/wave-dispatcher.mjs +53 -3
  20. package/lib/crew-lead/ws-router.mjs +219 -27
  21. package/lib/engines/engine-registry.mjs +9 -0
  22. package/lib/engines/rt-envelope.mjs +1 -0
  23. package/lib/engines/runners.mjs +26 -2
  24. package/lib/runtime/config.mjs +7 -0
  25. package/lib/runtime/paths.mjs +12 -8
  26. package/lib/sessions/session-manager.mjs +287 -0
  27. package/package.json +35 -15
  28. package/scripts/capture-build-flow.mjs +118 -0
  29. package/scripts/coverage-report.mjs +209 -0
  30. package/scripts/coverage-summary.mjs +47 -0
  31. package/scripts/dashboard-validation.mjs +74 -0
  32. package/scripts/dashboard.mjs +560 -70
  33. package/scripts/live-bridge-matrix.mjs +79 -0
  34. package/scripts/live-cli-matrix.mjs +166 -0
  35. package/scripts/live-crewchat-check.mjs +42 -0
  36. package/scripts/live-engine-matrix.mjs +50 -0
  37. package/scripts/live-provider-failover-matrix.mjs +107 -0
  38. package/scripts/live-provider-matrix.mjs +228 -0
  39. package/scripts/restart-all-from-repo.sh +4 -4
  40. package/scripts/smoke-dispatch.mjs +4 -1
  41. package/scripts/test-blast-radius.mjs +204 -0
  42. package/scripts/test-report-summary.mjs +88 -0
  43. package/scripts/test-reporter.mjs +651 -0
  44. package/scripts/test-rerun.mjs +136 -0
  45. package/scripts/tmux-bridge +130 -0
  46. package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
  47. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  48. package/apps/dashboard/dist/assets/components-BS9fQjE_.js.br +0 -0
  49. package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js.br +0 -0
  50. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  51. package/apps/dashboard/dist/assets/index-DnClJ1ee.js +0 -2
  52. package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
  53. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  54. package/apps/dashboard/dist/assets/setup-wizard-CA0Or47w.js.br +0 -0
  55. package/apps/dashboard/dist/assets/tab-agents-tab-BgpIsjkw.js.br +0 -0
  56. package/apps/dashboard/dist/assets/tab-comms-tab-kguqTIzD.js.br +0 -0
  57. package/apps/dashboard/dist/assets/tab-contacts-tab-DiOyMYth.js.br +0 -0
  58. package/apps/dashboard/dist/assets/tab-engines-tab-BsdZVvU0.js.br +0 -0
  59. package/apps/dashboard/dist/assets/tab-memory-tab-Cu6u13EQ.js.br +0 -0
  60. package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
  61. package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
  62. package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
  63. package/apps/dashboard/dist/assets/tab-prompts-tab-DVkUNaJd.js.br +0 -0
  64. package/apps/dashboard/dist/assets/tab-services-tab-DU_LH3uG.js.br +0 -0
  65. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js +0 -1
  66. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
  67. package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
  68. package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js.br +0 -0
  69. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BNrd88-r.js.br +0 -0
  70. package/apps/dashboard/dist/assets/tab-swarm-tab-B1AcjL1W.js.br +0 -0
  71. package/apps/dashboard/dist/assets/tab-usage-tab-BIOOnB-Y.js.br +0 -0
  72. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  73. package/apps/dashboard/dist/assets/tab-workflows-tab-B-soSy1k.js.br +0 -0
  74. package/apps/dashboard/dist/index.html.br +0 -0
  75. package/apps/dashboard/index.html +0 -6459
  76. package/apps/dashboard/package.json +0 -15
  77. package/apps/dashboard/src/app.js +0 -2823
  78. package/apps/dashboard/src/app.js.br +0 -0
  79. package/apps/dashboard/src/app.js.gz +0 -0
  80. package/apps/dashboard/src/chat/chat-actions.js +0 -1847
  81. package/apps/dashboard/src/chat/chat-actions.js.br +0 -0
  82. package/apps/dashboard/src/chat/unified-messages.js +0 -327
  83. package/apps/dashboard/src/chat/unified-messages.js.br +0 -0
  84. package/apps/dashboard/src/cli-process.js +0 -208
  85. package/apps/dashboard/src/cli-process.js.br +0 -0
  86. package/apps/dashboard/src/cli-process.js.gz +0 -0
  87. package/apps/dashboard/src/components/active-tasks-panel.js +0 -175
  88. package/apps/dashboard/src/components/active-tasks-panel.js.br +0 -0
  89. package/apps/dashboard/src/core/api.js +0 -18
  90. package/apps/dashboard/src/core/api.js.br +0 -0
  91. package/apps/dashboard/src/core/dom.js +0 -228
  92. package/apps/dashboard/src/core/dom.js.br +0 -0
  93. package/apps/dashboard/src/core/state.js +0 -91
  94. package/apps/dashboard/src/core/state.js.br +0 -0
  95. package/apps/dashboard/src/core/task-manager.js +0 -134
  96. package/apps/dashboard/src/core/task-manager.js.br +0 -0
  97. package/apps/dashboard/src/orchestration-status.js +0 -127
  98. package/apps/dashboard/src/orchestration-status.js.br +0 -0
  99. package/apps/dashboard/src/setup-wizard.js +0 -562
  100. package/apps/dashboard/src/setup-wizard.js.br +0 -0
  101. package/apps/dashboard/src/styles.css +0 -2085
  102. package/apps/dashboard/src/styles.css.br +0 -0
  103. package/apps/dashboard/src/styles.css.gz +0 -0
  104. package/apps/dashboard/src/tabs/agents-tab.js +0 -2237
  105. package/apps/dashboard/src/tabs/agents-tab.js.br +0 -0
  106. package/apps/dashboard/src/tabs/benchmarks-tab.js +0 -229
  107. package/apps/dashboard/src/tabs/benchmarks-tab.js.br +0 -0
  108. package/apps/dashboard/src/tabs/comms-tab.js +0 -955
  109. package/apps/dashboard/src/tabs/comms-tab.js.br +0 -0
  110. package/apps/dashboard/src/tabs/contacts-tab.js +0 -654
  111. package/apps/dashboard/src/tabs/contacts-tab.js.br +0 -0
  112. package/apps/dashboard/src/tabs/engines-tab.js +0 -175
  113. package/apps/dashboard/src/tabs/engines-tab.js.br +0 -0
  114. package/apps/dashboard/src/tabs/memory-tab.js +0 -182
  115. package/apps/dashboard/src/tabs/memory-tab.js.br +0 -0
  116. package/apps/dashboard/src/tabs/models-tab.js +0 -450
  117. package/apps/dashboard/src/tabs/models-tab.js.br +0 -0
  118. package/apps/dashboard/src/tabs/pm-loop-tab.js +0 -185
  119. package/apps/dashboard/src/tabs/pm-loop-tab.js.br +0 -0
  120. package/apps/dashboard/src/tabs/projects-tab.js +0 -663
  121. package/apps/dashboard/src/tabs/projects-tab.js.br +0 -0
  122. package/apps/dashboard/src/tabs/projects-tab.js.gz +0 -0
  123. package/apps/dashboard/src/tabs/prompts-tab.js +0 -160
  124. package/apps/dashboard/src/tabs/prompts-tab.js.br +0 -0
  125. package/apps/dashboard/src/tabs/services-tab.js +0 -202
  126. package/apps/dashboard/src/tabs/services-tab.js.br +0 -0
  127. package/apps/dashboard/src/tabs/settings-tab.js +0 -803
  128. package/apps/dashboard/src/tabs/settings-tab.js.br +0 -0
  129. package/apps/dashboard/src/tabs/skills-tab.js +0 -284
  130. package/apps/dashboard/src/tabs/skills-tab.js.br +0 -0
  131. package/apps/dashboard/src/tabs/spending-tab.js +0 -173
  132. package/apps/dashboard/src/tabs/spending-tab.js.br +0 -0
  133. package/apps/dashboard/src/tabs/swarm-chat-tab.js +0 -660
  134. package/apps/dashboard/src/tabs/swarm-chat-tab.js.br +0 -0
  135. package/apps/dashboard/src/tabs/swarm-tab.js +0 -538
  136. package/apps/dashboard/src/tabs/swarm-tab.js.br +0 -0
  137. package/apps/dashboard/src/tabs/usage-tab.js +0 -390
  138. package/apps/dashboard/src/tabs/usage-tab.js.br +0 -0
  139. package/apps/dashboard/src/tabs/waves-tab.js +0 -238
  140. package/apps/dashboard/src/tabs/waves-tab.js.br +0 -0
  141. package/apps/dashboard/src/tabs/workflows-tab.js +0 -747
  142. package/apps/dashboard/src/tabs/workflows-tab.js.br +0 -0
  143. package/apps/vibe/.crew/agent-memory/pipeline.json +0 -304
  144. package/apps/vibe/.crew/cost.json +0 -17
  145. package/apps/vibe/.crew/json-parse-metrics.jsonl +0 -27
  146. package/apps/vibe/.crew/pipeline-metrics.jsonl +0 -27
  147. package/apps/vibe/.crew/pipeline-runs/pipeline-0f90c392-2425-4ae5-850c-bd9d17b1d690.jsonl +0 -5
  148. package/apps/vibe/.crew/pipeline-runs/pipeline-1c269dd9-a63f-4fba-af81-5cf08048ef06.jsonl +0 -5
  149. package/apps/vibe/.crew/pipeline-runs/pipeline-288a7765-da24-4a22-89bc-1f3cc9b0562c.jsonl +0 -5
  150. package/apps/vibe/.crew/pipeline-runs/pipeline-2c78fd22-a657-4bd1-bc49-0679fb384409.jsonl +0 -5
  151. package/apps/vibe/.crew/pipeline-runs/pipeline-3da23550-22ed-4904-9a0a-8e79c1f3024c.jsonl +0 -5
  152. package/apps/vibe/.crew/pipeline-runs/pipeline-3e6fe08d-3264-404a-8df3-aab7efef10e7.jsonl +0 -5
  153. package/apps/vibe/.crew/pipeline-runs/pipeline-42eec610-57fe-4e09-9e7e-b315038495c2.jsonl +0 -5
  154. package/apps/vibe/.crew/pipeline-runs/pipeline-4438eb4c-ae13-42b1-90e2-b043d8983be8.jsonl +0 -5
  155. package/apps/vibe/.crew/pipeline-runs/pipeline-4740a9f5-86e7-44b6-a394-de433e291727.jsonl +0 -5
  156. package/apps/vibe/.crew/pipeline-runs/pipeline-49e1da6a-957e-48fd-9220-415019e4f8e2.jsonl +0 -5
  157. package/apps/vibe/.crew/pipeline-runs/pipeline-4c9251db-be68-427b-a3fc-a264f2b5778d.jsonl +0 -5
  158. package/apps/vibe/.crew/pipeline-runs/pipeline-6413fa33-a802-4b57-a8c0-a9056ad67842.jsonl +0 -5
  159. package/apps/vibe/.crew/pipeline-runs/pipeline-65e29a57-664d-4196-8109-017e364f182e.jsonl +0 -5
  160. package/apps/vibe/.crew/pipeline-runs/pipeline-6aa04bc5-9593-4b1f-b58d-3bf2978cb602.jsonl +0 -5
  161. package/apps/vibe/.crew/pipeline-runs/pipeline-6e1cba53-9b70-457e-99e0-59199149dd21.jsonl +0 -5
  162. package/apps/vibe/.crew/pipeline-runs/pipeline-749f41cc-4dac-4204-be64-873a6080a0d2.jsonl +0 -5
  163. package/apps/vibe/.crew/pipeline-runs/pipeline-74d68121-e181-4864-bd9a-c3211341dfaf.jsonl +0 -5
  164. package/apps/vibe/.crew/pipeline-runs/pipeline-8509bc24-142d-4e07-b44a-a50bf99d1103.jsonl +0 -5
  165. package/apps/vibe/.crew/pipeline-runs/pipeline-960339c6-07ca-43ce-9900-f6e1702b39b9.jsonl +0 -5
  166. package/apps/vibe/.crew/pipeline-runs/pipeline-9bef2dd2-6122-42e5-b3d9-19f4d80f9e40.jsonl +0 -5
  167. package/apps/vibe/.crew/pipeline-runs/pipeline-9c6480a9-7031-4146-b241-825b9a2d1de1.jsonl +0 -5
  168. package/apps/vibe/.crew/pipeline-runs/pipeline-9fd42426-8492-4157-9d5f-e1537c060489.jsonl +0 -2
  169. package/apps/vibe/.crew/pipeline-runs/pipeline-ad6d40a3-2f5e-46a9-a345-47caaccc51aa.jsonl +0 -5
  170. package/apps/vibe/.crew/pipeline-runs/pipeline-bc606133-8d5b-4535-8d85-f1a29cdaa981.jsonl +0 -5
  171. package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +0 -5
  172. package/apps/vibe/.crew/pipeline-runs/pipeline-c1a13ccd-634a-4d01-a4a7-1177b8a752ff.jsonl +0 -5
  173. package/apps/vibe/.crew/pipeline-runs/pipeline-c7d27b42-249e-4bd4-8f26-6aa998110b8a.jsonl +0 -5
  174. package/apps/vibe/.crew/pipeline-runs/pipeline-cca2e9b9-4a34-4d25-a311-5c793fa7e91e.jsonl +0 -5
  175. package/apps/vibe/.crew/sandbox.json +0 -7
  176. package/apps/vibe/.crew/session.json +0 -330
  177. package/apps/vibe/.crew/training-data.jsonl +0 -0
  178. package/apps/vibe/.github/workflows/studio-quality.yml +0 -37
  179. package/apps/vibe/.studio-data/project-messages/chuck-norris.jsonl +0 -18
  180. package/apps/vibe/.studio-data/project-messages/general.jsonl +0 -81
  181. package/apps/vibe/.studio-data/project-messages/studio-local.jsonl +0 -18
  182. package/apps/vibe/ARCHITECTURE.md +0 -3393
  183. package/apps/vibe/QUICK-REFERENCE.md +0 -211
  184. package/apps/vibe/ROADMAP.md +0 -41
  185. package/apps/vibe/STUDIO-SETUP-COMPLETE.md +0 -35
  186. package/apps/vibe/VISUAL-GUIDE.md +0 -378
  187. package/apps/vibe/capture-demo.mjs +0 -160
  188. package/apps/vibe/capture-full-demo.mjs +0 -255
  189. package/apps/vibe/capture-quickstart.mjs +0 -256
  190. package/apps/vibe/capture-vibe-assets.mjs +0 -71
  191. package/apps/vibe/capture-vibe-video.mjs +0 -260
  192. package/apps/vibe/check-buttons.js +0 -41
  193. package/apps/vibe/diagnose.html +0 -106
  194. package/apps/vibe/fix-buttons.js +0 -103
  195. package/apps/vibe/index.html +0 -3404
  196. package/apps/vibe/package-lock.json +0 -920
  197. package/apps/vibe/scripts/studio-pty-host.py +0 -117
  198. package/apps/vibe/src/main.js +0 -2940
  199. package/apps/vibe/src/register-all-languages.js +0 -98
  200. package/apps/vibe/start-studio.sh +0 -11
  201. package/apps/vibe/test/accessibility-tests.js +0 -77
  202. package/apps/vibe/test/browser-performance-audit.mjs +0 -205
  203. package/apps/vibe/test/performance-tests.js +0 -120
  204. package/apps/vibe/test/security-tests.js +0 -213
  205. package/apps/vibe/tests/e2e.local.mjs +0 -54
  206. package/apps/vibe/tests/server.smoke.mjs +0 -106
  207. package/apps/vibe/update_website.mjs +0 -74
  208. package/apps/vibe/vite.config.js +0 -19
  209. package/lib/crew-lead/chat-handler.mjs.bak +0 -1274
  210. package/lib/engines/rt-envelope.mjs.backup-current +0 -870
@@ -1,160 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * CrewSwarm Demo Video — Real UI Recording
4
- *
5
- * Records a ~45s demo: Vibe IDE chat + Dashboard tour
6
- * Outputs mp4 + webm via ffmpeg.
7
- *
8
- * Requires: dashboard on :4319, vibe on :3333, playwright, ffmpeg
9
- */
10
- import { chromium } from "playwright";
11
- import { mkdirSync, rmSync, existsSync, statSync, renameSync, readdirSync } from "node:fs";
12
- import { join, dirname } from "node:path";
13
- import { fileURLToPath } from "node:url";
14
- import { execSync } from "node:child_process";
15
-
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const OUT = join(__dirname, "..", "..", "website", "vibe-assets");
18
- const FINAL_MP4 = join(OUT, "vibe-demo.mp4");
19
- const FINAL_WEBM = join(OUT, "vibe-demo.webm");
20
-
21
- const DASHBOARD_URL = "http://127.0.0.1:4319";
22
- const VIBE_URL = "http://127.0.0.1:3333";
23
- const VIEWPORT = { width: 1440, height: 900 };
24
-
25
- mkdirSync(OUT, { recursive: true });
26
-
27
- async function record() {
28
- console.log("⏳ Checking services...");
29
-
30
- const browser = await chromium.launch({ headless: true });
31
- const context = await browser.newContext({
32
- recordVideo: { dir: OUT, size: VIEWPORT },
33
- viewport: VIEWPORT,
34
- colorScheme: "dark",
35
- });
36
- const page = await context.newPage();
37
-
38
- try {
39
- // ─── SCENE 1: Vibe IDE ──────────────────────────
40
- console.log("🎬 Scene 1: Vibe IDE");
41
- await page.goto(VIBE_URL, { waitUntil: "load", timeout: 30_000 });
42
- await page.waitForTimeout(3_000);
43
-
44
- // Select Studio Workspace project
45
- console.log(" → Selecting project...");
46
- try {
47
- const selects = page.locator("select");
48
- const count = await selects.count();
49
- if (count > 0) {
50
- await selects.first().selectOption({ label: "Studio Workspace" });
51
- await page.waitForTimeout(2_000);
52
- }
53
- } catch (e) { console.log(" (skip project select:", e.message, ")"); }
54
-
55
- // Click a file in the explorer
56
- console.log(" → Opening file...");
57
- try {
58
- // Click on server.mjs in the file tree
59
- await page.locator("text=server.mjs").first().click({ timeout: 3000 });
60
- await page.waitForTimeout(3_000);
61
- } catch { console.log(" (no file to click)"); }
62
-
63
- // Type a message in chat
64
- console.log(" → Typing in chat...");
65
- try {
66
- const textarea = page.locator("textarea").first();
67
- await textarea.click();
68
- const msg = "Add a GET /health endpoint that returns { status: \"ok\" }";
69
- for (const ch of msg) {
70
- await page.keyboard.type(ch, { delay: 30 });
71
- }
72
- await page.waitForTimeout(500);
73
- console.log(" → Sending message...");
74
- await page.keyboard.press("Enter");
75
- // Wait for agent response to stream
76
- console.log(" → Waiting for response (20s)...");
77
- await page.waitForTimeout(20_000);
78
- } catch (e) { console.log(" (chat error:", e.message, ")"); }
79
-
80
- // Show terminal
81
- console.log(" → Toggling terminal...");
82
- try {
83
- await page.locator("button", { hasText: "Terminal" }).click({ timeout: 2000 });
84
- await page.waitForTimeout(2_000);
85
- } catch { console.log(" (no terminal button)"); }
86
-
87
- // Hold for a beat
88
- await page.waitForTimeout(2_000);
89
-
90
- // ─── SCENE 2: Dashboard ─────────────────────────
91
- console.log("🎬 Scene 2: Dashboard");
92
- await page.goto(DASHBOARD_URL, { waitUntil: "load", timeout: 60_000 });
93
- await page.waitForTimeout(4_000);
94
-
95
- // Click through sidebar tabs
96
- const tabs = ["Sessions", "Agents", "Models", "Engines", "Swarm"];
97
- for (const name of tabs) {
98
- try {
99
- console.log(` → ${name}...`);
100
- await page.locator(`text="${name}"`).first().click({ timeout: 2000 });
101
- await page.waitForTimeout(3_500);
102
- } catch { console.log(` (skip ${name})`); }
103
- }
104
-
105
- // End on Chat
106
- try {
107
- await page.locator('text="Chat"').first().click({ timeout: 2000 });
108
- await page.waitForTimeout(3_000);
109
- } catch {}
110
-
111
- } finally {
112
- console.log("💾 Saving...");
113
- await page.close();
114
- await context.close();
115
- await browser.close();
116
- }
117
-
118
- // Find the recorded webm (Playwright names it randomly)
119
- const webms = readdirSync(OUT).filter(f => f.endsWith(".webm") && f !== "vibe-demo.webm");
120
- if (webms.length === 0) {
121
- console.error("❌ No recording found");
122
- process.exit(1);
123
- }
124
- // Use the newest one
125
- webms.sort((a, b) => statSync(join(OUT, b)).mtimeMs - statSync(join(OUT, a)).mtimeMs);
126
- const rawPath = join(OUT, webms[0]);
127
- console.log(`📼 Raw recording: ${rawPath}`);
128
-
129
- // Convert to mp4
130
- console.log("🎞️ Converting to mp4...");
131
- rmSync(FINAL_MP4, { force: true });
132
- execSync(
133
- `ffmpeg -y -i "${rawPath}" -vcodec libx264 -crf 23 -preset slow -vf "scale=1440:900:flags=lanczos" -movflags +faststart -an "${FINAL_MP4}"`,
134
- { stdio: "inherit" }
135
- );
136
-
137
- // Convert to webm (for web embed)
138
- console.log("🎞️ Converting to webm...");
139
- rmSync(FINAL_WEBM, { force: true });
140
- execSync(
141
- `ffmpeg -y -i "${rawPath}" -c:v libvpx-vp9 -crf 30 -b:v 0 -vf "scale=1440:900:flags=lanczos" -an "${FINAL_WEBM}"`,
142
- { stdio: "inherit" }
143
- );
144
-
145
- // Clean up raw
146
- rmSync(rawPath, { force: true });
147
-
148
- const mp4KB = Math.round(statSync(FINAL_MP4).size / 1024);
149
- const webmKB = Math.round(statSync(FINAL_WEBM).size / 1024);
150
- console.log(`\n✨ Done:`);
151
- console.log(` mp4: ${FINAL_MP4} (${mp4KB} KB)`);
152
- console.log(` webm: ${FINAL_WEBM} (${webmKB} KB)`);
153
- }
154
-
155
- record()
156
- .then(() => console.log("\n🎬 Demo capture complete!"))
157
- .catch((err) => {
158
- console.error("❌ Failed:", err.message);
159
- process.exit(1);
160
- });
@@ -1,255 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * CrewSwarm Full Demo — Screenshot Capture + Slideshow Video
4
- *
5
- * Takes screenshots of all key features across Vibe + Dashboard,
6
- * then stitches them into a crossfade slideshow video.
7
- *
8
- * Requires: vibe on :3333, dashboard on :4319, playwright, ffmpeg
9
- */
10
- import { chromium } from "playwright";
11
- import { mkdirSync, rmSync, existsSync, statSync, readdirSync } from "node:fs";
12
- import { join, dirname } from "node:path";
13
- import { fileURLToPath } from "node:url";
14
- import { execSync } from "node:child_process";
15
-
16
- const __dirname = dirname(fileURLToPath(import.meta.url));
17
- const OUT = join(__dirname, "..", "..", "website", "vibe-assets");
18
- const FINAL_MP4 = join(OUT, "vibe-demo.mp4");
19
- const FINAL_WEBM = join(OUT, "vibe-demo.webm");
20
-
21
- const VIBE_URL = "http://127.0.0.1:3333";
22
- const DASHBOARD_URL = "http://127.0.0.1:4319";
23
- const VIEWPORT = { width: 1440, height: 900 };
24
-
25
- // Slide duration in seconds for the final video
26
- const SLIDE_DURATION = 3.5;
27
- const CROSSFADE_DURATION = 0.8;
28
-
29
- mkdirSync(OUT, { recursive: true });
30
-
31
- // Clean old slides
32
- for (const f of readdirSync(OUT)) {
33
- if (f.startsWith("slide-") && f.endsWith(".png")) {
34
- rmSync(join(OUT, f), { force: true });
35
- }
36
- }
37
-
38
- let slideNum = 0;
39
- function slidePath() {
40
- slideNum++;
41
- return join(OUT, `slide-${String(slideNum).padStart(2, "0")}.png`);
42
- }
43
-
44
- async function capture() {
45
- console.log("Checking services...");
46
-
47
- const browser = await chromium.launch({ headless: true });
48
-
49
- // ─── VIBE SCREENSHOTS ─────────────────────────────────
50
- console.log("\n=== VIBE IDE ===");
51
- const vibeCtx = await browser.newContext({
52
- viewport: VIEWPORT,
53
- colorScheme: "dark",
54
- });
55
- const vibe = await vibeCtx.newPage();
56
-
57
- // Slide 1: Vibe IDE — editor view
58
- console.log(" [1] Vibe IDE — editor overview");
59
- await vibe.goto(VIBE_URL, { waitUntil: "load", timeout: 30_000 });
60
- await vibe.waitForTimeout(3_000);
61
- // Try to open a file
62
- try {
63
- await vibe.locator("text=server.mjs").first().click({ timeout: 3000 });
64
- await vibe.waitForTimeout(2_000);
65
- } catch { console.log(" (no file to open)"); }
66
- await vibe.screenshot({ path: slidePath() });
67
-
68
- // Slide 2: Vibe — Claude Code selected
69
- console.log(" [2] Vibe — Claude Code engine");
70
- try {
71
- const sel = vibe.locator("#chat-mode-selector");
72
- await sel.selectOption("cli:claude");
73
- await vibe.waitForTimeout(1_000);
74
- } catch { console.log(" (skip engine select)"); }
75
- await vibe.screenshot({ path: slidePath() });
76
-
77
- // Slide 3: Vibe — Cursor CLI selected
78
- console.log(" [3] Vibe — Cursor CLI engine");
79
- try {
80
- const sel = vibe.locator("#chat-mode-selector");
81
- await sel.selectOption("cli:cursor");
82
- await vibe.waitForTimeout(1_000);
83
- } catch { console.log(" (skip engine select)"); }
84
- await vibe.screenshot({ path: slidePath() });
85
-
86
- // Slide 4: Vibe — Gemini CLI selected
87
- console.log(" [4] Vibe — Gemini CLI engine");
88
- try {
89
- const sel = vibe.locator("#chat-mode-selector");
90
- await sel.selectOption("cli:gemini");
91
- await vibe.waitForTimeout(1_000);
92
- } catch { console.log(" (skip engine select)"); }
93
- await vibe.screenshot({ path: slidePath() });
94
-
95
- // Slide 5: Vibe — typing a prompt in the chat input
96
- console.log(" [5] Vibe — typing prompt");
97
- try {
98
- const sel = vibe.locator("#chat-mode-selector");
99
- await sel.selectOption("cli:claude");
100
- await vibe.waitForTimeout(500);
101
- const chatInput = vibe.locator("#chat-input");
102
- await chatInput.click({ timeout: 5000 });
103
- const msg = "Add session resume for all CLI engines with --resume flag";
104
- await chatInput.fill(msg);
105
- await vibe.waitForTimeout(500);
106
- } catch (e) { console.log(" (skip prompt:", e.message, ")"); }
107
- await vibe.screenshot({ path: slidePath() });
108
-
109
- // Slide 6: Vibe — send and capture response
110
- console.log(" [6] Vibe — agent working");
111
- try {
112
- await vibe.keyboard.press("Enter");
113
- // Wait for response to stream
114
- await vibe.waitForTimeout(18_000);
115
- } catch { console.log(" (skip response)"); }
116
- await vibe.screenshot({ path: slidePath() });
117
-
118
- // Slide 7: Vibe — terminal view
119
- console.log(" [7] Vibe — terminal");
120
- try {
121
- await vibe.locator("button", { hasText: "Terminal" }).click({ timeout: 2000 });
122
- await vibe.waitForTimeout(2_000);
123
- } catch { console.log(" (no terminal)"); }
124
- await vibe.screenshot({ path: slidePath() });
125
-
126
- await vibe.close();
127
- await vibeCtx.close();
128
-
129
- // ─── DASHBOARD SCREENSHOTS ────────────────────────────
130
- console.log("\n=== DASHBOARD ===");
131
- const dashCtx = await browser.newContext({
132
- viewport: VIEWPORT,
133
- colorScheme: "dark",
134
- });
135
- const dash = await dashCtx.newPage();
136
-
137
- await dash.goto(DASHBOARD_URL, { waitUntil: "load", timeout: 60_000 });
138
- await dash.waitForTimeout(4_000);
139
-
140
- // Slide 8: Dashboard — Chat view (default)
141
- console.log(" [8] Dashboard — Chat");
142
- await dash.screenshot({ path: slidePath() });
143
-
144
- // Dashboard tabs to cycle through
145
- const dashTabs = [
146
- { name: "Sessions", label: "9" },
147
- { name: "Agents", label: "10" },
148
- { name: "Engines", label: "11" },
149
- { name: "Models", label: "12" },
150
- { name: "Build", label: "13" },
151
- { name: "Swarm", label: "14" },
152
- ];
153
-
154
- for (const tab of dashTabs) {
155
- console.log(` [${tab.label}] Dashboard — ${tab.name}`);
156
- try {
157
- await dash.locator(`text="${tab.name}"`).first().click({ timeout: 3000 });
158
- await dash.waitForTimeout(2_500);
159
- await dash.screenshot({ path: slidePath() });
160
- } catch {
161
- console.log(` (skip ${tab.name})`);
162
- }
163
- }
164
-
165
- await dash.close();
166
- await dashCtx.close();
167
- await browser.close();
168
-
169
- console.log(`\n${slideNum} screenshots captured.`);
170
- return slideNum;
171
- }
172
-
173
- function buildVideo(totalSlides) {
174
- console.log("\n=== BUILDING VIDEO ===");
175
-
176
- // Build ffmpeg filter for crossfade slideshow
177
- // Each slide shows for SLIDE_DURATION, with CROSSFADE_DURATION transition
178
- const slides = [];
179
- for (let i = 1; i <= totalSlides; i++) {
180
- const p = join(OUT, `slide-${String(i).padStart(2, "0")}.png`);
181
- if (!existsSync(p)) continue;
182
- slides.push(p);
183
- }
184
-
185
- if (slides.length === 0) {
186
- console.error("No slides found!");
187
- process.exit(1);
188
- }
189
-
190
- // Simple approach: use concat demuxer with each image shown for SLIDE_DURATION
191
- // Then add crossfade in a second pass
192
- const totalDuration = slides.length * SLIDE_DURATION;
193
- console.log(` ${slides.length} slides, ${SLIDE_DURATION}s each = ~${Math.round(totalDuration)}s video`);
194
-
195
- // Build input args and filter complex for crossfade
196
- const inputs = slides.map(s => `-loop 1 -t ${SLIDE_DURATION} -i "${s}"`).join(" ");
197
-
198
- let filterComplex = "";
199
- if (slides.length === 1) {
200
- filterComplex = `[0:v]scale=${VIEWPORT.width}:${VIEWPORT.height},format=yuv420p[outv]`;
201
- } else {
202
- // Chain crossfades: [0][1]xfade -> [v01], [v01][2]xfade -> [v012], etc.
203
- const cf = CROSSFADE_DURATION;
204
- let lastLabel = "0:v";
205
- for (let i = 1; i < slides.length; i++) {
206
- const offset = i * SLIDE_DURATION - i * cf;
207
- const outLabel = i === slides.length - 1 ? "outv" : `v${i}`;
208
- filterComplex += `[${lastLabel}][${i}:v]xfade=transition=fade:duration=${cf}:offset=${offset.toFixed(2)}[${outLabel}];\n`;
209
- lastLabel = outLabel;
210
- }
211
- // Remove trailing semicolon+newline if present
212
- filterComplex = filterComplex.replace(/;\n$/, "");
213
- }
214
-
215
- // Generate MP4
216
- console.log(" Converting to mp4...");
217
- rmSync(FINAL_MP4, { force: true });
218
- const mp4Cmd = `ffmpeg -y ${inputs} -filter_complex "${filterComplex}" -map "[outv]" -c:v libx264 -crf 23 -preset slow -pix_fmt yuv420p -movflags +faststart -an "${FINAL_MP4}"`;
219
- try {
220
- execSync(mp4Cmd, { stdio: "pipe", timeout: 120_000 });
221
- } catch (e) {
222
- console.error(" mp4 error:", e.stderr?.toString().slice(-500));
223
- // Fallback: simple concat without crossfade
224
- console.log(" Trying simple concat fallback...");
225
- const concatInputs = slides.map(s => `-loop 1 -t ${SLIDE_DURATION} -i "${s}"`).join(" ");
226
- const concatFilter = slides.map((_, i) => `[${i}:v]scale=${VIEWPORT.width}:${VIEWPORT.height},format=yuv420p,setpts=PTS-STARTPTS[v${i}]`).join(";") +
227
- ";" + slides.map((_, i) => `[v${i}]`).join("") + `concat=n=${slides.length}:v=1:a=0[outv]`;
228
- execSync(`ffmpeg -y ${concatInputs} -filter_complex "${concatFilter}" -map "[outv]" -c:v libx264 -crf 23 -preset slow -movflags +faststart -an "${FINAL_MP4}"`,
229
- { stdio: "pipe", timeout: 120_000 });
230
- }
231
-
232
- // Generate WebM
233
- console.log(" Converting to webm...");
234
- rmSync(FINAL_WEBM, { force: true });
235
- execSync(
236
- `ffmpeg -y -i "${FINAL_MP4}" -c:v libvpx-vp9 -crf 30 -b:v 0 -an "${FINAL_WEBM}"`,
237
- { stdio: "pipe", timeout: 120_000 }
238
- );
239
-
240
- const mp4KB = Math.round(statSync(FINAL_MP4).size / 1024);
241
- const webmKB = Math.round(statSync(FINAL_WEBM).size / 1024);
242
- console.log(`\nDone:`);
243
- console.log(` mp4: ${FINAL_MP4} (${mp4KB} KB)`);
244
- console.log(` webm: ${FINAL_WEBM} (${webmKB} KB)`);
245
- }
246
-
247
- capture()
248
- .then((total) => {
249
- buildVideo(total);
250
- console.log("\nDemo capture complete!");
251
- })
252
- .catch((err) => {
253
- console.error("Failed:", err.message);
254
- process.exit(1);
255
- });
@@ -1,256 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * CrewSwarm Quickstart Video — Simulated Install + First Run
4
- *
5
- * Creates a terminal-style recording showing the install and first use flow.
6
- * Uses Playwright to render HTML terminal frames and capture as screenshots,
7
- * then stitches into a video with ffmpeg.
8
- */
9
- import { chromium } from "playwright";
10
- import { mkdirSync, rmSync, existsSync, statSync, readdirSync, writeFileSync } from "node:fs";
11
- import { join, dirname } from "node:path";
12
- import { fileURLToPath } from "node:url";
13
- import { execSync } from "node:child_process";
14
-
15
- const __dirname = dirname(fileURLToPath(import.meta.url));
16
- const OUT = join(__dirname, "..", "..", "website", "vibe-assets");
17
- const FINAL_MP4 = join(OUT, "quickstart.mp4");
18
- const FINAL_WEBM = join(OUT, "quickstart.webm");
19
- const VIEWPORT = { width: 900, height: 560 };
20
- const SLIDE_DURATION = 3;
21
-
22
- mkdirSync(OUT, { recursive: true });
23
-
24
- // Clean old quickstart slides
25
- for (const f of readdirSync(OUT)) {
26
- if (f.startsWith("qs-") && f.endsWith(".png")) rmSync(join(OUT, f), { force: true });
27
- }
28
-
29
- function terminalHTML(lines, title = "Terminal — crewswarm") {
30
- const content = lines.map(l => {
31
- if (l.startsWith("$")) return `<span style="color:#4ade80;">${esc(l)}</span>`;
32
- if (l.startsWith("//")) return `<span style="color:#6b7280;font-style:italic;">${esc(l)}</span>`;
33
- if (l.includes("✓") || l.includes("✔") || l.includes("Done") || l.includes("ready")) return `<span style="color:#4ade80;">${esc(l)}</span>`;
34
- if (l.includes("⚡") || l.includes("→")) return `<span style="color:#60a5fa;">${esc(l)}</span>`;
35
- if (l.includes("🧠") || l.includes("📐") || l.includes("🔧")) return `<span style="color:#fbbf24;">${esc(l)}</span>`;
36
- return esc(l);
37
- }).join("\n");
38
-
39
- return `<!DOCTYPE html>
40
- <html><head><style>
41
- * { margin:0; padding:0; box-sizing:border-box; }
42
- body { background:#0a0e17; font-family:'SF Mono','Fira Code',monospace; padding:20px; }
43
- .terminal { background:#0d1117; border:1px solid #21262d; border-radius:12px; overflow:hidden; }
44
- .bar { background:#161b22; padding:10px 14px; display:flex; align-items:center; gap:8px; }
45
- .dot { width:12px; height:12px; border-radius:50%; }
46
- .red { background:#ff5f57; } .yellow { background:#febc2e; } .green { background:#28c840; }
47
- .title { color:#8b949e; font-size:13px; margin-left:8px; }
48
- .body { padding:16px 20px; color:#c9d1d9; font-size:14px; line-height:1.7; white-space:pre-wrap; min-height:400px; }
49
- </style></head><body>
50
- <div class="terminal">
51
- <div class="bar">
52
- <div class="dot red"></div><div class="dot yellow"></div><div class="dot green"></div>
53
- <span class="title">${esc(title)}</span>
54
- </div>
55
- <div class="body">${content}</div>
56
- </div>
57
- </body></html>`;
58
- }
59
-
60
- function esc(s) {
61
- return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
62
- }
63
-
64
- const frames = [
65
- {
66
- title: "Install — real output from Docker",
67
- lines: [
68
- "$ npm install -g crewswarm",
69
- "",
70
- "added 59 packages in 9s",
71
- "",
72
- "$ crewswarm --version",
73
- "0.8.2-beta",
74
- "",
75
- "$ crewswarm",
76
- "",
77
- "⚡ crewswarm v0.8.2-beta",
78
- "→ Dashboard: http://localhost:4319",
79
- "→ Vibe IDE: http://localhost:3333",
80
- "→ crew-lead: http://localhost:5010",
81
- "→ MCP server: http://localhost:5020",
82
- "",
83
- "✓ All services ready",
84
- ],
85
- },
86
- {
87
- title: "Configure — pick your models",
88
- lines: [
89
- "// Open Dashboard → Models tab",
90
- "// Set a model per agent — or use CLI OAuth (no keys needed)",
91
- "",
92
- " crew-lead ......... Groq Llama 3.3 70B Free",
93
- " crew-pm ........... Gemini 2.5 Flash $0.075/M",
94
- " crew-coder ........ Claude Sonnet 4.6 $3/M",
95
- " crew-coder-front .. Cursor (composer-2) Cursor sub",
96
- " crew-qa ........... Gemini CLI (OAuth) Free",
97
- " crew-fixer ........ Codex CLI (OAuth) Codex sub",
98
- "",
99
- "// Or use Claude Code / Cursor / Gemini CLI directly —",
100
- "// just login once with OAuth, no API keys",
101
- "",
102
- "✓ Models configured from dashboard — no config files",
103
- ],
104
- },
105
- {
106
- title: "Build — one sentence, full feature",
107
- lines: [
108
- '$ crew run "Build a REST API with auth, tests, and docs"',
109
- "",
110
- "🧠 crew-pm planning...",
111
- " → Phase MVP: 3 tasks (auth, routes, tests)",
112
- " → Phase 1: 2 tasks (docs, error handling)",
113
- "",
114
- "📐 Wave 1: dispatching to 3 agents in parallel",
115
- " → crew-coder-back: auth middleware + JWT",
116
- " → crew-coder-back: CRUD routes + validation",
117
- " → crew-qa: test suite (jest)",
118
- "",
119
- "✓ Wave 1 complete (2m 14s)",
120
- "",
121
- "📐 Wave 2: dispatching to 2 agents",
122
- " → crew-coder: API docs (OpenAPI spec)",
123
- " → crew-fixer: error handling + edge cases",
124
- ],
125
- },
126
- {
127
- title: "Build — done",
128
- lines: [
129
- "✓ Wave 2 complete (1m 38s)",
130
- "",
131
- "🧠 crew-pm: all phases complete",
132
- "",
133
- " Files created:",
134
- " src/middleware/auth.js ✓",
135
- " src/routes/users.js ✓",
136
- " src/routes/posts.js ✓",
137
- " tests/auth.test.js ✓",
138
- " tests/routes.test.js ✓",
139
- " docs/openapi.yaml ✓",
140
- "",
141
- " Tests: 14 passed, 0 failed",
142
- " Duration: 3m 52s (2 phases, 2 waves)",
143
- "",
144
- "✓ Build complete. Files on disk. Ship it.",
145
- ],
146
- },
147
- {
148
- title: "Rate limited? Switch engines",
149
- lines: [
150
- "// Claude hit rate limit mid-session?",
151
- "// Switch to Cursor or Gemini — session context preserved",
152
- "",
153
- " Dashboard → Engines tab → click any engine",
154
- "",
155
- " Claude Code .... --resume <session-id>",
156
- " Cursor CLI ..... --resume=<chat-id>",
157
- " Gemini CLI ..... --resume <session-id>",
158
- " Codex CLI ...... codex resume <thread-id>",
159
- " OpenCode ....... --continue",
160
- "",
161
- "// Or in Vibe: just pick a different CLI from the dropdown",
162
- "// Your conversation continues where you left off",
163
- "",
164
- "✓ 6 engines. Native session resume. No vendor lock-in.",
165
- ],
166
- },
167
- {
168
- title: "Vibe IDE — code in your browser",
169
- lines: [
170
- "// Open http://localhost:3333",
171
- "",
172
- " ┌─────────────────────────────────────────────┐",
173
- " │ Files │ Monaco Editor │ Chat │",
174
- " │ │ │ │",
175
- " │ src/ │ server.mjs │ Claude Code │",
176
- " │ tests/ │ import http... │ Cursor CLI │",
177
- " │ docs/ │ const app = ... │ Gemini CLI │",
178
- " │ │ │ OpenCode │",
179
- " │ │──────────────────│ Codex CLI │",
180
- " │ │ Terminal │ │",
181
- " │ │ $ npm test │ [Clear] │",
182
- " └─────────────────────────────────────────────┘",
183
- "",
184
- " Editor + terminal + chat + 6 engines. All in one tab.",
185
- ],
186
- },
187
- ];
188
-
189
- async function capture() {
190
- console.log("Capturing quickstart frames...");
191
- const browser = await chromium.launch({ headless: true });
192
- const ctx = await browser.newContext({ viewport: VIEWPORT, colorScheme: "dark" });
193
-
194
- let slideNum = 0;
195
- for (const frame of frames) {
196
- slideNum++;
197
- const page = await ctx.newPage();
198
- const html = terminalHTML(frame.lines, frame.title);
199
- const tmpHtml = join(OUT, `_qs_tmp.html`);
200
- writeFileSync(tmpHtml, html);
201
- await page.goto(`file://${tmpHtml}`, { waitUntil: "load" });
202
- await page.waitForTimeout(500);
203
- const path = join(OUT, `qs-${String(slideNum).padStart(2, "0")}.png`);
204
- await page.screenshot({ path });
205
- console.log(` [${slideNum}] ${frame.title}`);
206
- await page.close();
207
- }
208
-
209
- rmSync(join(OUT, "_qs_tmp.html"), { force: true });
210
- await ctx.close();
211
- await browser.close();
212
- return slideNum;
213
- }
214
-
215
- function buildVideo(totalSlides) {
216
- console.log("\nBuilding quickstart video...");
217
- const slides = [];
218
- for (let i = 1; i <= totalSlides; i++) {
219
- const p = join(OUT, `qs-${String(i).padStart(2, "0")}.png`);
220
- if (existsSync(p)) slides.push(p);
221
- }
222
-
223
- const inputs = slides.map(s => `-loop 1 -t ${SLIDE_DURATION} -i "${s}"`).join(" ");
224
- const cf = 0.6;
225
-
226
- let filterComplex = "";
227
- let lastLabel = "0:v";
228
- for (let i = 1; i < slides.length; i++) {
229
- const offset = i * SLIDE_DURATION - i * cf;
230
- const outLabel = i === slides.length - 1 ? "outv" : `v${i}`;
231
- filterComplex += `[${lastLabel}][${i}:v]xfade=transition=fade:duration=${cf}:offset=${offset.toFixed(2)}[${outLabel}];`;
232
- lastLabel = outLabel;
233
- }
234
- filterComplex = filterComplex.replace(/;$/, "");
235
-
236
- rmSync(FINAL_MP4, { force: true });
237
- rmSync(FINAL_WEBM, { force: true });
238
-
239
- console.log(" → mp4...");
240
- execSync(`ffmpeg -y ${inputs} -filter_complex "${filterComplex}" -map "[outv]" -c:v libx264 -crf 23 -preset slow -pix_fmt yuv420p -movflags +faststart -an "${FINAL_MP4}"`,
241
- { stdio: "pipe", timeout: 60_000 });
242
-
243
- console.log(" → webm...");
244
- execSync(`ffmpeg -y -i "${FINAL_MP4}" -c:v libvpx-vp9 -crf 30 -b:v 0 -an "${FINAL_WEBM}"`,
245
- { stdio: "pipe", timeout: 60_000 });
246
-
247
- const mp4KB = Math.round(statSync(FINAL_MP4).size / 1024);
248
- const webmKB = Math.round(statSync(FINAL_WEBM).size / 1024);
249
- console.log(`\nDone:`);
250
- console.log(` mp4: ${mp4KB} KB`);
251
- console.log(` webm: ${webmKB} KB`);
252
- }
253
-
254
- capture()
255
- .then(n => { buildVideo(n); console.log("\nQuickstart video complete!"); })
256
- .catch(e => { console.error("Failed:", e.message); process.exit(1); });