crewswarm 0.9.0 → 0.9.2

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 (84) hide show
  1. package/README.md +2 -2
  2. package/apps/dashboard/dist/assets/{chat-core-CMoqlR6D.js → chat-core-Cx4sTxDd.js} +1 -1
  3. package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
  4. package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
  5. package/apps/dashboard/dist/assets/{components-CSUb80ze.js → components-BS9fQjE_.js} +1 -1
  6. package/apps/dashboard/dist/assets/components-BS9fQjE_.js.br +0 -0
  7. package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js +1 -0
  8. package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js.br +0 -0
  9. package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
  10. package/apps/dashboard/dist/assets/{index-DqVVQLTW.js → index-DnClJ1ee.js} +2 -2
  11. package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
  12. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  13. package/apps/dashboard/dist/assets/{setup-wizard-D4g5DMhW.js → setup-wizard-CA0Or47w.js} +1 -1
  14. package/apps/dashboard/dist/assets/setup-wizard-CA0Or47w.js.br +0 -0
  15. package/apps/dashboard/dist/assets/{tab-agents-tab-BThdsdJY.js → tab-agents-tab-BgpIsjkw.js} +1 -1
  16. package/apps/dashboard/dist/assets/tab-agents-tab-BgpIsjkw.js.br +0 -0
  17. package/apps/dashboard/dist/assets/{tab-benchmarks-tab-DfCuAClu.js → tab-benchmarks-tab-BHjKCPm3.js} +1 -1
  18. package/apps/dashboard/dist/assets/{tab-comms-tab-eHpOSBhG.js → tab-comms-tab-kguqTIzD.js} +1 -1
  19. package/apps/dashboard/dist/assets/tab-comms-tab-kguqTIzD.js.br +0 -0
  20. package/apps/dashboard/dist/assets/{tab-contacts-tab-5LHSthJM.js → tab-contacts-tab-DiOyMYth.js} +1 -1
  21. package/apps/dashboard/dist/assets/tab-contacts-tab-DiOyMYth.js.br +0 -0
  22. package/apps/dashboard/dist/assets/{tab-engines-tab-C3DYxTwy.js → tab-engines-tab-BsdZVvU0.js} +1 -1
  23. package/apps/dashboard/dist/assets/tab-engines-tab-BsdZVvU0.js.br +0 -0
  24. package/apps/dashboard/dist/assets/{tab-memory-tab-C59BYFQD.js → tab-memory-tab-Cu6u13EQ.js} +1 -1
  25. package/apps/dashboard/dist/assets/tab-memory-tab-Cu6u13EQ.js.br +0 -0
  26. package/apps/dashboard/dist/assets/{tab-models-tab-CQzvaeVh.js → tab-models-tab-BLEjmd19.js} +1 -1
  27. package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
  28. package/apps/dashboard/dist/assets/{tab-pm-loop-tab-D7mnDelU.js → tab-pm-loop-tab-Bfd449B4.js} +1 -1
  29. package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
  30. package/apps/dashboard/dist/assets/{tab-projects-tab-C6h2Mv1K.js → tab-projects-tab-DhNWnlzt.js} +1 -1
  31. package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
  32. package/apps/dashboard/dist/assets/{tab-prompts-tab-C0wZvWK3.js → tab-prompts-tab-DVkUNaJd.js} +1 -1
  33. package/apps/dashboard/dist/assets/tab-prompts-tab-DVkUNaJd.js.br +0 -0
  34. package/apps/dashboard/dist/assets/{tab-services-tab-DBj_w3bc.js → tab-services-tab-DU_LH3uG.js} +1 -1
  35. package/apps/dashboard/dist/assets/tab-services-tab-DU_LH3uG.js.br +0 -0
  36. package/apps/dashboard/dist/assets/{tab-settings-tab-ezeqAjZk.js → tab-settings-tab-Bn4nXtDe.js} +1 -1
  37. package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
  38. package/apps/dashboard/dist/assets/{tab-skills-tab-BYdU2whk.js → tab-skills-tab-BpY0uZHW.js} +1 -1
  39. package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
  40. package/apps/dashboard/dist/assets/{tab-spending-tab-Bg6w9t_p.js → tab-spending-tab-DEccQHnt.js} +1 -1
  41. package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js.br +0 -0
  42. package/apps/dashboard/dist/assets/{tab-swarm-chat-tab-BBV9HB2X.js → tab-swarm-chat-tab-BNrd88-r.js} +1 -1
  43. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BNrd88-r.js.br +0 -0
  44. package/apps/dashboard/dist/assets/{tab-swarm-tab-ChqLlEVs.js → tab-swarm-tab-B1AcjL1W.js} +1 -1
  45. package/apps/dashboard/dist/assets/tab-swarm-tab-B1AcjL1W.js.br +0 -0
  46. package/apps/dashboard/dist/assets/{tab-usage-tab-B2UWXenJ.js → tab-usage-tab-BIOOnB-Y.js} +1 -1
  47. package/apps/dashboard/dist/assets/tab-usage-tab-BIOOnB-Y.js.br +0 -0
  48. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  49. package/apps/dashboard/dist/assets/{tab-workflows-tab-6QSXLJ0i.js → tab-workflows-tab-B-soSy1k.js} +1 -1
  50. package/apps/dashboard/dist/assets/tab-workflows-tab-B-soSy1k.js.br +0 -0
  51. package/apps/dashboard/dist/index.html +23 -23
  52. package/apps/dashboard/dist/index.html.br +0 -0
  53. package/apps/dashboard/dist/index.html.gz +0 -0
  54. package/apps/dashboard/index.html +71 -1
  55. package/apps/dashboard/src/app.js +5 -0
  56. package/apps/dashboard/src/core/dom.js +8 -0
  57. package/apps/dashboard/src/tabs/settings-tab.js +58 -0
  58. package/apps/vibe/.crew/agent-memory/pipeline.json +12 -1
  59. package/apps/vibe/.crew/cost.json +3 -3
  60. package/apps/vibe/.crew/json-parse-metrics.jsonl +1 -0
  61. package/apps/vibe/.crew/pipeline-metrics.jsonl +1 -0
  62. package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +5 -0
  63. package/apps/vibe/.crew/session.json +10 -1
  64. package/apps/vibe/.studio-data/project-messages/general.jsonl +3 -0
  65. package/apps/vibe/index.html +4 -2
  66. package/apps/vibe/server.mjs +75 -3
  67. package/apps/vibe/src/main.js +126 -53
  68. package/crew-lead.mjs +14 -1
  69. package/lib/bridges/cli-executor.mjs +0 -2
  70. package/lib/bridges/tmux-bridge.mjs +200 -0
  71. package/lib/chat/unified-history.mjs +1 -1
  72. package/lib/cli-process-tracker.mjs +2 -1
  73. package/lib/crew-lead/http-server.mjs +286 -1
  74. package/lib/crew-lead/wave-dispatcher.mjs +40 -3
  75. package/lib/engines/crew-cli.mjs +3 -2
  76. package/lib/engines/llm-direct.mjs +4 -1
  77. package/lib/engines/rt-envelope.mjs +14 -5
  78. package/lib/engines/runners.mjs +30 -4
  79. package/lib/runtime/config.mjs +7 -0
  80. package/lib/sessions/session-manager.mjs +287 -0
  81. package/package.json +1 -1
  82. package/scripts/bench/performance_optimization.py +81 -0
  83. package/whatsapp-bridge.mjs +54 -10
  84. package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js +0 -1
@@ -1 +1 @@
1
- import{a as t,p as e,s as n,g as a,e as o}from"./core-utils-CAVnDoe1.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 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 +1 @@
1
- import{a as t,b as e,g as n,s as o,p as r,e as a}from"./core-utils-CAVnDoe1.js";let d=null,i=()=>{},s=()=>{};function p(t={}){i=t.hideAllViews||i,s=t.setNavActive||s}async function m(){i();const r=document.getElementById("promptsView");r&&r.classList.add("active"),s("navPrompts"),t.activeTab="prompts",e();const a=document.getElementById("promptsList");a&&!a.dataset.wired&&(a.dataset.wired="true",a.addEventListener("click",t=>{if(t.target.closest(".prompt-edit-btn")){const r=t.target.closest(".prompt-edit-btn").dataset.agent;d=e=r,n("/api/prompts").then(t=>{const n=t.prompts[e]||"";document.getElementById("promptEditorAgent").textContent=e,document.getElementById("promptEditorTextarea").value=n,document.getElementById("promptEditorChar").textContent=n.length,document.getElementById("promptEditorLine").textContent=n.split("\n").length,document.getElementById("promptEditor").style.display="block",document.getElementById("promptEditorTextarea").focus(),document.getElementById("promptEditorTextarea").oninput=t=>{const e=t.target.value;document.getElementById("promptEditorChar").textContent=e.length,document.getElementById("promptEditorLine").textContent=e.split("\n").length}}).catch(t=>{o("Failed to load prompt: "+t.message,"error")})}var e}));const p=document.getElementById("promptEditorCancel"),m=document.getElementById("promptEditorSave");p&&!p.dataset.wired&&(p.dataset.wired="true",p.addEventListener("click",c)),m&&!m.dataset.wired&&(m.dataset.wired="true",m.addEventListener("click",g)),await l()}async function l(){try{const t=await n("/api/prompts"),e=document.getElementById("promptsList");if(!e)return;const o=Object.entries(t.prompts||{});if(!o.length)return void(e.innerHTML='<p style="color:var(--text-2);padding:16px;">No agent prompts configured.</p>');const r=o.map(([t,e])=>{const n=(e||"").slice(0,150).replace(/\n/g," "),o=(e||"").split("\n").length,r=(e||"").length;return`\n <div class="prompt-card">\n <div class="prompt-header">\n <div>\n <strong style="font-size:14px;">${a(t)}</strong>\n <div style="font-size:11px;color:var(--text-3);margin-top:2px;">\n ${o} lines · ${r} chars\n </div>\n </div>\n <button class="btn-secondary prompt-edit-btn" data-agent="${a(t)}">\n Edit\n </button>\n </div>\n <div class="prompt-preview">\n ${a(n)}${e.length>150?"...":""}\n </div>\n </div>\n `}).join("");e.innerHTML=r,document.getElementById("promptsCount").textContent=o.length}catch(t){o("Failed to load prompts: "+t.message,"error")}}function c(){document.getElementById("promptEditor").style.display="none",d=null}async function g(){if(!d)return;const t=document.getElementById("promptEditorTextarea").value,e=document.getElementById("promptEditorSave");e.disabled=!0,e.textContent="Saving...";try{await r("/api/prompts",{agent:d,prompt:t}),o(`Prompt updated for ${d}. Restart its bridge to apply.`),c(),await l()}catch(n){o("Save failed: "+n.message,"error")}finally{e.disabled=!1,e.textContent="Save"}}export{m as a,p as i};
1
+ import{a as t,b as e,g as n,s as o,p as r,e as a}from"./core-utils-CmOkXgzi.js";let d=null,i=()=>{},s=()=>{};function p(t={}){i=t.hideAllViews||i,s=t.setNavActive||s}async function m(){i();const r=document.getElementById("promptsView");r&&r.classList.add("active"),s("navPrompts"),t.activeTab="prompts",e();const a=document.getElementById("promptsList");a&&!a.dataset.wired&&(a.dataset.wired="true",a.addEventListener("click",t=>{if(t.target.closest(".prompt-edit-btn")){const r=t.target.closest(".prompt-edit-btn").dataset.agent;d=e=r,n("/api/prompts").then(t=>{const n=t.prompts[e]||"";document.getElementById("promptEditorAgent").textContent=e,document.getElementById("promptEditorTextarea").value=n,document.getElementById("promptEditorChar").textContent=n.length,document.getElementById("promptEditorLine").textContent=n.split("\n").length,document.getElementById("promptEditor").style.display="block",document.getElementById("promptEditorTextarea").focus(),document.getElementById("promptEditorTextarea").oninput=t=>{const e=t.target.value;document.getElementById("promptEditorChar").textContent=e.length,document.getElementById("promptEditorLine").textContent=e.split("\n").length}}).catch(t=>{o("Failed to load prompt: "+t.message,"error")})}var e}));const p=document.getElementById("promptEditorCancel"),m=document.getElementById("promptEditorSave");p&&!p.dataset.wired&&(p.dataset.wired="true",p.addEventListener("click",c)),m&&!m.dataset.wired&&(m.dataset.wired="true",m.addEventListener("click",g)),await l()}async function l(){try{const t=await n("/api/prompts"),e=document.getElementById("promptsList");if(!e)return;const o=Object.entries(t.prompts||{});if(!o.length)return void(e.innerHTML='<p style="color:var(--text-2);padding:16px;">No agent prompts configured.</p>');const r=o.map(([t,e])=>{const n=(e||"").slice(0,150).replace(/\n/g," "),o=(e||"").split("\n").length,r=(e||"").length;return`\n <div class="prompt-card">\n <div class="prompt-header">\n <div>\n <strong style="font-size:14px;">${a(t)}</strong>\n <div style="font-size:11px;color:var(--text-3);margin-top:2px;">\n ${o} lines · ${r} chars\n </div>\n </div>\n <button class="btn-secondary prompt-edit-btn" data-agent="${a(t)}">\n Edit\n </button>\n </div>\n <div class="prompt-preview">\n ${a(n)}${e.length>150?"...":""}\n </div>\n </div>\n `}).join("");e.innerHTML=r,document.getElementById("promptsCount").textContent=o.length}catch(t){o("Failed to load prompts: "+t.message,"error")}}function c(){document.getElementById("promptEditor").style.display="none",d=null}async function g(){if(!d)return;const t=document.getElementById("promptEditorTextarea").value,e=document.getElementById("promptEditorSave");e.disabled=!0,e.textContent="Saving...";try{await r("/api/prompts",{agent:d,prompt:t}),o(`Prompt updated for ${d}. Restart its bridge to apply.`),c(),await l()}catch(n){o("Save failed: "+n.message,"error")}finally{e.disabled=!1,e.textContent="Save"}}export{m as a,p as i};
@@ -1 +1 @@
1
- import{g as e,e as t,s,p as a}from"./core-utils-CAVnDoe1.js";let i=null,r=()=>{},n=()=>{};function o(e={}){r=e.hideAllViews||r,n=e.setNavActive||n}function l(){r(),document.getElementById("servicesView").classList.add("active"),n("navServices"),c(),i&&clearInterval(i),i=setInterval(()=>{document.getElementById("servicesView").classList.contains("active")?c():(clearInterval(i),i=null)},1e4)}async function c(){const a=document.getElementById("servicesGrid"),i=document.getElementById("servicesSummary");if(!a)return;const r=a.children.length>0;r||(a.innerHTML='<div class="meta" style="padding:20px;">Checking services...</div>');try{const s=await e("/api/services/status"),r=s.filter(e=>!e.running&&!e.optional).length,n=s.filter(e=>!e.running&&e.optional).length,o=document.getElementById("servicesBadge");if(o&&(r>0?(o.textContent=r,o.classList.remove("hidden")):o.classList.add("hidden")),i){const e=s.filter(e=>e.running).length,a=s.length;let o="rgba(52, 211, 153, 0.08)",l="rgba(52, 211, 153, 0.26)",c=`Healthy: ${e}/${a} services are up`,d="You can keep working normally.";r>0?(o="rgba(248, 113, 113, 0.08)",l="rgba(248, 113, 113, 0.28)",c=`${r} required service${1===r?"":"s"} down`,d="Try the service-specific restart first. If multiple services are down, run `npm run restart-all`, wait a few seconds, then refresh this tab."):n>0&&(o="rgba(251, 191, 36, 0.08)",l="rgba(251, 191, 36, 0.28)",c=`${n} optional service${1===n?"":"s"} down`,d="Core chat/runtime is still available. Start the optional service only if you need that surface."),i.style.display="block",i.style.background=o,i.style.borderColor=l,i.innerHTML='<div style="font-weight:700;margin-bottom:6px;">'+t(c)+'</div><div style="font-size:12px;color:var(--text-2);line-height:1.5;">'+t(d)+"</div>"}a.innerHTML=s.map(e=>{const s=e.running,a=e.canRestart,i=s?"var(--green-hi)":"var(--red-hi)",r=e.statusText||(s?e.pid?"● running pid "+e.pid:"● running":"● stopped"),n=e.uptimeSec?(o=e.uptimeSec)<60?o+"s":o<3600?Math.floor(o/60)+"m "+o%60+"s":Math.floor(o/3600)+"h "+Math.floor(o%3600/60)+"m":"";var o;const l=e.noteText||(a?"":"status only");return'<div class="card" style="display:flex;flex-direction:column;gap:10px;"><div style="display:flex;justify-content:space-between;align-items:flex-start;"><div><div style="font-weight:700;font-size:14px;margin-bottom:3px;">'+t(e.label)+'</div><div style="font-size:11px;color:var(--text-3);">'+t(e.description)+'</div></div><span style="font-size:11px;font-weight:600;color:'+i+';white-space:nowrap;margin-left:8px;">'+r+"</span></div>"+(n?'<div style="font-size:11px;color:var(--text-3);">Up '+n+"</div>":"")+(e.port?'<div style="font-size:11px;color:var(--text-3);">Port '+e.port+"</div>":"")+'<div style="display:flex;gap:6px;flex-wrap:wrap;">'+(a&&s?'<button class="btn-ghost" style="font-size:12px;" data-action="restartService" data-arg="'+e.id+'">↻ Restart</button>':"")+(a&&!s?'<button class="btn-green" style="font-size:12px;" data-action="restartService" data-arg="'+e.id+'">▶ Start</button>':"")+(a&&s?'<button class="btn-red" style="font-size:12px;" data-action="stopService" data-arg="'+e.id+'">⏹ Stop</button>':"")+(a?"":'<span style="font-size:11px;color:var(--text-3);align-self:center;">'+t(l)+"</span>")+"</div></div>"}).join("")}catch(n){i&&(i.style.display="block",i.style.background="rgba(248, 113, 113, 0.08)",i.style.borderColor="rgba(248, 113, 113, 0.28)",i.innerHTML='<div style="font-weight:700;margin-bottom:6px;">Services status unavailable</div><div style="font-size:12px;color:var(--text-2);line-height:1.5;">Run <code>npm run doctor</code> to check the stack, then try <code>npm run restart-all</code> if the dashboard API is up but service status is stale.</div>'),r||(a.innerHTML='<div class="meta" style="padding:20px;color:var(--red-hi);">Error loading services: '+n.message+'<div style="margin-top:8px;color:var(--text-3);font-size:12px;">Try <code>npm run doctor</code>, then <code>npm run restart-all</code> if core services are down.</div></div>'),s("⚠️ Failed to load services: "+n.message,!0)}}async function d(e){const t=document.querySelector(`button[data-action="restartService"][data-arg="${e}"]`);t&&(t.disabled=!0,t.style.opacity="0.5",t.style.cursor="not-allowed");const i=Date.now(),r=window._lastServiceRestart||{};if(r[e]&&i-r[e]<3e3)return s("⏳ Restart already in progress...","warning"),void(t&&(t.disabled=!1,t.style.opacity="",t.style.cursor=""));window._lastServiceRestart||(window._lastServiceRestart={}),window._lastServiceRestart[e]=i;try{const t=await a("/api/services/restart",{id:e});t&&!1===t.ok&&t.message?s("⚠️ "+t.message,"warning"):(s("Restarting "+e+"... Refresh in a few seconds if the status looks stale."),setTimeout(c,"crew-lead"===e?4e3:3e3))}catch(n){s("❌ Restart failed: "+n.message+" — try `npm run doctor` or a full `npm run restart-all`.",!0),t&&(t.disabled=!1,t.style.opacity="",t.style.cursor="")}}async function p(e){const t=document.querySelectorAll(`button[data-arg="${e}"]`);t.forEach(e=>{e.disabled=!0,e.style.opacity="0.5",e.style.cursor="not-allowed"});const i=Date.now(),r=window._lastServiceStop||{};if(r[e]&&i-r[e]<2e3)return s("⏳ Stop already in progress...","warning"),void t.forEach(e=>{e.disabled=!1,e.style.opacity="",e.style.cursor=""});window._lastServiceStop||(window._lastServiceStop={}),window._lastServiceStop[e]=i;try{const t=await a("/api/services/stop",{id:e});t&&!1===t.ok&&t.message?s("⚠️ "+t.message,"warning"):(s("Stopping "+e+"..."),setTimeout(c,1500))}catch(n){s("❌ Stop failed: "+n.message+" — use `npm run doctor` if service state looks inconsistent.",!0),t.forEach(e=>{e.disabled=!1,e.style.opacity="",e.style.cursor=""})}}export{p as a,o as i,c as l,d as r,l as s};
1
+ import{g as e,e as t,s,p as a}from"./core-utils-CmOkXgzi.js";let i=null,r=()=>{},n=()=>{};function o(e={}){r=e.hideAllViews||r,n=e.setNavActive||n}function l(){r(),document.getElementById("servicesView").classList.add("active"),n("navServices"),c(),i&&clearInterval(i),i=setInterval(()=>{document.getElementById("servicesView").classList.contains("active")?c():(clearInterval(i),i=null)},1e4)}async function c(){const a=document.getElementById("servicesGrid"),i=document.getElementById("servicesSummary");if(!a)return;const r=a.children.length>0;r||(a.innerHTML='<div class="meta" style="padding:20px;">Checking services...</div>');try{const s=await e("/api/services/status"),r=s.filter(e=>!e.running&&!e.optional).length,n=s.filter(e=>!e.running&&e.optional).length,o=document.getElementById("servicesBadge");if(o&&(r>0?(o.textContent=r,o.classList.remove("hidden")):o.classList.add("hidden")),i){const e=s.filter(e=>e.running).length,a=s.length;let o="rgba(52, 211, 153, 0.08)",l="rgba(52, 211, 153, 0.26)",c=`Healthy: ${e}/${a} services are up`,d="You can keep working normally.";r>0?(o="rgba(248, 113, 113, 0.08)",l="rgba(248, 113, 113, 0.28)",c=`${r} required service${1===r?"":"s"} down`,d="Try the service-specific restart first. If multiple services are down, run `npm run restart-all`, wait a few seconds, then refresh this tab."):n>0&&(o="rgba(251, 191, 36, 0.08)",l="rgba(251, 191, 36, 0.28)",c=`${n} optional service${1===n?"":"s"} down`,d="Core chat/runtime is still available. Start the optional service only if you need that surface."),i.style.display="block",i.style.background=o,i.style.borderColor=l,i.innerHTML='<div style="font-weight:700;margin-bottom:6px;">'+t(c)+'</div><div style="font-size:12px;color:var(--text-2);line-height:1.5;">'+t(d)+"</div>"}a.innerHTML=s.map(e=>{const s=e.running,a=e.canRestart,i=s?"var(--green-hi)":"var(--red-hi)",r=e.statusText||(s?e.pid?"● running pid "+e.pid:"● running":"● stopped"),n=e.uptimeSec?(o=e.uptimeSec)<60?o+"s":o<3600?Math.floor(o/60)+"m "+o%60+"s":Math.floor(o/3600)+"h "+Math.floor(o%3600/60)+"m":"";var o;const l=e.noteText||(a?"":"status only");return'<div class="card" style="display:flex;flex-direction:column;gap:10px;"><div style="display:flex;justify-content:space-between;align-items:flex-start;"><div><div style="font-weight:700;font-size:14px;margin-bottom:3px;">'+t(e.label)+'</div><div style="font-size:11px;color:var(--text-3);">'+t(e.description)+'</div></div><span style="font-size:11px;font-weight:600;color:'+i+';white-space:nowrap;margin-left:8px;">'+r+"</span></div>"+(n?'<div style="font-size:11px;color:var(--text-3);">Up '+n+"</div>":"")+(e.port?'<div style="font-size:11px;color:var(--text-3);">Port '+e.port+"</div>":"")+'<div style="display:flex;gap:6px;flex-wrap:wrap;">'+(a&&s?'<button class="btn-ghost" style="font-size:12px;" data-action="restartService" data-arg="'+e.id+'">↻ Restart</button>':"")+(a&&!s?'<button class="btn-green" style="font-size:12px;" data-action="restartService" data-arg="'+e.id+'">▶ Start</button>':"")+(a&&s?'<button class="btn-red" style="font-size:12px;" data-action="stopService" data-arg="'+e.id+'">⏹ Stop</button>':"")+(a?"":'<span style="font-size:11px;color:var(--text-3);align-self:center;">'+t(l)+"</span>")+"</div></div>"}).join("")}catch(n){i&&(i.style.display="block",i.style.background="rgba(248, 113, 113, 0.08)",i.style.borderColor="rgba(248, 113, 113, 0.28)",i.innerHTML='<div style="font-weight:700;margin-bottom:6px;">Services status unavailable</div><div style="font-size:12px;color:var(--text-2);line-height:1.5;">Run <code>npm run doctor</code> to check the stack, then try <code>npm run restart-all</code> if the dashboard API is up but service status is stale.</div>'),r||(a.innerHTML='<div class="meta" style="padding:20px;color:var(--red-hi);">Error loading services: '+n.message+'<div style="margin-top:8px;color:var(--text-3);font-size:12px;">Try <code>npm run doctor</code>, then <code>npm run restart-all</code> if core services are down.</div></div>'),s("⚠️ Failed to load services: "+n.message,!0)}}async function d(e){const t=document.querySelector(`button[data-action="restartService"][data-arg="${e}"]`);t&&(t.disabled=!0,t.style.opacity="0.5",t.style.cursor="not-allowed");const i=Date.now(),r=window._lastServiceRestart||{};if(r[e]&&i-r[e]<3e3)return s("⏳ Restart already in progress...","warning"),void(t&&(t.disabled=!1,t.style.opacity="",t.style.cursor=""));window._lastServiceRestart||(window._lastServiceRestart={}),window._lastServiceRestart[e]=i;try{const t=await a("/api/services/restart",{id:e});t&&!1===t.ok&&t.message?s("⚠️ "+t.message,"warning"):(s("Restarting "+e+"... Refresh in a few seconds if the status looks stale."),setTimeout(c,"crew-lead"===e?4e3:3e3))}catch(n){s("❌ Restart failed: "+n.message+" — try `npm run doctor` or a full `npm run restart-all`.",!0),t&&(t.disabled=!1,t.style.opacity="",t.style.cursor="")}}async function p(e){const t=document.querySelectorAll(`button[data-arg="${e}"]`);t.forEach(e=>{e.disabled=!0,e.style.opacity="0.5",e.style.cursor="not-allowed"});const i=Date.now(),r=window._lastServiceStop||{};if(r[e]&&i-r[e]<2e3)return s("⏳ Stop already in progress...","warning"),void t.forEach(e=>{e.disabled=!1,e.style.opacity="",e.style.cursor=""});window._lastServiceStop||(window._lastServiceStop={}),window._lastServiceStop[e]=i;try{const t=await a("/api/services/stop",{id:e});t&&!1===t.ok&&t.message?s("⚠️ "+t.message,"warning"):(s("Stopping "+e+"..."),setTimeout(c,1500))}catch(n){s("❌ Stop failed: "+n.message+" — use `npm run doctor` if service state looks inconsistent.",!0),t.forEach(e=>{e.disabled=!1,e.style.opacity="",e.style.cursor=""})}}export{p as a,o as i,c as l,d as r,l as s};
@@ -1 +1 @@
1
- import{p as e,s as t,g as o,a,e as n}from"./core-utils-CAVnDoe1.js";import{s,u as r}from"./tab-projects-tab-C6h2Mv1K.js";let l=null,c=null;function i({getModels:e,populateModelDropdown:t}={}){l=e||l,c=t||c}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 y(){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 m(){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(),c&&c("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(),c&&c("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(),c=((null==(n=document.getElementById("opencodeFallbackSelect"))?void 0:n.value)||"").trim();try{if(await e("/api/settings/opencode-project",{dir:l||void 0,fallbackModel:c||void 0}),t("OpenCode settings saved — fallback takes effect on next task (no restart needed)"),m(),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(i){t("Save failed: "+i.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 v(){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 h(){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 C(){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")),h()}catch(a){t("Failed: "+a.message,"error")}}async function k(){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 x(){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")),k()}catch(a){t("Failed: "+a.message,"error")}}async function w(){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 M(){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")),w()}catch(a){t("Failed: "+a.message,"error")}}async function I(){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 S(){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")),I()}catch(a){t("Failed: "+a.message,"error")}}async function _(){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 O(){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")),_()}catch(a){t("Failed: "+a.message,"error")}}async function A(){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 B(){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")),A()}catch(a){t("Failed: "+a.message,"error")}}async function R(){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 L(){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")),R()}catch(a){t("Failed: "+a.message,"error")}}async function D(){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 N(){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"),D()}catch(n){t("Failed: "+n.message,"error")}}async function T(){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 W(){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 P(){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 F(){try{const e=await o("/api/settings/passthrough-notify"),t=document.getElementById("passthroughNotifySelect");t&&(t.value=e.value||"both")}catch(e){}}async function G(){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 j(){try{const e=await o("/api/settings/loop-brain"),t=document.getElementById("loopBrainModel");t&&e.loopBrain&&(t.value=e.loopBrain)}catch{}}const U=[{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:"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 U){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??"",c=null===r,i=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 ${c&&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(i)}"\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{_ as A,A as B,R as C,T as D,j as E,F,$ as G,i as H,P as a,W as b,B as c,O as d,S as e,M as f,x as g,C as h,E as i,N as j,f as k,p as l,g as m,d as n,v as o,m as p,b as q,D as r,G as s,L as t,y as u,u as v,h as w,k as x,w as y,I as z};
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-DhNWnlzt.js";let l=null,c=null;function i({getModels:e,populateModelDropdown:t}={}){l=e||l,c=t||c}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 y(){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 m(){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(),c&&c("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(),c&&c("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(),c=((null==(n=document.getElementById("opencodeFallbackSelect"))?void 0:n.value)||"").trim();try{if(await e("/api/settings/opencode-project",{dir:l||void 0,fallbackModel:c||void 0}),t("OpenCode settings saved — fallback takes effect on next task (no restart needed)"),m(),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(i){t("Save failed: "+i.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 v(){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 h(){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 C(){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")),h()}catch(a){t("Failed: "+a.message,"error")}}async function k(){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 x(){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")),k()}catch(a){t("Failed: "+a.message,"error")}}async function w(){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 M(){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")),w()}catch(a){t("Failed: "+a.message,"error")}}async function I(){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 S(){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")),I()}catch(a){t("Failed: "+a.message,"error")}}async function _(){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 O(){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")),_()}catch(a){t("Failed: "+a.message,"error")}}async function A(){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 B(){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")),A()}catch(a){t("Failed: "+a.message,"error")}}async function R(){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 L(){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")),R()}catch(a){t("Failed: "+a.message,"error")}}async function D(){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 N(){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"),D()}catch(n){t("Failed: "+n.message,"error")}}async function T(){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 W(){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 P(){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 F(){try{const e=await o("/api/settings/passthrough-notify"),t=document.getElementById("passthroughNotifySelect");t&&(t.value=e.value||"both")}catch(e){}}async function G(){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 j(){try{const e=await o("/api/settings/loop-brain"),t=document.getElementById("loopBrainModel");t&&e.loopBrain&&(t.value=e.loopBrain)}catch{}}const U=[{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:"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 U){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??"",c=null===r,i=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 ${c&&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(i)}"\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{_ as A,A as B,R as C,T as D,j as E,F,$ as G,i as H,P as a,W as b,B as c,O as d,S as e,M as f,x as g,C as h,E as i,N as j,f as k,p as l,g as m,d as n,v as o,m as p,b as q,D as r,G as s,L as t,y as u,u as v,h as w,k as x,w as y,I as z};
@@ -1 +1 @@
1
- import{s as e}from"./core-utils-CAVnDoe1.js";let t=[];function n(){document.querySelectorAll(".view").forEach(e=>e.classList.remove("active")),document.getElementById("skillsView").classList.add("active"),document.querySelectorAll(".nav-item").forEach(e=>e.classList.remove("active"));const e=document.getElementById("navSkills");e&&e.classList.add("active"),s(),"function"==typeof loadPendingApprovals&&loadPendingApprovals()}function l(){document.querySelectorAll(".view").forEach(e=>e.classList.remove("active"));const e=document.getElementById("runSkillsView");e&&e.classList.add("active"),document.querySelectorAll(".nav-item").forEach(e=>e.classList.remove("active"));const t=document.getElementById("navRunSkills");t&&t.classList.add("active"),a()}async function a(){const e=document.getElementById("runSkillsGrid");if(e)try{const t=((await(await fetch("/api/health")).json()).skills||[]).filter(e=>!e.error&&e.url);if(!t.length)return void(e.innerHTML='<div style="color:var(--text-3);font-size:13px;">No API skills found. Add API skills (with a URL endpoint) in the Skills tab.</div>');e.innerHTML=t.map(e=>{const t=e.defaultParams&&Object.keys(e.defaultParams).length?JSON.stringify(e.defaultParams,null,2):"{}",n=(e.paramNotes||e.description||"").slice(0,120),l=(e.name||"").replace(/"/g,"&quot;");return'<div class="card" style="display:flex;flex-direction:column;"><div class="card-title" style="margin-bottom:6px;">'+(e.name||"unnamed")+'</div><div style="font-size:12px;color:var(--text-3);margin-bottom:10px;line-height:1.4;">'+(e.description||"")+"</div>"+(n?'<div style="font-size:11px;color:var(--text-2);margin-bottom:8px;">'+n+"</div>":"")+'<label style="font-size:11px;color:var(--text-2);margin-bottom:4px;">Params (JSON)</label><textarea data-skill="'+l+'" rows="4" style="font-family:monospace;font-size:12px;width:100%;margin-bottom:10px;resize:vertical;" class="runskills-params">'+t.replace(/</g,"&lt;")+'</textarea><div style="display:flex;align-items:center;gap:8px;margin-top:auto;"><button class="btn-green" style="font-size:12px;" data-action="runSkillFromUI" data-arg="'+l+'">Run</button><span class="runskills-result" data-skill="'+l+'" style="font-size:11px;color:var(--text-3);"></span></div></div>'}).join("")}catch(t){e.innerHTML='<div style="color:var(--red);font-size:12px;">Error loading health/skills: '+(t.message||"")+"</div>"}}async function o(e){const t=document.querySelector('.runskills-params[data-skill="'+(e||"").replace(/"/g,'\\"')+'"]'),n=document.querySelector('.runskills-result[data-skill="'+(e||"").replace(/"/g,'\\"')+'"]');if(!t)return;let l={};try{l=JSON.parse(t.value.trim()||"{}")}catch(a){return void(n&&(n.textContent="Invalid JSON"))}n&&(n.textContent="Running…");try{const t=await fetch("/api/skills/"+encodeURIComponent(e)+"/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({params:l})}),a=await t.json();if(n&&(a.ok?n.textContent="Done":n.textContent=a.error||"Error",n.style.color=a.ok?"var(--green)":"var(--red)"),!a.ok)return;if(void 0!==a.result&&n){const e="string"==typeof a.result?a.result:JSON.stringify(a.result).slice(0,120);n.textContent=e+(e.length>=120?"…":"")}}catch(a){n&&(n.textContent=a.message||"Request failed",n.style.color="var(--red)")}}async function s(){const e=document.getElementById("skillsList");try{const e=await(await fetch("/api/skills")).json();t=e.skills||[],i(t)}catch(n){e&&(e.innerHTML='<div style="color:var(--text-3);font-size:12px;">Error loading skills</div>')}}function i(e){const t=document.getElementById("skillsList");if(!t)return;if(!e.length)return void(t.innerHTML='<div style="color:var(--text-3);font-size:12px;padding:8px 0;">No skills match. Add one above or copy JSONs to ~/.crewswarm/skills/</div>');const n=e.filter(e=>"api"===e.type||!e.type&&e.url),l=e.filter(e=>"knowledge"===e.type||!e.type&&!e.url);function a(e){const t="knowledge"===e.type,n=e.requiresApproval?'<span style="margin-left:6px;font-size:10px;background:rgba(251,191,36,0.15);color:var(--yellow);padding:2px 6px;border-radius:4px;">⚠️ approval</span>':"",l=t?'<span style="margin-left:6px;font-size:10px;background:rgba(99,102,241,0.15);color:#818cf8;padding:2px 6px;border-radius:4px;">knowledge</span>':'<span style="margin-left:6px;font-size:10px;background:rgba(34,197,94,0.12);color:var(--green);padding:2px 6px;border-radius:4px;">API</span>',a=e.url?' · <code style="background:var(--bg-1);padding:1px 4px;border-radius:3px;">'+(e.method||"POST")+" "+(e.url||"").slice(0,55)+"</code>":"",o=e.aliases&&e.aliases.length?'<span style="margin-left:6px;font-size:10px;color:var(--text-3);">aliases: '+e.aliases.join(", ")+"</span>":"";return'<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:var(--bg-2);border-radius:var(--radius);border:1px solid var(--border);"><div style="min-width:0;"><div style="display:flex;align-items:center;flex-wrap:wrap;gap:2px;"><span style="font-weight:600;font-size:13px;">'+e.name+"</span>"+l+n+o+'</div><div style="font-size:11px;color:var(--text-3);margin-top:3px;">'+(e.description||"")+a+'</div></div><div style="display:flex;gap:6px;flex-shrink:0;margin-left:12px;">'+(t?"":'<button class="btn-ghost" style="font-size:11px;" data-action="editSkill" data-arg="'+e.name+'">Edit</button>')+'<button class="btn-ghost" style="font-size:11px;color:var(--red);" data-action="deleteSkill" data-arg="'+e.name+'">Delete</button></div></div>'}function o(e,t,n){return t.length?'<div style="margin-bottom:20px;"><div style="font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3);margin-bottom:8px;">'+e+' <span style="font-weight:400;opacity:.7;">('+t.length+')</span></div><div style="display:flex;flex-direction:column;gap:6px;">'+t.map(a).join("")+"</div></div>":""}t.innerHTML=o("Knowledge",l)+o("API Integrations",n)}function r(e){const n=e.toLowerCase();i(n?t.filter(e=>(e.name||"").toLowerCase().includes(n)||(e.description||"").toLowerCase().includes(n)||(e.url||"").toLowerCase().includes(n)||(e.aliases||[]).some(e=>e.toLowerCase().includes(n))):t)}function d(e){var n,l,a,o;const s=t.find(t=>t.name===e);if(!s)return;document.getElementById("skEditName").value=e,document.getElementById("addSkillFormTitle").textContent="Edit Skill",document.getElementById("saveSkillBtn").textContent="Update Skill",document.getElementById("skName").value=s.name||"",document.getElementById("skDesc").value=s.description||"",document.getElementById("skUrl").value=s.url||"";const i=document.getElementById("skMethod");for(let t=0;t<i.options.length;t++)if(i.options[t].value===s.method){i.selectedIndex=t;break}const r=(null==(n=s.auth)?void 0:n.type)||"";document.getElementById("skAuthType").value=r,document.getElementById("skAuthKey").value=(null==(l=s.auth)?void 0:l.keyFrom)||(null==(a=s.auth)?void 0:a.token)||"",document.getElementById("skAuthHeader").value=(null==(o=s.auth)?void 0:o.header)||"",document.getElementById("skRequiresApproval").checked=!!s.requiresApproval,document.getElementById("skDefaults").value=s.defaultParams&&Object.keys(s.defaultParams).length?JSON.stringify(s.defaultParams,null,2):"",y();const d=document.getElementById("addSkillForm");d.style.display="block",d.scrollIntoView({behavior:"smooth",block:"start"})}function c(){p(),document.getElementById("importSkillForm").style.display="none";const e=document.getElementById("addSkillForm");e.style.display="none"===e.style.display?"block":"none"}function m(){p();const e=document.getElementById("importSkillForm");e.style.display="none"===e.style.display?"block":"none","none"!==e.style.display&&setTimeout(()=>document.getElementById("importSkillUrl").focus(),50)}async function u(){const e=document.getElementById("importSkillUrl"),t=document.getElementById("importSkillStatus"),n=document.getElementById("importSkillBtn"),l=e.value.trim();if(!l)return t.style.color="var(--red)",void(t.textContent="Paste a URL first.");n.disabled=!0,n.textContent="Importing…",t.style.color="var(--text-3)",t.textContent="Fetching & scanning…";try{const n=await fetch("/api/skills/import",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({url:l})}),a=await n.json();if(!n.ok||a.error)throw new Error(a.error||"Import failed");if(a.warnings&&a.warnings.length){t.style.color="var(--yellow)";const e={cmd_skill:"⚠ executes shell commands",ssrf_risk:"⚠ targets private network",insecure_url:"⚠ non-HTTPS endpoint",no_approval:"⚠ no approval gate on write"},n=a.warnings.map(t=>e[t.split(":")[0]]||t);t.innerHTML='✓ Imported <strong>"'+a.name+'"</strong> — '+n.join(" · ")}else t.style.color="var(--green)",t.textContent='✓ Imported "'+a.name+'" — no security warnings';e.value="",await s(),a.warnings&&a.warnings.length||setTimeout(()=>{document.getElementById("importSkillForm").style.display="none",t.textContent=""},3e3)}catch(a){t.style.color="var(--red)",t.textContent="Error: "+a.message}finally{n.disabled=!1,n.textContent="Import"}}function p(){document.getElementById("skEditName").value="",document.getElementById("addSkillFormTitle").textContent="New Skill",document.getElementById("saveSkillBtn").textContent="Save Skill",document.getElementById("addSkillForm").style.display="none",["skName","skDesc","skUrl","skAuthKey","skAuthHeader","skDefaults"].forEach(e=>{const t=document.getElementById(e);t&&(t.value="")}),document.getElementById("skAuthType").value="",document.getElementById("skRequiresApproval").checked=!1,y()}function y(){const e=document.getElementById("skAuthType").value;document.getElementById("skAuthHeaderWrap").style.display="header"===e?"block":"none"}async function g(){const t=document.getElementById("skName").value.trim(),n=document.getElementById("skUrl").value.trim();if(!t||!n)return void alert("Skill name and URL are required");let l={};try{const e=document.getElementById("skDefaults").value.trim();e&&(l=JSON.parse(e))}catch{return void alert("Default Params must be valid JSON")}const a=document.getElementById("skAuthType").value,o=document.getElementById("skAuthKey").value.trim();let i={};a&&o&&(i={type:a},o.startsWith("providers.")||o.startsWith("env.")?i.keyFrom=o:i.token=o,"header"===a&&(i.header=document.getElementById("skAuthHeader").value.trim()||"X-API-Key"));const r=document.getElementById("skEditName").value.trim(),d={name:t,url:n,method:document.getElementById("skMethod").value,description:document.getElementById("skDesc").value.trim(),auth:Object.keys(i).length?i:void 0,defaultParams:l,requiresApproval:document.getElementById("skRequiresApproval").checked};try{r&&r!==t&&await fetch("/api/skills/"+r,{method:"DELETE"});const n=await fetch("/api/skills",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(d)});if(!n.ok)throw new Error(await n.text());p(),s(),e(r?"Skill updated":"Skill saved")}catch(c){e("Failed: "+c.message,"error")}}async function v(t){if(confirm('Delete skill "'+t+'"?'))try{const n=await fetch("/api/skills/"+t,{method:"DELETE"});if(!n.ok)throw new Error(await n.text());s(),e("Deleted")}catch(n){e("Delete failed: "+n.message,"error")}}export{n as a,g as b,p as c,c as d,d as e,r as f,v as g,u as i,a as l,o as r,l as s,m as t,y as u};
1
+ import{s as e}from"./core-utils-CmOkXgzi.js";let t=[];function n(){document.querySelectorAll(".view").forEach(e=>e.classList.remove("active")),document.getElementById("skillsView").classList.add("active"),document.querySelectorAll(".nav-item").forEach(e=>e.classList.remove("active"));const e=document.getElementById("navSkills");e&&e.classList.add("active"),s(),"function"==typeof loadPendingApprovals&&loadPendingApprovals()}function l(){document.querySelectorAll(".view").forEach(e=>e.classList.remove("active"));const e=document.getElementById("runSkillsView");e&&e.classList.add("active"),document.querySelectorAll(".nav-item").forEach(e=>e.classList.remove("active"));const t=document.getElementById("navRunSkills");t&&t.classList.add("active"),a()}async function a(){const e=document.getElementById("runSkillsGrid");if(e)try{const t=((await(await fetch("/api/health")).json()).skills||[]).filter(e=>!e.error&&e.url);if(!t.length)return void(e.innerHTML='<div style="color:var(--text-3);font-size:13px;">No API skills found. Add API skills (with a URL endpoint) in the Skills tab.</div>');e.innerHTML=t.map(e=>{const t=e.defaultParams&&Object.keys(e.defaultParams).length?JSON.stringify(e.defaultParams,null,2):"{}",n=(e.paramNotes||e.description||"").slice(0,120),l=(e.name||"").replace(/"/g,"&quot;");return'<div class="card" style="display:flex;flex-direction:column;"><div class="card-title" style="margin-bottom:6px;">'+(e.name||"unnamed")+'</div><div style="font-size:12px;color:var(--text-3);margin-bottom:10px;line-height:1.4;">'+(e.description||"")+"</div>"+(n?'<div style="font-size:11px;color:var(--text-2);margin-bottom:8px;">'+n+"</div>":"")+'<label style="font-size:11px;color:var(--text-2);margin-bottom:4px;">Params (JSON)</label><textarea data-skill="'+l+'" rows="4" style="font-family:monospace;font-size:12px;width:100%;margin-bottom:10px;resize:vertical;" class="runskills-params">'+t.replace(/</g,"&lt;")+'</textarea><div style="display:flex;align-items:center;gap:8px;margin-top:auto;"><button class="btn-green" style="font-size:12px;" data-action="runSkillFromUI" data-arg="'+l+'">Run</button><span class="runskills-result" data-skill="'+l+'" style="font-size:11px;color:var(--text-3);"></span></div></div>'}).join("")}catch(t){e.innerHTML='<div style="color:var(--red);font-size:12px;">Error loading health/skills: '+(t.message||"")+"</div>"}}async function o(e){const t=document.querySelector('.runskills-params[data-skill="'+(e||"").replace(/"/g,'\\"')+'"]'),n=document.querySelector('.runskills-result[data-skill="'+(e||"").replace(/"/g,'\\"')+'"]');if(!t)return;let l={};try{l=JSON.parse(t.value.trim()||"{}")}catch(a){return void(n&&(n.textContent="Invalid JSON"))}n&&(n.textContent="Running…");try{const t=await fetch("/api/skills/"+encodeURIComponent(e)+"/run",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({params:l})}),a=await t.json();if(n&&(a.ok?n.textContent="Done":n.textContent=a.error||"Error",n.style.color=a.ok?"var(--green)":"var(--red)"),!a.ok)return;if(void 0!==a.result&&n){const e="string"==typeof a.result?a.result:JSON.stringify(a.result).slice(0,120);n.textContent=e+(e.length>=120?"…":"")}}catch(a){n&&(n.textContent=a.message||"Request failed",n.style.color="var(--red)")}}async function s(){const e=document.getElementById("skillsList");try{const e=await(await fetch("/api/skills")).json();t=e.skills||[],i(t)}catch(n){e&&(e.innerHTML='<div style="color:var(--text-3);font-size:12px;">Error loading skills</div>')}}function i(e){const t=document.getElementById("skillsList");if(!t)return;if(!e.length)return void(t.innerHTML='<div style="color:var(--text-3);font-size:12px;padding:8px 0;">No skills match. Add one above or copy JSONs to ~/.crewswarm/skills/</div>');const n=e.filter(e=>"api"===e.type||!e.type&&e.url),l=e.filter(e=>"knowledge"===e.type||!e.type&&!e.url);function a(e){const t="knowledge"===e.type,n=e.requiresApproval?'<span style="margin-left:6px;font-size:10px;background:rgba(251,191,36,0.15);color:var(--yellow);padding:2px 6px;border-radius:4px;">⚠️ approval</span>':"",l=t?'<span style="margin-left:6px;font-size:10px;background:rgba(99,102,241,0.15);color:#818cf8;padding:2px 6px;border-radius:4px;">knowledge</span>':'<span style="margin-left:6px;font-size:10px;background:rgba(34,197,94,0.12);color:var(--green);padding:2px 6px;border-radius:4px;">API</span>',a=e.url?' · <code style="background:var(--bg-1);padding:1px 4px;border-radius:3px;">'+(e.method||"POST")+" "+(e.url||"").slice(0,55)+"</code>":"",o=e.aliases&&e.aliases.length?'<span style="margin-left:6px;font-size:10px;color:var(--text-3);">aliases: '+e.aliases.join(", ")+"</span>":"";return'<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:var(--bg-2);border-radius:var(--radius);border:1px solid var(--border);"><div style="min-width:0;"><div style="display:flex;align-items:center;flex-wrap:wrap;gap:2px;"><span style="font-weight:600;font-size:13px;">'+e.name+"</span>"+l+n+o+'</div><div style="font-size:11px;color:var(--text-3);margin-top:3px;">'+(e.description||"")+a+'</div></div><div style="display:flex;gap:6px;flex-shrink:0;margin-left:12px;">'+(t?"":'<button class="btn-ghost" style="font-size:11px;" data-action="editSkill" data-arg="'+e.name+'">Edit</button>')+'<button class="btn-ghost" style="font-size:11px;color:var(--red);" data-action="deleteSkill" data-arg="'+e.name+'">Delete</button></div></div>'}function o(e,t,n){return t.length?'<div style="margin-bottom:20px;"><div style="font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--text-3);margin-bottom:8px;">'+e+' <span style="font-weight:400;opacity:.7;">('+t.length+')</span></div><div style="display:flex;flex-direction:column;gap:6px;">'+t.map(a).join("")+"</div></div>":""}t.innerHTML=o("Knowledge",l)+o("API Integrations",n)}function r(e){const n=e.toLowerCase();i(n?t.filter(e=>(e.name||"").toLowerCase().includes(n)||(e.description||"").toLowerCase().includes(n)||(e.url||"").toLowerCase().includes(n)||(e.aliases||[]).some(e=>e.toLowerCase().includes(n))):t)}function d(e){var n,l,a,o;const s=t.find(t=>t.name===e);if(!s)return;document.getElementById("skEditName").value=e,document.getElementById("addSkillFormTitle").textContent="Edit Skill",document.getElementById("saveSkillBtn").textContent="Update Skill",document.getElementById("skName").value=s.name||"",document.getElementById("skDesc").value=s.description||"",document.getElementById("skUrl").value=s.url||"";const i=document.getElementById("skMethod");for(let t=0;t<i.options.length;t++)if(i.options[t].value===s.method){i.selectedIndex=t;break}const r=(null==(n=s.auth)?void 0:n.type)||"";document.getElementById("skAuthType").value=r,document.getElementById("skAuthKey").value=(null==(l=s.auth)?void 0:l.keyFrom)||(null==(a=s.auth)?void 0:a.token)||"",document.getElementById("skAuthHeader").value=(null==(o=s.auth)?void 0:o.header)||"",document.getElementById("skRequiresApproval").checked=!!s.requiresApproval,document.getElementById("skDefaults").value=s.defaultParams&&Object.keys(s.defaultParams).length?JSON.stringify(s.defaultParams,null,2):"",y();const d=document.getElementById("addSkillForm");d.style.display="block",d.scrollIntoView({behavior:"smooth",block:"start"})}function c(){p(),document.getElementById("importSkillForm").style.display="none";const e=document.getElementById("addSkillForm");e.style.display="none"===e.style.display?"block":"none"}function m(){p();const e=document.getElementById("importSkillForm");e.style.display="none"===e.style.display?"block":"none","none"!==e.style.display&&setTimeout(()=>document.getElementById("importSkillUrl").focus(),50)}async function u(){const e=document.getElementById("importSkillUrl"),t=document.getElementById("importSkillStatus"),n=document.getElementById("importSkillBtn"),l=e.value.trim();if(!l)return t.style.color="var(--red)",void(t.textContent="Paste a URL first.");n.disabled=!0,n.textContent="Importing…",t.style.color="var(--text-3)",t.textContent="Fetching & scanning…";try{const n=await fetch("/api/skills/import",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({url:l})}),a=await n.json();if(!n.ok||a.error)throw new Error(a.error||"Import failed");if(a.warnings&&a.warnings.length){t.style.color="var(--yellow)";const e={cmd_skill:"⚠ executes shell commands",ssrf_risk:"⚠ targets private network",insecure_url:"⚠ non-HTTPS endpoint",no_approval:"⚠ no approval gate on write"},n=a.warnings.map(t=>e[t.split(":")[0]]||t);t.innerHTML='✓ Imported <strong>"'+a.name+'"</strong> — '+n.join(" · ")}else t.style.color="var(--green)",t.textContent='✓ Imported "'+a.name+'" — no security warnings';e.value="",await s(),a.warnings&&a.warnings.length||setTimeout(()=>{document.getElementById("importSkillForm").style.display="none",t.textContent=""},3e3)}catch(a){t.style.color="var(--red)",t.textContent="Error: "+a.message}finally{n.disabled=!1,n.textContent="Import"}}function p(){document.getElementById("skEditName").value="",document.getElementById("addSkillFormTitle").textContent="New Skill",document.getElementById("saveSkillBtn").textContent="Save Skill",document.getElementById("addSkillForm").style.display="none",["skName","skDesc","skUrl","skAuthKey","skAuthHeader","skDefaults"].forEach(e=>{const t=document.getElementById(e);t&&(t.value="")}),document.getElementById("skAuthType").value="",document.getElementById("skRequiresApproval").checked=!1,y()}function y(){const e=document.getElementById("skAuthType").value;document.getElementById("skAuthHeaderWrap").style.display="header"===e?"block":"none"}async function g(){const t=document.getElementById("skName").value.trim(),n=document.getElementById("skUrl").value.trim();if(!t||!n)return void alert("Skill name and URL are required");let l={};try{const e=document.getElementById("skDefaults").value.trim();e&&(l=JSON.parse(e))}catch{return void alert("Default Params must be valid JSON")}const a=document.getElementById("skAuthType").value,o=document.getElementById("skAuthKey").value.trim();let i={};a&&o&&(i={type:a},o.startsWith("providers.")||o.startsWith("env.")?i.keyFrom=o:i.token=o,"header"===a&&(i.header=document.getElementById("skAuthHeader").value.trim()||"X-API-Key"));const r=document.getElementById("skEditName").value.trim(),d={name:t,url:n,method:document.getElementById("skMethod").value,description:document.getElementById("skDesc").value.trim(),auth:Object.keys(i).length?i:void 0,defaultParams:l,requiresApproval:document.getElementById("skRequiresApproval").checked};try{r&&r!==t&&await fetch("/api/skills/"+r,{method:"DELETE"});const n=await fetch("/api/skills",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(d)});if(!n.ok)throw new Error(await n.text());p(),s(),e(r?"Skill updated":"Skill saved")}catch(c){e("Failed: "+c.message,"error")}}async function v(t){if(confirm('Delete skill "'+t+'"?'))try{const n=await fetch("/api/skills/"+t,{method:"DELETE"});if(!n.ok)throw new Error(await n.text());s(),e("Deleted")}catch(n){e("Delete failed: "+n.message,"error")}}export{n as a,g as b,p as c,c as d,d as e,r as f,v as g,u as i,a as l,o as r,l as s,m as t,y as u};
@@ -1 +1 @@
1
- import{s as t,g as e,d as n}from"./core-utils-CAVnDoe1.js";import{e as o,l as a}from"./tab-usage-tab-B2UWXenJ.js";var i=null,l=null;function s(){var t=i,e=l,n=document.getElementById("gtAgentCost"),o=document.getElementById("gtOcCost"),a=document.getElementById("gtTotal");n&&(null!==t&&(n.textContent="$"+t.toFixed(4)),null!==e&&(o.textContent="$"+e.toFixed(4)),null!==t&&null!==e&&(a.textContent="$"+(t+e).toFixed(4)))}function r(t){l=t,s()}async function d(){var t,e=parseInt((null==(t=document.getElementById("grandTotalDays"))?void 0:t.value)||"14"),n=document.getElementById("ocStatsDays"),o=document.getElementById("spendingDays");n&&(n.value=String(e)),o&&(o.value=String(1===e?1:e)),i=null,l=null,document.getElementById("gtAgentCost").textContent="—",document.getElementById("gtOcCost").textContent="—",document.getElementById("gtTotal").textContent="—",c(),a(r)}async function c(){var t,a,l,r,d;const c=document.getElementById("spendingWidget"),p=parseInt((null==(t=document.getElementById("spendingDays"))?void 0:t.value)||"1");try{if(p<=1){const t=await(await fetch("/api/spending")).json(),{spending:e,caps:n}=t,o=(null==(a=e.global)?void 0:a.tokens)||0,p=(null==(l=e.global)?void 0:l.costUSD)||0,g=null==(r=n.global)?void 0:r.dailyTokenLimit,m=null==(d=n.global)?void 0:d.dailyCostLimitUSD;let y='<div style="margin-bottom:10px;"><div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:4px;text-transform:uppercase;letter-spacing:.06em;">Global &middot; '+(e.date||"today")+'</div><div style="display:flex;gap:20px;"><span>'+o.toLocaleString()+" tokens"+(g?" / "+Number(g).toLocaleString():"")+'</span><span style="color:var(--yellow);font-weight:600;">$'+p.toFixed(4)+"</span>"+(m?"<span> / $"+m+"</span>":"")+"</div>";if(g){const t=Math.min(100,o/g*100);y+='<div style="margin-top:4px;height:4px;background:var(--border);border-radius:2px;"><div style="width:'+t+"%;height:100%;background:"+(t>80?"var(--red)":t>50?"var(--yellow)":"var(--green)")+';border-radius:2px;transition:width .3s;"></div></div>'}y+="</div>";const u=Object.entries(e.agents||{});u.length?(y+='<div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:6px;text-transform:uppercase;letter-spacing:.06em;">Per Agent</div>',y+=u.map(function(t){var e=t[0],o=t[1];const a=n.agents&&n.agents[e],i=o.tokens||0,l=(o.costUSD||0).toFixed(4),s=a&&a.dailyTokenLimit,r=s?Math.min(100,i/s*100):null;let d='<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px;"><span style="min-width:140px;font-size:12px;">'+e+'</span><span style="font-size:12px;">'+i.toLocaleString()+" tok"+(s?" / "+Number(s).toLocaleString():"")+' &middot; <span style="color:var(--yellow);">$'+l+"</span></span>";if(null!==r){d+='<div style="flex:1;height:3px;background:var(--border);border-radius:2px;"><div style="width:'+r+"%;height:100%;background:"+(r>80?"var(--red)":"var(--accent)")+';border-radius:2px;"></div></div>'}return d+"</div>"}).join("")):y+='<div style="color:var(--text-3);">No per-agent data yet for today.</div>',g&&(document.getElementById("gcapTokens").value=g),m&&(document.getElementById("gcapCost").value=m),i=p,s(),c.innerHTML=y}else{const t=(await e("/api/token-usage").catch(function(){return{}})).byDay||{},n=new Date(Date.now()-864e5*p).toISOString().slice(0,10),a=Object.keys(t).filter(function(t){return t>=n}).sort().reverse();if(!a.length)return c.innerHTML='<div style="color:var(--text-3);">No data for this period.</div>',i=0,void s();const l={};var g=0;a.forEach(function(e){const n=t[e].byModel||{};Object.entries(n).forEach(function(t){var e=t[0],n=t[1];l[e]||(l[e]={prompt:0,completion:0}),l[e].prompt+=n.prompt||0,l[e].completion+=n.completion||0,(n.prompt||0)+(n.completion||0)})}),g=o(l);let r='<div style="margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;"><span style="font-size:12px;color:var(--text-3);">Last '+p+" days &middot; "+a.length+' days of data</span><span style="font-size:16px;font-weight:700;color:var(--yellow);">$'+g.toFixed(4)+"</span></div>";const d=Math.max(...a.map(function(e){return o(t[e].byModel||{})}),1e-4),m=(new Date).toISOString().slice(0,10);r+='<div style="display:flex;flex-direction:column;gap:3px;margin-bottom:12px;">',a.forEach(function(e){const n=o(t[e].byModel||{}),a=Math.max(n/d*100,n>0?2:0),i=e===m,l=((t[e].prompt||0)+(t[e].completion||0))/1e3;r+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:64px;color:var(--text-3);flex-shrink:0;">'+(i?"today":e.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:12px;overflow:hidden;"><div style="width:'+a.toFixed(1)+"%;height:100%;background:"+(i?"var(--accent)":"var(--green)")+';border-radius:3px;opacity:.8;"></div></div><span style="width:58px;text-align:right;color:var(--yellow);font-weight:600;">$'+n.toFixed(4)+'</span><span style="width:40px;text-align:right;color:var(--text-3);">'+l.toFixed(0)+"k</span></div>"}),r+="</div>";const y=Object.entries(l).sort(function(t,e){return o({b:e[1]})-o({a:t[1]})});y.length&&(r+='<div style="font-size:11px;color:var(--text-3);margin-bottom:4px;">By model</div>',y.slice(0,8).forEach(function(t){var e=t[0],n=t[1];const a=o({x:n}),i=((n.prompt||0)+(n.completion||0))/1e3;r+='<div style="display:flex;justify-content:space-between;font-size:11px;padding:2px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+i.toFixed(1)+'k tok &middot; <span style="color:var(--yellow);">$'+a.toFixed(4)+"</span></span></div>"})),i=g,s(),c.innerHTML=r}}catch(m){n(c,"Error: "+m.message)}}async function p(){if(confirm("Reset today's spending counters?"))try{await fetch("/api/spending/reset",{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),c(),t("Spending reset")}catch(e){t("Reset failed",!0)}}async function g(){const e=parseInt(document.getElementById("gcapTokens").value)||null,n=parseFloat(document.getElementById("gcapCost").value)||null;t('Add to ~/.crewswarm/crewswarm.json: "globalSpendingCaps": {"dailyTokenLimit":'+(e||"null")+',"dailyCostLimitUSD":'+(n||"null")+"}","warning")}export{d as a,r as b,c as l,p as r,g as s};
1
+ import{s as t,g as e,d as n}from"./core-utils-CmOkXgzi.js";import{e as o,l as a}from"./tab-usage-tab-BIOOnB-Y.js";var i=null,l=null;function s(){var t=i,e=l,n=document.getElementById("gtAgentCost"),o=document.getElementById("gtOcCost"),a=document.getElementById("gtTotal");n&&(null!==t&&(n.textContent="$"+t.toFixed(4)),null!==e&&(o.textContent="$"+e.toFixed(4)),null!==t&&null!==e&&(a.textContent="$"+(t+e).toFixed(4)))}function r(t){l=t,s()}async function d(){var t,e=parseInt((null==(t=document.getElementById("grandTotalDays"))?void 0:t.value)||"14"),n=document.getElementById("ocStatsDays"),o=document.getElementById("spendingDays");n&&(n.value=String(e)),o&&(o.value=String(1===e?1:e)),i=null,l=null,document.getElementById("gtAgentCost").textContent="—",document.getElementById("gtOcCost").textContent="—",document.getElementById("gtTotal").textContent="—",c(),a(r)}async function c(){var t,a,l,r,d;const c=document.getElementById("spendingWidget"),p=parseInt((null==(t=document.getElementById("spendingDays"))?void 0:t.value)||"1");try{if(p<=1){const t=await(await fetch("/api/spending")).json(),{spending:e,caps:n}=t,o=(null==(a=e.global)?void 0:a.tokens)||0,p=(null==(l=e.global)?void 0:l.costUSD)||0,g=null==(r=n.global)?void 0:r.dailyTokenLimit,m=null==(d=n.global)?void 0:d.dailyCostLimitUSD;let y='<div style="margin-bottom:10px;"><div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:4px;text-transform:uppercase;letter-spacing:.06em;">Global &middot; '+(e.date||"today")+'</div><div style="display:flex;gap:20px;"><span>'+o.toLocaleString()+" tokens"+(g?" / "+Number(g).toLocaleString():"")+'</span><span style="color:var(--yellow);font-weight:600;">$'+p.toFixed(4)+"</span>"+(m?"<span> / $"+m+"</span>":"")+"</div>";if(g){const t=Math.min(100,o/g*100);y+='<div style="margin-top:4px;height:4px;background:var(--border);border-radius:2px;"><div style="width:'+t+"%;height:100%;background:"+(t>80?"var(--red)":t>50?"var(--yellow)":"var(--green)")+';border-radius:2px;transition:width .3s;"></div></div>'}y+="</div>";const u=Object.entries(e.agents||{});u.length?(y+='<div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:6px;text-transform:uppercase;letter-spacing:.06em;">Per Agent</div>',y+=u.map(function(t){var e=t[0],o=t[1];const a=n.agents&&n.agents[e],i=o.tokens||0,l=(o.costUSD||0).toFixed(4),s=a&&a.dailyTokenLimit,r=s?Math.min(100,i/s*100):null;let d='<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px;"><span style="min-width:140px;font-size:12px;">'+e+'</span><span style="font-size:12px;">'+i.toLocaleString()+" tok"+(s?" / "+Number(s).toLocaleString():"")+' &middot; <span style="color:var(--yellow);">$'+l+"</span></span>";if(null!==r){d+='<div style="flex:1;height:3px;background:var(--border);border-radius:2px;"><div style="width:'+r+"%;height:100%;background:"+(r>80?"var(--red)":"var(--accent)")+';border-radius:2px;"></div></div>'}return d+"</div>"}).join("")):y+='<div style="color:var(--text-3);">No per-agent data yet for today.</div>',g&&(document.getElementById("gcapTokens").value=g),m&&(document.getElementById("gcapCost").value=m),i=p,s(),c.innerHTML=y}else{const t=(await e("/api/token-usage").catch(function(){return{}})).byDay||{},n=new Date(Date.now()-864e5*p).toISOString().slice(0,10),a=Object.keys(t).filter(function(t){return t>=n}).sort().reverse();if(!a.length)return c.innerHTML='<div style="color:var(--text-3);">No data for this period.</div>',i=0,void s();const l={};var g=0;a.forEach(function(e){const n=t[e].byModel||{};Object.entries(n).forEach(function(t){var e=t[0],n=t[1];l[e]||(l[e]={prompt:0,completion:0}),l[e].prompt+=n.prompt||0,l[e].completion+=n.completion||0,(n.prompt||0)+(n.completion||0)})}),g=o(l);let r='<div style="margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;"><span style="font-size:12px;color:var(--text-3);">Last '+p+" days &middot; "+a.length+' days of data</span><span style="font-size:16px;font-weight:700;color:var(--yellow);">$'+g.toFixed(4)+"</span></div>";const d=Math.max(...a.map(function(e){return o(t[e].byModel||{})}),1e-4),m=(new Date).toISOString().slice(0,10);r+='<div style="display:flex;flex-direction:column;gap:3px;margin-bottom:12px;">',a.forEach(function(e){const n=o(t[e].byModel||{}),a=Math.max(n/d*100,n>0?2:0),i=e===m,l=((t[e].prompt||0)+(t[e].completion||0))/1e3;r+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:64px;color:var(--text-3);flex-shrink:0;">'+(i?"today":e.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:12px;overflow:hidden;"><div style="width:'+a.toFixed(1)+"%;height:100%;background:"+(i?"var(--accent)":"var(--green)")+';border-radius:3px;opacity:.8;"></div></div><span style="width:58px;text-align:right;color:var(--yellow);font-weight:600;">$'+n.toFixed(4)+'</span><span style="width:40px;text-align:right;color:var(--text-3);">'+l.toFixed(0)+"k</span></div>"}),r+="</div>";const y=Object.entries(l).sort(function(t,e){return o({b:e[1]})-o({a:t[1]})});y.length&&(r+='<div style="font-size:11px;color:var(--text-3);margin-bottom:4px;">By model</div>',y.slice(0,8).forEach(function(t){var e=t[0],n=t[1];const a=o({x:n}),i=((n.prompt||0)+(n.completion||0))/1e3;r+='<div style="display:flex;justify-content:space-between;font-size:11px;padding:2px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+i.toFixed(1)+'k tok &middot; <span style="color:var(--yellow);">$'+a.toFixed(4)+"</span></span></div>"})),i=g,s(),c.innerHTML=r}}catch(m){n(c,"Error: "+m.message)}}async function p(){if(confirm("Reset today's spending counters?"))try{await fetch("/api/spending/reset",{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),c(),t("Spending reset")}catch(e){t("Reset failed",!0)}}async function g(){const e=parseInt(document.getElementById("gcapTokens").value)||null,n=parseFloat(document.getElementById("gcapCost").value)||null;t('Add to ~/.crewswarm/crewswarm.json: "globalSpendingCaps": {"dailyTokenLimit":'+(e||"null")+',"dailyCostLimitUSD":'+(n||"null")+"}","warning")}export{d as a,r as b,c as l,p as r,g as s};
@@ -1 +1 @@
1
- import{a as e,b as t,s as n,g as a,e as o,c as r,d as i,p as s}from"./core-utils-CAVnDoe1.js";let l=()=>{},d=()=>{},c=[],m=!1,u=[],p=0,g=null,w=null,y=null;function h(e){var t;const n=document.getElementById("swarmChatMessages");n&&(n.firstElementChild&&(null==(t=n.firstElementChild.textContent)?void 0:t.includes("No shared channel messages yet."))&&(n.innerHTML=""),c.push(e),n.insertAdjacentHTML("beforeend",$(e)),n.scrollTop=n.scrollHeight)}function f(){var e;null==(e=document.getElementById("swarm-typing-wrapper"))||e.remove()}const v={dashboard:{emoji:"🧠",label:"crew-lead"},agent:{emoji:"🤖",label:"agent"},"sub-agent":{emoji:"👷",label:"sub-agent"},cli:{emoji:"⚡",label:"cli"},discord:{emoji:"🎮",label:"discord"},system:{emoji:"🛰",label:"system"}};function x(e={}){l=e.hideAllViews||l,d=e.setNavActive||d,b()}function b(){if(m)return;const r=document.getElementById("swarmChatProject"),i=document.getElementById("swarmChatRefresh"),l=document.getElementById("swarmAutonomyBtn"),d=document.getElementById("swarmChatForm"),g=document.getElementById("swarmChatInput"),w=document.getElementById("swarmChatSend"),y=document.getElementById("swarmChatMessages");r&&i&&d&&g&&w&&y&&(m=!0,r.addEventListener("change",async()=>{e.swarmChatProjectId=r.value||"general",t(),await j()}),i.addEventListener("click",()=>{C().then(j).catch(e=>{n(`Failed to refresh Swarm: ${e.message}`,"error")})}),null==l||l.addEventListener("click",()=>{(async function(){const e=await a("/api/settings/autonomous-mentions"),t=await s("/api/settings/autonomous-mentions",{enabled:!e.enabled});n("Swarm autonomy "+(t.enabled?"ENABLED 🕸":"DISABLED")),await E()})().catch(e=>{n(`Failed to toggle autonomy: ${e.message}`,"error")})}),d.addEventListener("submit",e=>{e.preventDefault(),e.stopPropagation(),T()}),w.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),T()}),g.addEventListener("keydown",e=>{const t=document.getElementById("swarmMentionMenu");if(t&&"block"===t.style.display&&("Enter"===e.key||"Tab"===e.key)){const n=t.firstElementChild;if(n)return e.preventDefault(),void n.click()}"Enter"!==e.key||e.shiftKey||(e.preventDefault(),T())}),g.addEventListener("input",()=>{(async function(){const e=document.getElementById("swarmChatInput"),t=document.getElementById("swarmMentionMenu"),n=document.getElementById("swarmMentionHint");if(!e||!t||!n)return;const o=e.value||"",r=e.selectionStart||0,i=o.slice(0,r).match(/(^|\s)@([a-zA-Z0-9_-]*)$/);if(!i)return t.style.display="none",void(n.style.display="none");const s=(i[2]||"").toLowerCase(),l=(await async function(e=!1){const t=Date.now();if(!e&&u.length&&t-p<3e4)return u;const n=((await a("/api/chat-participants")).participants||[]).filter(e=>e.id).sort((e,t)=>e.id.localeCompare(t.id)).map(e=>({id:e.id,name:"cli"===e.kind?`${e.runtime} runtime`:e.kind,role:e.kind,kind:e.kind}));return u=n,p=t,n}()).filter(e=>e.id.toLowerCase().includes(s)).slice(0,8);if(!l.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.innerHTML="",l.forEach(a=>{const s=document.createElement("div");s.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",s.onmouseenter=()=>{s.style.background="var(--bg-hover)"},s.onmouseleave=()=>{s.style.background=""},s.innerHTML=`<span style="color:var(--accent);font-weight:600;">@${a.id}</span> <span style="color:var(--text-3);">${a.name||a.role||"agent"}</span>`,s.onclick=()=>{const s=r-i[0].length+i[1].length,l=`@${a.id} `;e.value=o.slice(0,s)+l+o.slice(r);const d=s+l.length;e.selectionStart=e.selectionEnd=d,e.focus(),t.style.display="none",n.style.display="block",n.textContent="crew-lead"===a.id?"Mention target: @crew-lead. Use this for notes or routing guidance.":`Mention target: @${a.id}. Use a specific work order if you want execution.`},t.appendChild(s)}),n.style.display="block",n.textContent=s?`Matching participants for @${s}`:"Type a participant, e.g. @crew-lead for notes or @crew-coder with a specific work order."})().catch(()=>{})}),y.addEventListener("click",e=>{const t=e.target.closest("[data-swarm-message-id]");t&&function(e){var t;const n=document.getElementById("swarmTracePanel");if(!n)return;const a=c.find(t=>t.id===e);if(!a)return;const r=a.metadata||{},i=[["messageId",a.id],["source",a.source],["agent",a.agent||null],["taskId",r.taskId||null],["threadId",a.threadId||r.originThreadId||null],["parentId",a.parentId||r.originMessageId||null],["originProjectId",r.originProjectId||null],["originChannel",r.originChannel||r.channel||null],["triggeredBy",r.triggeredBy||null],["mentionedBy",r.mentionedBy||null]].filter(([,e])=>e);n.style.display="block",n.innerHTML=`\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;">\n <strong style="color:var(--text-1);">Trace</strong>\n <button type="button" id="swarmTraceClose" class="btn-ghost" style="font-size:11px;padding:4px 8px;">Close</button>\n </div>\n <div style="display:grid;grid-template-columns:140px 1fr;gap:6px 10px;">\n ${i.map(([e,t])=>`<div style="color:var(--text-3);">${o(e)}</div><div style="font-family:monospace;word-break:break-all;">${o(String(t))}</div>`).join("")}\n </div>\n `,null==(t=n.querySelector("#swarmTraceClose"))||t.addEventListener("click",B,{once:!0})}(t.dataset.swarmMessageId)}))}async function I(){var n,a;b(),l(),null==(n=document.getElementById("swarmChatView"))||n.classList.add("active"),d("navSwarmChat"),e.activeTab="swarm-chat",e.swarmChatProjectId||(e.swarmChatProjectId=e.chatActiveProjectId||"general"),t(),await C(),await E(),await j(),null==(a=document.getElementById("swarmChatInput"))||a.focus()}async function E(){const e=document.getElementById("swarmAutonomyBtn"),t=document.getElementById("swarmAutonomyStatus"),n=document.getElementById("swarmChatInput"),o=!1!==(await a("/api/settings/autonomous-mentions")).enabled;e&&(e.textContent=o?"🕸 Auto ON":"⚫ Auto OFF",e.style.background=o?"rgba(52,211,153,0.15)":"",e.style.borderColor=o?"rgba(52,211,153,0.3)":"",e.style.color=o?"var(--green)":""),t&&(t.textContent=o?"Autonomous routing is live in this room. @mentions can dispatch agents or run CLI participants.":"Autonomous routing is off. @mentions stay visible in chat, but nothing auto-runs."),n&&(n.placeholder=o?"Talk in-channel. Use @crew-* or @codex/@cursor/@claude/@opencode/@gemini/@crew-cli to route work.":"Autonomy is off. @mentions are informational until you turn routing back on.")}async function C(){const n=document.getElementById("swarmChatProject");if(!n)return;const r=e.swarmChatProjectId||e.chatActiveProjectId||"general",i=[{id:"general",name:"General"}];try{const e=await a("/api/projects");for(const t of e.projects||[])i.push({id:t.id,name:t.name||t.id})}catch{}n.innerHTML=i.map(e=>{const t=e.id===r?" selected":"";return`<option value="${o(e.id)}"${t}>${o(e.name)}</option>`}).join(""),e.swarmChatProjectId=n.value||"general",t();const s=document.getElementById("swarmChatHint");if(s){const t=i.find(t=>t.id===e.swarmChatProjectId);s.textContent="general"===e.swarmChatProjectId?"Shared global room. Same unified history store as Chat.":`Project channel for ${(null==t?void 0:t.name)||e.swarmChatProjectId}. Same history store as Chat.`}}async function j(){const t=document.getElementById("swarmChatMessages");if(!t)return;const n=e.swarmChatProjectId||"general";t.innerHTML="";try{const e=(await a(`/api/crew-lead/project-messages?projectId=${encodeURIComponent(n)}&limit=300&excludeDirect=true`)).messages||[];if(c=e,!e.length)return B(),void r(t,"No shared channel messages yet.");t.innerHTML=e.map($).join(""),t.scrollTop=t.scrollHeight}catch(o){i(t,`Failed to load shared channel: ${o.message}`)}}function $(e){var t,n,a,r,i,s,l,d,c,m;const u=v[e.source]||{emoji:"📝",label:e.source||"message"},p="user"===e.role,g=(null==(t=e.metadata)?void 0:t.agentEmoji)||(p?"👤":u.emoji),w=(null==(n=e.metadata)?void 0:n.agentName)||e.agent||(p?"You":u.label),y=new Date(e.ts||Date.now()).toLocaleTimeString(),h=[];return(null==(a=e.metadata)?void 0:a.channel)&&h.push(`#${e.metadata.channel}`),(null==(r=e.metadata)?void 0:r.directChat)&&h.push("direct"),(null==(i=e.metadata)?void 0:i.engine)&&h.push(e.metadata.engine),Array.isArray(null==(s=e.metadata)?void 0:s.mentions)&&e.metadata.mentions.forEach(e=>h.push(`@${e}`)),("mention"===(null==(l=e.metadata)?void 0:l.triggeredBy)||(null==(d=e.metadata)?void 0:d.autonomous))&&h.push("@mention"),(e.parentId||(null==(c=e.metadata)?void 0:c.originMessageId))&&h.push("linked"),(e.threadId||(null==(m=e.metadata)?void 0:m.originThreadId))&&h.push("thread"),`\n <div data-swarm-message-id="${o(e.id||"")}" style="display:flex;flex-direction:column;align-items:${p?"flex-end":"flex-start"};gap:4px;margin-bottom:10px;cursor:pointer;">\n <div style="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;gap:6px;align-items:center;flex-wrap:wrap;">\n <span>${o(g)} ${o(w)}</span>\n <span style="opacity:0.7;">${o(y)}</span>\n ${h.map(e=>`<span style="padding:1px 6px;border-radius:999px;background:var(--bg-card2);border:1px solid var(--border);">${o(e)}</span>`).join("")}\n </div>\n <div style="max-width:84%;padding:10px 14px;border-radius:${p?"14px 14px 4px 14px":"14px 14px 14px 4px"};background:${p?"var(--purple)":"var(--surface-2)"};color:${p?"#fff":"var(--text-2)"};font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;border:1px solid var(--border);">${o(e.content||"")}</div>\n </div>\n `}function k(t){const n=document.getElementById("swarmChatMessages");if(!n)return!1;const a=e.swarmChatProjectId||"general",o=`swarm-${a}`,r=e=>e&&"general"!==e?e:"general";if(r(t.projectId)!==r(a)||t.sessionId!==o)return!1;if("chat_stream"===t.type){f();let e=document.getElementById("swarm-streaming-bubble");if(!e){const a=document.createElement("div");a.id="swarm-streaming-wrapper",a.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;margin-bottom:10px;";const o=document.createElement("div");o.style.cssText="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;gap:6px;align-items:center;flex-wrap:wrap;";const r=t.agentName||t.agentEmoji?{name:t.agentName||t.agent||"agent",emoji:t.agentEmoji||"🤖"}:y||window._crewLeadInfo||{emoji:"🧠",name:"crew-lead"};o.textContent=`${r.emoji} ${r.name}`,e=document.createElement("div"),e.id="swarm-streaming-bubble",e.style.cssText="max-width:84%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;border:1px solid var(--border);",e._textNode=document.createTextNode(""),e.appendChild(e._textNode),a.appendChild(o),a.appendChild(e),n.appendChild(a)}return e._textNode.textContent+=t.token||"",n.scrollTop=n.scrollHeight,!0}if("chat_message"!==t.type)return!1;const i=document.getElementById("swarm-streaming-wrapper");if(i&&"assistant"===t.role&&i.remove(),"assistant"===t.role&&(f(),y=null),"user"===t.role){if(t.content===g)return!0;g=t.content}else if("assistant"===t.role){if(t.content===w)return!0;w=t.content}const s="assistant"===t.role?t.agent||("agent"===t.source||"cli"===t.source?null:"crew-lead"):null;return h({id:`live-${t.role}-${Date.now()}`,ts:Date.now(),source:t.source||"dashboard",role:t.role,content:t.content||"",agent:s,metadata:"assistant"===t.role?{agentName:t.agentName||("crew-lead"===s?(window._crewLeadInfo||{}).name||"crew-lead":s||"agent"),agentEmoji:t.agentEmoji||("crew-lead"===s?(window._crewLeadInfo||{}).emoji||"🧠":"🤖"),model:t.model||null,...t.directChat?{directChat:!0}:{},...t.multiDirect?{multiDirect:!0}:{}}:{agentName:"You",agentEmoji:"👤"}}),!0}function B(){const e=document.getElementById("swarmTracePanel");e&&(e.style.display="none",e.innerHTML="")}async function T(){var t;const a=document.getElementById("swarmChatInput"),r=document.getElementById("swarmChatSend");if(!a||!r)return;const i=a.value.trim();if(!i)return;const l=e.swarmChatProjectId||"general";r.disabled=!0,a.value="",y=function(e=""){const t=Array.from(String(e||"").matchAll(/@([a-zA-Z0-9_-]+)/g)).map(e=>e[1]);if(1!==t.length)return null;const n=t[0],a=u.find(e=>e.id===n)||u.find(e=>e.id===`crew-${n}`);return a?{id:a.id,name:a.name||a.displayName||a.id,emoji:a.emoji||"🤖"}:{id:n,name:n,emoji:"🤖"}}(i),h({id:`local-user-${Date.now()}`,ts:Date.now(),source:"dashboard",role:"user",content:i,agent:null,metadata:{agentName:"You",agentEmoji:"👤"}}),g=i,function(e=null){const t=document.getElementById("swarmChatMessages");if(!t||document.getElementById("swarm-typing-wrapper"))return;const n=e||y||window._crewLeadInfo||{emoji:"🧠",name:"crew-lead"},a=document.createElement("div");a.id="swarm-typing-wrapper",a.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;margin-bottom:10px;",a.innerHTML=`\n <div style="font-size:11px;color:var(--text-3);padding:0 6px;">${o(n.emoji)} ${o(n.name)}</div>\n <div style="max-width:84%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);font-size:14px;line-height:1.5;border:1px solid var(--border);font-style:italic;opacity:0.8;">thinking...</div>\n `,t.appendChild(a),t.scrollTop=t.scrollHeight}(y);try{const e=await s("/api/chat/unified",{message:i,sessionId:`swarm-${l}`,projectId:l,channelMode:!0});if(Array.isArray(null==e?void 0:e.replies)&&e.replies.length){f();for(const t of e.replies)h({id:`local-assistant-${t.agent}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ts:Date.now(),source:"agent",role:"assistant",content:t.reply||"",agent:t.agent||null,metadata:{agentName:t.agentName||t.agent||"agent",agentEmoji:t.agentEmoji||"🤖",directChat:!0,multiDirect:!0}});return w=(null==(t=e.replies[e.replies.length-1])?void 0:t.reply)||null,void(y=null)}if((null==e?void 0:e.reply)&&e.reply!==w&&!document.getElementById("swarm-streaming-wrapper")){f();const t=e.agent||e.routedTo||"crew-lead",n=e.agentName||(null==y?void 0:y.name)||("crew-lead"===t?(window._crewLeadInfo||{}).name||"crew-lead":t),a=e.agentEmoji||(null==y?void 0:y.emoji)||("crew-lead"===t?(window._crewLeadInfo||{}).emoji||"🧠":"🤖");h({id:`local-assistant-${Date.now()}`,ts:Date.now(),source:e.directChat?"agent":"dashboard",role:"assistant",content:e.reply,agent:t,metadata:{agentName:n,agentEmoji:a,...e.directChat?{directChat:!0}:{}}}),w=e.reply,y=null}}catch(d){f(),y=null,n(`Swarm send failed: ${d.message}`,"error"),h({id:`local-error-${Date.now()}`,ts:Date.now(),source:"system",role:"assistant",content:`Failed to send: ${d.message}`,agent:"crew-lead",metadata:{agentName:"system",agentEmoji:"🛰"}})}finally{r.disabled=!1,a.focus()}}export{k as h,x as i,I as s};
1
+ import{a as e,b as t,s as n,g as a,e as o,c as r,d as i,p as s}from"./core-utils-CmOkXgzi.js";let l=()=>{},d=()=>{},c=[],m=!1,u=[],p=0,g=null,w=null,y=null;function h(e){var t;const n=document.getElementById("swarmChatMessages");n&&(n.firstElementChild&&(null==(t=n.firstElementChild.textContent)?void 0:t.includes("No shared channel messages yet."))&&(n.innerHTML=""),c.push(e),n.insertAdjacentHTML("beforeend",$(e)),n.scrollTop=n.scrollHeight)}function f(){var e;null==(e=document.getElementById("swarm-typing-wrapper"))||e.remove()}const v={dashboard:{emoji:"🧠",label:"crew-lead"},agent:{emoji:"🤖",label:"agent"},"sub-agent":{emoji:"👷",label:"sub-agent"},cli:{emoji:"⚡",label:"cli"},discord:{emoji:"🎮",label:"discord"},system:{emoji:"🛰",label:"system"}};function x(e={}){l=e.hideAllViews||l,d=e.setNavActive||d,b()}function b(){if(m)return;const r=document.getElementById("swarmChatProject"),i=document.getElementById("swarmChatRefresh"),l=document.getElementById("swarmAutonomyBtn"),d=document.getElementById("swarmChatForm"),g=document.getElementById("swarmChatInput"),w=document.getElementById("swarmChatSend"),y=document.getElementById("swarmChatMessages");r&&i&&d&&g&&w&&y&&(m=!0,r.addEventListener("change",async()=>{e.swarmChatProjectId=r.value||"general",t(),await j()}),i.addEventListener("click",()=>{C().then(j).catch(e=>{n(`Failed to refresh Swarm: ${e.message}`,"error")})}),null==l||l.addEventListener("click",()=>{(async function(){const e=await a("/api/settings/autonomous-mentions"),t=await s("/api/settings/autonomous-mentions",{enabled:!e.enabled});n("Swarm autonomy "+(t.enabled?"ENABLED 🕸":"DISABLED")),await E()})().catch(e=>{n(`Failed to toggle autonomy: ${e.message}`,"error")})}),d.addEventListener("submit",e=>{e.preventDefault(),e.stopPropagation(),T()}),w.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),T()}),g.addEventListener("keydown",e=>{const t=document.getElementById("swarmMentionMenu");if(t&&"block"===t.style.display&&("Enter"===e.key||"Tab"===e.key)){const n=t.firstElementChild;if(n)return e.preventDefault(),void n.click()}"Enter"!==e.key||e.shiftKey||(e.preventDefault(),T())}),g.addEventListener("input",()=>{(async function(){const e=document.getElementById("swarmChatInput"),t=document.getElementById("swarmMentionMenu"),n=document.getElementById("swarmMentionHint");if(!e||!t||!n)return;const o=e.value||"",r=e.selectionStart||0,i=o.slice(0,r).match(/(^|\s)@([a-zA-Z0-9_-]*)$/);if(!i)return t.style.display="none",void(n.style.display="none");const s=(i[2]||"").toLowerCase(),l=(await async function(e=!1){const t=Date.now();if(!e&&u.length&&t-p<3e4)return u;const n=((await a("/api/chat-participants")).participants||[]).filter(e=>e.id).sort((e,t)=>e.id.localeCompare(t.id)).map(e=>({id:e.id,name:"cli"===e.kind?`${e.runtime} runtime`:e.kind,role:e.kind,kind:e.kind}));return u=n,p=t,n}()).filter(e=>e.id.toLowerCase().includes(s)).slice(0,8);if(!l.length)return t.style.display="none",void(n.style.display="none");t.style.display="block",t.innerHTML="",l.forEach(a=>{const s=document.createElement("div");s.style.cssText="padding:8px 12px;cursor:pointer;font-size:13px;border-bottom:1px solid var(--border);",s.onmouseenter=()=>{s.style.background="var(--bg-hover)"},s.onmouseleave=()=>{s.style.background=""},s.innerHTML=`<span style="color:var(--accent);font-weight:600;">@${a.id}</span> <span style="color:var(--text-3);">${a.name||a.role||"agent"}</span>`,s.onclick=()=>{const s=r-i[0].length+i[1].length,l=`@${a.id} `;e.value=o.slice(0,s)+l+o.slice(r);const d=s+l.length;e.selectionStart=e.selectionEnd=d,e.focus(),t.style.display="none",n.style.display="block",n.textContent="crew-lead"===a.id?"Mention target: @crew-lead. Use this for notes or routing guidance.":`Mention target: @${a.id}. Use a specific work order if you want execution.`},t.appendChild(s)}),n.style.display="block",n.textContent=s?`Matching participants for @${s}`:"Type a participant, e.g. @crew-lead for notes or @crew-coder with a specific work order."})().catch(()=>{})}),y.addEventListener("click",e=>{const t=e.target.closest("[data-swarm-message-id]");t&&function(e){var t;const n=document.getElementById("swarmTracePanel");if(!n)return;const a=c.find(t=>t.id===e);if(!a)return;const r=a.metadata||{},i=[["messageId",a.id],["source",a.source],["agent",a.agent||null],["taskId",r.taskId||null],["threadId",a.threadId||r.originThreadId||null],["parentId",a.parentId||r.originMessageId||null],["originProjectId",r.originProjectId||null],["originChannel",r.originChannel||r.channel||null],["triggeredBy",r.triggeredBy||null],["mentionedBy",r.mentionedBy||null]].filter(([,e])=>e);n.style.display="block",n.innerHTML=`\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;">\n <strong style="color:var(--text-1);">Trace</strong>\n <button type="button" id="swarmTraceClose" class="btn-ghost" style="font-size:11px;padding:4px 8px;">Close</button>\n </div>\n <div style="display:grid;grid-template-columns:140px 1fr;gap:6px 10px;">\n ${i.map(([e,t])=>`<div style="color:var(--text-3);">${o(e)}</div><div style="font-family:monospace;word-break:break-all;">${o(String(t))}</div>`).join("")}\n </div>\n `,null==(t=n.querySelector("#swarmTraceClose"))||t.addEventListener("click",B,{once:!0})}(t.dataset.swarmMessageId)}))}async function I(){var n,a;b(),l(),null==(n=document.getElementById("swarmChatView"))||n.classList.add("active"),d("navSwarmChat"),e.activeTab="swarm-chat",e.swarmChatProjectId||(e.swarmChatProjectId=e.chatActiveProjectId||"general"),t(),await C(),await E(),await j(),null==(a=document.getElementById("swarmChatInput"))||a.focus()}async function E(){const e=document.getElementById("swarmAutonomyBtn"),t=document.getElementById("swarmAutonomyStatus"),n=document.getElementById("swarmChatInput"),o=!1!==(await a("/api/settings/autonomous-mentions")).enabled;e&&(e.textContent=o?"🕸 Auto ON":"⚫ Auto OFF",e.style.background=o?"rgba(52,211,153,0.15)":"",e.style.borderColor=o?"rgba(52,211,153,0.3)":"",e.style.color=o?"var(--green)":""),t&&(t.textContent=o?"Autonomous routing is live in this room. @mentions can dispatch agents or run CLI participants.":"Autonomous routing is off. @mentions stay visible in chat, but nothing auto-runs."),n&&(n.placeholder=o?"Talk in-channel. Use @crew-* or @codex/@cursor/@claude/@opencode/@gemini/@crew-cli to route work.":"Autonomy is off. @mentions are informational until you turn routing back on.")}async function C(){const n=document.getElementById("swarmChatProject");if(!n)return;const r=e.swarmChatProjectId||e.chatActiveProjectId||"general",i=[{id:"general",name:"General"}];try{const e=await a("/api/projects");for(const t of e.projects||[])i.push({id:t.id,name:t.name||t.id})}catch{}n.innerHTML=i.map(e=>{const t=e.id===r?" selected":"";return`<option value="${o(e.id)}"${t}>${o(e.name)}</option>`}).join(""),e.swarmChatProjectId=n.value||"general",t();const s=document.getElementById("swarmChatHint");if(s){const t=i.find(t=>t.id===e.swarmChatProjectId);s.textContent="general"===e.swarmChatProjectId?"Shared global room. Same unified history store as Chat.":`Project channel for ${(null==t?void 0:t.name)||e.swarmChatProjectId}. Same history store as Chat.`}}async function j(){const t=document.getElementById("swarmChatMessages");if(!t)return;const n=e.swarmChatProjectId||"general";t.innerHTML="";try{const e=(await a(`/api/crew-lead/project-messages?projectId=${encodeURIComponent(n)}&limit=300&excludeDirect=true`)).messages||[];if(c=e,!e.length)return B(),void r(t,"No shared channel messages yet.");t.innerHTML=e.map($).join(""),t.scrollTop=t.scrollHeight}catch(o){i(t,`Failed to load shared channel: ${o.message}`)}}function $(e){var t,n,a,r,i,s,l,d,c,m;const u=v[e.source]||{emoji:"📝",label:e.source||"message"},p="user"===e.role,g=(null==(t=e.metadata)?void 0:t.agentEmoji)||(p?"👤":u.emoji),w=(null==(n=e.metadata)?void 0:n.agentName)||e.agent||(p?"You":u.label),y=new Date(e.ts||Date.now()).toLocaleTimeString(),h=[];return(null==(a=e.metadata)?void 0:a.channel)&&h.push(`#${e.metadata.channel}`),(null==(r=e.metadata)?void 0:r.directChat)&&h.push("direct"),(null==(i=e.metadata)?void 0:i.engine)&&h.push(e.metadata.engine),Array.isArray(null==(s=e.metadata)?void 0:s.mentions)&&e.metadata.mentions.forEach(e=>h.push(`@${e}`)),("mention"===(null==(l=e.metadata)?void 0:l.triggeredBy)||(null==(d=e.metadata)?void 0:d.autonomous))&&h.push("@mention"),(e.parentId||(null==(c=e.metadata)?void 0:c.originMessageId))&&h.push("linked"),(e.threadId||(null==(m=e.metadata)?void 0:m.originThreadId))&&h.push("thread"),`\n <div data-swarm-message-id="${o(e.id||"")}" style="display:flex;flex-direction:column;align-items:${p?"flex-end":"flex-start"};gap:4px;margin-bottom:10px;cursor:pointer;">\n <div style="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;gap:6px;align-items:center;flex-wrap:wrap;">\n <span>${o(g)} ${o(w)}</span>\n <span style="opacity:0.7;">${o(y)}</span>\n ${h.map(e=>`<span style="padding:1px 6px;border-radius:999px;background:var(--bg-card2);border:1px solid var(--border);">${o(e)}</span>`).join("")}\n </div>\n <div style="max-width:84%;padding:10px 14px;border-radius:${p?"14px 14px 4px 14px":"14px 14px 14px 4px"};background:${p?"var(--purple)":"var(--surface-2)"};color:${p?"#fff":"var(--text-2)"};font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;border:1px solid var(--border);">${o(e.content||"")}</div>\n </div>\n `}function k(t){const n=document.getElementById("swarmChatMessages");if(!n)return!1;const a=e.swarmChatProjectId||"general",o=`swarm-${a}`,r=e=>e&&"general"!==e?e:"general";if(r(t.projectId)!==r(a)||t.sessionId!==o)return!1;if("chat_stream"===t.type){f();let e=document.getElementById("swarm-streaming-bubble");if(!e){const a=document.createElement("div");a.id="swarm-streaming-wrapper",a.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;margin-bottom:10px;";const o=document.createElement("div");o.style.cssText="font-size:11px;color:var(--text-3);padding:0 6px;display:flex;gap:6px;align-items:center;flex-wrap:wrap;";const r=t.agentName||t.agentEmoji?{name:t.agentName||t.agent||"agent",emoji:t.agentEmoji||"🤖"}:y||window._crewLeadInfo||{emoji:"🧠",name:"crew-lead"};o.textContent=`${r.emoji} ${r.name}`,e=document.createElement("div"),e.id="swarm-streaming-bubble",e.style.cssText="max-width:84%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);font-size:14px;line-height:1.5;white-space:pre-wrap;word-break:break-word;border:1px solid var(--border);",e._textNode=document.createTextNode(""),e.appendChild(e._textNode),a.appendChild(o),a.appendChild(e),n.appendChild(a)}return e._textNode.textContent+=t.token||"",n.scrollTop=n.scrollHeight,!0}if("chat_message"!==t.type)return!1;const i=document.getElementById("swarm-streaming-wrapper");if(i&&"assistant"===t.role&&i.remove(),"assistant"===t.role&&(f(),y=null),"user"===t.role){if(t.content===g)return!0;g=t.content}else if("assistant"===t.role){if(t.content===w)return!0;w=t.content}const s="assistant"===t.role?t.agent||("agent"===t.source||"cli"===t.source?null:"crew-lead"):null;return h({id:`live-${t.role}-${Date.now()}`,ts:Date.now(),source:t.source||"dashboard",role:t.role,content:t.content||"",agent:s,metadata:"assistant"===t.role?{agentName:t.agentName||("crew-lead"===s?(window._crewLeadInfo||{}).name||"crew-lead":s||"agent"),agentEmoji:t.agentEmoji||("crew-lead"===s?(window._crewLeadInfo||{}).emoji||"🧠":"🤖"),model:t.model||null,...t.directChat?{directChat:!0}:{},...t.multiDirect?{multiDirect:!0}:{}}:{agentName:"You",agentEmoji:"👤"}}),!0}function B(){const e=document.getElementById("swarmTracePanel");e&&(e.style.display="none",e.innerHTML="")}async function T(){var t;const a=document.getElementById("swarmChatInput"),r=document.getElementById("swarmChatSend");if(!a||!r)return;const i=a.value.trim();if(!i)return;const l=e.swarmChatProjectId||"general";r.disabled=!0,a.value="",y=function(e=""){const t=Array.from(String(e||"").matchAll(/@([a-zA-Z0-9_-]+)/g)).map(e=>e[1]);if(1!==t.length)return null;const n=t[0],a=u.find(e=>e.id===n)||u.find(e=>e.id===`crew-${n}`);return a?{id:a.id,name:a.name||a.displayName||a.id,emoji:a.emoji||"🤖"}:{id:n,name:n,emoji:"🤖"}}(i),h({id:`local-user-${Date.now()}`,ts:Date.now(),source:"dashboard",role:"user",content:i,agent:null,metadata:{agentName:"You",agentEmoji:"👤"}}),g=i,function(e=null){const t=document.getElementById("swarmChatMessages");if(!t||document.getElementById("swarm-typing-wrapper"))return;const n=e||y||window._crewLeadInfo||{emoji:"🧠",name:"crew-lead"},a=document.createElement("div");a.id="swarm-typing-wrapper",a.style.cssText="display:flex;flex-direction:column;align-items:flex-start;gap:4px;margin-bottom:10px;",a.innerHTML=`\n <div style="font-size:11px;color:var(--text-3);padding:0 6px;">${o(n.emoji)} ${o(n.name)}</div>\n <div style="max-width:84%;padding:10px 14px;border-radius:14px 14px 14px 4px;background:var(--surface-2);color:var(--text-2);font-size:14px;line-height:1.5;border:1px solid var(--border);font-style:italic;opacity:0.8;">thinking...</div>\n `,t.appendChild(a),t.scrollTop=t.scrollHeight}(y);try{const e=await s("/api/chat/unified",{message:i,sessionId:`swarm-${l}`,projectId:l,channelMode:!0});if(Array.isArray(null==e?void 0:e.replies)&&e.replies.length){f();for(const t of e.replies)h({id:`local-assistant-${t.agent}-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,ts:Date.now(),source:"agent",role:"assistant",content:t.reply||"",agent:t.agent||null,metadata:{agentName:t.agentName||t.agent||"agent",agentEmoji:t.agentEmoji||"🤖",directChat:!0,multiDirect:!0}});return w=(null==(t=e.replies[e.replies.length-1])?void 0:t.reply)||null,void(y=null)}if((null==e?void 0:e.reply)&&e.reply!==w&&!document.getElementById("swarm-streaming-wrapper")){f();const t=e.agent||e.routedTo||"crew-lead",n=e.agentName||(null==y?void 0:y.name)||("crew-lead"===t?(window._crewLeadInfo||{}).name||"crew-lead":t),a=e.agentEmoji||(null==y?void 0:y.emoji)||("crew-lead"===t?(window._crewLeadInfo||{}).emoji||"🧠":"🤖");h({id:`local-assistant-${Date.now()}`,ts:Date.now(),source:e.directChat?"agent":"dashboard",role:"assistant",content:e.reply,agent:t,metadata:{agentName:n,agentEmoji:a,...e.directChat?{directChat:!0}:{}}}),w=e.reply,y=null}}catch(d){f(),y=null,n(`Swarm send failed: ${d.message}`,"error"),h({id:`local-error-${Date.now()}`,ts:Date.now(),source:"system",role:"assistant",content:`Failed to send: ${d.message}`,agent:"crew-lead",metadata:{agentName:"system",agentEmoji:"🛰"}})}finally{r.disabled=!1,a.focus()}}export{k as h,x as i,I as s};