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 +1 @@
1
- import{a as t,p as e,s as n,g as a,e as o}from"./core-utils-CmOkXgzi.js";function i(t){t.hideAllViews(),document.getElementById("buildView").classList.add("active"),t.setNavActive("navBuild"),z()}function d(t){t.hideAllViews(),document.getElementById("projectsView").classList.add("active"),t.setNavActive("navProjects"),s()}async function s(){const e=document.getElementById("projectsList");e.innerHTML='<div class="meta" style="padding:20px;">Loading projects...</div>';try{const n=(await a("/api/projects")).projects||[];if(t.projectsData={},n.forEach(e=>{t.projectsData[e.id]=e}),m(n),!n.length)return void(e.innerHTML='<div class="meta" style="padding:20px;">No projects yet. Click &quot;+ New Project&quot; to create one.</div>');e.innerHTML=n.map(t=>{const e=o(t.id),n=t.roadmap.total?Math.round(t.roadmap.done/t.roadmap.total*100):0,a=100===n?"var(--green)":n>50?"var(--accent)":"var(--yellow)",i="active"===t.status?"rgba(52,211,153,0.1)":"var(--bg-card2)",d="active"===t.status?"var(--green)":"var(--text-3)",s=t.roadmap.failed?'<button data-action="retry-failed" data-id="'+e+'" style="background:rgba(248,113,113,0.15);color:var(--red);border:1px solid rgba(248,113,113,0.3);border-radius:6px;padding:6px 12px;cursor:pointer;font-size:13px;font-weight:600;">↩ Retry '+t.roadmap.failed+" failed</button>":"";return'<div class="card" id="proj-card-'+e+'" data-proj-id="'+e+'"><div id="proj-view-'+e+'"><div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px;"><div><strong style="font-size:15px;">'+o(t.name)+'</strong><span style="margin-left:10px;font-size:11px;padding:2px 8px;border-radius:999px;background:'+i+";color:"+d+";border:1px solid "+d+'40;">'+o(t.status)+"</span>"+(t.running?'<span style="margin-left:8px;font-size:11px;padding:2px 8px;border-radius:999px;background:rgba(99,102,241,0.15);color:var(--purple);border:1px solid rgba(99,102,241,0.3);">▶ running</span>':"")+(t.description?'<div class="meta" style="margin-top:4px;">'+o(t.description)+"</div>":"")+'</div><div class="meta">'+new Date(t.created).toLocaleDateString()+'</div></div><div style="margin-bottom:12px;"><div style="display:flex;justify-content:space-between;margin-bottom:6px;"><span class="meta">Roadmap</span><span class="meta">'+t.roadmap.done+"/"+t.roadmap.total+" done"+(t.roadmap.failed?" · "+t.roadmap.failed+" failed":"")+" · "+t.roadmap.pending+' pending</span></div><div class="prog-bar"><div class="prog-fill" style="width:'+n+"%;background:"+a+';"></div></div></div><div style="font-size:11px;color:var(--text-3);margin-bottom:12px;font-family:monospace;">'+o(t.outputDir)+'</div><div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;"><button data-action="pm-toggle" data-id="'+e+'" class="'+(t.running?"btn-red":"btn-green")+'" style="font-size:13px;">'+(t.running?"⏹ Stop PM Loop":"▶ Start PM Loop")+'</button><button data-action="open-build" data-id="'+e+'" class="btn-ghost" style="font-size:13px;">🔧 Build tab</button><button data-action="edit-roadmap" data-id="'+e+'" class="btn-ghost" style="font-size:13px;" id="roadmap-btn-'+e+'">📋 Roadmap</button><button data-action="chat-project" data-id="'+e+'" data-name="'+o(t.name)+'" class="btn-ghost" style="font-size:13px;">🧠 Chat</button>'+s+'<label style="margin-left:auto;display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;color:var(--text-3);user-select:none;" title="When enabled, crew-lead automatically starts the next ROADMAP phase when the current pipeline completes"><input type="checkbox" data-action="toggle-auto-advance" data-id="'+e+'" '+(t.autoAdvance?"checked":"")+' style="accent-color:var(--green);width:14px;height:14px;cursor:pointer;">⚡ Auto-advance</label><button data-action="edit" data-id="'+e+'" style="background:transparent;color:var(--text-3);border:1px solid var(--border);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px;" title="Edit project">✎ Edit</button><button data-action="delete" data-id="'+e+'" style="background:transparent;color:var(--text-3);border:1px solid var(--border);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px;" title="Remove from dashboard (files stay on disk)">🗑 Delete</button></div></div><div id="proj-edit-'+e+'" style="display:none;padding:12px;border-top:1px solid var(--border);margin-top:12px;"><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Name</label><input id="proj-name-'+e+'" type="text" value="'+o(t.name)+'" style="margin-top:4px;" /></div><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Description</label><input id="proj-desc-'+e+'" type="text" value="'+o(t.description||"")+'" style="margin-top:4px;" placeholder="Optional" /></div><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Output directory</label><input id="proj-dir-'+e+'" type="text" value="'+o(t.outputDir||"")+'" style="margin-top:4px;" /></div><div style="display:flex;gap:8px;"><button data-action="save-project-edit" data-id="'+e+'" class="btn-green" style="font-size:12px;">Save</button><button data-action="cancel-project-edit" data-id="'+e+'" class="btn-ghost" style="font-size:12px;">Cancel</button></div></div><div id="proj-pm-status-'+e+'" style="display:none;margin-top:10px;font-size:12px;padding:8px 12px;background:rgba(99,102,241,0.08);border-radius:6px;border:1px solid rgba(99,102,241,0.2);color:#a5b4fc;"></div><div id="rm-editor-'+e+'" style="display:none;margin-top:14px;"><div style="display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap;"><span class="field-label" style="margin:0;">ROADMAP</span><span class="meta" style="font-family:monospace;">'+o(t.roadmapFile)+'</span><div style="margin-left:auto;display:flex;gap:6px;"><button data-action="add-item" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--green);color:#000;">+ Add item</button><button data-action="skip-next" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--yellow);color:#000;">⏭ Skip next</button><button data-action="reset-failed" data-id="'+e+'" style="font-size:11px;padding:3px 10px;" class="btn-ghost">↩ Reset failed</button><button data-action="save-roadmap" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--accent);color:#000;">💾 Save</button><button data-action="close-editor" data-id="'+e+'" style="font-size:11px;padding:3px 10px;" class="btn-ghost">✕</button></div></div><div style="display:flex;gap:8px;margin-bottom:8px;"><input id="rm-add-'+e+'" type="text" placeholder="New item text… (Enter to add)" style="flex:1;font-size:13px;" data-rm-add-id="'+e+'" /></div><textarea id="rm-ta-'+e+'" rows="16" class="rm-textarea" spellcheck="false"></textarea><div id="rm-status-'+e+'" class="meta" style="margin-top:6px;min-height:16px;"></div></div></div>'}).join(""),e.querySelectorAll("[data-rm-add-id]").forEach(t=>{t.addEventListener("keydown",e=>{"Enter"===e.key&&A(t.dataset.rmAddId)})})}catch(n){e.innerHTML='<div class="meta" style="padding:20px;color:var(--red-hi);">Failed to load projects: '+o(n.message)+"</div>"}}function r(t){const e=document.getElementById("proj-view-"+t),n=document.getElementById("proj-edit-"+t);if(!e||!n)return;const a="none"!==n.style.display;e.style.display=a?"":"none",n.style.display=a?"none":"block"}function l(a){const o=document.getElementById("projectsList");o&&o.addEventListener("click",o=>{var i;const d=o.target.closest("[data-action]");if(!d)return;const l=d.dataset.id,c=t.projectsData[l];switch(d.dataset.action){case"pm-toggle":c&&c.running?b(l):f(l);break;case"open-build":!function(t,e){e.showBuild(),j().then(()=>{const e=document.getElementById("buildProjectPicker");e&&(e.value=t,I())})}(l,a);break;case"edit-roadmap":c&&P(l,c.roadmapFile);break;case"retry-failed":c&&k(c.roadmapFile);break;case"delete":!async function(a){const i=t.projectsData[a],d=i?i.name:a;if(!confirm('Remove "'+d+'" from the dashboard registry?\n\nFiles on disk are NOT deleted.'))return;try{await e("/api/projects/delete",{projectId:a}),n('Project "'+d+'" removed from dashboard.'),s()}catch(o){n("Delete failed: "+o.message,!0)}}(l);break;case"chat-project":a.showChat(),v(l),null==(i=document.getElementById("chatInput"))||i.focus();break;case"toggle-auto-advance":{const a=d.checked;return void e("/api/projects/update",{projectId:l,autoAdvance:a}).then(()=>{t.projectsData[l]&&(t.projectsData[l].autoAdvance=a),n("Auto-advance "+(a?"enabled":"disabled")+" for "+((null==c?void 0:c.name)||l))}).catch(t=>{n("Failed: "+t.message,!0),d.checked=!a})}case"edit":case"cancel-project-edit":r(l);break;case"save-project-edit":!async function(t){var a,i,d,l,c,p;const u=null==(i=null==(a=document.getElementById("proj-name-"+t))?void 0:a.value)?void 0:i.trim(),m=null==(l=null==(d=document.getElementById("proj-desc-"+t))?void 0:d.value)?void 0:l.trim(),g=null==(p=null==(c=document.getElementById("proj-dir-"+t))?void 0:c.value)?void 0:p.trim();if(u)try{await e("/api/projects/update",{projectId:t,name:u,description:m,outputDir:g}),n("Project saved"),r(t),s()}catch(o){n("Failed: "+o.message,!0)}else n("Project name is required",!0)}(l);break;case"add-item":A(l);break;case"skip-next":!function(t){const e=document.getElementById("rm-ta-"+t);if(!e)return;const n=e.value.split("\n");let a=!1;for(let o=0;o<n.length;o++)if(/^- \[ \]/.test(n[o])){n[o]=n[o].replace("- [ ]","- [x]")+" ✓ skipped",a=!0;break}a?(e.value=n.join("\n"),S(t,"Next pending item skipped — click 💾 Save to persist")):S(t,"No pending items to skip")}(l);break;case"reset-failed":T(l);break;case"save-roadmap":L(l);break;case"close-editor":C(l)}})}const c="crewswarm_chat_active_project_id";function p(t){try{t?localStorage.setItem(c,t):localStorage.removeItem(c)}catch{}}function u(t){const e=t&&String(t).trim()&&"undefined"!==t?String(t).trim():"general";return fetch("/api/ui/active-project",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({projectId:e})}).catch(()=>{})}function m(e){const n=document.getElementById("chatProjectTabs");if(!n)return;const a=function(){try{return localStorage.getItem(c)||""}catch{return""}}()||t.chatActiveProjectId||"general";for(;n.children.length>1;)n.removeChild(n.lastChild);const o=new Set,i=(e||[]).filter(t=>{const e=t.id||t.name&&t.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");return!(!e||o.has(e))&&(o.add(e),!0)}).map(t=>({...t,id:t.id||t.name&&t.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}));i.forEach(t=>{if(!t.id)return;const e=document.createElement("button");e.className="project-tab",e.dataset.projectId=t.id,e.textContent=`📁 ${t.name||t.id}`,e.onclick=()=>window.selectProjectTab(t.id),n.appendChild(e)}),console.log("[Projects] Populated tabs:",i.length,"projects");const d=new Set(["general",...i.map(t=>t.id).filter(Boolean)]).has(a)?a:"general";t.chatActiveProjectId=d,p(d),u(d),Array.from(n.children).forEach(t=>{t.classList.toggle("active",t.dataset.projectId===d)})}function g(){const e=document.getElementById("chatProjectSelect");e&&(t.chatActiveProjectId=e.value,p(t.chatActiveProjectId),u(t.chatActiveProjectId),y())}function y(){const e=document.getElementById("chatProjectHint");if(e)if(t.chatActiveProjectId&&t.projectsData[t.chatActiveProjectId]){const n=t.projectsData[t.chatActiveProjectId];e.textContent=n.outputDir||"",e.style.display=n.outputDir?"block":"none"}else e.style.display="none"}function v(e){t.chatActiveProjectId=e,p(e),u(e);const n=document.getElementById("chatProjectSelect");n&&n.querySelector('option[value="'+e+'"]')&&(n.value=e,y())}async function b(t){try{await e("/api/pm-loop/stop",{projectId:t}),n("Stop signal sent — PM will finish current task then halt.");const a=document.getElementById("proj-pm-status-"+t);a&&(a.style.display="block",a.textContent="⛔ Stopping after current task…"),setTimeout(s,3e3)}catch(a){n("Stop failed: "+a.message,!0)}}async function f(t){const a=document.getElementById("proj-pm-status-"+t);try{a&&(a.style.display="block",a.textContent="⚙ Starting PM Loop…");const o=await e("/api/pm-loop/start",{projectId:t});if(o.alreadyRunning)return n("PM Loop already running (pid "+o.pid+")",!0),void(a&&(a.textContent="▶ Already running (pid "+o.pid+")"));n("PM Loop started (pid "+o.pid+")"),a&&(a.textContent="▶ Running (pid "+o.pid+") — check Build tab for live log"),setTimeout(s,3e3)}catch(o){n("Start failed: "+o.message,!0),a&&(a.style.display="none")}}let x={};function h(t){return x[t]||null}async function j(){try{const t=await a("/api/projects");x={};const e=document.getElementById("buildProjectPicker"),n=e?e.value:"";if(!e)return;e.innerHTML='<option value="">— No project (use defaults) —</option>',(t.projects||[]).forEach(t=>{x[t.id]=t;const a=document.createElement("option");a.value=t.id,a.textContent=t.name+(t.running?" ▶":"")+" ("+t.roadmap.pending+" pending)",t.id===n&&(a.selected=!0),e.appendChild(a)}),I()}catch(t){}}function I(){const t=document.getElementById("buildProjectPicker"),e=document.getElementById("buildProjectInfo"),n=document.getElementById("pmLoopProjectLabel"),a=document.getElementById("phasedProgressLabel"),o=x[t?t.value:""];o?(e.style.display="block",e.innerHTML="<b>"+o.name+"</b><br>Output: "+o.outputDir+"<br>Roadmap: "+o.roadmapFile+"<br>Tasks: "+o.roadmap.done+" done · "+o.roadmap.pending+" pending · "+o.roadmap.failed+" failed"+(o.running?'<br><span style="color:var(--purple);">▶ PM Loop is running</span>':""),n&&(n.innerHTML='<b style="color:var(--accent);">▶ '+o.name+"</b> &nbsp;·&nbsp; "+o.roadmap.done+" done · "+o.roadmap.pending+" pending"+(o.running?' &nbsp;<span style="color:var(--green-hi); font-weight:600;">● running</span>':"")),a&&(a.textContent="▶ "+o.name)):(e.style.display="none",n&&(n.innerHTML="← Select a project above"),a&&(a.textContent="All projects (no project selected)")),z()}async function B(){try{await e("/api/build/stop",{}),n("Build stop signal sent"),document.getElementById("stopBuildBtn").style.display="none",document.getElementById("runBuildBtn").style.display="",document.getElementById("buildStatus").textContent=""}catch(t){n("Stop failed: "+t.message,!0)}}async function E(){try{await e("/api/continuous-build/stop",{}),n("Continuous build stop signal sent"),document.getElementById("stopContinuousBtn").style.display="none",document.getElementById("continuousBuildBtn").style.display=""}catch(t){n("Stop failed: "+t.message,!0)}}async function k(t){if(confirm("Reset all [!] failed items back to [ ] pending so the PM Loop retries them?"))try{const a=await e("/api/roadmap/retry-failed",{roadmapFile:t});if(0===a.count)return void n("No failed items found in roadmap",!0);n("↩ "+a.count+" failed item"+(1!==a.count?"s":"")+" reset — click Resume to retry"),await s()}catch(a){n("Retry failed: "+a.message,!0)}}const w={};async function P(t,n){w[t]=n;const a=document.getElementById("rm-editor-"+t),o=document.getElementById("rm-ta-"+t),i=document.getElementById("roadmap-btn-"+t);if(a&&o)if("none"===a.style.display){a.style.display="block",i&&(i.textContent="📋 Editing…"),o.value="Loading…";try{const a=await e("/api/roadmap/read",{roadmapFile:n});o.value=a.content||"",S(t,"Loaded · "+(a.content||"").split("\n").length+" lines")}catch(d){o.value="",S(t,"Error: "+d.message,!0)}}else C(t)}function C(t){const e=document.getElementById("rm-editor-"+t),n=document.getElementById("roadmap-btn-"+t);e&&(e.style.display="none"),n&&(n.textContent="📋 Edit Roadmap")}function S(t,e,n){const a=document.getElementById("rm-status-"+t);a&&(a.textContent=e,a.style.color=n?"var(--red)":"var(--text-2)")}async function L(t){const a=document.getElementById("rm-ta-"+t),o=w[t];if(a&&o)try{await e("/api/roadmap/write",{roadmapFile:o,content:a.value}),S(t,"✓ Saved — "+(new Date).toLocaleTimeString()),n("Roadmap saved"),setTimeout(s,800)}catch(i){S(t,"Save failed: "+i.message,!0)}}function A(t){const e=document.getElementById("rm-ta-"+t),n=document.getElementById("rm-add-"+t);if(!e)return;const a="- [ ] "+((n?n.value.trim():"")||"New task");e.value=e.value.trimEnd()+"\n"+a+"\n",e.scrollTop=e.scrollHeight,n&&(n.value=""),S(t,"Item added — click 💾 Save to persist")}async function T(t){const e=document.getElementById("rm-ta-"+t);if(!e)return;const n=(e.value.match(/\[!\]/g)||[]).length;n?(e.value=e.value.split("\n").map(t=>t.replace(/\[!\]/,"[ ]").replace(/\s+✗\s+\d+:\d+:\d+/g,"")).join("\n"),S(t,n+" failed item(s) reset — click 💾 Save to persist")):S(t,"No failed items to reset")}async function z(){var t;const e=document.getElementById("phasedProgress");if(!e)return;const n=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"",o=document.getElementById("phasedProgressLabel");try{const t="/api/phased-progress"+(n?"?projectId="+encodeURIComponent(n):""),i=await a(t),d=n?"This project":"All projects (no project selected)";if(o&&(o.textContent=d),!i.length)return void(n?e.innerHTML='<div style="padding:20px;color:var(--text-3);text-align:center;">No phased builds yet for this project.<br><br>💡 Tip: Click <b>▶ Run Build</b> or <b>🔁 Build Until Done</b> above to start.</div>':e.textContent="No phased runs yet.");e.innerHTML=i.map(t=>{const e=t.phase||"?",a=t.agent||"?",o=(t.task||"").slice(0,50)+((t.task||"").length>50?"...":""),i="completed"===t.status?"✅":"❌",d=null!=t.duration_s?t.duration_s+"s":"";let s="";if(t.timestamp){const e=new Date(t.timestamp),n=e.getHours();s=`${n%12||12}:${e.getMinutes().toString().padStart(2,"0")} ${n>=12?"PM":"AM"}`}return`<div style="margin-bottom:4px;">${i} [${e}] ${a}: ${o} ${d}${s?` <span style="color:var(--text-3);font-size:10px;">· ${s}</span>`:""}${!n&&t.projectId&&x[t.projectId]?`<span style="color:var(--text-3);font-size:10px;"> · ${x[t.projectId].name}</span>`:""}</div>`}).join(""),e.scrollTop=e.scrollHeight}catch(i){e.textContent="Could not load progress."}}async function M(){var t;const a=document.getElementById("buildRequirement").value.trim();if(!a)return void n("Enter a requirement",!0);const o=document.getElementById("buildStatus"),i=document.getElementById("runBuildBtn"),d=document.getElementById("stopBuildBtn"),s=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"";try{o.textContent="Starting...",i.disabled=!0;const t=await e("/api/build",{requirement:a,projectId:s});n("Build started (pid "+t.pid+"). Watch RT Messages or Phased Progress."),o.textContent="Running (pid "+t.pid+")",i.style.display="none",d&&(d.style.display=""),setTimeout(()=>{o.textContent="",i.disabled=!1,i.style.display="",d&&(d.style.display="none")},12e4)}catch(r){n("Build failed: "+r.message,!0),o.textContent="",i.disabled=!1}}async function R(){const t=document.getElementById("buildRequirement"),a=t.value.trim(),o=document.getElementById("enhancePromptBtn");if(a)try{o.disabled=!0,document.getElementById("buildStatus").textContent="Enhancing...";const i=await e("/api/enhance-prompt",{text:a});i.enhanced?(t.value=i.enhanced,n("Prompt updated")):n(i.error||"No result",!0)}catch(i){n("Enhance failed: "+i.message,!0)}finally{o.disabled=!1,document.getElementById("buildStatus").textContent=""}else n("Type an idea first",!0)}async function D(){var t;const a=document.getElementById("buildRequirement").value.trim();if(!a)return void n("Enter a requirement first",!0);const o=document.getElementById("buildStatus"),i=document.getElementById("continuousBuildBtn"),d=document.getElementById("stopContinuousBtn"),s=document.getElementById("buildLiveLog"),r=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"";try{o.textContent="Running continuously...",i.disabled=!0,i.style.display="none",d&&(d.style.display=""),s.style.display="block",s.textContent="⚙ Starting continuous build...\n";const t=await e("/api/continuous-build",{requirement:a,projectId:r});s.textContent+="✅ Spawned (pid "+t.pid+"). Checking progress below and in RT Messages tab.\n",n("Continuous build started — will keep going until all sections are done."),o.textContent="Running (continuous)";const l=setInterval(async()=>{try{const t=await fetch("/api/continuous-build/log").then(t=>t.json());if(t.lines&&t.lines.length){s.textContent=t.lines.map(t=>`${"completed"===t.status?"✅":"failed"===t.status?"❌":"done"===t.status?"🏁":"·"} [rd${t.round||"?"}] ${t.agent?t.agent+": ":""}${t.task||t.status||JSON.stringify(t)}`).join("\n"),s.scrollTop=s.scrollHeight;const e=t.lines[t.lines.length-1];e&&"done"===e.status&&(clearInterval(l),i.disabled=!1,i.style.display="",d&&(d.style.display="none"),o.textContent="🏁 Done!",n("🏁 Continuous build complete!"))}}catch(t){}},4e3);setTimeout(()=>{clearInterval(l),i.disabled=!1,i.style.display="",d&&(d.style.display="none"),o.textContent.includes("continuous")&&(o.textContent="")},18e5)}catch(l){n("Continuous build failed: "+l.message,!0),o.textContent="",i.disabled=!1,i.style.display="",d&&(d.style.display="none")}}export{B as a,E as b,D as c,s as d,R as e,I as f,h as g,d as h,l as i,i as j,T as k,j as l,L as m,k as n,g as o,m as p,P as q,M as r,p as s,b as t,y as u,f as v,v as w};
1
+ import{a as t,p as e,s as n,g as a,e as o}from"./core-utils-CmOkXgzi.js";function i(t){t.hideAllViews(),document.getElementById("buildView").classList.add("active"),t.setNavActive("navBuild"),z()}function d(t){t.hideAllViews(),document.getElementById("projectsView").classList.add("active"),t.setNavActive("navProjects"),s()}async function s(){const e=document.getElementById("projectsList");e.innerHTML='<div class="meta" style="padding:20px;">Loading projects...</div>';try{const n=(await a("/api/projects")).projects||[];if(t.projectsData={},n.forEach(e=>{t.projectsData[e.id]=e}),m(n),!n.length)return void(e.innerHTML='<div class="meta" style="padding:20px;">No projects yet. Click &quot;+ New Project&quot; to create one.</div>');e.innerHTML=n.map(t=>{const e=o(t.id),n=t.roadmap.total?Math.round(t.roadmap.done/t.roadmap.total*100):0,a=100===n?"var(--green)":n>50?"var(--accent)":"var(--yellow)",i="active"===t.status?"rgba(52,211,153,0.1)":"var(--bg-card2)",d="active"===t.status?"var(--green)":"var(--text-3)",s=t.roadmap.failed?'<button data-action="retry-failed" data-id="'+e+'" style="background:rgba(248,113,113,0.15);color:var(--red);border:1px solid rgba(248,113,113,0.3);border-radius:6px;padding:6px 12px;cursor:pointer;font-size:13px;font-weight:600;">↩ Retry '+t.roadmap.failed+" failed</button>":"";return'<div class="card" id="proj-card-'+e+'" data-proj-id="'+e+'"><div id="proj-view-'+e+'"><div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:12px;"><div><strong style="font-size:15px;">'+o(t.name)+'</strong><span style="margin-left:10px;font-size:11px;padding:2px 8px;border-radius:999px;background:'+i+";color:"+d+";border:1px solid "+d+'40;">'+o(t.status)+"</span>"+(t.running?'<span style="margin-left:8px;font-size:11px;padding:2px 8px;border-radius:999px;background:rgba(99,102,241,0.15);color:var(--purple);border:1px solid rgba(99,102,241,0.3);">▶ running</span>':"")+(t.description?'<div class="meta" style="margin-top:4px;">'+o(t.description)+"</div>":"")+'</div><div class="meta">'+new Date(t.created).toLocaleDateString()+'</div></div><div style="margin-bottom:12px;"><div style="display:flex;justify-content:space-between;margin-bottom:6px;"><span class="meta">Roadmap</span><span class="meta">'+t.roadmap.done+"/"+t.roadmap.total+" done"+(t.roadmap.failed?" · "+t.roadmap.failed+" failed":"")+" · "+t.roadmap.pending+' pending</span></div><div class="prog-bar"><div class="prog-fill" style="width:'+n+"%;background:"+a+';"></div></div></div><div style="font-size:11px;color:var(--text-3);margin-bottom:12px;font-family:monospace;">'+o(t.outputDir)+'</div><div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;"><button data-action="pm-toggle" data-id="'+e+'" class="'+(t.running?"btn-red":"btn-green")+'" style="font-size:13px;">'+(t.running?"⏹ Stop PM Loop":"▶ Start PM Loop")+'</button><button data-action="open-build" data-id="'+e+'" class="btn-ghost" style="font-size:13px;">🔧 Build tab</button><button data-action="edit-roadmap" data-id="'+e+'" class="btn-ghost" style="font-size:13px;" id="roadmap-btn-'+e+'">📋 Roadmap</button><button data-action="chat-project" data-id="'+e+'" data-name="'+o(t.name)+'" class="btn-ghost" style="font-size:13px;">🧠 Chat</button>'+s+'<label style="margin-left:auto;display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;color:var(--text-3);user-select:none;" title="When enabled, crew-lead automatically starts the next ROADMAP phase when the current pipeline completes"><input type="checkbox" data-action="toggle-auto-advance" data-id="'+e+'" '+(t.autoAdvance?"checked":"")+' style="accent-color:var(--green);width:14px;height:14px;cursor:pointer;">⚡ Auto-advance</label><button data-action="edit" data-id="'+e+'" style="background:transparent;color:var(--text-3);border:1px solid var(--border);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px;" title="Edit project">✎ Edit</button><button data-action="delete" data-id="'+e+'" style="background:transparent;color:var(--text-3);border:1px solid var(--border);border-radius:6px;padding:4px 10px;cursor:pointer;font-size:12px;" title="Remove from dashboard (files stay on disk)">🗑 Delete</button></div></div><div id="proj-edit-'+e+'" style="display:none;padding:12px;border-top:1px solid var(--border);margin-top:12px;"><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Name</label><input id="proj-name-'+e+'" type="text" value="'+o(t.name)+'" style="margin-top:4px;" /></div><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Description</label><input id="proj-desc-'+e+'" type="text" value="'+o(t.description||"")+'" style="margin-top:4px;" placeholder="Optional" /></div><div style="margin-bottom:8px;"><label style="font-size:11px;color:var(--text-3);">Output directory</label><input id="proj-dir-'+e+'" type="text" value="'+o(t.outputDir||"")+'" style="margin-top:4px;" /></div><div style="display:flex;gap:8px;"><button data-action="save-project-edit" data-id="'+e+'" class="btn-green" style="font-size:12px;">Save</button><button data-action="cancel-project-edit" data-id="'+e+'" class="btn-ghost" style="font-size:12px;">Cancel</button></div></div><div id="proj-pm-status-'+e+'" style="display:none;margin-top:10px;font-size:12px;padding:8px 12px;background:rgba(99,102,241,0.08);border-radius:6px;border:1px solid rgba(99,102,241,0.2);color:#a5b4fc;"></div><div id="rm-editor-'+e+'" style="display:none;margin-top:14px;"><div style="display:flex;gap:8px;align-items:center;margin-bottom:8px;flex-wrap:wrap;"><span class="field-label" style="margin:0;">ROADMAP</span><span class="meta" style="font-family:monospace;">'+o(t.roadmapFile)+'</span><div style="margin-left:auto;display:flex;gap:6px;"><button data-action="add-item" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--green);color:#000;">+ Add item</button><button data-action="skip-next" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--yellow);color:#000;">⏭ Skip next</button><button data-action="reset-failed" data-id="'+e+'" style="font-size:11px;padding:3px 10px;" class="btn-ghost">↩ Reset failed</button><button data-action="save-roadmap" data-id="'+e+'" style="font-size:11px;padding:3px 10px;background:var(--accent);color:#000;">💾 Save</button><button data-action="close-editor" data-id="'+e+'" style="font-size:11px;padding:3px 10px;" class="btn-ghost">✕</button></div></div><div style="display:flex;gap:8px;margin-bottom:8px;"><input id="rm-add-'+e+'" type="text" placeholder="New item text… (Enter to add)" style="flex:1;font-size:13px;" data-rm-add-id="'+e+'" /></div><textarea id="rm-ta-'+e+'" rows="16" class="rm-textarea" spellcheck="false"></textarea><div id="rm-status-'+e+'" class="meta" style="margin-top:6px;min-height:16px;"></div></div></div>'}).join(""),e.querySelectorAll("[data-rm-add-id]").forEach(t=>{t.addEventListener("keydown",e=>{"Enter"===e.key&&A(t.dataset.rmAddId)})})}catch(n){e.innerHTML='<div class="meta" style="padding:20px;color:var(--red-hi);">Failed to load projects: '+o(n.message)+"</div>"}}function r(t){const e=document.getElementById("proj-view-"+t),n=document.getElementById("proj-edit-"+t);if(!e||!n)return;const a="none"!==n.style.display;e.style.display=a?"":"none",n.style.display=a?"none":"block"}function l(a){const o=document.getElementById("projectsList");o&&o.addEventListener("click",o=>{var i;const d=o.target.closest("[data-action]");if(!d)return;const l=d.dataset.id,c=t.projectsData[l];switch(d.dataset.action){case"pm-toggle":c&&c.running?b(l):f(l);break;case"open-build":!function(t,e){e.showBuild(),j().then(()=>{const e=document.getElementById("buildProjectPicker");e&&(e.value=t,I())})}(l,a);break;case"edit-roadmap":c&&P(l,c.roadmapFile);break;case"retry-failed":c&&k(c.roadmapFile);break;case"delete":!async function(a){const i=t.projectsData[a],d=i?i.name:a;if(!confirm('Remove "'+d+'" from the dashboard registry?\n\nFiles on disk are NOT deleted.'))return;try{await e("/api/projects/delete",{projectId:a}),n('Project "'+d+'" removed from dashboard.'),s()}catch(o){n("Delete failed: "+o.message,!0)}}(l);break;case"chat-project":a.showChat(),v(l),null==(i=document.getElementById("chatInput"))||i.focus();break;case"toggle-auto-advance":{const a=d.checked;return void e("/api/projects/update",{projectId:l,autoAdvance:a}).then(()=>{t.projectsData[l]&&(t.projectsData[l].autoAdvance=a),n("Auto-advance "+(a?"enabled":"disabled")+" for "+((null==c?void 0:c.name)||l))}).catch(t=>{n("Failed: "+t.message,!0),d.checked=!a})}case"edit":case"cancel-project-edit":r(l);break;case"save-project-edit":!async function(t){var a,i,d,l,c,p;const u=null==(i=null==(a=document.getElementById("proj-name-"+t))?void 0:a.value)?void 0:i.trim(),m=null==(l=null==(d=document.getElementById("proj-desc-"+t))?void 0:d.value)?void 0:l.trim(),g=null==(p=null==(c=document.getElementById("proj-dir-"+t))?void 0:c.value)?void 0:p.trim();if(u)try{await e("/api/projects/update",{projectId:t,name:u,description:m,outputDir:g}),n("Project saved"),r(t),s()}catch(o){n("Failed: "+o.message,!0)}else n("Project name is required",!0)}(l);break;case"add-item":A(l);break;case"skip-next":!function(t){const e=document.getElementById("rm-ta-"+t);if(!e)return;const n=e.value.split("\n");let a=!1;for(let o=0;o<n.length;o++)if(/^- \[ \]/.test(n[o])){n[o]=n[o].replace("- [ ]","- [x]")+" ✓ skipped",a=!0;break}a?(e.value=n.join("\n"),S(t,"Next pending item skipped — click 💾 Save to persist")):S(t,"No pending items to skip")}(l);break;case"reset-failed":T(l);break;case"save-roadmap":L(l);break;case"close-editor":C(l)}})}const c="crewswarm_chat_active_project_id";function p(t){try{t?localStorage.setItem(c,t):localStorage.removeItem(c)}catch{}}function u(t){const e=t&&String(t).trim()&&"undefined"!==t?String(t).trim():"general";return fetch("/api/ui/active-project",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({projectId:e})}).catch(()=>{})}function m(e){const n=document.getElementById("chatProjectTabs");if(!n)return;const a=function(){try{return localStorage.getItem(c)||""}catch{return""}}()||t.chatActiveProjectId||"general";for(;n.children.length>1;)n.removeChild(n.lastChild);const o=new Set,i=(e||[]).filter(t=>{const e=t.id||t.name&&t.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");return!(!e||o.has(e))&&(o.add(e),!0)}).map(t=>({...t,id:t.id||t.name&&t.name.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}));i.forEach(t=>{if(!t.id)return;const e=document.createElement("button");e.className="project-tab",e.dataset.projectId=t.id,e.textContent=`📁 ${t.name||t.id}`,e.onclick=()=>window.selectProjectTab(t.id),n.appendChild(e)}),console.log("[Projects] Populated tabs:",i.length,"projects");const d=new Set(["general",...i.map(t=>t.id).filter(Boolean)]).has(a)?a:"general";t.chatActiveProjectId=d,p(d),u(d),Array.from(n.children).forEach(t=>{t.classList.toggle("active",t.dataset.projectId===d)})}function g(){const e=document.getElementById("chatProjectSelect");e&&(t.chatActiveProjectId=e.value,p(t.chatActiveProjectId),u(t.chatActiveProjectId),y())}function y(){const e=document.getElementById("chatProjectHint");if(e)if(t.chatActiveProjectId&&t.projectsData[t.chatActiveProjectId]){const n=t.projectsData[t.chatActiveProjectId];e.textContent=n.outputDir||"",e.style.display=n.outputDir?"block":"none"}else e.style.display="none"}function v(e){t.chatActiveProjectId=e,p(e),u(e);const n=document.getElementById("chatProjectSelect");n&&n.querySelector('option[value="'+e+'"]')&&(n.value=e,y())}async function b(t){try{await e("/api/pm-loop/stop",{projectId:t}),n("Stop signal sent — PM will finish current task then halt.");const a=document.getElementById("proj-pm-status-"+t);a&&(a.style.display="block",a.textContent="⛔ Stopping after current task…"),setTimeout(s,3e3)}catch(a){n("Stop failed: "+a.message,!0)}}async function f(t){const a=document.getElementById("proj-pm-status-"+t);try{a&&(a.style.display="block",a.textContent="⚙ Starting PM Loop…");const o=await e("/api/pm-loop/start",{projectId:t});if(o.alreadyRunning)return n("PM Loop already running (pid "+o.pid+")",!0),void(a&&(a.textContent="▶ Already running (pid "+o.pid+")"));n("PM Loop started (pid "+o.pid+")"),a&&(a.textContent="▶ Running (pid "+o.pid+") — check Build tab for live log"),setTimeout(s,3e3)}catch(o){n("Start failed: "+o.message,!0),a&&(a.style.display="none")}}let x={};function h(t){return x[t]||null}async function j(){try{const t=await a("/api/projects");x={};const e=document.getElementById("buildProjectPicker"),n=e?e.value:"";if(!e)return;e.innerHTML='<option value="">— No project (use defaults) —</option>',(t.projects||[]).forEach(t=>{x[t.id]=t;const a=document.createElement("option");a.value=t.id,a.textContent=t.name+(t.running?" ▶":"")+" ("+t.roadmap.pending+" pending)",t.id===n&&(a.selected=!0),e.appendChild(a)}),I()}catch(t){}}function I(){const t=document.getElementById("buildProjectPicker"),e=document.getElementById("buildProjectInfo"),n=document.getElementById("pmLoopProjectLabel"),a=document.getElementById("phasedProgressLabel"),o=x[t?t.value:""];o?(e.style.display="block",e.innerHTML="<b>"+o.name+"</b><br>Output: "+o.outputDir+"<br>Roadmap: "+o.roadmapFile+"<br>Tasks: "+o.roadmap.done+" done · "+o.roadmap.pending+" pending · "+o.roadmap.failed+" failed"+(o.running?'<br><span style="color:var(--purple);">▶ PM Loop is running</span>':""),n&&(n.innerHTML='<b style="color:var(--accent);">▶ '+o.name+"</b> &nbsp;·&nbsp; "+o.roadmap.done+" done · "+o.roadmap.pending+" pending"+(o.running?' &nbsp;<span style="color:var(--green-hi); font-weight:600;">● running</span>':"")),a&&(a.textContent="▶ "+o.name)):(e.style.display="none",n&&(n.innerHTML="← Select a project above"),a&&(a.textContent="All projects (no project selected)")),z()}async function B(){try{await e("/api/build/stop",{}),n("Build stop signal sent"),document.getElementById("stopBuildBtn").style.display="none",document.getElementById("runBuildBtn").style.display="",document.getElementById("buildStatus").textContent=""}catch(t){n("Stop failed: "+t.message,!0)}}async function E(){try{await e("/api/continuous-build/stop",{}),n("Continuous build stop signal sent"),document.getElementById("stopContinuousBtn").style.display="none",document.getElementById("continuousBuildBtn").style.display=""}catch(t){n("Stop failed: "+t.message,!0)}}async function k(t){if(confirm("Reset all [!] failed items back to [ ] pending so the PM Loop retries them?"))try{const a=await e("/api/roadmap/retry-failed",{roadmapFile:t});if(0===a.count)return void n("No failed items found in roadmap",!0);n("↩ "+a.count+" failed item"+(1!==a.count?"s":"")+" reset — click Resume to retry"),await s()}catch(a){n("Retry failed: "+a.message,!0)}}const w={};async function P(t,n){w[t]=n;const a=document.getElementById("rm-editor-"+t),o=document.getElementById("rm-ta-"+t),i=document.getElementById("roadmap-btn-"+t);if(a&&o)if("none"===a.style.display){a.style.display="block",i&&(i.textContent="📋 Editing…"),o.value="Loading…";try{const a=await e("/api/roadmap/read",{roadmapFile:n});o.value=a.content||"",S(t,"Loaded · "+(a.content||"").split("\n").length+" lines")}catch(d){o.value="",S(t,"Error: "+d.message,!0)}}else C(t)}function C(t){const e=document.getElementById("rm-editor-"+t),n=document.getElementById("roadmap-btn-"+t);e&&(e.style.display="none"),n&&(n.textContent="📋 Edit Roadmap")}function S(t,e,n){const a=document.getElementById("rm-status-"+t);a&&(a.textContent=e,a.style.color=n?"var(--red)":"var(--text-2)")}async function L(t){const a=document.getElementById("rm-ta-"+t),o=w[t];if(a&&o)try{await e("/api/roadmap/write",{roadmapFile:o,content:a.value}),S(t,"✓ Saved — "+(new Date).toLocaleTimeString()),n("Roadmap saved"),setTimeout(s,800)}catch(i){S(t,"Save failed: "+i.message,!0)}}function A(t){const e=document.getElementById("rm-ta-"+t),n=document.getElementById("rm-add-"+t);if(!e)return;const a="- [ ] "+((n?n.value.trim():"")||"New task");e.value=e.value.trimEnd()+"\n"+a+"\n",e.scrollTop=e.scrollHeight,n&&(n.value=""),S(t,"Item added — click 💾 Save to persist")}async function T(t){const e=document.getElementById("rm-ta-"+t);if(!e)return;const n=(e.value.match(/\[!\]/g)||[]).length;n?(e.value=e.value.split("\n").map(t=>t.replace(/\[!\]/,"[ ]").replace(/\s+✗\s+\d+:\d+:\d+/g,"")).join("\n"),S(t,n+" failed item(s) reset — click 💾 Save to persist")):S(t,"No failed items to reset")}async function z(){var t;const e=document.getElementById("phasedProgress");if(!e)return;const n=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"",o=document.getElementById("phasedProgressLabel");try{const t="/api/phased-progress"+(n?"?projectId="+encodeURIComponent(n):""),i=await a(t),d=n?"This project":"All projects (no project selected)";if(o&&(o.textContent=d),!i.length)return void(n?e.innerHTML='<div style="padding:20px;color:var(--text-3);text-align:center;">No phased builds yet for this project.<br><br>💡 Tip: Click <b>▶ Run Build</b> or <b>🔁 Build Until Done</b> above to start.</div>':e.textContent="No phased runs yet.");e.innerHTML=i.map(t=>{const e=t.phase||"?",a=t.agent||"?",o=(t.task||"").slice(0,50)+((t.task||"").length>50?"...":""),i="completed"===t.status?"✅":"❌",d=null!=t.duration_s?t.duration_s+"s":"";let s="";if(t.timestamp){const e=new Date(t.timestamp),n=e.getHours();s=`${n%12||12}:${e.getMinutes().toString().padStart(2,"0")} ${n>=12?"PM":"AM"}`}return`<div style="margin-bottom:4px;">${i} [${e}] ${a}: ${o} ${d}${s?` <span style="color:var(--text-3);font-size:10px;">· ${s}</span>`:""}${!n&&t.projectId&&x[t.projectId]?`<span style="color:var(--text-3);font-size:10px;"> · ${x[t.projectId].name}</span>`:""}</div>`}).join(""),e.scrollTop=e.scrollHeight}catch(i){e.textContent="Could not load progress."}}async function R(){var t;const a=document.getElementById("buildRequirement").value.trim();if(!a)return void n("Enter a requirement",!0);const o=document.getElementById("buildStatus"),i=document.getElementById("runBuildBtn"),d=document.getElementById("stopBuildBtn"),s=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"";try{o.textContent="Starting...",i.disabled=!0;const t=await e("/api/build",{requirement:a,projectId:s});n("Build started (pid "+t.pid+"). Watch RT Messages or Phased Progress."),o.textContent="Running (pid "+t.pid+")",i.style.display="none",d&&(d.style.display=""),setTimeout(()=>{o.textContent="",i.disabled=!1,i.style.display="",d&&(d.style.display="none")},12e4)}catch(r){n("Build failed: "+r.message,!0),o.textContent="",i.disabled=!1}}async function M(){var t;const a=document.getElementById("buildRequirement"),o=a.value.trim(),i=document.getElementById("enhancePromptBtn"),d=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"";if(o)try{i.disabled=!0,document.getElementById("buildStatus").textContent="Planning...";const t=await e("/api/enhance-prompt",{text:o,projectId:d});if(t.enhanced){a.value=t.enhanced;const e=t.engine?` via ${t.engine}`:"",o=t.warning?` (${t.warning})`:"";n(`Requirement planned${e}${o}`)}else n(t.error||"No result",!0)}catch(s){n("Planning failed: "+s.message,!0)}finally{i.disabled=!1,document.getElementById("buildStatus").textContent=""}else n("Type an idea first",!0)}async function D(){var t;const a=document.getElementById("buildRequirement").value.trim();if(!a)return void n("Enter a requirement first",!0);const o=document.getElementById("buildStatus"),i=document.getElementById("continuousBuildBtn"),d=document.getElementById("stopContinuousBtn"),s=document.getElementById("buildLiveLog"),r=(null==(t=document.getElementById("buildProjectPicker"))?void 0:t.value)||"";try{o.textContent="Running continuously...",i.disabled=!0,i.style.display="none",d&&(d.style.display=""),s.style.display="block",s.textContent="⚙ Starting continuous build...\n";const t=await e("/api/continuous-build",{requirement:a,projectId:r});s.textContent+="✅ Spawned (pid "+t.pid+"). Checking progress below and in RT Messages tab.\n",n("Continuous build started — will keep going until all sections are done."),o.textContent="Running (continuous)";const l=setInterval(async()=>{try{const t=await fetch("/api/continuous-build/log").then(t=>t.json());if(t.lines&&t.lines.length){s.textContent=t.lines.map(t=>`${"completed"===t.status?"✅":"failed"===t.status?"❌":"done"===t.status?"🏁":"·"} [rd${t.round||"?"}] ${t.agent?t.agent+": ":""}${t.task||t.status||JSON.stringify(t)}`).join("\n"),s.scrollTop=s.scrollHeight;const e=t.lines[t.lines.length-1];e&&"done"===e.status&&(clearInterval(l),i.disabled=!1,i.style.display="",d&&(d.style.display="none"),o.textContent="🏁 Done!",n("🏁 Continuous build complete!"))}}catch(t){}},4e3);setTimeout(()=>{clearInterval(l),i.disabled=!1,i.style.display="",d&&(d.style.display="none"),o.textContent.includes("continuous")&&(o.textContent="")},18e5)}catch(l){n("Continuous build failed: "+l.message,!0),o.textContent="",i.disabled=!1,i.style.display="",d&&(d.style.display="none")}}export{B as a,E as b,D as c,s as d,M as e,I as f,h as g,d as h,l as i,i as j,T as k,j as l,L as m,k as n,g as o,m as p,P as q,R as r,p as s,b as t,y as u,f as v,v as w};
@@ -0,0 +1 @@
1
+ import{p as e,s as t,g as o,a,e as n}from"./core-utils-CmOkXgzi.js";import{s,u as r}from"./tab-projects-tab-SFH4E--a.js";let l=null,i=null;function c({getModels:e,populateModelDropdown:t}={}){l=e||l,i=t||i}async function d(){const a=document.getElementById("rtTokenInput").value.trim();if(a)try{await e("/api/settings/rt-token",{token:a}),t("RT Bus token saved"),document.getElementById("rtTokenInput").value="",async function(){try{const e=await o("/api/settings/rt-token"),t=document.getElementById("rtTokenBadge"),a=document.getElementById("rtTokenInput");e.token?(t.textContent="set ✓",t.style.background="rgba(52,211,153,0.15)",t.style.color="var(--green)",t.style.borderColor="rgba(52,211,153,0.3)",a.placeholder="••••••••••••••••••••••• (saved)"):(t.textContent="not set",t.style.background="rgba(251,191,36,0.15)",t.style.color="var(--yellow)",t.style.borderColor="rgba(251,191,36,0.3)")}catch{}}()}catch(n){t("Save failed: "+n.message,"error")}else t("Paste a token first","error")}async function u(){const e=document.getElementById("configLockBadge"),t=document.getElementById("configLockStatus"),a=document.querySelector('[data-action="lockConfig"]'),n=document.querySelector('[data-action="unlockConfig"]');try{(await o("/api/config/lock-status")).locked?(e.textContent="🔒 Locked",e.style.background="rgba(52,211,153,0.15)",e.style.color="var(--green)",e.style.borderColor="rgba(52,211,153,0.3)",t&&(t.textContent="✓ Config is protected from overwrites"),a&&(a.className="btn-primary",a.style.opacity="0.6",a.style.pointerEvents="none"),n&&(n.className="btn-ghost",n.style.opacity="1",n.style.pointerEvents="auto")):(e.textContent="🔓 Unlocked",e.style.background="rgba(251,191,36,0.15)",e.style.color="var(--yellow)",e.style.borderColor="rgba(251,191,36,0.3)",t&&(t.textContent="⚠️ Config can be modified — lock it after making changes"),a&&(a.className="btn-primary",a.style.opacity="1",a.style.pointerEvents="auto"),n&&(n.className="btn-ghost",n.style.opacity="0.6",n.style.pointerEvents="none"))}catch{e&&(e.textContent="? unknown")}}async function g(){try{await e("/api/config/lock",{}),t("✓ Config locked — protected from overwrites"),u()}catch(o){t("Lock failed: "+o.message,"error")}}async function m(){try{await e("/api/config/unlock",{}),t("✓ Config unlocked — you can now make changes"),u()}catch(o){t("Unlock failed: "+o.message,"error")}}async function y(){try{const e=await o("/api/settings/opencode-project"),t=document.getElementById("opencodeProjInput"),a=document.getElementById("opencodeProjStatus");t&&(t.placeholder=e.dir||"e.g. /Users/you/Desktop/myproject",t.value=e.dir||""),a&&(a.textContent=e.dir?"✅ Current: "+e.dir:"⚠️ Not set — OpenCode will write files to the crewswarm repo root. Set this to your project folder."),document.getElementById("opencodeFallbackSelect")&&l&&(await l(),i&&i("opencodeFallbackSelect",e.fallbackModel||""));const n=document.getElementById("opencodeFallbackStatus");n&&(n.textContent=e.fallbackModel?"✅ Fallback: "+e.fallbackModel:"⚠️ Using default groq/kimi-k2-instruct-0905"),document.getElementById("opencodeModelSelect")&&l&&(await l(),i&&i("opencodeModelSelect",e.opencodeModel||""));const s=document.getElementById("opencodeModelStatus");s&&(s.textContent=e.opencodeModel?"✅ Primary: "+e.opencodeModel:"⚠️ Using default groq/moonshotai/kimi-k2-instruct-0905");const r=document.getElementById("crewLeadModelSelect");r&&e.crewLeadModel&&(r.value=e.crewLeadModel)}catch{}}async function p(){var o,n;const l=((null==(o=document.getElementById("opencodeProjInput"))?void 0:o.value)||"").trim(),i=((null==(n=document.getElementById("opencodeFallbackSelect"))?void 0:n.value)||"").trim();try{if(await e("/api/settings/opencode-project",{dir:l||void 0,fallbackModel:i||void 0}),t("OpenCode settings saved — fallback takes effect on next task (no restart needed)"),y(),l&&a.projectsData){const e=Object.values(a.projectsData).find(e=>e.outputDir===l);if(e){a.chatActiveProjectId=e.id,s(e.id);const t=document.getElementById("chatProjectSelect");t&&(t.value=e.id),r()}}}catch(c){t("Save failed: "+c.message,"error")}}async function f(){const o=document.getElementById("opencodeModelSelect"),a=((null==o?void 0:o.value)||"").trim(),n=document.getElementById("opencodeModelStatus");try{await e("/api/settings/opencode-project",{opencodeModel:a||void 0}),n&&(n.textContent="✓ Saved",n.style.color="var(--green-hi)"),t(a?`Primary OpenCode model → ${a}`:"OpenCode model reset to default"),setTimeout(()=>{n&&(n.textContent=a?"✅ Primary: "+a:"⚠️ Using default groq/moonshotai/kimi-k2-instruct-0905")},3e3)}catch(s){n&&(n.textContent="Error: "+s.message,n.style.color="var(--red)"),t("Save failed: "+s.message,"error")}}async function b(){const e=document.getElementById("bgConsciousnessBtn"),t=document.getElementById("bgConsciousnessStatus"),a=document.getElementById("bgConsciousnessModel");try{const n=await o("/api/settings/bg-consciousness"),s=n.enabled;e&&(e.textContent=s?"🟢 ON":"⚫ OFF",e.style.background=s?"rgba(34,197,94,0.15)":"var(--surface-2)",e.style.borderColor=s?"var(--green-hi)":"var(--border)",e.style.color=s?"var(--green-hi)":"var(--text-2)"),a&&n.model&&(a.placeholder=n.model),t&&(t.textContent=s?"Active — crew-lead reflects every "+Math.round(n.intervalMs/6e4)+"min when idle. Model: "+n.model:"Off — crew-lead will not self-reflect between tasks.")}catch(n){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+n.message)}}async function E(){try{const a=await o("/api/settings/bg-consciousness"),n=await e("/api/settings/bg-consciousness",{enabled:!a.enabled});t("Background consciousness "+(n.enabled?"ENABLED":"DISABLED")),b()}catch(a){t("Failed: "+a.message,"error")}}async function h(){const o=document.getElementById("bgConsciousnessModel"),a=((null==o?void 0:o.value)||"").trim();if(a)try{await e("/api/settings/bg-consciousness",{model:a}),t("Background consciousness model → "+a),o.value="",b()}catch(n){t("Failed: "+n.message,"error")}else t("Enter a model first (e.g. groq/llama-3.3-70b-versatile)","error")}async function C(){const e=document.getElementById("cursorWavesBtn"),t=document.getElementById("cursorWavesStatus");try{const a=(await o("/api/settings/cursor-waves")).enabled;e&&(e.textContent=a?"⚡ ON":"⚫ OFF",e.style.background=a?"rgba(168,85,247,0.15)":"var(--surface-2)",e.style.borderColor=a?"#a855f7":"var(--border)",e.style.color=a?"#c084fc":"var(--text-2)"),t&&(t.textContent=a?"Active — multi-agent waves fan out to Cursor subagents in parallel. crew-orchestrator coordinates each wave.":"Off — each agent in a wave dispatches independently through the standard gateway.")}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message)}}async function v(){try{const a=await o("/api/settings/cursor-waves"),n=await e("/api/settings/cursor-waves",{enabled:!a.enabled});t("Cursor Parallel Waves "+(n.enabled?"ENABLED ⚡":"DISABLED")),C()}catch(a){t("Failed: "+a.message,"error")}}async function k(){const e=document.getElementById("tmuxBridgeBtn"),t=document.getElementById("tmuxBridgeStatus");try{const a=(await o("/api/settings/tmux-bridge")).enabled;e&&(e.textContent=a?"🔌 ON":"⚫ OFF",e.style.background=a?"rgba(52,211,153,0.15)":"var(--surface-2)",e.style.borderColor=a?"rgba(52,211,153,0.3)":"var(--border)",e.style.color=a?"var(--green)":"var(--text-2)"),t&&(t.textContent=a?"Active — agents can share persistent tmux sessions across pipeline waves. Requires tmux + smux.":"Off — agents use standard cold-start execution (no session persistence).")}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message)}}async function x(){try{const a=await o("/api/settings/tmux-bridge"),n=await e("/api/settings/tmux-bridge",{enabled:!a.enabled});t("tmux-bridge "+(n.enabled?"ENABLED 🔌":"DISABLED")),k()}catch(a){t("Failed: "+a.message,"error")}}async function w(){const e=document.getElementById("autonomousMentionsBtn"),t=document.getElementById("autonomousMentionsStatus");try{const a=!1!==(await o("/api/settings/autonomous-mentions")).enabled;e&&(e.textContent=a?"🕸 ON":"⚫ OFF",e.style.background=a?"rgba(52,211,153,0.15)":"var(--surface-2)",e.style.borderColor=a?"rgba(52,211,153,0.3)":"var(--border)",e.style.color=a?"var(--green)":"var(--text-2)"),t&&(t.textContent=a?"Active — shared chat @mentions can auto-route to agents and CLI participants.":"Off — @mentions are recorded in chat history, but no autonomous routing will fire.",t.style.color="var(--text-3)")}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message)}}async function I(){try{const a=await o("/api/settings/autonomous-mentions"),n=await e("/api/settings/autonomous-mentions",{enabled:!a.enabled});t("Autonomous mention routing "+(n.enabled?"ENABLED 🕸":"DISABLED")),w()}catch(a){t("Failed: "+a.message,"error")}}async function M(){const e=document.getElementById("claudeCodeBtn"),t=document.getElementById("claudeCodeStatus");try{const a=await o("/api/settings/claude-code"),n=a.enabled;e&&(e.textContent=n?"🤖 ON":"⚫ OFF",e.style.background=n?"rgba(245,158,11,0.15)":"var(--surface-2)",e.style.borderColor=n?"var(--amber)":"var(--border)",e.style.color=n?"var(--yellow)":"var(--text-2)"),t&&(a.hasKey?(t.textContent=n?"Active — tasks route through Claude Code CLI. Per-agent override: set useClaudeCode: true in crewswarm.json.":"Off — tasks use direct LLM or OpenCode. Enable to run agents through Claude Code CLI.",t.style.color="var(--text-3)"):(t.textContent="⚠️ ANTHROPIC_API_KEY not set — add it to ~/.crewswarm/crewswarm.json under providers.anthropic.apiKey or set the env var.",t.style.color="var(--amber)"))}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message)}}async function S(){try{const a=await o("/api/settings/claude-code");if(!a.hasKey)return void t("Set ANTHROPIC_API_KEY first — add it in ~/.crewswarm/crewswarm.json under providers.anthropic.apiKey","error");const n=await e("/api/settings/claude-code",{enabled:!a.enabled});t("Claude Code executor "+(n.enabled?"ENABLED 🤖":"DISABLED")),M()}catch(a){t("Failed: "+a.message,"error")}}async function _(){const e=document.getElementById("codexBtn"),t=document.getElementById("codexStatus");try{const a=(await o("/api/settings/codex")).enabled;e&&(e.textContent=a?"🟣 ON":"⚫ OFF",e.style.background=a?"rgba(168,85,247,0.15)":"var(--surface-2)",e.style.borderColor=a?"#a855f7":"var(--border)",e.style.color=a?"#a855f7":"var(--text-2)"),t&&(t.textContent=a?"Active — tasks route through Codex CLI. Per-agent override: set useCodex: true in crewswarm.json.":"Off — tasks use direct LLM or other engine. Enable to route all coding agents through Codex CLI.",t.style.color="var(--text-3)")}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message,t.style.color="var(--text-3)")}}async function A(){try{const a=await o("/api/settings/codex"),n=await e("/api/settings/codex",{enabled:!a.enabled});t("Codex CLI executor "+(n.enabled?"ENABLED 🟣":"DISABLED")),_()}catch(a){t("Failed: "+a.message,"error")}}async function O(){const e=document.getElementById("geminiCliBtn"),t=document.getElementById("geminiCliStatus");try{const a=await o("/api/settings/gemini-cli"),n=a.enabled;e&&(e.textContent=n?"🔵 ON":"⚫ OFF",e.style.background=n?"rgba(66,133,244,0.15)":"var(--surface-2)",e.style.borderColor=n?"#4285f4":"var(--border)",e.style.color=n?"#4285f4":"var(--text-2)"),t&&(a.installed?(t.textContent=n?"Active — tasks route through Gemini CLI. Run gemini auth login if you haven't authenticated yet.":"Off — tasks use direct LLM or other engine. Enable to route coding agents through Gemini CLI (free Google OAuth tier).",t.style.color="var(--text-3)"):(t.textContent="⚠️ gemini binary not found — run: npm install -g @google/gemini-cli",t.style.color="var(--amber)"))}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load: "+a.message,t.style.color="var(--text-3)")}}async function R(){try{const a=await o("/api/settings/gemini-cli");if(!a.installed)return void t("Install Gemini CLI first: npm install -g @google/gemini-cli","error");const n=await e("/api/settings/gemini-cli",{enabled:!a.enabled});t("Gemini CLI executor "+(n.enabled?"ENABLED 🔵":"DISABLED")),O()}catch(a){t("Failed: "+a.message,"error")}}async function B(){const e=document.getElementById("crewCliBtn"),t=document.getElementById("crewCliStatus");try{const a=(await o("/api/settings/crew-cli")).enabled;e&&(e.textContent=a?"🔧 ON":"⚫ OFF",e.style.background=a?"rgba(16,185,129,0.15)":"var(--surface-2)",e.style.borderColor=a?"#10b981":"var(--border)",e.style.color=a?"#10b981":"var(--text-2)"),t&&(t.textContent=a?"Active — multi-agent swarm tasks route through crew-cli with intelligent dispatch to specialists.":"Off — tasks use direct LLM or other engine. Enable to route all coding agents through crew-cli natively.")}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load status")}}async function L(){try{const a=await o("/api/settings/crew-cli"),n=await e("/api/settings/crew-cli",{enabled:!a.enabled});t("Crew CLI executor "+(n.enabled?"ENABLED 🔧":"DISABLED")),B()}catch(a){t("Failed: "+a.message,"error")}}async function D(){const e=document.getElementById("opencodeBtn"),t=document.getElementById("opencodeStatus");try{const a=await o("/api/settings/opencode"),n=a.enabled;e&&(e.textContent=n?"⚡ ON":"⚫ OFF",e.style.background=n?"rgba(52,211,153,0.15)":"var(--surface-2)",e.style.borderColor=n?"rgba(52,211,153,0.3)":"var(--border)",e.style.color=n?"var(--green)":"var(--text-2)"),t&&(a.installed?(t.textContent=n?"⚡ Active — coding agents route through OpenCode for full IDE context and session persistence.":"⚫ Off — tasks use direct LLM or other configured engine. Enable to run agents through OpenCode CLI.",t.style.color="var(--text-3)"):(t.textContent="⚠️ opencode binary not found — install: npm install -g opencode",t.style.color="var(--amber)"))}catch(a){e&&(e.textContent="Error"),t&&(t.textContent="Could not load status",t.style.color="var(--text-3)")}}async function N(){try{const a=await o("/api/settings/opencode");if(!a.installed)return void t("Install OpenCode CLI first: npm install -g opencode","error");const n=await e("/api/settings/opencode",{enabled:!a.enabled});t("OpenCode executor "+(n.enabled?"ENABLED ⚡":"DISABLED")),D()}catch(a){t("Failed: "+a.message,"error")}}async function W(){try{const e=await o("/api/settings/global-fallback"),t=document.getElementById("globalFallbackInput");t&&(t.value=e.globalFallbackModel||"");const a=document.getElementById("globalFallbackStatus");a&&(a.textContent=e.globalFallbackModel?"Active: any agent without a per-agent fallback will use "+e.globalFallbackModel:"Not set — agents without fallback will use the built-in default (groq/llama-3.3-70b-versatile).")}catch(e){console.warn("loadGlobalFallback:",e.message)}}async function T(){var o;const a=((null==(o=document.getElementById("globalFallbackInput"))?void 0:o.value)||"").trim();try{await e("/api/settings/global-fallback",{globalFallbackModel:a}),t(a?"Global fallback → "+a:"Global fallback cleared"),W()}catch(n){t("Failed: "+n.message,"error")}}async function P(){try{const e=await o("/api/settings/global-oc-loop"),t=document.getElementById("globalOcLoop"),a=document.getElementById("globalOcLoopRounds");t&&(t.checked=e.enabled||!1),a&&(a.value=e.maxRounds??10)}catch(e){}}async function F(){var o;const a=null==(o=document.getElementById("globalOcLoop"))?void 0:o.checked;try{await e("/api/settings/global-oc-loop",{enabled:a}),t("Global OC loop "+(a?"enabled":"disabled"))}catch(n){t("Failed: "+n.message,!0)}}async function G(){var o;const a=parseInt(null==(o=document.getElementById("globalOcLoopRounds"))?void 0:o.value)||10;try{await e("/api/settings/global-oc-loop",{maxRounds:a}),t("Max rounds set to "+a)}catch(n){t("Failed: "+n.message,!0)}}async function j(){try{const e=await o("/api/settings/passthrough-notify"),t=document.getElementById("passthroughNotifySelect");t&&(t.value=e.value||"both")}catch(e){}}async function U(){var o;const a=(null==(o=document.getElementById("passthroughNotifySelect"))?void 0:o.value)||"both",n=document.getElementById("passthroughNotifyStatus");try{await e("/api/settings/passthrough-notify",{value:a}),n&&(n.textContent="✓ Saved — takes effect on the next passthrough",n.style.color="var(--green-hi)"),t("Passthrough notifications → "+a)}catch(s){n&&(n.textContent="Error: "+s.message,n.style.color="var(--red)")}}async function H(){try{const e=await o("/api/settings/loop-brain"),t=document.getElementById("loopBrainModel");t&&e.loopBrain&&(t.value=e.loopBrain)}catch{}}const q=[{label:"Engine — OpenCode",vars:[{key:"CREWSWARM_OPENCODE_ENABLED",hint:"Route coding agents through OpenCode globally",default:"off"},{key:"CREWSWARM_OPENCODE_MODEL",hint:"Model passed to OpenCode — leave blank to use per-agent model",default:"per-agent"},{key:"CREWSWARM_OPENCODE_TIMEOUT_MS",hint:"ms before an OpenCode task is killed",default:"300000"},{key:"CREWSWARM_OPENCODE_AGENT",hint:"Override agent name passed to OpenCode",default:"auto"}]},{label:"Engine — Claude Code & Cursor",note:"Both use OAuth login (run claude or cursor once). No API key required.",vars:[{key:"CREWSWARM_CLAUDE_CODE_MODEL",hint:"Model passed to claude -p — leave blank for Claude Code default",default:"claude default"},{key:"CREWSWARM_CURSOR_MODEL",hint:"Cursor CLI --model when agent has no cursorCliModel (default: composer-2-fast)",default:"composer-2-fast"}]},{label:"Engine — Codex & crew-cli",note:"These are the dashboard-wide defaults when an agent does not have a per-route model override.",vars:[{key:"CREWSWARM_CODEX_MODEL",hint:"Model passed to codex exec --model (leave blank for Codex default)",default:"codex default"},{key:"CREWSWARM_CREW_CLI_MODEL",hint:"Model passed to crew chat --model and gateway crew-cli engine",default:"gemini-2.5-flash"}]},{label:"Engine — Gemini CLI",note:"Free tier via Google account — 60 req/min. Run gemini once to auth.",vars:[{key:"CREWSWARM_GEMINI_CLI_ENABLED",hint:"Route agents through Gemini CLI globally",default:"off"},{key:"CREWSWARM_GEMINI_CLI_MODEL",hint:"Model passed to gemini -p (e.g. gemini-2.0-flash) — blank for default",default:"gemini default"}]},{label:"Engine — Docker Sandbox",note:"Runs any inner engine inside an isolated Docker microVM. API keys injected by network proxy — never exposed to the agent.",vars:[{key:"CREWSWARM_DOCKER_SANDBOX",hint:"Route all coding agents through Docker Sandbox globally",default:"off"},{key:"CREWSWARM_DOCKER_SANDBOX_NAME",hint:"Pre-created sandbox name",default:"crewswarm"},{key:"CREWSWARM_DOCKER_SANDBOX_INNER_ENGINE",hint:"Engine inside the sandbox: claude, opencode, or codex",default:"claude"},{key:"CREWSWARM_DOCKER_SANDBOX_TIMEOUT_MS",hint:"ms before a sandboxed task is killed",default:"300000"}]},{label:"Engine Loop & Dispatch",vars:[{key:"CREWSWARM_ENGINE_LOOP",hint:"Enable Ouroboros engine loop for all agents",default:"off"},{key:"CREWSWARM_ENGINE_LOOP_MAX_ROUNDS",hint:"Max STEP iterations per loop run",default:"10"},{key:"CREWSWARM_ENGINE_IDLE_TIMEOUT_MS",hint:"Kill engine (Cursor/Claude) if no output for this many ms",default:"300000"},{key:"CREWSWARM_ENGINE_MAX_TOTAL_MS",hint:"Absolute max ms for any single engine task",default:"2700000"},{key:"CREWSWARM_DISPATCH_TIMEOUT_MS",hint:"ms before an unclaimed dispatch times out",default:"300000"},{key:"CREWSWARM_DISPATCH_CLAIMED_TIMEOUT_MS",hint:"ms before a claimed (in-progress) dispatch times out",default:"900000"},{key:"CREWSWARM_RT_AGENT",hint:"Agent ID used for the RT bus",default:"crew-coder"}]},{label:"Ports",vars:[{key:"CREW_LEAD_PORT",hint:"crew-lead HTTP server port",default:"5010"},{key:"SWARM_DASH_PORT",hint:"Dashboard port",default:"4319"},{key:"WA_HTTP_PORT",hint:"WhatsApp bridge HTTP port",default:"3000"}]},{label:"Background Consciousness",vars:[{key:"CREWSWARM_BG_CONSCIOUSNESS",hint:"Enable idle reflection loop",default:"off"},{key:"CREWSWARM_BG_CONSCIOUSNESS_INTERVAL_MS",hint:"Idle reflection interval in ms",default:"900000"},{key:"CREWSWARM_BG_CONSCIOUSNESS_MODEL",hint:"Model for background cycle (e.g. groq/llama-3.1-8b-instant)",default:"groq/llama-3.1-8b-instant"}]},{label:"Messaging",vars:[{key:"TELEGRAM_ALLOWED_USERNAMES",hint:"Comma-separated Telegram usernames allowed to message the bot",default:"all allowed"},{key:"WA_ALLOWED_NUMBERS",hint:"Comma-separated WhatsApp numbers in intl format (+1555…)",default:"all allowed"}]},{label:"Memory",vars:[{key:"SHARED_MEMORY_NAMESPACE",hint:"Namespace prefix for shared memory keys",default:"crewswarm"},{key:"SHARED_MEMORY_DIR",hint:"Directory for shared memory files",default:"~/.crewswarm/memory"}]},{label:"crew-cli — Streaming & Hooks",note:"Controls for crew-cli streaming output, tool hooks, and session token limits.",vars:[{key:"CREW_NO_STREAM",hint:"Disable streaming output — tokens arrive after full response (true/false)",default:"false"},{key:"CREW_HOOKS_FILE",hint:"Path to hooks.json for PreToolUse/PostToolUse hooks",default:".crew/hooks.json"},{key:"CREW_MAX_SESSION_TOKENS",hint:"Max estimated tokens per session before oldest turns are trimmed",default:"100000"}]},{label:"crew-cli — Codebase Index & RAG",note:"Codebase embedding index auto-builds on startup. Injects relevant file context into every worker prompt.",vars:[{key:"CREW_RAG_MODE",hint:"RAG mode: auto (use index when ready, else keyword), semantic, keyword, import-graph, off",default:"auto"},{key:"CREW_EMBEDDING_PROVIDER",hint:"Embedding provider: local (zero-cost), openai (best), gemini (free tier)",default:"local"},{key:"CREW_RAG_WORKER_BUDGET",hint:"Max tokens of RAG context injected per worker (approximate)",default:"4000"},{key:"CREW_RAG_MAX_FILES",hint:"Max code files to index (larger repos should increase this)",default:"2000"},{key:"CREW_RAG_BATCH_SIZE",hint:"Files per embedding batch (higher = faster but more API calls)",default:"20"}]},{label:"crew-cli — Checkpointing",note:"Automatic git checkpoints during pipeline execution for easy rollback.",vars:[{key:"CREW_AUTO_CHECKPOINT",hint:"Enable auto-commit at task boundaries (true/false)",default:"true"},{key:"CREW_CHECKPOINT_INTERVAL_MS",hint:"Periodic git stash snapshot interval during long tasks (ms, 0=off)",default:"60000"}]},{label:"PM Loop",vars:[{key:"PM_MAX_ITEMS",hint:"Max roadmap items per PM loop run",default:"10"},{key:"PM_MAX_CONCURRENT",hint:"Max concurrent agent tasks in PM loop",default:"20"},{key:"PM_USE_QA",hint:"Include crew-qa review after each PM task",default:"off"},{key:"PM_USE_SECURITY",hint:"Include crew-security review for auth/key tasks",default:"off"},{key:"PM_USE_SPECIALISTS",hint:"Route tasks to specialist agents (front/back/github) by keyword",default:"on"},{key:"PM_SELF_EXTEND",hint:"Auto-generate new roadmap items when queue is empty",default:"on"},{key:"PM_EXTEND_EVERY",hint:"Generate new items every N completions (0 = only when empty)",default:"5"},{key:"PM_CODER_AGENT",hint:"Override default coding agent for PM loop (e.g. crew-coder-front)",default:"crew-coder"},{key:"PM_AGENT_IDLE_TIMEOUT_MS",hint:"Kill PM dispatch if no activity for this many ms",default:"900000"},{key:"PHASED_TASK_TIMEOUT_MS",hint:"Overall timeout for a single agent task in the PM loop",default:"600000"}]}];async function $(){const e=document.getElementById("envAdvancedWidget");if(e)try{const[t,o]=await Promise.all([fetch("/api/env").then(e=>e.json()).catch(()=>({})),fetch("/api/env-advanced").then(e=>e.json()).catch(()=>({env:{}}))]),a=o.env||{},s=null!=t.uptime?t.uptime<60?t.uptime+"s":Math.floor(t.uptime/60)+"m":"—";let r=`<div style="display:flex;gap:24px;flex-wrap:wrap;font-size:11px;color:var(--text-3);margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid var(--border);">\n <span>cwd: <code style="color:var(--text-2);">${n(t.cwd||"—")}</code></span>\n <span>node: <code style="color:var(--text-2);">${n(t.node||"—")}</code></span>\n <span>uptime: <code style="color:var(--text-2);">${s}</code></span>\n </div>`;e.innerHTML=r;for(const l of q){const t=document.createElement("div");t.style.cssText="margin-bottom:18px;",t.innerHTML=`<div style="font-size:11px;font-weight:700;color:var(--text-3);text-transform:uppercase;letter-spacing:.06em;margin-bottom:${l.note?"4px":"8px"};">${n(l.label)}</div>`+(l.note?`<div style="font-size:11px;color:var(--accent);margin-bottom:8px;line-height:1.4;">${n(l.note)}</div>`:"");for(const{key:e,hint:o,default:s}of l.vars){const r=a[e]??null,l=r??s??"",i=null===r,c=s?`default: ${s}`:"not set",d=document.createElement("div");d.style.cssText="margin-bottom:8px;",d.innerHTML=`\n <div style="display:flex;align-items:baseline;gap:6px;margin-bottom:3px;">\n <span style="font-size:11px;font-family:monospace;color:var(--accent);">${n(e)}</span>\n ${i&&s?'<span style="font-size:10px;color:var(--text-3);font-family:monospace;background:var(--bg-1);padding:1px 5px;border-radius:4px;border:1px solid var(--border);">default</span>':""}\n </div>\n <div style="font-size:10px;color:var(--text-3);margin-bottom:4px;">${n(o)}</div>\n <div style="display:flex;gap:6px;align-items:center;">\n <input data-env-key="${n(e)}" data-env-default="${n(s||"")}" type="text" value="${n(l)}"\n placeholder="${n(c)}"\n class="inp-sm inp-mono inp-flex" />\n <button data-env-save="${n(e)}" style="font-size:11px;padding:5px 10px;border-radius:6px;cursor:pointer;border:1px solid var(--border);background:var(--surface-2);color:var(--text-2);white-space:nowrap;">Save</button>\n <span data-env-status="${n(e)}" style="font-size:11px;min-width:50px;"></span>\n </div>`,t.appendChild(d)}e.appendChild(t)}e.querySelectorAll("[data-env-save]").forEach(t=>{t.addEventListener("click",()=>{const o=t.dataset.envSave,a=e.querySelector(`[data-env-key="${o}"]`),n=e.querySelector(`[data-env-status="${o}"]`);a&&n&&async function(e,t,o){const a=t.value.trim();o.textContent="Saving…",o.style.color="var(--text-3)";try{const t=await fetch("/api/env-advanced",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({[e]:a||null})}),n=await t.json();n.ok?(o.textContent=a?"✓ Saved":"✓ Cleared",o.style.color="var(--green)"):(o.textContent="Error: "+(n.error||"unknown"),o.style.color="var(--red, #f87171)")}catch(n){o.textContent="Error: "+n.message,o.style.color="var(--red, #f87171)"}setTimeout(()=>{o.textContent=""},3e3)}(o,a,n)})}),e.querySelectorAll("[data-env-key]").forEach(e=>{e.addEventListener("input",()=>{const t=e.value===(e.dataset.envDefault||"");e.style.color="var(--text-1)",e.style.opacity=t?"0.65":"1"})})}catch(t){e&&(e.textContent="Could not load: "+t.message)}}export{M as A,_ as B,O as C,B as D,D as E,P as F,H as G,j as H,$ as I,c as J,G as a,F as b,L as c,R as d,A as e,S as f,I as g,x as h,v as i,E as j,T as k,f as l,p as m,g as n,d as o,h as p,y as q,b as r,U as s,N as t,m as u,W as v,u as w,C as x,k as y,w as z};
@@ -6,13 +6,13 @@
6
6
  <title>crewswarm dashboard</title>
7
7
  <link rel="icon" type="image/png" href="/favicon.png" />
8
8
  <!-- Font: system stack only to avoid CORS when dashboard (4319) and studio (3333) both load Inter from Google -->
9
- <script type="module" crossorigin src="/assets/index-DnClJ1ee.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-GSWxxEPO.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/core-utils-CmOkXgzi.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/setup-wizard-CA0Or47w.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/components-BS9fQjE_.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/orchestration-Ca2DLWN-.js">
14
14
  <link rel="modulepreload" crossorigin href="/assets/cli-process-COMRNPqr.js">
15
- <link rel="modulepreload" crossorigin href="/assets/chat-core-Cx4sTxDd.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/chat-core-3KirthZA.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/tab-swarm-chat-tab-BNrd88-r.js">
17
17
  <link rel="modulepreload" crossorigin href="/assets/tab-waves-tab-SaJDkb4x.js">
18
18
  <link rel="modulepreload" crossorigin href="/assets/tab-workflows-tab-B-soSy1k.js">
@@ -25,12 +25,12 @@
25
25
  <link rel="modulepreload" crossorigin href="/assets/tab-engines-tab-BsdZVvU0.js">
26
26
  <link rel="modulepreload" crossorigin href="/assets/tab-swarm-tab-B1AcjL1W.js">
27
27
  <link rel="modulepreload" crossorigin href="/assets/tab-models-tab-BLEjmd19.js">
28
- <link rel="modulepreload" crossorigin href="/assets/tab-projects-tab-DhNWnlzt.js">
29
- <link rel="modulepreload" crossorigin href="/assets/tab-settings-tab-Bn4nXtDe.js">
28
+ <link rel="modulepreload" crossorigin href="/assets/tab-projects-tab-SFH4E--a.js">
29
+ <link rel="modulepreload" crossorigin href="/assets/tab-settings-tab-BselH1c0.js">
30
30
  <link rel="modulepreload" crossorigin href="/assets/tab-comms-tab-kguqTIzD.js">
31
31
  <link rel="modulepreload" crossorigin href="/assets/tab-usage-tab-BIOOnB-Y.js">
32
32
  <link rel="modulepreload" crossorigin href="/assets/tab-spending-tab-DEccQHnt.js">
33
- <link rel="modulepreload" crossorigin href="/assets/tab-pm-loop-tab-Bfd449B4.js">
33
+ <link rel="modulepreload" crossorigin href="/assets/tab-pm-loop-tab-DiAPTJXu.js">
34
34
  <link rel="stylesheet" crossorigin href="/assets/index-CF0aJRtC.css">
35
35
  </head>
36
36
  <body>
@@ -4427,6 +4427,76 @@
4427
4427
  ></div>
4428
4428
  </div>
4429
4429
 
4430
+ <div class="card" style="margin-top: 16px">
4431
+ <div
4432
+ style="
4433
+ display: flex;
4434
+ align-items: center;
4435
+ justify-content: space-between;
4436
+ flex-wrap: wrap;
4437
+ gap: 12px;
4438
+ "
4439
+ >
4440
+ <div>
4441
+ <div class="card-title" style="margin-bottom: 2px">
4442
+ 🔌 tmux-bridge Sessions
4443
+ </div>
4444
+ <div
4445
+ style="
4446
+ font-size: 11px;
4447
+ color: var(--text-3);
4448
+ line-height: 1.5;
4449
+ "
4450
+ >
4451
+ Enable persistent tmux sessions that survive across pipeline
4452
+ waves. Agents can hand off live execution context (running
4453
+ servers, env vars, cwd) to the next wave instead of
4454
+ cold-starting. Requires
4455
+ <code
4456
+ style="
4457
+ background: var(--bg-1);
4458
+ padding: 1px 4px;
4459
+ border-radius: 3px;
4460
+ "
4461
+ >tmux</code
4462
+ >
4463
+ +
4464
+ <code
4465
+ style="
4466
+ background: var(--bg-1);
4467
+ padding: 1px 4px;
4468
+ border-radius: 3px;
4469
+ "
4470
+ >smux</code
4471
+ >
4472
+ installed. One writer per session (lock enforced).
4473
+ </div>
4474
+ </div>
4475
+ <button
4476
+ id="tmuxBridgeBtn"
4477
+ data-action="toggleTmuxBridge"
4478
+ style="
4479
+ font-size: 12px;
4480
+ font-weight: 700;
4481
+ padding: 8px 18px;
4482
+ border-radius: 8px;
4483
+ cursor: pointer;
4484
+ border: 1px solid var(--border);
4485
+ background: var(--surface-2);
4486
+ color: var(--text-2);
4487
+ white-space: nowrap;
4488
+ min-width: 80px;
4489
+ "
4490
+ >
4491
+ Loading…
4492
+ </button>
4493
+ </div>
4494
+ <div
4495
+ id="tmuxBridgeStatus"
4496
+ style="margin-top: 8px; font-size: 12px; color: var(--text-3)"
4497
+ ></div>
4498
+ </div>
4499
+
4430
4500
  <div class="card" style="margin-top: 16px">
4431
4501
  <div
4432
4502
  style="
@@ -5977,9 +6047,9 @@
5977
6047
  <button
5978
6048
  id="enhancePromptBtn"
5979
6049
  class="btn-purple"
5980
- title="AI-enhance your requirement"
6050
+ title="Plan the requirement with the configured crew-pm CLI engine"
5981
6051
  >
5982
- Enhance
6052
+ 🧭 Plan
5983
6053
  </button>
5984
6054
  <span class="meta" id="buildStatus"></span>
5985
6055
  </div>
@@ -5991,10 +6061,11 @@
5991
6061
  <div
5992
6062
  style="margin-top: 10px; font-size: 11px; color: var(--text-3)"
5993
6063
  >
5994
- <b>▶ Run Build</b> — one phased build (MVP→Ph1→Ph2), runs in
5995
- background. <b>🔁 Build Until Done</b> — loops continuously until
5996
- roadmap exhausted. <b>PM Loop ▶</b> — reads ROADMAP.md and
5997
- dispatches each item one at a time.
6064
+ <b>🧭 Plan</b> — turns a rough idea into a concrete build brief
6065
+ using the configured PM engine. <b>▶ Run Build</b> — one phased
6066
+ build (MVP→Ph1→Ph2), runs in background. <b>🔁 Build Until Done</b>
6067
+ loops continuously until roadmap exhausted. <b>PM Loop ▶</b> —
6068
+ reads ROADMAP.md and dispatches each item one at a time.
5998
6069
  </div>
5999
6070
  </div>
6000
6071
 
@@ -48,7 +48,7 @@ npm run perf:audit
48
48
  ```
49
49
 
50
50
  `npm run test` runs the standalone smoke, accessibility, performance, and security checks.
51
- `npm run test:e2e` runs a self-contained local HTTP/API end-to-end check for the shipped Studio bundle and server routes.
51
+ `npm run test:e2e` runs a self-contained local HTTP/API end-to-end check for the shipped Vibe bundle and server routes.
52
52
 
53
53
  ## Performance Tooling
54
54
 
@@ -60,7 +60,7 @@ python3 ../../scripts/bench/load_testing.py \
60
60
  --requests 40 \
61
61
  --concurrency 4 \
62
62
  --profile-command "npm start" \
63
- --profile-output /tmp/crewswarm-studio.speedscope.json
63
+ --profile-output /tmp/crewswarm-vibe.speedscope.json
64
64
  ```
65
65
 
66
66
  Use `npm run perf:audit` for a browser-level audit of the shipped Vibe bundle. It boots the local Vibe server on an isolated port, captures navigation timing, transfer size, long tasks, and heap usage through Playwright + the browser Performance APIs, then writes a report to `apps/vibe/output/performance-audit.json`.
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "crewswarm-studio",
2
+ "name": "crewswarm-vibe",
3
3
  "version": "1.0.0",
4
4
  "type": "module",
5
5
  "scripts": {
@@ -40,9 +40,9 @@ const SHARED_PROJECTS_FILE = path.join(CREWSWARM_CFG_DIR, "projects.json");
40
40
  const UI_STATE_FILE = path.join(CREWSWARM_CFG_DIR, "ui-state.json");
41
41
  const DEFAULT_PROJECT = {
42
42
  id: DEFAULT_PROJECT_ID,
43
- name: "Studio Workspace",
43
+ name: "Vibe Workspace",
44
44
  outputDir: WORKSPACE_DIR,
45
- description: "Local Studio workspace",
45
+ description: "Local Vibe workspace",
46
46
  };
47
47
 
48
48
  const MIME_TYPES = {
@@ -1862,7 +1862,7 @@ export const server = http.createServer(async (req, res) => {
1862
1862
  const body = await readBody(req);
1863
1863
  if (body.mode !== "cli") {
1864
1864
  sendJson(res, 400, {
1865
- error: "Local Studio chat only supports CLI passthrough right now",
1865
+ error: "Local Vibe chat only supports CLI passthrough right now",
1866
1866
  });
1867
1867
  return;
1868
1868
  }
package/crew-lead.mjs CHANGED
@@ -33,8 +33,10 @@ import {
33
33
  DISPATCH_TIMEOUT_MS,
34
34
  DISPATCH_CLAIMED_TIMEOUT_MS,
35
35
  loadCursorWavesEnabled,
36
- loadClaudeCodeEnabled
36
+ loadClaudeCodeEnabled,
37
+ loadTmuxBridgeEnabled
37
38
  } from "./lib/runtime/config.mjs";
39
+ import { _reset as resetTmuxBridge } from "./lib/bridges/tmux-bridge.mjs";
38
40
  import {
39
41
  CREWSWARM_TOOL_NAMES,
40
42
  readAgentTools,
@@ -99,6 +101,7 @@ import {
99
101
  } from "./lib/crew-lead/wave-dispatcher.mjs";
100
102
  import { normalizeRtAgentId } from "./lib/agent-registry.mjs";
101
103
  import { handleAutonomousMentions } from "./lib/chat/autonomous-mentions.mjs";
104
+ import { saveProjectMessage } from "./lib/chat/project-messages.mjs";
102
105
  import { initIntervalManagers } from "./lib/crew-lead/interval-manager.mjs";
103
106
 
104
107
  // ── Single instance + canonical PID (dashboard / restart-crew-lead.sh use this path) ──
@@ -126,6 +129,11 @@ const agentLastHeartbeat = new Map(); // agentId → timestamp (ms) — tracks
126
129
  // SSE message throttling to prevent dashboard flashing
127
130
  const SSE_THROTTLE_MS = 500; // Only send same agent_working/idle once per 500ms
128
131
  const sseThrottle = new Map(); // key → lastSentMs
132
+ // Clean stale throttle entries every 10 minutes (#17)
133
+ setInterval(() => {
134
+ const cutoff = Date.now() - 3600_000; // 1 hour TTL
135
+ for (const [k, v] of sseThrottle) { if (v < cutoff) sseThrottle.delete(k); }
136
+ }, 600_000);
129
137
 
130
138
 
131
139
 
@@ -157,6 +165,7 @@ function broadcastSSE(payload) {
157
165
 
158
166
  let _cursorWavesEnabled = loadCursorWavesEnabled();
159
167
  let _claudeCodeEnabled = loadClaudeCodeEnabled();
168
+ let _tmuxBridgeEnabled = loadTmuxBridgeEnabled();
160
169
 
161
170
  const BG_CONSCIOUSNESS_INTERVAL_MS = Number(process.env.CREWSWARM_BG_CONSCIOUSNESS_INTERVAL_MS) || 15 * 60 * 1000;
162
171
  let BG_CONSCIOUSNESS_MODEL = (() => {
@@ -501,6 +510,15 @@ const bgConsciousnessRef = {
501
510
  };
502
511
  const cursorWavesRef = { get enabled() { return _cursorWavesEnabled; }, set enabled(v) { _cursorWavesEnabled = v; } };
503
512
  const claudeCodeRef = { get enabled() { return _claudeCodeEnabled; }, set enabled(v) { _claudeCodeEnabled = v; } };
513
+ const tmuxBridgeRef = {
514
+ get enabled() { return _tmuxBridgeEnabled; },
515
+ set enabled(v) {
516
+ _tmuxBridgeEnabled = v;
517
+ // Sync env var and reset detection cache so tmux-bridge module picks up runtime changes
518
+ process.env.CREWSWARM_TMUX_BRIDGE = v ? "1" : "0";
519
+ resetTmuxBridge();
520
+ },
521
+ };
504
522
 
505
523
  // connectRT is initialized after RT_URL/RT_TOKEN — use a mutable ref so HTTP server can call it
506
524
  let _connectRT = () => { throw new Error("connectRT not initialized yet"); };
@@ -544,6 +562,7 @@ initHttpServer({
544
562
  bgConsciousnessIntervalMs: BG_CONSCIOUSNESS_INTERVAL_MS,
545
563
  cursorWavesRef,
546
564
  claudeCodeRef,
565
+ tmuxBridgeRef,
547
566
  });
548
567
  createAndStartServer(PORT);
549
568
 
@@ -568,11 +587,33 @@ process.on("unhandledRejection", (reason) => {
568
587
  });
569
588
 
570
589
  process.on("uncaughtException", (err) => {
571
- console.error("[crew-lead] uncaught exception:", err?.stack || err?.message);
590
+ const msg = String(err?.message || err || "");
591
+ console.error("[crew-lead] uncaught exception:", err?.stack || msg);
592
+
593
+ // Benign errors from engine passthrough / WebSocket streams — keep alive
594
+ if (
595
+ msg === "terminated" ||
596
+ msg === "aborted" ||
597
+ /client.*disconnect/i.test(msg) ||
598
+ /socket hang up/i.test(msg) ||
599
+ /ECONNRESET/i.test(msg) ||
600
+ /EPIPE/i.test(msg) ||
601
+ /fetch failed/i.test(msg) ||
602
+ /UND_ERR/i.test(msg) ||
603
+ /ECONNREFUSED/i.test(msg)
604
+ ) {
605
+ console.error("[crew-lead] Non-fatal uncaughtException — keeping alive");
606
+ return;
607
+ }
572
608
 
573
- // Always exit on uncaught exceptionsthey leave process in undefined state
574
- console.error("[crew-lead] FATAL exiting due to uncaught exception");
575
- process.exit(1);
609
+ // Fatal errors: port conflicts, permissions, OOM must exit
610
+ if (/EADDRINUSE|EACCES|out of memory|cannot allocate/i.test(msg)) {
611
+ console.error("[crew-lead] FATAL — exiting due to uncaught exception");
612
+ process.exit(1);
613
+ }
614
+
615
+ // Default: log but keep alive
616
+ console.error("[crew-lead] Unexpected uncaughtException — keeping alive (not fatal)");
576
617
  });
577
618
 
578
619
  // ── RT Bus listener — receives replies from agents ────────────────────────────
@@ -603,6 +644,7 @@ initWaveDispatcher({
603
644
  bumpOpsCounter,
604
645
  tryRead,
605
646
  _cursorWavesEnabled,
647
+ loadAgentList: loadAgentListFromConfig,
606
648
  getClaudeCodeEnabled: () => _claudeCodeEnabled,
607
649
  dispatchTimeoutMs: DISPATCH_TIMEOUT_MS,
608
650
  dispatchClaimedTimeoutMs: DISPATCH_CLAIMED_TIMEOUT_MS,
@@ -633,6 +675,7 @@ const connectRT = initWsRouter({
633
675
  appendHistory,
634
676
  pendingPipelines,
635
677
  handleAutonomousMentions,
678
+ saveProjectMessage,
636
679
  checkWaveQualityGate,
637
680
  failPipelineOnQualityGate,
638
681
  savePipelineState,
@@ -43,6 +43,10 @@ export function initGatewayWs(deps) {
43
43
 
44
44
  const client = {
45
45
  publish({ channel, type, to = "broadcast", taskId, correlationId, priority = "medium", payload = {} }) {
46
+ if (!ready) {
47
+ console.warn(`[gateway-ws] Publish skipped — client not ready (channel=${channel}, to=${to})`);
48
+ return;
49
+ }
46
50
  sendFrame({
47
51
  type: "publish",
48
52
  channel,