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.
- package/README.md +2 -2
- package/apps/dashboard/dist/assets/{chat-core-CMoqlR6D.js → chat-core-Cx4sTxDd.js} +1 -1
- package/apps/dashboard/dist/assets/chat-core-Cx4sTxDd.js.br +0 -0
- package/apps/dashboard/dist/assets/cli-process-COMRNPqr.js.br +0 -0
- package/apps/dashboard/dist/assets/{components-CSUb80ze.js → components-BS9fQjE_.js} +1 -1
- package/apps/dashboard/dist/assets/components-BS9fQjE_.js.br +0 -0
- package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js +1 -0
- package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js.br +0 -0
- package/apps/dashboard/dist/assets/index-CF0aJRtC.css.br +0 -0
- package/apps/dashboard/dist/assets/{index-DqVVQLTW.js → index-DnClJ1ee.js} +2 -2
- package/apps/dashboard/dist/assets/index-DnClJ1ee.js.br +0 -0
- package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
- package/apps/dashboard/dist/assets/{setup-wizard-D4g5DMhW.js → setup-wizard-CA0Or47w.js} +1 -1
- package/apps/dashboard/dist/assets/setup-wizard-CA0Or47w.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-agents-tab-BThdsdJY.js → tab-agents-tab-BgpIsjkw.js} +1 -1
- package/apps/dashboard/dist/assets/tab-agents-tab-BgpIsjkw.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-benchmarks-tab-DfCuAClu.js → tab-benchmarks-tab-BHjKCPm3.js} +1 -1
- package/apps/dashboard/dist/assets/{tab-comms-tab-eHpOSBhG.js → tab-comms-tab-kguqTIzD.js} +1 -1
- package/apps/dashboard/dist/assets/tab-comms-tab-kguqTIzD.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-contacts-tab-5LHSthJM.js → tab-contacts-tab-DiOyMYth.js} +1 -1
- package/apps/dashboard/dist/assets/tab-contacts-tab-DiOyMYth.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-engines-tab-C3DYxTwy.js → tab-engines-tab-BsdZVvU0.js} +1 -1
- package/apps/dashboard/dist/assets/tab-engines-tab-BsdZVvU0.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-memory-tab-C59BYFQD.js → tab-memory-tab-Cu6u13EQ.js} +1 -1
- package/apps/dashboard/dist/assets/tab-memory-tab-Cu6u13EQ.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-models-tab-CQzvaeVh.js → tab-models-tab-BLEjmd19.js} +1 -1
- package/apps/dashboard/dist/assets/tab-models-tab-BLEjmd19.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-pm-loop-tab-D7mnDelU.js → tab-pm-loop-tab-Bfd449B4.js} +1 -1
- package/apps/dashboard/dist/assets/tab-pm-loop-tab-Bfd449B4.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-projects-tab-C6h2Mv1K.js → tab-projects-tab-DhNWnlzt.js} +1 -1
- package/apps/dashboard/dist/assets/tab-projects-tab-DhNWnlzt.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-prompts-tab-C0wZvWK3.js → tab-prompts-tab-DVkUNaJd.js} +1 -1
- package/apps/dashboard/dist/assets/tab-prompts-tab-DVkUNaJd.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-services-tab-DBj_w3bc.js → tab-services-tab-DU_LH3uG.js} +1 -1
- package/apps/dashboard/dist/assets/tab-services-tab-DU_LH3uG.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-settings-tab-ezeqAjZk.js → tab-settings-tab-Bn4nXtDe.js} +1 -1
- package/apps/dashboard/dist/assets/tab-settings-tab-Bn4nXtDe.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-skills-tab-BYdU2whk.js → tab-skills-tab-BpY0uZHW.js} +1 -1
- package/apps/dashboard/dist/assets/tab-skills-tab-BpY0uZHW.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-spending-tab-Bg6w9t_p.js → tab-spending-tab-DEccQHnt.js} +1 -1
- package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-swarm-chat-tab-BBV9HB2X.js → tab-swarm-chat-tab-BNrd88-r.js} +1 -1
- package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BNrd88-r.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-swarm-tab-ChqLlEVs.js → tab-swarm-tab-B1AcjL1W.js} +1 -1
- package/apps/dashboard/dist/assets/tab-swarm-tab-B1AcjL1W.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-usage-tab-B2UWXenJ.js → tab-usage-tab-BIOOnB-Y.js} +1 -1
- package/apps/dashboard/dist/assets/tab-usage-tab-BIOOnB-Y.js.br +0 -0
- package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
- package/apps/dashboard/dist/assets/{tab-workflows-tab-6QSXLJ0i.js → tab-workflows-tab-B-soSy1k.js} +1 -1
- package/apps/dashboard/dist/assets/tab-workflows-tab-B-soSy1k.js.br +0 -0
- package/apps/dashboard/dist/index.html +23 -23
- package/apps/dashboard/dist/index.html.br +0 -0
- package/apps/dashboard/dist/index.html.gz +0 -0
- package/apps/dashboard/index.html +71 -1
- package/apps/dashboard/src/app.js +5 -0
- package/apps/dashboard/src/core/dom.js +8 -0
- package/apps/dashboard/src/tabs/settings-tab.js +58 -0
- package/apps/vibe/.crew/agent-memory/pipeline.json +12 -1
- package/apps/vibe/.crew/cost.json +3 -3
- package/apps/vibe/.crew/json-parse-metrics.jsonl +1 -0
- package/apps/vibe/.crew/pipeline-metrics.jsonl +1 -0
- package/apps/vibe/.crew/pipeline-runs/pipeline-c1418f4e-b773-4ca1-84a3-216acf36e2f2.jsonl +5 -0
- package/apps/vibe/.crew/session.json +10 -1
- package/apps/vibe/.studio-data/project-messages/general.jsonl +3 -0
- package/apps/vibe/index.html +4 -2
- package/apps/vibe/server.mjs +75 -3
- package/apps/vibe/src/main.js +126 -53
- package/crew-lead.mjs +14 -1
- package/lib/bridges/cli-executor.mjs +0 -2
- package/lib/bridges/tmux-bridge.mjs +200 -0
- package/lib/chat/unified-history.mjs +1 -1
- package/lib/cli-process-tracker.mjs +2 -1
- package/lib/crew-lead/http-server.mjs +286 -1
- package/lib/crew-lead/wave-dispatcher.mjs +40 -3
- package/lib/engines/crew-cli.mjs +3 -2
- package/lib/engines/llm-direct.mjs +4 -1
- package/lib/engines/rt-envelope.mjs +14 -5
- package/lib/engines/runners.mjs +30 -4
- package/lib/runtime/config.mjs +7 -0
- package/lib/sessions/session-manager.mjs +287 -0
- package/package.json +1 -1
- package/scripts/bench/performance_optimization.py +81 -0
- package/whatsapp-bridge.mjs +54 -10
- package/apps/dashboard/dist/assets/core-utils-CAVnDoe1.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,b as t,h as n,g as s,e as o,i,j as a,s as r,p as l}from"./core-utils-CAVnDoe1.js";let c=()=>{},d=()=>{};function p({hideAllViews:e,setNavActive:t}={}){c=e||c,d=t||d}let m=e.selected||null,u=e.selectedEngine||"opencode";async function g(){const n=document.getElementById("sessions");n&&(n.innerHTML='<div style="padding:20px;">Loading…</div>');const i=n.parentElement;let a=document.getElementById("engine-selector");a||(a=document.createElement("div"),a.id="engine-selector",a.style.cssText="padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;",a.innerHTML='<label style="font-size:13px;font-weight:500;color:var(--text-2);">CLI:</label><select id="engine-select" style="padding:6px 10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-1);color:var(--text-1);font-size:13px;cursor:pointer;"><option value="opencode">OpenCode</option><option value="claude">Claude Code</option><option value="codex">Codex CLI</option><option value="gemini">Gemini CLI</option><option value="crew-cli">crew-cli</option></select><span style="font-size:12px;color:var(--text-3);margin-left:8px;" id="session-count"></span>',i.insertBefore(a,n),document.getElementById("engine-select").addEventListener("change",n=>{u=n.target.value,e.selectedEngine=u,t(),m=null,g()}));const r=document.getElementById("engine-select");r&&(r.value=u);try{let n=function(e){if(!e||"string"!=typeof e)return null;const t=e.match(/\[?(crew-\w+)\]?/);return t?t[1]:null},i=function(e){return e&&"string"==typeof e?/\bFixer\b|fixer\s+task|fix\s+.*\.py|syntax\s+error/i.test(e)?"fixer":/\bQA\b|qa\s+audit|audit:/i.test(e)?"qa":/\bPM\b|crew-pm|roadmap\b/i.test(e)?"pm":/\bCoder\b|coder\s+task|frontend\b|backend\b/i.test(e)?"coder":/\bSecurity\b|security\s+review/i.test(e)?"security":/\bCopywriter\b|copy\s+task/i.test(e)?"copywriter":null:null},a=function(e){return e&&/^[a-z]+-[a-z]+$/.test(e)&&!e.startsWith("crew-")};const r=e.chatActiveProjectId||"general",l="/api/engine-sessions?engine="+encodeURIComponent(u)+"&projectId="+encodeURIComponent(r),c=await s(l),d=c.sessions||c||[],p=document.getElementById("sessions"),f=document.getElementById("session-count");if(p.innerHTML="",!d.length){const e={opencode:"OpenCode",claude:"Claude Code",codex:"Codex CLI",gemini:"Gemini CLI","crew-cli":"crew-cli"}[u]||u;return p.innerHTML=`<div style="padding:20px 16px;"><div style="font-size:13px;font-weight:600;margin-bottom:6px;">No ${e} sessions</div><div style="font-size:12px;color:var(--text-3);line-height:1.6;">No session history found for <strong>${e}</strong>. Run a task using this engine to see sessions here.</div></div>`,void(f&&(f.textContent=""))}f&&(f.textContent=`${d.length} session${1!==d.length?"s":""}`),!m&&d[0]&&(m=d[0].id),d.forEach(s=>{const r=document.createElement("div"),l=s.id||s.sessionId||"";r.className="row"+(l===m?" active":""),r.onclick=()=>{m=l,e.selected=l,t(),g(),x()};let c=s.title||s.slug||l,d=s.directory||"",f="";if("opencode"===u){const e=n(c),t=i(c),o=s.slug||"",r=e||(o&&!a(o)?o:null)||t,l=a(o)?" ("+o+")":"";f=r?"Assigned to: "+r+l:o?"Assigned to: "+o+" (OpenCode session)":""}else"claude"===u?d=s.file?s.file.split("/").pop().replace(".jsonl",""):"":"codex"===u?d=s.file||"":"gemini"===u?d="Project: "+l:"crew-cli"===u&&(f=s.engine+" / "+s.project,d=s.file||"");c.length>80&&(c=c.slice(0,77)+"..."),r.innerHTML="<div><strong>"+o(c)+"</strong></div>"+(d?'<div class="meta">'+o(d)+"</div>":"")+(f?'<div class="meta" style="font-size:11px;color:var(--accent);">'+o(f)+"</div>":""),p.appendChild(r)})}catch(l){const e=document.getElementById("sessions");e&&(e.innerHTML='<div class="meta" style="padding:20px; color:var(--red-hi);">Error loading sessions.</div>')}}async function x(){const e=document.getElementById("messages");if(m)try{if("opencode"===u){const t=await s("/api/messages?session="+encodeURIComponent(m));e.innerHTML="",t.slice(-40).forEach(t=>{const n=(t.parts||[]).filter(e=>"text"===e.type).map(e=>e.text).join("").trim();if(!n)return;const s=document.createElement("div");s.className="msg "+("assistant"===(t.info&&t.info.role)?"a":"u"),s.innerHTML='<div class="meta">'+(t.info&&t.info.role)+" • "+i(a(t.info))+'</div><div class="t"></div>',s.querySelector(".t").textContent=n,e.appendChild(s)})}else{const t={claude:"/api/claude-sessions",codex:"/api/codex-sessions",gemini:"/api/gemini-sessions","crew-cli":"/api/crew-cli-sessions"}[u];if(!t)return void(e.innerHTML='<div class="meta">Engine not supported</div>');const n=await s(t),o=(n.sessions||n||[]).find(e=>e.id===m||e.sessionId===m);if(!o||!o.messages)return void(e.innerHTML='<div class="meta">No messages found</div>');e.innerHTML="",o.messages.slice(-40).forEach(t=>{const n=document.createElement("div");n.className="msg "+("assistant"===t.role?"a":"u");const s=t.ts?new Date(t.ts).toLocaleString():"";n.innerHTML='<div class="meta">'+t.role+(s?" • "+s:"")+'</div><div class="t"></div>',n.querySelector(".t").textContent=t.text||"",e.appendChild(n)})}e.scrollTop=e.scrollHeight}catch(t){e&&(e.innerHTML='<div class="meta">Error: '+t.message+"</div>")}else e&&(e.innerHTML='<div class="meta">No session selected.</div>')}function f(){c(),document.getElementById("sessionsView").classList.add("active"),d("navSwarm"),e.activeTab="swarm",t();const s=document.getElementById("sessions");s&&s.children.length>1?n("swarm"):(g(),x())}let y=!1,v="tasks",h="";const b=new Set(["agent.heartbeat","agent.online","agent.offline"]),w=new Set(["task.dispatched","task.done","task.completed","task.failed","task.cancelled","task.started","task.reply"]);function C(e){if(b.has(e.type))return!1;const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"";if(!n||"run_task"===n)return!1;if("tasks"===v&&!w.has(e.type))return!1;if("replies"===v&&!(t.reply||t.message||t.content))return!1;if(h){const t=h.toLowerCase();if(!((e.from||"").toLowerCase().includes(t)||(e.to||"").toLowerCase().includes(t)||n.toLowerCase().includes(t)||(e.type||"").toLowerCase().includes(t)))return!1}return!0}const E={"task.dispatched":{color:"var(--purple)",label:"dispatched"},"task.started":{color:"var(--amber)",label:"started"},"task.done":{color:"var(--green-hi)",label:"done"},"task.completed":{color:"var(--green-hi)",label:"completed"},"task.reply":{color:"var(--accent)",label:"reply"},"task.failed":{color:"var(--red-hi)",label:"failed"},"task.cancelled":{color:"var(--text-3)",label:"cancelled"}};async function L(){if(y)return;const e=document.getElementById("rtMessages"),t=document.getElementById("rtView");if(!e||!t)return;const n=0===e.children.length;if(n){const t=document.createElement("div");t.style.cssText="padding:20px;",t.textContent="Loading…",e.replaceChildren(t)}const o=(await s("/api/rt-messages")).filter(C).slice(-100),i=o.map(e=>{const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"";return`${e.type}|${e.from}|${e.to}|${n.slice(0,100)}`}).join("::");if(i===window._rtLastHash&&!n)return;window._rtLastHash=i;const a=()=>t.scrollHeight-t.scrollTop-t.clientHeight<100,r=a(),l=t.scrollTop,c=document.createDocumentFragment();if(o.length){const e=document.createElement("div");e.style.cssText="display:grid;grid-template-columns:auto auto 1fr auto;gap:10px;padding:4px 10px 6px;font-size:10px;font-weight:600;color:var(--text-3);letter-spacing:.06em;text-transform:uppercase;border-bottom:2px solid var(--border);margin-bottom:2px;",["Agent","Phase","Summary","Time"].forEach(t=>{const n=document.createElement("span");n.textContent=t,e.appendChild(n)}),c.appendChild(e),o.forEach(e=>c.appendChild(function(e){const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"",s=e.type||"",o=E[s],i=e.ts?new Date(e.ts).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):"",a=n.split("\n").map(e=>e.trim()).find(e=>e.length>2)||n,r=a.length>90?a.slice(0,90)+"…":a,l=n.length>r.length||n.split("\n").length>1,c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:auto auto 1fr auto;align-items:center;gap:10px;padding:7px 10px;border-radius:6px;cursor:"+(l?"pointer":"default")+";transition:background .12s;border-bottom:1px solid var(--border);",c.onmouseenter=()=>{c.style.background="var(--bg-2)"},c.onmouseleave=()=>{c.style.background=""};const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:5px;white-space:nowrap;min-width:0;";const p=document.createElement("span");if(p.style.cssText="font-size:11px;font-weight:600;color:var(--text-1);max-width:110px;overflow:hidden;text-overflow:ellipsis;",p.textContent=(e.from||"?").replace("crew-",""),p.title=e.from||"",d.appendChild(p),e.to&&e.to!==e.from){const t=document.createElement("span");t.style.cssText="font-size:10px;color:var(--text-3);flex-shrink:0;",t.textContent="→";const n=document.createElement("span");n.style.cssText="font-size:11px;color:var(--text-2);max-width:110px;overflow:hidden;text-overflow:ellipsis;",n.textContent=(e.to||"").replace("crew-",""),n.title=e.to||"",d.appendChild(t),d.appendChild(n)}const m=document.createElement("div");m.style.cssText="display:flex;align-items:center;gap:4px;flex-shrink:0;";const u=document.createElement("span"),g=o||{color:"var(--text-3)",label:s.split(".").pop()||s};if(u.style.cssText="font-size:10px;font-weight:600;padding:2px 7px;border-radius:20px;white-space:nowrap;flex-shrink:0;color:#fff;background:"+g.color+";letter-spacing:.03em;",u.textContent=g.label,m.appendChild(u),"task.done"===s&&t.engineUsed){const e={claude:"#e07a5f",codex:"#8338ec",cursor:"#3d405b",opencode:"#06d6a0",gemini:"#4285f4","docker-sandbox":"#0db7ed"},n={claude:"🤖",codex:"🟣",cursor:"🖱",opencode:"⚡",gemini:"✨","docker-sandbox":"🐳"},s=t.engineUsed,o=document.createElement("span");o.style.cssText="font-size:10px;font-weight:600;padding:2px 6px;border-radius:20px;white-space:nowrap;flex-shrink:0;color:#fff;background:"+(e[s]||"var(--text-3)")+";",o.textContent=(n[s]||"")+" "+s,o.title="Executed by "+s,m.appendChild(o)}const x=document.createElement("span");x.style.cssText="font-size:12px;color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;",x.textContent=r;const f=document.createElement("div");f.style.cssText="display:flex;align-items:center;gap:6px;flex-shrink:0;";const y=document.createElement("span");if(y.style.cssText="font-size:10px;color:var(--text-3);white-space:nowrap;",y.textContent=i,f.appendChild(y),l){const e=document.createElement("span");e.style.cssText="font-size:10px;color:var(--text-3);",e.textContent="▸",f.appendChild(e)}if(c.appendChild(d),c.appendChild(m),c.appendChild(x),c.appendChild(f),l){const e=document.createElement("div");e.style.cssText="display:none;grid-column:1/-1;padding:8px 6px 4px;font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word;max-height:300px;overflow-y:auto;border-top:1px solid var(--border);margin-top:4px;font-family:monospace;",e.textContent=n;const t=document.createElement("div");t.style.cssText="display:grid;grid-template-columns:1fr;border-radius:6px;overflow:hidden;border-bottom:1px solid var(--border);",c.style.borderBottom="none";let s=!1;return c.onclick=()=>{s=!s,e.style.display=s?"block":"none";const t=f.querySelector("span:last-child");t&&(t.textContent=s?"▾":"▸")},t.appendChild(c),t.appendChild(e),t}return c}(e)))}else{const e=document.createElement("div");e.style.cssText="padding:24px;text-align:center;font-size:12px;color:var(--text-3);",e.textContent="No events match the current filter.",c.appendChild(e)}if(e.replaceChildren(c),r)t.scrollTop=t.scrollHeight;else{const e=Math.max(0,t.scrollHeight-t.clientHeight);t.scrollTop=Math.min(l,e)}const d=document.getElementById("rtScrollBtn");d&&(d.style.display=a()?"none":"block"),t._scrollListenerBound||(t._scrollListenerBound=!0,t.addEventListener("scroll",()=>{d&&(d.style.display=a()?"none":"block")}))}function k(){y=!y;const e=document.getElementById("rtPauseBtn");e&&(e.textContent=y?"▶ Resume":"⏸ Pause",e.style.background=y?"var(--accent)":"",e.style.color=y?"#fff":"")}function T(){const e=document.getElementById("rtMessages");e&&(e.innerHTML='<div class="meta" style="padding:20px;text-align:center;opacity:.6;">Cleared. New messages will appear on next poll.</div>')}function I(){c(),document.getElementById("rtView").classList.add("active"),d("navRT"),function(){document.querySelectorAll(".rt-filter-chip").forEach(e=>{e.addEventListener("click",()=>{v=e.dataset.filter,document.querySelectorAll(".rt-filter-chip").forEach(t=>{const n=t===e;t.style.background=n?"var(--accent)":"transparent",t.style.color=n?"#fff":"var(--text-2)",t.classList.toggle("active",n)}),L()})});const e=document.getElementById("rtSearch");e&&e.addEventListener("input",()=>{h=e.value.trim(),L()})}(),L();const e=document.getElementById("rtScrollBtn");e&&(e.style.display="none")}async function B(){const e=document.getElementById("dlqMessages");e&&(e.innerHTML='<div style="padding:20px;">Loading…</div>');const t=await s("/api/dlq"),n=document.getElementById("dlqBadge");n&&(n.textContent=t.length,n.classList.toggle("hidden",!t.length)),e&&(e.innerHTML=t.length?t.map(e=>{const t=e.key||(e.filename||"").replace(".json","")||"?",n=o(t);return'<div class="msg dlq-item"><div class="meta"><strong>⚠️ Failed</strong> | '+(e.agent||"?")+" | "+(e.failedAt?new Date(e.failedAt).toLocaleString():"")+' <button class="replay-btn" data-action="replayDLQ" data-arg="'+n+'">Replay</button> <button data-action="deleteDLQ" data-arg="'+n+'" style="font-size:11px;padding:3px 8px;border-radius:4px;border:1px solid var(--red-hi);background:transparent;color:var(--red-hi);cursor:pointer;">Delete</button></div><div class="t">'+(e.error||"")+"</div></div>"}).join(""):'<div class="meta" style="padding:20px; text-align:center;">✓ DLQ empty</div>')}async function H(e){confirm("Replay?")&&(await l("/api/dlq/replay",{key:e}),r("Replayed"),B())}async function M(e){if(confirm("Delete this DLQ entry?"))try{await fetch("/api/dlq/"+encodeURIComponent(e),{method:"DELETE"}),r("DLQ entry deleted"),B()}catch(t){r("Failed: "+t.message,!0)}}function z(){c(),document.getElementById("dlqView").classList.add("active"),d("navDLQ"),B()}export{I as a,f as b,T as c,M as d,p as i,H as r,z as s,k as t};
|
|
1
|
+
import{a as e,b as t,h as n,g as s,e as o,i,j as a,s as r,p as l}from"./core-utils-CmOkXgzi.js";let c=()=>{},d=()=>{};function p({hideAllViews:e,setNavActive:t}={}){c=e||c,d=t||d}let m=e.selected||null,u=e.selectedEngine||"opencode";async function g(){const n=document.getElementById("sessions");n&&(n.innerHTML='<div style="padding:20px;">Loading…</div>');const i=n.parentElement;let a=document.getElementById("engine-selector");a||(a=document.createElement("div"),a.id="engine-selector",a.style.cssText="padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;",a.innerHTML='<label style="font-size:13px;font-weight:500;color:var(--text-2);">CLI:</label><select id="engine-select" style="padding:6px 10px;border:1px solid var(--border);border-radius:6px;background:var(--bg-1);color:var(--text-1);font-size:13px;cursor:pointer;"><option value="opencode">OpenCode</option><option value="claude">Claude Code</option><option value="codex">Codex CLI</option><option value="gemini">Gemini CLI</option><option value="crew-cli">crew-cli</option></select><span style="font-size:12px;color:var(--text-3);margin-left:8px;" id="session-count"></span>',i.insertBefore(a,n),document.getElementById("engine-select").addEventListener("change",n=>{u=n.target.value,e.selectedEngine=u,t(),m=null,g()}));const r=document.getElementById("engine-select");r&&(r.value=u);try{let n=function(e){if(!e||"string"!=typeof e)return null;const t=e.match(/\[?(crew-\w+)\]?/);return t?t[1]:null},i=function(e){return e&&"string"==typeof e?/\bFixer\b|fixer\s+task|fix\s+.*\.py|syntax\s+error/i.test(e)?"fixer":/\bQA\b|qa\s+audit|audit:/i.test(e)?"qa":/\bPM\b|crew-pm|roadmap\b/i.test(e)?"pm":/\bCoder\b|coder\s+task|frontend\b|backend\b/i.test(e)?"coder":/\bSecurity\b|security\s+review/i.test(e)?"security":/\bCopywriter\b|copy\s+task/i.test(e)?"copywriter":null:null},a=function(e){return e&&/^[a-z]+-[a-z]+$/.test(e)&&!e.startsWith("crew-")};const r=e.chatActiveProjectId||"general",l="/api/engine-sessions?engine="+encodeURIComponent(u)+"&projectId="+encodeURIComponent(r),c=await s(l),d=c.sessions||c||[],p=document.getElementById("sessions"),f=document.getElementById("session-count");if(p.innerHTML="",!d.length){const e={opencode:"OpenCode",claude:"Claude Code",codex:"Codex CLI",gemini:"Gemini CLI","crew-cli":"crew-cli"}[u]||u;return p.innerHTML=`<div style="padding:20px 16px;"><div style="font-size:13px;font-weight:600;margin-bottom:6px;">No ${e} sessions</div><div style="font-size:12px;color:var(--text-3);line-height:1.6;">No session history found for <strong>${e}</strong>. Run a task using this engine to see sessions here.</div></div>`,void(f&&(f.textContent=""))}f&&(f.textContent=`${d.length} session${1!==d.length?"s":""}`),!m&&d[0]&&(m=d[0].id),d.forEach(s=>{const r=document.createElement("div"),l=s.id||s.sessionId||"";r.className="row"+(l===m?" active":""),r.onclick=()=>{m=l,e.selected=l,t(),g(),x()};let c=s.title||s.slug||l,d=s.directory||"",f="";if("opencode"===u){const e=n(c),t=i(c),o=s.slug||"",r=e||(o&&!a(o)?o:null)||t,l=a(o)?" ("+o+")":"";f=r?"Assigned to: "+r+l:o?"Assigned to: "+o+" (OpenCode session)":""}else"claude"===u?d=s.file?s.file.split("/").pop().replace(".jsonl",""):"":"codex"===u?d=s.file||"":"gemini"===u?d="Project: "+l:"crew-cli"===u&&(f=s.engine+" / "+s.project,d=s.file||"");c.length>80&&(c=c.slice(0,77)+"..."),r.innerHTML="<div><strong>"+o(c)+"</strong></div>"+(d?'<div class="meta">'+o(d)+"</div>":"")+(f?'<div class="meta" style="font-size:11px;color:var(--accent);">'+o(f)+"</div>":""),p.appendChild(r)})}catch(l){const e=document.getElementById("sessions");e&&(e.innerHTML='<div class="meta" style="padding:20px; color:var(--red-hi);">Error loading sessions.</div>')}}async function x(){const e=document.getElementById("messages");if(m)try{if("opencode"===u){const t=await s("/api/messages?session="+encodeURIComponent(m));e.innerHTML="",t.slice(-40).forEach(t=>{const n=(t.parts||[]).filter(e=>"text"===e.type).map(e=>e.text).join("").trim();if(!n)return;const s=document.createElement("div");s.className="msg "+("assistant"===(t.info&&t.info.role)?"a":"u"),s.innerHTML='<div class="meta">'+(t.info&&t.info.role)+" • "+i(a(t.info))+'</div><div class="t"></div>',s.querySelector(".t").textContent=n,e.appendChild(s)})}else{const t={claude:"/api/claude-sessions",codex:"/api/codex-sessions",gemini:"/api/gemini-sessions","crew-cli":"/api/crew-cli-sessions"}[u];if(!t)return void(e.innerHTML='<div class="meta">Engine not supported</div>');const n=await s(t),o=(n.sessions||n||[]).find(e=>e.id===m||e.sessionId===m);if(!o||!o.messages)return void(e.innerHTML='<div class="meta">No messages found</div>');e.innerHTML="",o.messages.slice(-40).forEach(t=>{const n=document.createElement("div");n.className="msg "+("assistant"===t.role?"a":"u");const s=t.ts?new Date(t.ts).toLocaleString():"";n.innerHTML='<div class="meta">'+t.role+(s?" • "+s:"")+'</div><div class="t"></div>',n.querySelector(".t").textContent=t.text||"",e.appendChild(n)})}e.scrollTop=e.scrollHeight}catch(t){e&&(e.innerHTML='<div class="meta">Error: '+t.message+"</div>")}else e&&(e.innerHTML='<div class="meta">No session selected.</div>')}function f(){c(),document.getElementById("sessionsView").classList.add("active"),d("navSwarm"),e.activeTab="swarm",t();const s=document.getElementById("sessions");s&&s.children.length>1?n("swarm"):(g(),x())}let y=!1,v="tasks",h="";const b=new Set(["agent.heartbeat","agent.online","agent.offline"]),w=new Set(["task.dispatched","task.done","task.completed","task.failed","task.cancelled","task.started","task.reply"]);function C(e){if(b.has(e.type))return!1;const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"";if(!n||"run_task"===n)return!1;if("tasks"===v&&!w.has(e.type))return!1;if("replies"===v&&!(t.reply||t.message||t.content))return!1;if(h){const t=h.toLowerCase();if(!((e.from||"").toLowerCase().includes(t)||(e.to||"").toLowerCase().includes(t)||n.toLowerCase().includes(t)||(e.type||"").toLowerCase().includes(t)))return!1}return!0}const E={"task.dispatched":{color:"var(--purple)",label:"dispatched"},"task.started":{color:"var(--amber)",label:"started"},"task.done":{color:"var(--green-hi)",label:"done"},"task.completed":{color:"var(--green-hi)",label:"completed"},"task.reply":{color:"var(--accent)",label:"reply"},"task.failed":{color:"var(--red-hi)",label:"failed"},"task.cancelled":{color:"var(--text-3)",label:"cancelled"}};async function L(){if(y)return;const e=document.getElementById("rtMessages"),t=document.getElementById("rtView");if(!e||!t)return;const n=0===e.children.length;if(n){const t=document.createElement("div");t.style.cssText="padding:20px;",t.textContent="Loading…",e.replaceChildren(t)}const o=(await s("/api/rt-messages")).filter(C).slice(-100),i=o.map(e=>{const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"";return`${e.type}|${e.from}|${e.to}|${n.slice(0,100)}`}).join("::");if(i===window._rtLastHash&&!n)return;window._rtLastHash=i;const a=()=>t.scrollHeight-t.scrollTop-t.clientHeight<100,r=a(),l=t.scrollTop,c=document.createDocumentFragment();if(o.length){const e=document.createElement("div");e.style.cssText="display:grid;grid-template-columns:auto auto 1fr auto;gap:10px;padding:4px 10px 6px;font-size:10px;font-weight:600;color:var(--text-3);letter-spacing:.06em;text-transform:uppercase;border-bottom:2px solid var(--border);margin-bottom:2px;",["Agent","Phase","Summary","Time"].forEach(t=>{const n=document.createElement("span");n.textContent=t,e.appendChild(n)}),c.appendChild(e),o.forEach(e=>c.appendChild(function(e){const t=e.payload||{},n=t.reply||t.prompt||t.message||t.content||"",s=e.type||"",o=E[s],i=e.ts?new Date(e.ts).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):"",a=n.split("\n").map(e=>e.trim()).find(e=>e.length>2)||n,r=a.length>90?a.slice(0,90)+"…":a,l=n.length>r.length||n.split("\n").length>1,c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:auto auto 1fr auto;align-items:center;gap:10px;padding:7px 10px;border-radius:6px;cursor:"+(l?"pointer":"default")+";transition:background .12s;border-bottom:1px solid var(--border);",c.onmouseenter=()=>{c.style.background="var(--bg-2)"},c.onmouseleave=()=>{c.style.background=""};const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:5px;white-space:nowrap;min-width:0;";const p=document.createElement("span");if(p.style.cssText="font-size:11px;font-weight:600;color:var(--text-1);max-width:110px;overflow:hidden;text-overflow:ellipsis;",p.textContent=(e.from||"?").replace("crew-",""),p.title=e.from||"",d.appendChild(p),e.to&&e.to!==e.from){const t=document.createElement("span");t.style.cssText="font-size:10px;color:var(--text-3);flex-shrink:0;",t.textContent="→";const n=document.createElement("span");n.style.cssText="font-size:11px;color:var(--text-2);max-width:110px;overflow:hidden;text-overflow:ellipsis;",n.textContent=(e.to||"").replace("crew-",""),n.title=e.to||"",d.appendChild(t),d.appendChild(n)}const m=document.createElement("div");m.style.cssText="display:flex;align-items:center;gap:4px;flex-shrink:0;";const u=document.createElement("span"),g=o||{color:"var(--text-3)",label:s.split(".").pop()||s};if(u.style.cssText="font-size:10px;font-weight:600;padding:2px 7px;border-radius:20px;white-space:nowrap;flex-shrink:0;color:#fff;background:"+g.color+";letter-spacing:.03em;",u.textContent=g.label,m.appendChild(u),"task.done"===s&&t.engineUsed){const e={claude:"#e07a5f",codex:"#8338ec",cursor:"#3d405b",opencode:"#06d6a0",gemini:"#4285f4","docker-sandbox":"#0db7ed"},n={claude:"🤖",codex:"🟣",cursor:"🖱",opencode:"⚡",gemini:"✨","docker-sandbox":"🐳"},s=t.engineUsed,o=document.createElement("span");o.style.cssText="font-size:10px;font-weight:600;padding:2px 6px;border-radius:20px;white-space:nowrap;flex-shrink:0;color:#fff;background:"+(e[s]||"var(--text-3)")+";",o.textContent=(n[s]||"")+" "+s,o.title="Executed by "+s,m.appendChild(o)}const x=document.createElement("span");x.style.cssText="font-size:12px;color:var(--text-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;",x.textContent=r;const f=document.createElement("div");f.style.cssText="display:flex;align-items:center;gap:6px;flex-shrink:0;";const y=document.createElement("span");if(y.style.cssText="font-size:10px;color:var(--text-3);white-space:nowrap;",y.textContent=i,f.appendChild(y),l){const e=document.createElement("span");e.style.cssText="font-size:10px;color:var(--text-3);",e.textContent="▸",f.appendChild(e)}if(c.appendChild(d),c.appendChild(m),c.appendChild(x),c.appendChild(f),l){const e=document.createElement("div");e.style.cssText="display:none;grid-column:1/-1;padding:8px 6px 4px;font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word;max-height:300px;overflow-y:auto;border-top:1px solid var(--border);margin-top:4px;font-family:monospace;",e.textContent=n;const t=document.createElement("div");t.style.cssText="display:grid;grid-template-columns:1fr;border-radius:6px;overflow:hidden;border-bottom:1px solid var(--border);",c.style.borderBottom="none";let s=!1;return c.onclick=()=>{s=!s,e.style.display=s?"block":"none";const t=f.querySelector("span:last-child");t&&(t.textContent=s?"▾":"▸")},t.appendChild(c),t.appendChild(e),t}return c}(e)))}else{const e=document.createElement("div");e.style.cssText="padding:24px;text-align:center;font-size:12px;color:var(--text-3);",e.textContent="No events match the current filter.",c.appendChild(e)}if(e.replaceChildren(c),r)t.scrollTop=t.scrollHeight;else{const e=Math.max(0,t.scrollHeight-t.clientHeight);t.scrollTop=Math.min(l,e)}const d=document.getElementById("rtScrollBtn");d&&(d.style.display=a()?"none":"block"),t._scrollListenerBound||(t._scrollListenerBound=!0,t.addEventListener("scroll",()=>{d&&(d.style.display=a()?"none":"block")}))}function k(){y=!y;const e=document.getElementById("rtPauseBtn");e&&(e.textContent=y?"▶ Resume":"⏸ Pause",e.style.background=y?"var(--accent)":"",e.style.color=y?"#fff":"")}function T(){const e=document.getElementById("rtMessages");e&&(e.innerHTML='<div class="meta" style="padding:20px;text-align:center;opacity:.6;">Cleared. New messages will appear on next poll.</div>')}function I(){c(),document.getElementById("rtView").classList.add("active"),d("navRT"),function(){document.querySelectorAll(".rt-filter-chip").forEach(e=>{e.addEventListener("click",()=>{v=e.dataset.filter,document.querySelectorAll(".rt-filter-chip").forEach(t=>{const n=t===e;t.style.background=n?"var(--accent)":"transparent",t.style.color=n?"#fff":"var(--text-2)",t.classList.toggle("active",n)}),L()})});const e=document.getElementById("rtSearch");e&&e.addEventListener("input",()=>{h=e.value.trim(),L()})}(),L();const e=document.getElementById("rtScrollBtn");e&&(e.style.display="none")}async function B(){const e=document.getElementById("dlqMessages");e&&(e.innerHTML='<div style="padding:20px;">Loading…</div>');const t=await s("/api/dlq"),n=document.getElementById("dlqBadge");n&&(n.textContent=t.length,n.classList.toggle("hidden",!t.length)),e&&(e.innerHTML=t.length?t.map(e=>{const t=e.key||(e.filename||"").replace(".json","")||"?",n=o(t);return'<div class="msg dlq-item"><div class="meta"><strong>⚠️ Failed</strong> | '+(e.agent||"?")+" | "+(e.failedAt?new Date(e.failedAt).toLocaleString():"")+' <button class="replay-btn" data-action="replayDLQ" data-arg="'+n+'">Replay</button> <button data-action="deleteDLQ" data-arg="'+n+'" style="font-size:11px;padding:3px 8px;border-radius:4px;border:1px solid var(--red-hi);background:transparent;color:var(--red-hi);cursor:pointer;">Delete</button></div><div class="t">'+(e.error||"")+"</div></div>"}).join(""):'<div class="meta" style="padding:20px; text-align:center;">✓ DLQ empty</div>')}async function H(e){confirm("Replay?")&&(await l("/api/dlq/replay",{key:e}),r("Replayed"),B())}async function M(e){if(confirm("Delete this DLQ entry?"))try{await fetch("/api/dlq/"+encodeURIComponent(e),{method:"DELETE"}),r("DLQ entry deleted"),B()}catch(t){r("Failed: "+t.message,!0)}}function z(){c(),document.getElementById("dlqView").classList.add("active"),d("navDLQ"),B()}export{I as a,f as b,T as c,M as d,p as i,H as r,z as s,k as t};
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as t,s as e,g as o,k as i,c as a}from"./core-utils-CAVnDoe1.js";const n={"grok-4-1-fast":[.2,.5],"grok-4-fast":[.2,.5],"grok-4":[3,15],"grok-3-mini":[.3,.5],"grok-3":[3,15],"grok-code-fast":[.2,1.5],"grok-beta":[5,15],"gpt-5.3-codex":[2.5,20],"gpt-5.2-codex":[1.75,14],"gpt-5.2":[1.75,14],"gpt-5.1-codex-max":[2.5,20],"gpt-5.1-codex-mini":[.25,2],"gpt-5.1-codex":[1.25,10],"gpt-5.1":[1.25,10],"gpt-5-codex":[1.25,10],"gpt-5-nano":[.15,.6],"gpt-5":[1.25,10],"codex-mini":[.25,2],"gpt-oss-120b":[.9,.9],"gpt-oss-20b":[.2,.2],"gpt-4o-mini":[.15,.6],"gpt-4o":[2.5,10],"gpt-4":[30,60],"deepseek-reasoner":[.7,2.5],"deepseek-chat":[.27,1.1],"mistral-large":[.5,1.5],"mistral-small":[.1,.3],"gemini-3.1-pro":[2.5,15],"gemini-3.1-flash":[.075,.3],"gemini-3-pro":[2.5,15],"gemini-3-flash":[.075,.3],"gemini-2.5-pro":[1.25,10],"gemini-2.5-flash-lite":[.04,.15],"gemini-2.5-flash":[.075,.3],"gemini-2.0-flash-lite":[.075,.3],"gemini-2.0-flash":[.1,.4],"claude-opus-4":[15,75],"claude-sonnet-4":[3,15],"claude-haiku-4":[.8,4],"claude-3-5-haiku":[.8,4],"claude-3-haiku":[.25,1.25],"claude-3-5-sonnet":[3,15],"claude-3-7-sonnet":[3,15],"kimi-k2-instruct":[1,3],"kimi-k2":[.6,2.5],"llama-4-maverick":[.5,.77],"llama-4-scout":[.11,.34],"llama-3.3-70b":[.59,.79],"llama-3.1-70b":[.59,.79],"llama3.1-70b":[.59,.79],"llama-3.1-8b":[.05,.08],"llama3.1-8b":[.1,.1],"qwen3-32b":[.29,.39],"llama-guard":[.2,.2],"sonar-pro":[3,15],sonar:[1,1],"big-pickle":[0,0],"trinity-large-preview":[0,0],"minimax-m2.5-free":[0,0],"glm-":[.1,.1],minimax:[.3,1],default:[1,3]};function s(t){let e=0;for(const[o,i]of Object.entries(t||{})){const t=Object.keys(n).find(t=>o.toLowerCase().includes(t))||"default",[a,s]=n[t];e+=i.prompt/1e6*a+i.completion/1e6*s}return e}async function r(){const t=document.getElementById("tokenUsageWidget");if(!t)return;const e=await o("/api/token-usage").catch(()=>({})),i=(e.prompt||0)+(e.completion||0),a=s(e.byModel);let r='<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:12px;"><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--accent);">'+(e.calls||0).toLocaleString()+'</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">LLM calls</div></div><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--green);">'+(i/1e3).toFixed(1)+'k</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">total tokens</div></div><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--yellow);">$'+a.toFixed(4)+'</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">est. cost (all-time)</div></div></div>';const l=e.byDay||{},d=Object.keys(l).sort().reverse().slice(0,14);if(d.length){const t=Math.max(...d.map(function(t){return s(l[t].byModel||{})}),1e-4);r+='<div style="font-size:11px;font-weight:600;color:var(--text-2);margin:12px 0 6px;">Daily cost (last '+d.length+" days)</div>",r+='<div style="display:flex;flex-direction:column;gap:3px;">',d.forEach(function(e){const o=l[e],i=s(o.byModel||{}),a=Math.max(i/t*100,2),n=((o.prompt||0)+(o.completion||0))/1e3,d=e===(new Date).toISOString().slice(0,10);r+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:70px;color:var(--text-3);flex-shrink:0;">'+(d?"today":e.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:14px;overflow:hidden;"><div style="width:'+a.toFixed(1)+"%;height:100%;background:"+(d?"var(--accent)":"var(--green)")+';border-radius:3px;"></div></div><span style="width:52px;text-align:right;color:var(--yellow);font-weight:600;">$'+i.toFixed(4)+'</span><span style="width:44px;text-align:right;color:var(--text-3);">'+n.toFixed(1)+"k</span></div>"}),r+="</div>"}else r+='<div style="font-size:11px;color:var(--text-3);margin-top:8px;">No daily history yet — data accumulates with next LLM call after restart.</div>';Object.keys(e.byModel||{}).length&&(r+='<div style="font-size:11px;color:var(--text-3);margin:12px 0 6px;">By model (all-time)</div>',Object.entries(e.byModel||{}).sort((t,e)=>e[1].prompt+e[1].completion-(t[1].prompt+t[1].completion)).forEach(function(t){const e=t[0],o=t[1],i=Object.keys(n).find(function(t){return e.toLowerCase().includes(t)})||"default",a=n[i],s=o.prompt/1e6*a[0]+o.completion/1e6*a[1];r+='<div style="display:flex;justify-content:space-between;font-size:11px;padding:3px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+((o.prompt+o.completion)/1e3).toFixed(1)+"k tok · $"+s.toFixed(4)+"</span></div>"})),t.innerHTML=r}async function l(e){var n;const s=document.getElementById("ocStatsWidget");if(!s)return;const r=(null==(n=document.getElementById("ocStatsDays"))?void 0:n.value)||"14";e&&e(null),i(s);try{const t=await o("/api/opencode-stats?days="+r);if(!t.ok||!Object.keys(t.byDay||{}).length)return void a(s,t.error||"No OpenCode data found");const i=t.byDay,n=Object.keys(i).sort().reverse(),l=n.reduce(function(t,e){return t+i[e].cost},0),d=n.reduce(function(t,e){return t+i[e].input_tok},0),c=n.reduce(function(t,e){return t+i[e].output_tok},0),p=n.reduce(function(t,e){return t+i[e].calls},0),g=Math.max(...n.map(function(t){return i[t].cost}),1e-4);let x='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:16px;"><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--yellow);">$'+l.toFixed(4)+'</div><div style="font-size:11px;color:var(--text-3);">total cost</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--accent);">'+p.toLocaleString()+'</div><div style="font-size:11px;color:var(--text-3);">messages</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--green);">'+(d/1e6).toFixed(1)+'M</div><div style="font-size:11px;color:var(--text-3);">input tokens</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--green);">'+(c/1e6).toFixed(2)+'M</div><div style="font-size:11px;color:var(--text-3);">output tokens</div></div></div>';x+='<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:16px;">';const y=(new Date).toISOString().slice(0,10);n.forEach(function(t){const e=i[t],o=Math.max(e.cost/g*100,e.cost>0?2:0),a=t===y,n=(e.input_tok+e.output_tok)/1e6;x+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:70px;color:var(--text-3);flex-shrink:0;">'+(a?"today":t.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:16px;overflow:hidden;"><div style="width:'+o.toFixed(1)+"%;height:100%;background:"+(a?"var(--accent)":"var(--green)")+';border-radius:3px;opacity:0.85;"></div></div><span style="width:60px;text-align:right;color:var(--yellow);font-weight:600;">$'+e.cost.toFixed(4)+'</span><span style="width:50px;text-align:right;color:var(--text-3);">'+n.toFixed(2)+'M</span><span style="width:36px;text-align:right;color:var(--text-3);">'+e.calls+"</span></div>"}),x+="</div>";const v={};n.forEach(function(t){Object.entries(i[t].byModel||{}).forEach(function(t){const e=t[0],o=t[1];v[e]||(v[e]={cost:0,input_tok:0,output_tok:0,calls:0}),v[e].cost+=o.cost,v[e].input_tok+=o.input_tok,v[e].output_tok+=o.output_tok,v[e].calls+=o.calls})});const f=Object.entries(v).sort(function(t,e){return e[1].cost-t[1].cost});f.length&&(x+='<div style="font-size:11px;color:var(--text-3);margin-bottom:6px;">By model</div>',f.forEach(function(t){const e=t[0],o=t[1],i=(o.input_tok+o.output_tok)/1e6;x+='<div style="display:flex;justify-content:space-between;align-items:center;font-size:11px;padding:3px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+i.toFixed(2)+"M tok · "+o.calls+' calls · <span style="color:var(--yellow);font-weight:600;">$'+o.cost.toFixed(4)+"</span></span></div>"})),e&&e(l),s.innerHTML=x}catch(l){t(s,"Error: "+l.message)}}async function d(){try{const t=await o("/api/crew-lead/status"),e=document.getElementById("crewLeadBadge");t.online?(e.textContent="● online",e.className="status-badge status-running"):(e.textContent="● offline",e.className="status-badge status-stopped")}catch{}}function c(t){const e=document.getElementById("taskLifecycleContainer");if(!e)return;if(!(t=t||[]).length)return void(e.innerHTML='<div class="card" style="padding:12px;"><div class="meta" style="font-size:12px;">Recent task lifecycle (dispatched → completed/failed/cancelled). Dispatch a task to see events.</div></div>');const o=t.slice().reverse().slice(0,15).map(t=>{const e=t.data||{},o=e.phase||"",i="completed"===o?"var(--green)":"failed"===o||"cancelled"===o?"var(--red)":"var(--accent)";return'<tr style="border-bottom:1px solid var(--border);"><td style="padding:6px 10px;font-size:11px;color:var(--text-3);">'+(t.occurredAt||"").replace("T"," ").slice(0,19)+'</td><td style="padding:6px 10px;font-size:12px;"><span style="color:'+i+';">'+o+'</span></td><td style="padding:6px 10px;font-size:12px;">'+(e.agentId||"")+'</td><td style="padding:6px 10px;font-size:11px;color:var(--text-3);">'+(e.taskId||"").slice(0,20)+"</td></tr>"}).join("");e.innerHTML='<div class="card" style="overflow:auto;"><div style="font-size:12px;font-weight:600;padding:8px 12px;border-bottom:1px solid var(--border);">Task lifecycle (schema 1.1)</div><table style="width:100%;border-collapse:collapse;font-size:12px;"><thead><tr style="border-bottom:1px solid var(--border);"><th style="text-align:left;padding:6px 10px;">Time</th><th style="text-align:left;padding:6px 10px;">Phase</th><th style="text-align:left;padding:6px 10px;">Agent</th><th style="text-align:left;padding:6px 10px;">Task ID</th></tr></thead><tbody>'+o+"</tbody></table></div>"}const p={read_file:"read",write_file:"write",mkdir:"mkdir",run_cmd:"run",dispatch:"dispatch",skill:"skill",define_skill:"define_skill",git:"git",telegram:"tg",whatsapp:"wa"};async function g(){const e=document.getElementById("toolMatrixContainer");if(e)try{const t=await fetch("/api/health"),o=await t.json().catch(()=>({}));if(!t.ok||!o.ok){const i=o.error||(401===t.status?"Unauthorized":t.statusText||"Request failed");return void(e.innerHTML='<div class="card" style="padding:16px;"><div style="color:var(--yellow);font-size:13px;font-weight:600;">Health check failed</div><div style="color:var(--text-2);font-size:12px;margin-top:8px;">'+(401===t.status?"RT token missing or invalid. Set it in Settings → System (RT token) or in ~/.crewswarm/crewswarm.json (rt.authToken).":i)+'</div><div style="color:var(--text-3);font-size:11px;margin-top:8px;">Ensure crew-lead is running on :5010 (Services tab).</div></div>')}window._telemetryEvents=o.telemetry||[],c(o.telemetry||[]);const i=(o.agents||[]).filter(t=>"crew-lead"!==(t.id||"").toLowerCase()),a=window._crewLeadInfo||{name:"Crew Lead",emoji:"🧠"},n=[{id:"crew-lead",name:a.name,emoji:a.emoji,tools:["read_file","write_file","mkdir","run_cmd","web_search","web_fetch","skill","define_skill","dispatch","telegram","whatsapp"]},...i],s=[...new Set(["define_skill","skill",...n.flatMap(t=>Array.isArray(t.tools)?t.tools:Object.keys(t.tools||{}))])].sort(),r=s.map(t=>p[t]||t);if(!n.length)return void(e.innerHTML='<div class="card" style="padding:16px;"><div style="color:var(--text-2);font-size:13px;">No agents in roster.</div><div style="color:var(--text-3);font-size:12px;margin-top:6px;">Add agents in Settings → Agents (or ~/.crewswarm/crewswarm.json), then start bridges from Services.</div></div>');let l='<div class="card" style="overflow:auto;"><table style="width:100%;border-collapse:collapse;font-size:12px;"><thead><tr style="border-bottom:1px solid var(--border);"><th style="text-align:left;padding:8px 12px;">Agent</th>';s.forEach((t,e)=>{l+='<th style="text-align:center;padding:8px 8px;" title="'+(t||"")+'">'+(r[e]||t)+"</th>"}),l+='<th style="text-align:right;padding:8px 12px;">Quick action</th></tr></thead><tbody>',n.forEach(t=>{const e=Array.isArray(t.tools)?t.tools:t.tools?Object.keys(t.tools).filter(e=>t.tools[e]):[],o=(t.emoji||"")+" "+(t.name||t.id||"");l+='<tr style="border-bottom:1px solid var(--border);">',l+='<td style="padding:8px 12px;"><strong>'+(o||t.id).replace(/</g,"<")+"</strong></td>",s.forEach(t=>{const o=e.includes(t);l+='<td style="text-align:center;padding:6px 8px;">'+(o?'<span style="color:var(--green);" title="'+t+'">✓</span>':'<span style="color:var(--text-3);">—</span>')+"</td>"}),l+='<td style="text-align:right;padding:8px 12px;"><button class="btn-ghost" style="font-size:11px;" data-action="restartAgentFromUI" data-arg="'+(t.id||"").replace(/"/g,""")+'">Restart</button></td></tr>'}),l+="</tbody></table></div>",e.innerHTML=l}catch(o){t(e,"Error loading health: "+(o.message||""))}}async function x(t){if(!t)return;const o=document.querySelector(`button[data-action="restartAgentFromUI"][data-arg="${t}"]`);o&&(o.disabled=!0,o.style.opacity="0.5",o.style.cursor="not-allowed");const i=Date.now(),a=window._lastAgentRestart||{};if(a[t]&&i-a[t]<3e3)return e("⏳ Restart already in progress...","warning"),void(o&&(o.disabled=!1,o.style.opacity="",o.style.cursor=""));window._lastAgentRestart||(window._lastAgentRestart={}),window._lastAgentRestart[t]=i;try{const i=await fetch("/api/agents/"+encodeURIComponent(t)+"/restart",{method:"POST",headers:{"Content-Type":"application/json"}}),a=await i.json();a.ok?(e("Restarting "+t+"…"),setTimeout(()=>{var t;if("usage"===(null==(t=window.appState)?void 0:t.activeTab)){const t=document.getElementById("healthAgentList");t&&null!==t.offsetParent&&window.loadAgentHealth&&window.loadAgentHealth()}},3e3)):(e(a.error||"Restart failed","error"),o&&(o.disabled=!1,o.style.opacity="",o.style.cursor=""))}catch(n){e(n.message||"Request failed","error"),o&&(o.disabled=!1,o.style.opacity="",o.style.cursor="")}}export{g as a,r as b,d as c,c as d,s as e,l,x as r};
|
|
1
|
+
import{d as t,s as e,g as o,k as i,c as a}from"./core-utils-CmOkXgzi.js";const n={"grok-4-1-fast":[.2,.5],"grok-4-fast":[.2,.5],"grok-4":[3,15],"grok-3-mini":[.3,.5],"grok-3":[3,15],"grok-code-fast":[.2,1.5],"grok-beta":[5,15],"gpt-5.3-codex":[2.5,20],"gpt-5.2-codex":[1.75,14],"gpt-5.2":[1.75,14],"gpt-5.1-codex-max":[2.5,20],"gpt-5.1-codex-mini":[.25,2],"gpt-5.1-codex":[1.25,10],"gpt-5.1":[1.25,10],"gpt-5-codex":[1.25,10],"gpt-5-nano":[.15,.6],"gpt-5":[1.25,10],"codex-mini":[.25,2],"gpt-oss-120b":[.9,.9],"gpt-oss-20b":[.2,.2],"gpt-4o-mini":[.15,.6],"gpt-4o":[2.5,10],"gpt-4":[30,60],"deepseek-reasoner":[.7,2.5],"deepseek-chat":[.27,1.1],"mistral-large":[.5,1.5],"mistral-small":[.1,.3],"gemini-3.1-pro":[2.5,15],"gemini-3.1-flash":[.075,.3],"gemini-3-pro":[2.5,15],"gemini-3-flash":[.075,.3],"gemini-2.5-pro":[1.25,10],"gemini-2.5-flash-lite":[.04,.15],"gemini-2.5-flash":[.075,.3],"gemini-2.0-flash-lite":[.075,.3],"gemini-2.0-flash":[.1,.4],"claude-opus-4":[15,75],"claude-sonnet-4":[3,15],"claude-haiku-4":[.8,4],"claude-3-5-haiku":[.8,4],"claude-3-haiku":[.25,1.25],"claude-3-5-sonnet":[3,15],"claude-3-7-sonnet":[3,15],"kimi-k2-instruct":[1,3],"kimi-k2":[.6,2.5],"llama-4-maverick":[.5,.77],"llama-4-scout":[.11,.34],"llama-3.3-70b":[.59,.79],"llama-3.1-70b":[.59,.79],"llama3.1-70b":[.59,.79],"llama-3.1-8b":[.05,.08],"llama3.1-8b":[.1,.1],"qwen3-32b":[.29,.39],"llama-guard":[.2,.2],"sonar-pro":[3,15],sonar:[1,1],"big-pickle":[0,0],"trinity-large-preview":[0,0],"minimax-m2.5-free":[0,0],"glm-":[.1,.1],minimax:[.3,1],default:[1,3]};function s(t){let e=0;for(const[o,i]of Object.entries(t||{})){const t=Object.keys(n).find(t=>o.toLowerCase().includes(t))||"default",[a,s]=n[t];e+=i.prompt/1e6*a+i.completion/1e6*s}return e}async function r(){const t=document.getElementById("tokenUsageWidget");if(!t)return;const e=await o("/api/token-usage").catch(()=>({})),i=(e.prompt||0)+(e.completion||0),a=s(e.byModel);let r='<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:12px;"><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--accent);">'+(e.calls||0).toLocaleString()+'</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">LLM calls</div></div><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--green);">'+(i/1e3).toFixed(1)+'k</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">total tokens</div></div><div style="text-align:center;"><div style="font-size:20px;font-weight:700;color:var(--yellow);">$'+a.toFixed(4)+'</div><div style="font-size:11px;color:var(--text-3);margin-top:2px;">est. cost (all-time)</div></div></div>';const l=e.byDay||{},d=Object.keys(l).sort().reverse().slice(0,14);if(d.length){const t=Math.max(...d.map(function(t){return s(l[t].byModel||{})}),1e-4);r+='<div style="font-size:11px;font-weight:600;color:var(--text-2);margin:12px 0 6px;">Daily cost (last '+d.length+" days)</div>",r+='<div style="display:flex;flex-direction:column;gap:3px;">',d.forEach(function(e){const o=l[e],i=s(o.byModel||{}),a=Math.max(i/t*100,2),n=((o.prompt||0)+(o.completion||0))/1e3,d=e===(new Date).toISOString().slice(0,10);r+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:70px;color:var(--text-3);flex-shrink:0;">'+(d?"today":e.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:14px;overflow:hidden;"><div style="width:'+a.toFixed(1)+"%;height:100%;background:"+(d?"var(--accent)":"var(--green)")+';border-radius:3px;"></div></div><span style="width:52px;text-align:right;color:var(--yellow);font-weight:600;">$'+i.toFixed(4)+'</span><span style="width:44px;text-align:right;color:var(--text-3);">'+n.toFixed(1)+"k</span></div>"}),r+="</div>"}else r+='<div style="font-size:11px;color:var(--text-3);margin-top:8px;">No daily history yet — data accumulates with next LLM call after restart.</div>';Object.keys(e.byModel||{}).length&&(r+='<div style="font-size:11px;color:var(--text-3);margin:12px 0 6px;">By model (all-time)</div>',Object.entries(e.byModel||{}).sort((t,e)=>e[1].prompt+e[1].completion-(t[1].prompt+t[1].completion)).forEach(function(t){const e=t[0],o=t[1],i=Object.keys(n).find(function(t){return e.toLowerCase().includes(t)})||"default",a=n[i],s=o.prompt/1e6*a[0]+o.completion/1e6*a[1];r+='<div style="display:flex;justify-content:space-between;font-size:11px;padding:3px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+((o.prompt+o.completion)/1e3).toFixed(1)+"k tok · $"+s.toFixed(4)+"</span></div>"})),t.innerHTML=r}async function l(e){var n;const s=document.getElementById("ocStatsWidget");if(!s)return;const r=(null==(n=document.getElementById("ocStatsDays"))?void 0:n.value)||"14";e&&e(null),i(s);try{const t=await o("/api/opencode-stats?days="+r);if(!t.ok||!Object.keys(t.byDay||{}).length)return void a(s,t.error||"No OpenCode data found");const i=t.byDay,n=Object.keys(i).sort().reverse(),l=n.reduce(function(t,e){return t+i[e].cost},0),d=n.reduce(function(t,e){return t+i[e].input_tok},0),c=n.reduce(function(t,e){return t+i[e].output_tok},0),p=n.reduce(function(t,e){return t+i[e].calls},0),g=Math.max(...n.map(function(t){return i[t].cost}),1e-4);let x='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:16px;"><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--yellow);">$'+l.toFixed(4)+'</div><div style="font-size:11px;color:var(--text-3);">total cost</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--accent);">'+p.toLocaleString()+'</div><div style="font-size:11px;color:var(--text-3);">messages</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--green);">'+(d/1e6).toFixed(1)+'M</div><div style="font-size:11px;color:var(--text-3);">input tokens</div></div><div style="text-align:center;"><div style="font-size:18px;font-weight:700;color:var(--green);">'+(c/1e6).toFixed(2)+'M</div><div style="font-size:11px;color:var(--text-3);">output tokens</div></div></div>';x+='<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:16px;">';const y=(new Date).toISOString().slice(0,10);n.forEach(function(t){const e=i[t],o=Math.max(e.cost/g*100,e.cost>0?2:0),a=t===y,n=(e.input_tok+e.output_tok)/1e6;x+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:70px;color:var(--text-3);flex-shrink:0;">'+(a?"today":t.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:16px;overflow:hidden;"><div style="width:'+o.toFixed(1)+"%;height:100%;background:"+(a?"var(--accent)":"var(--green)")+';border-radius:3px;opacity:0.85;"></div></div><span style="width:60px;text-align:right;color:var(--yellow);font-weight:600;">$'+e.cost.toFixed(4)+'</span><span style="width:50px;text-align:right;color:var(--text-3);">'+n.toFixed(2)+'M</span><span style="width:36px;text-align:right;color:var(--text-3);">'+e.calls+"</span></div>"}),x+="</div>";const v={};n.forEach(function(t){Object.entries(i[t].byModel||{}).forEach(function(t){const e=t[0],o=t[1];v[e]||(v[e]={cost:0,input_tok:0,output_tok:0,calls:0}),v[e].cost+=o.cost,v[e].input_tok+=o.input_tok,v[e].output_tok+=o.output_tok,v[e].calls+=o.calls})});const f=Object.entries(v).sort(function(t,e){return e[1].cost-t[1].cost});f.length&&(x+='<div style="font-size:11px;color:var(--text-3);margin-bottom:6px;">By model</div>',f.forEach(function(t){const e=t[0],o=t[1],i=(o.input_tok+o.output_tok)/1e6;x+='<div style="display:flex;justify-content:space-between;align-items:center;font-size:11px;padding:3px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+i.toFixed(2)+"M tok · "+o.calls+' calls · <span style="color:var(--yellow);font-weight:600;">$'+o.cost.toFixed(4)+"</span></span></div>"})),e&&e(l),s.innerHTML=x}catch(l){t(s,"Error: "+l.message)}}async function d(){try{const t=await o("/api/crew-lead/status"),e=document.getElementById("crewLeadBadge");t.online?(e.textContent="● online",e.className="status-badge status-running"):(e.textContent="● offline",e.className="status-badge status-stopped")}catch{}}function c(t){const e=document.getElementById("taskLifecycleContainer");if(!e)return;if(!(t=t||[]).length)return void(e.innerHTML='<div class="card" style="padding:12px;"><div class="meta" style="font-size:12px;">Recent task lifecycle (dispatched → completed/failed/cancelled). Dispatch a task to see events.</div></div>');const o=t.slice().reverse().slice(0,15).map(t=>{const e=t.data||{},o=e.phase||"",i="completed"===o?"var(--green)":"failed"===o||"cancelled"===o?"var(--red)":"var(--accent)";return'<tr style="border-bottom:1px solid var(--border);"><td style="padding:6px 10px;font-size:11px;color:var(--text-3);">'+(t.occurredAt||"").replace("T"," ").slice(0,19)+'</td><td style="padding:6px 10px;font-size:12px;"><span style="color:'+i+';">'+o+'</span></td><td style="padding:6px 10px;font-size:12px;">'+(e.agentId||"")+'</td><td style="padding:6px 10px;font-size:11px;color:var(--text-3);">'+(e.taskId||"").slice(0,20)+"</td></tr>"}).join("");e.innerHTML='<div class="card" style="overflow:auto;"><div style="font-size:12px;font-weight:600;padding:8px 12px;border-bottom:1px solid var(--border);">Task lifecycle (schema 1.1)</div><table style="width:100%;border-collapse:collapse;font-size:12px;"><thead><tr style="border-bottom:1px solid var(--border);"><th style="text-align:left;padding:6px 10px;">Time</th><th style="text-align:left;padding:6px 10px;">Phase</th><th style="text-align:left;padding:6px 10px;">Agent</th><th style="text-align:left;padding:6px 10px;">Task ID</th></tr></thead><tbody>'+o+"</tbody></table></div>"}const p={read_file:"read",write_file:"write",mkdir:"mkdir",run_cmd:"run",dispatch:"dispatch",skill:"skill",define_skill:"define_skill",git:"git",telegram:"tg",whatsapp:"wa"};async function g(){const e=document.getElementById("toolMatrixContainer");if(e)try{const t=await fetch("/api/health"),o=await t.json().catch(()=>({}));if(!t.ok||!o.ok){const i=o.error||(401===t.status?"Unauthorized":t.statusText||"Request failed");return void(e.innerHTML='<div class="card" style="padding:16px;"><div style="color:var(--yellow);font-size:13px;font-weight:600;">Health check failed</div><div style="color:var(--text-2);font-size:12px;margin-top:8px;">'+(401===t.status?"RT token missing or invalid. Set it in Settings → System (RT token) or in ~/.crewswarm/crewswarm.json (rt.authToken).":i)+'</div><div style="color:var(--text-3);font-size:11px;margin-top:8px;">Ensure crew-lead is running on :5010 (Services tab).</div></div>')}window._telemetryEvents=o.telemetry||[],c(o.telemetry||[]);const i=(o.agents||[]).filter(t=>"crew-lead"!==(t.id||"").toLowerCase()),a=window._crewLeadInfo||{name:"Crew Lead",emoji:"🧠"},n=[{id:"crew-lead",name:a.name,emoji:a.emoji,tools:["read_file","write_file","mkdir","run_cmd","web_search","web_fetch","skill","define_skill","dispatch","telegram","whatsapp"]},...i],s=[...new Set(["define_skill","skill",...n.flatMap(t=>Array.isArray(t.tools)?t.tools:Object.keys(t.tools||{}))])].sort(),r=s.map(t=>p[t]||t);if(!n.length)return void(e.innerHTML='<div class="card" style="padding:16px;"><div style="color:var(--text-2);font-size:13px;">No agents in roster.</div><div style="color:var(--text-3);font-size:12px;margin-top:6px;">Add agents in Settings → Agents (or ~/.crewswarm/crewswarm.json), then start bridges from Services.</div></div>');let l='<div class="card" style="overflow:auto;"><table style="width:100%;border-collapse:collapse;font-size:12px;"><thead><tr style="border-bottom:1px solid var(--border);"><th style="text-align:left;padding:8px 12px;">Agent</th>';s.forEach((t,e)=>{l+='<th style="text-align:center;padding:8px 8px;" title="'+(t||"")+'">'+(r[e]||t)+"</th>"}),l+='<th style="text-align:right;padding:8px 12px;">Quick action</th></tr></thead><tbody>',n.forEach(t=>{const e=Array.isArray(t.tools)?t.tools:t.tools?Object.keys(t.tools).filter(e=>t.tools[e]):[],o=(t.emoji||"")+" "+(t.name||t.id||"");l+='<tr style="border-bottom:1px solid var(--border);">',l+='<td style="padding:8px 12px;"><strong>'+(o||t.id).replace(/</g,"<")+"</strong></td>",s.forEach(t=>{const o=e.includes(t);l+='<td style="text-align:center;padding:6px 8px;">'+(o?'<span style="color:var(--green);" title="'+t+'">✓</span>':'<span style="color:var(--text-3);">—</span>')+"</td>"}),l+='<td style="text-align:right;padding:8px 12px;"><button class="btn-ghost" style="font-size:11px;" data-action="restartAgentFromUI" data-arg="'+(t.id||"").replace(/"/g,""")+'">Restart</button></td></tr>'}),l+="</tbody></table></div>",e.innerHTML=l}catch(o){t(e,"Error loading health: "+(o.message||""))}}async function x(t){if(!t)return;const o=document.querySelector(`button[data-action="restartAgentFromUI"][data-arg="${t}"]`);o&&(o.disabled=!0,o.style.opacity="0.5",o.style.cursor="not-allowed");const i=Date.now(),a=window._lastAgentRestart||{};if(a[t]&&i-a[t]<3e3)return e("⏳ Restart already in progress...","warning"),void(o&&(o.disabled=!1,o.style.opacity="",o.style.cursor=""));window._lastAgentRestart||(window._lastAgentRestart={}),window._lastAgentRestart[t]=i;try{const i=await fetch("/api/agents/"+encodeURIComponent(t)+"/restart",{method:"POST",headers:{"Content-Type":"application/json"}}),a=await i.json();a.ok?(e("Restarting "+t+"…"),setTimeout(()=>{var t;if("usage"===(null==(t=window.appState)?void 0:t.activeTab)){const t=document.getElementById("healthAgentList");t&&null!==t.offsetParent&&window.loadAgentHealth&&window.loadAgentHealth()}},3e3)):(e(a.error||"Restart failed","error"),o&&(o.disabled=!1,o.style.opacity="",o.style.cursor=""))}catch(n){e(n.message||"Request failed","error"),o&&(o.disabled=!1,o.style.opacity="",o.style.cursor="")}}export{g as a,r as b,d as c,c as d,s as e,l,x as r};
|
|
Binary file
|
|
Binary file
|
package/apps/dashboard/dist/assets/{tab-workflows-tab-6QSXLJ0i.js → tab-workflows-tab-B-soSy1k.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{g as e,e as t,s as n,p as o}from"./core-utils-CAVnDoe1.js";let a=()=>{},l=()=>{},s=[],i=[];const d={selectedName:"",list:[],runStatus:{},editorWorkflow:null},r=[{id:"daily-research",name:"Daily Research Brief",description:"Research, summarize, then QA-check every weekday morning.",schedule:"0 9 * * 1-5",stages:[{agent:"crew-researcher",task:"Research top 5 updates for our current project and summarize key signals."},{agent:"crew-pm",task:"Turn the research into a concise daily brief with priorities and risks."},{agent:"crew-qa",task:"Review the brief for factual clarity and missing edge cases."}]},{id:"seo-content",name:"SEO Content Pipeline",description:"Generate SEO topic ideas, draft copy, then edit.",schedule:"30 10 * * 1,3,5",stages:[{agent:"crew-seo",task:"Find one high-intent keyword cluster and propose a short content outline."},{agent:"crew-copywriter",task:"Write a first draft from the outline. Keep it scannable and conversion-focused."},{agent:"crew-main",task:"Polish the draft and produce final publish-ready copy."}]},{id:"code-health",name:"Code Health Sweep",description:"Automated PM->Coder->QA quality pass.",schedule:"0 14 * * 1-5",stages:[{agent:"crew-pm",task:"Pick one high-value backlog item from project context and define acceptance criteria."},{agent:"crew-coder",task:"Implement the scoped item in small safe changes and summarize files touched."},{agent:"crew-qa",task:"Audit the changes, run tests, and report any regressions with severity."}]}];function c(e=""){return{name:e,description:"",enabled:!1,schedule:"",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:[{agent:"crew-main",task:"",tool:""}]}}function p(e={}){a=e.hideAllViews||a,l=e.setNavActive||l}async function m(){var t;a(),null==(t=document.getElementById("workflowsView"))||t.classList.add("active"),l("navWorkflows"),await async function(){try{const t=await e("/api/agents");s=(t||[]).map(e=>"string"==typeof e?e:e.id||e.agent).filter(Boolean).sort()}catch{s=[]}}(),await async function(){try{const t=await e("/api/skills");i=(t.skills||[]).map(e=>({name:e.name||"",description:e.description||"",type:e.type||(e.url?"api":"knowledge")})).filter(e=>e.name).sort((e,t)=>e.name.localeCompare(t.name))}catch{i=[]}}(),await f()}async function f(){const n=document.getElementById("workflowList");if(n){n.innerHTML='<div class="meta" style="padding:10px;">Loading workflows...</div>';try{const t=await e("/api/workflows/list");d.list=t.workflows||[],u(),d.selectedName?await w(d.selectedName):y(c());const n=t.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,o=document.getElementById("workflowTimezoneLabel");o&&(o.textContent=`Local timezone: ${n}`)}catch(o){n.innerHTML=`<div class="meta" style="padding:10px;color:var(--red-hi);">Failed to load workflows: ${t(o.message)}</div>`}}}function u(){const e=document.getElementById("workflowList");if(!e)return;const n=d.list||[];n.length?(e.innerHTML=n.map(e=>{var n;const o=e.name===d.selectedName?"background:var(--bg-2);border-color:var(--accent);":"",a=e.schedule?t(e.schedule):'<span style="opacity:0.7;">no schedule</span>',l=(null==(n=e.runState)?void 0:n.running)?'<span style="color:var(--green-hi);font-size:11px;">running</span>':"";return`\n <button class="btn-ghost workflow-row" data-workflow-name="${t(e.name)}" style="width:100%;text-align:left;display:flex;flex-direction:column;gap:4px;padding:10px;margin-bottom:8px;${o}">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:8px;">\n <strong style="font-size:13px;">${t(e.name)}</strong>\n ${l}\n </div>\n <div style="font-size:11px;color:var(--text-3);">${e.enabled?"enabled":"disabled"} · ${e.stageCount||0} stage(s)</div>\n <div style="font-size:11px;color:var(--text-2);font-family:monospace;">${a}</div>\n </button>\n `}).join(""),e.querySelectorAll(".workflow-row").forEach(e=>{e.addEventListener("click",async()=>{const t=e.dataset.workflowName||"";await w(t)})})):e.innerHTML='<div class="meta" style="padding:10px;">No workflows yet.</div>'}async function w(t){if(t)try{const n=await e(`/api/workflows/item?name=${encodeURIComponent(t)}`);d.selectedName=t,d.runStatus=n.runState||{},u(),y({name:t,...n.workflow||{}},n),await async function(t){const n=document.getElementById("workflowLog");if(!n||!t)return;try{const o=(await e(`/api/workflows/log?name=${encodeURIComponent(t)}&limit=120`)).lines||[];n.textContent=o.length?o.join("\n"):"No log lines yet.",n.scrollTop=n.scrollHeight}catch(o){n.textContent=`Failed to load log: ${o.message}`}}(t)}catch(o){n(`Failed to load workflow: ${o.message}`,"error")}}function g(e){const t=String(e||"").trim();if(!t)return"No schedule set. Add a cron expression or use a preset.";return{"*/15 * * * *":"Runs every 15 minutes","0 * * * *":"Runs hourly at minute 0","0 9 * * 1-5":"Runs weekdays at 9:00","0 9 * * *":"Runs daily at 9:00","0 0 * * 1":"Runs every Monday at midnight","0 8 1 * *":"Runs monthly on day 1 at 8:00"}[t]||"Custom cron schedule"}function y(e,o={}){const a=document.getElementById("workflowEditor");if(!a)return;const l={...c(),...e},p=Array.isArray(l.stages)&&l.stages.length?l.stages:c().stages;d.editorWorkflow={...l,stages:p.map(e=>({...e}))};const m=o.cronExample?t(o.cronExample):`*/15 * * * * cd ${t(window.location.pathname||".")} && node scripts/run-scheduled-pipeline.mjs ${t(l.name||"my-workflow")}`,u={agents:s.length?s.map(e=>`<code style="font-size:11px;">${t(e)}</code>`).join(" "):'<span style="font-size:11px;color:var(--text-3);">No agents loaded</span>',skills:i.length?i.map(e=>`<div style="font-size:11px;line-height:1.4;"><code>${t(e.name)}</code> <span style="color:var(--text-3);">(${t(e.type)})</span></div>`).join(""):'<span style="font-size:11px;color:var(--text-3);">No skills loaded</span>'};a.innerHTML=`\n <div class="card" style="display:flex;flex-direction:column;gap:12px;">\n <div style="display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfOpenTemplateLibraryBtn" class="btn-ghost" style="font-size:12px;">📚 Job Library</button>\n <button id="wfOpenSkillGuideBtn" class="btn-ghost" style="font-size:12px;">🧩 Skills & Agent Options</button>\n <button id="wfOpenJsonEditorBtn" class="btn-ghost" style="font-size:12px;">{ } Advanced JSON</button>\n </div>\n\n <div style="display:flex;gap:10px;flex-wrap:wrap;">\n <div style="flex:1;min-width:260px;">\n <label style="font-size:12px;font-weight:600;">Name</label>\n <input id="wfName" type="text" value="${t(l.name||"")}" placeholder="daily-research" style="width:100%;margin-top:4px;padding:8px 10px;" />\n </div>\n <div style="flex:1;min-width:260px;">\n <label style="font-size:12px;font-weight:600;">Description</label>\n <input id="wfDescription" type="text" value="${t(l.description||"")}" placeholder="What this workflow does" style="width:100%;margin-top:4px;padding:8px 10px;" />\n </div>\n </div>\n\n <div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;">\n <div style="min-width:280px;flex:1;">\n <label style="font-size:12px;font-weight:600;">Cron Schedule</label>\n <input id="wfSchedule" type="text" value="${t(l.schedule||"")}" placeholder="0 9 * * 1-5" style="width:100%;margin-top:4px;padding:8px 10px;font-family:monospace;" />\n <div style="font-size:11px;color:var(--text-3);margin-top:4px;">Format: minute hour day month weekday</div>\n <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;">${[{label:"Every 15m",cron:"*/15 * * * *"},{label:"Hourly",cron:"0 * * * *"},{label:"Daily 9am",cron:"0 9 * * *"},{label:"Weekdays 9am",cron:"0 9 * * 1-5"},{label:"Weekly Mon",cron:"0 0 * * 1"},{label:"Monthly",cron:"0 8 1 * *"}].map(e=>`<button class="btn-ghost wf-cron-preset" data-cron="${t(e.cron)}" style="font-size:11px;padding:4px 8px;">${t(e.label)}</button>`).join("")}</div>\n <div id="wfScheduleHint" style="font-size:11px;color:var(--text-2);margin-top:6px;">${t(g(l.schedule))}</div>\n </div>\n <label style="display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;padding-bottom:8px;">\n <input id="wfEnabled" type="checkbox" ${l.enabled?"checked":""} />\n Enabled\n </label>\n </div>\n\n <div id="workflowTimezoneLabel" style="font-size:11px;color:var(--text-3);"></div>\n\n <div>\n <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">\n <label style="font-size:12px;font-weight:600;">Stages (wave-like, runs top to bottom)</label>\n <button id="wfAddStageBtn" class="btn-ghost" style="font-size:12px;">+ Add Stage</button>\n </div>\n <div id="wfStagesWrap" style="display:flex;flex-direction:column;gap:8px;">\n ${p.map((e,n)=>{return`\n <div class="wf-stage-row" data-stage-index="${n}" style="border:1px solid var(--border);border-radius:8px;padding:10px;background:var(--bg-2);">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;">\n <strong style="font-size:12px;">Stage ${n+1}</strong>\n <div style="display:flex;gap:6px;flex-wrap:wrap;">\n <button class="btn-ghost wf-move-stage-up" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">↑</button>\n <button class="btn-ghost wf-move-stage-down" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">↓</button>\n <button class="btn-ghost wf-duplicate-stage" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">Duplicate</button>\n <button class="btn-red wf-remove-stage" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">Remove</button>\n </div>\n </div>\n <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px;">\n <div style="flex:1;min-width:220px;">\n <label style="font-size:11px;font-weight:600;">Agent</label>\n <select class="wf-agent" style="width:100%;margin-top:4px;padding:6px 8px;">${o=e.agent,Array.from(new Set([...s||[],"crew-main","crew-pm","crew-qa","crew-coder","crew-coder-front","crew-coder-back","crew-copywriter",o||""])).filter(Boolean).sort().map(e=>`<option value="${t(e)}" ${e===o?"selected":""}>${t(e)}</option>`).join("")}</select>\n </div>\n <div style="width:180px;">\n <label style="font-size:11px;font-weight:600;">Tool hint (optional)</label>\n <input class="wf-tool" type="text" value="${t(e.tool||"")}" placeholder="write_file" style="width:100%;margin-top:4px;padding:6px 8px;" />\n </div>\n </div>\n <div>\n <label style="font-size:11px;font-weight:600;">Task</label>\n <textarea class="wf-task" rows="3" style="width:100%;margin-top:4px;padding:8px 10px;font-family:monospace;">${t(e.task||"")}</textarea>\n </div>\n </div>\n `;var o}).join("")}\n </div>\n </div>\n\n <div style="display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfSaveBtn" class="btn">Save Workflow</button>\n <button id="wfRunBtn" class="btn-green">Run Now</button>\n <button id="wfDeleteBtn" class="btn-red">Delete</button>\n <button id="wfNewBtn" class="btn-ghost">New</button>\n <button id="wfRefreshBtn" class="btn-ghost">Refresh</button>\n </div>\n\n <div>\n <div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:4px;">Crontab example</div>\n <code style="display:block;background:var(--bg-2);border:1px solid var(--border);padding:8px 10px;border-radius:6px;overflow:auto;white-space:nowrap;">${m}</code>\n </div>\n\n <div id="wfLibraryModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:12000;align-items:center;justify-content:center;padding:18px;">\n <div style="width:min(960px,100%);max-height:85vh;overflow:auto;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:14px;">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;">\n <div style="font-size:14px;font-weight:700;">Workflow Job Library</div>\n <button id="wfCloseLibraryBtn" class="btn-ghost" style="font-size:12px;">Close</button>\n </div>\n <div style="font-size:12px;color:var(--text-2);margin-bottom:10px;">Pick a starter template, then customize stages/tasks.</div>\n <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:10px;">${r.map(e=>`\n <div style="border:1px solid var(--border);border-radius:8px;padding:10px;background:var(--bg-2);">\n <div style="font-size:12px;font-weight:700;">${t(e.name)}</div>\n <div style="font-size:11px;color:var(--text-3);margin-top:4px;">${t(e.description)}</div>\n <div style="font-size:11px;color:var(--text-2);font-family:monospace;margin-top:6px;">${t(e.schedule)}</div>\n <div style="margin-top:8px;">\n <button class="btn-ghost wf-apply-template" data-template-id="${t(e.id)}" style="font-size:11px;">Use Template</button>\n </div>\n </div>\n `).join("")}</div>\n <hr style="border:none;border-top:1px solid var(--border);margin:14px 0;" />\n <div style="font-size:12px;font-weight:700;margin-bottom:6px;">Available Agents</div>\n <div style="display:flex;gap:6px;flex-wrap:wrap;">${u.agents}</div>\n <div style="font-size:12px;font-weight:700;margin:12px 0 6px;">Available Skills</div>\n <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:6px;">${u.skills}</div>\n </div>\n </div>\n\n <div id="wfJsonModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:12000;align-items:center;justify-content:center;padding:18px;">\n <div style="width:min(920px,100%);max-height:85vh;overflow:auto;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:14px;">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;">\n <div style="font-size:14px;font-weight:700;">Advanced Workflow JSON</div>\n <button id="wfCloseJsonBtn" class="btn-ghost" style="font-size:12px;">Close</button>\n </div>\n <div style="font-size:12px;color:var(--text-2);margin-bottom:8px;">Edit raw JSON. Supports both <code>stages</code> and <code>steps</code>.</div>\n <textarea id="wfJsonTextarea" rows="18" style="width:100%;font-family:monospace;font-size:12px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg-2);"></textarea>\n <div style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfApplyJsonBtn" class="btn-green">Apply JSON</button>\n </div>\n </div>\n </div>\n </div>\n `;const w=document.getElementById("workflowTimezoneLabel");var k,E,B,I,z,S,$,L,A,N,D,T,J,C,O;w&&(w.textContent=`Local timezone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`),null==(k=document.getElementById("wfOpenTemplateLibraryBtn"))||k.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="flex")}),null==(E=document.getElementById("wfOpenSkillGuideBtn"))||E.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="flex")}),null==(B=document.getElementById("wfCloseLibraryBtn"))||B.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="none")}),null==(I=document.getElementById("wfLibraryModal"))||I.addEventListener("click",e=>{var t;"wfLibraryModal"===(null==(t=e.target)?void 0:t.id)&&(e.currentTarget.style.display="none")}),null==(z=document.getElementById("wfOpenJsonEditorBtn"))||z.addEventListener("click",e=>{var t;e.preventDefault();const n={...v().workflow,...(null==(t=d.editorWorkflow)?void 0:t.steps)?{steps:d.editorWorkflow.steps}:{}},o=document.getElementById("wfJsonTextarea");o&&(o.value=JSON.stringify(n,null,2));const a=document.getElementById("wfJsonModal");a&&(a.style.display="flex")}),null==(S=document.getElementById("wfCloseJsonBtn"))||S.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfJsonModal");t&&(t.style.display="none")}),null==($=document.getElementById("wfJsonModal"))||$.addEventListener("click",e=>{var t;"wfJsonModal"===(null==(t=e.target)?void 0:t.id)&&(e.currentTarget.style.display="none")}),null==(L=document.getElementById("wfApplyJsonBtn"))||L.addEventListener("click",e=>{e.preventDefault();try{const e=document.getElementById("wfJsonTextarea"),t=JSON.parse((null==e?void 0:e.value)||"{}"),o=v();y({name:o.name,description:t.description||o.workflow.description,enabled:t.enabled??o.workflow.enabled,schedule:t.schedule||o.workflow.schedule,timezone:t.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,stages:Array.isArray(t.stages)&&t.stages.length?t.stages:o.workflow.stages,...Array.isArray(t.steps)?{steps:t.steps}:{}});const a=document.getElementById("wfJsonModal");a&&(a.style.display="none"),n("Applied advanced JSON","success")}catch(t){n(`Invalid JSON: ${t.message}`,"error")}}),document.querySelectorAll(".wf-apply-template").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const o=e.dataset.templateId||"",a=r.find(e=>e.id===o);if(!a)return;const l=v();y({name:l.name||a.id,description:a.description,enabled:l.workflow.enabled,schedule:a.schedule,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:a.stages.map(e=>({...e,tool:e.tool||""}))});const s=document.getElementById("wfLibraryModal");s&&(s.style.display="none"),n(`Applied template: ${a.name}`,"success")})}),document.querySelectorAll(".wf-cron-preset").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=e.dataset.cron||"",o=document.getElementById("wfSchedule"),a=document.getElementById("wfScheduleHint");o&&(o.value=n),a&&(a.textContent=g(n))})}),null==(A=document.getElementById("wfSchedule"))||A.addEventListener("input",e=>{const t=document.getElementById("wfScheduleHint");t&&(t.textContent=g(e.target.value))}),null==(N=document.getElementById("wfAddStageBtn"))||N.addEventListener("click",e=>{e.preventDefault();const t=v({includeIncompleteStages:!0});t.workflow.stages.push({agent:"crew-main",task:"",tool:""}),y({name:t.name,...t.workflow})}),document.querySelectorAll(".wf-remove-stage").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});o.workflow.stages=o.workflow.stages.filter((e,t)=>t!==n),o.workflow.stages.length||(o.workflow.stages=[{agent:"crew-main",task:"",tool:""}]),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-move-stage-up").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1");if(n<=0)return;const o=v({includeIncompleteStages:!0}),[a]=o.workflow.stages.splice(n,1);o.workflow.stages.splice(n-1,0,a),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-move-stage-down").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});if(n<0||n>=o.workflow.stages.length-1)return;const[a]=o.workflow.stages.splice(n,1);o.workflow.stages.splice(n+1,0,a),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-duplicate-stage").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});if(n<0||n>=o.workflow.stages.length)return;const a=o.workflow.stages[n];o.workflow.stages.splice(n+1,0,{...a}),y({name:o.name,...o.workflow})})}),null==(D=document.getElementById("wfSaveBtn"))||D.addEventListener("click",x),null==(T=document.getElementById("wfRunBtn"))||T.addEventListener("click",b),null==(J=document.getElementById("wfDeleteBtn"))||J.addEventListener("click",h),null==(C=document.getElementById("wfNewBtn"))||C.addEventListener("click",()=>{d.selectedName="",y(c());const e=document.getElementById("workflowLog");e&&(e.textContent="")}),null==(O=document.getElementById("wfRefreshBtn"))||O.addEventListener("click",async()=>{await f()})}function v(e={}){var t,n,o,a,l;const{includeIncompleteStages:s=!1}=e,i=((null==(t=document.getElementById("wfName"))?void 0:t.value)||"").trim(),r=((null==(n=document.getElementById("wfDescription"))?void 0:n.value)||"").trim(),c=((null==(o=document.getElementById("wfSchedule"))?void 0:o.value)||"").trim(),p=!!(null==(a=document.getElementById("wfEnabled"))?void 0:a.checked),m=Array.from(document.querySelectorAll(".wf-stage-row")).map(e=>{var t,n,o,a,l,s;const i=(null==(n=null==(t=e.querySelector(".wf-agent"))?void 0:t.value)?void 0:n.trim())||"",d=(null==(a=null==(o=e.querySelector(".wf-tool"))?void 0:o.value)?void 0:a.trim())||"";return{agent:i,task:(null==(s=null==(l=e.querySelector(".wf-task"))?void 0:l.value)?void 0:s.trim())||"",...d?{tool:d}:{}}}).filter(e=>s||e.agent&&e.task),f=Array.isArray(null==(l=d.editorWorkflow)?void 0:l.steps)?d.editorWorkflow.steps:[];return{name:i,workflow:{description:r,enabled:p,schedule:c,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:m,...f.length?{steps:f}:{}}}}async function x(){const e=v();if(e.name)if(e.workflow.stages.length)try{await o("/api/workflows/save",e),d.selectedName=e.name,n(`Saved workflow: ${e.name}`,"success"),await f(),await w(e.name)}catch(t){n(`Save failed: ${t.message}`,"error")}else n("Add at least one stage","error");else n("Workflow name is required","error")}async function b(){const e=v();if(e.name)try{const t=await o("/api/workflows/run",{name:e.name});n(`Started ${e.name}${t.pid?` (pid ${t.pid})`:""}`,"success"),await w(e.name)}catch(t){n(`Run failed: ${t.message}`,"error")}else n("Save workflow first (name required)","warning")}async function h(){const e=v();if(e.name){if(confirm(`Delete workflow "${e.name}"?`))try{await o("/api/workflows/delete",{name:e.name}),n(`Deleted ${e.name}`,"success"),d.selectedName="",await f(),y(c());const t=document.getElementById("workflowLog");t&&(t.textContent="")}catch(t){n(`Delete failed: ${t.message}`,"error")}}else n("No workflow selected","warning")}export{p as i,m as s};
|
|
1
|
+
import{g as e,e as t,s as n,p as o}from"./core-utils-CmOkXgzi.js";let a=()=>{},l=()=>{},s=[],i=[];const d={selectedName:"",list:[],runStatus:{},editorWorkflow:null},r=[{id:"daily-research",name:"Daily Research Brief",description:"Research, summarize, then QA-check every weekday morning.",schedule:"0 9 * * 1-5",stages:[{agent:"crew-researcher",task:"Research top 5 updates for our current project and summarize key signals."},{agent:"crew-pm",task:"Turn the research into a concise daily brief with priorities and risks."},{agent:"crew-qa",task:"Review the brief for factual clarity and missing edge cases."}]},{id:"seo-content",name:"SEO Content Pipeline",description:"Generate SEO topic ideas, draft copy, then edit.",schedule:"30 10 * * 1,3,5",stages:[{agent:"crew-seo",task:"Find one high-intent keyword cluster and propose a short content outline."},{agent:"crew-copywriter",task:"Write a first draft from the outline. Keep it scannable and conversion-focused."},{agent:"crew-main",task:"Polish the draft and produce final publish-ready copy."}]},{id:"code-health",name:"Code Health Sweep",description:"Automated PM->Coder->QA quality pass.",schedule:"0 14 * * 1-5",stages:[{agent:"crew-pm",task:"Pick one high-value backlog item from project context and define acceptance criteria."},{agent:"crew-coder",task:"Implement the scoped item in small safe changes and summarize files touched."},{agent:"crew-qa",task:"Audit the changes, run tests, and report any regressions with severity."}]}];function c(e=""){return{name:e,description:"",enabled:!1,schedule:"",timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:[{agent:"crew-main",task:"",tool:""}]}}function p(e={}){a=e.hideAllViews||a,l=e.setNavActive||l}async function m(){var t;a(),null==(t=document.getElementById("workflowsView"))||t.classList.add("active"),l("navWorkflows"),await async function(){try{const t=await e("/api/agents");s=(t||[]).map(e=>"string"==typeof e?e:e.id||e.agent).filter(Boolean).sort()}catch{s=[]}}(),await async function(){try{const t=await e("/api/skills");i=(t.skills||[]).map(e=>({name:e.name||"",description:e.description||"",type:e.type||(e.url?"api":"knowledge")})).filter(e=>e.name).sort((e,t)=>e.name.localeCompare(t.name))}catch{i=[]}}(),await f()}async function f(){const n=document.getElementById("workflowList");if(n){n.innerHTML='<div class="meta" style="padding:10px;">Loading workflows...</div>';try{const t=await e("/api/workflows/list");d.list=t.workflows||[],u(),d.selectedName?await w(d.selectedName):y(c());const n=t.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,o=document.getElementById("workflowTimezoneLabel");o&&(o.textContent=`Local timezone: ${n}`)}catch(o){n.innerHTML=`<div class="meta" style="padding:10px;color:var(--red-hi);">Failed to load workflows: ${t(o.message)}</div>`}}}function u(){const e=document.getElementById("workflowList");if(!e)return;const n=d.list||[];n.length?(e.innerHTML=n.map(e=>{var n;const o=e.name===d.selectedName?"background:var(--bg-2);border-color:var(--accent);":"",a=e.schedule?t(e.schedule):'<span style="opacity:0.7;">no schedule</span>',l=(null==(n=e.runState)?void 0:n.running)?'<span style="color:var(--green-hi);font-size:11px;">running</span>':"";return`\n <button class="btn-ghost workflow-row" data-workflow-name="${t(e.name)}" style="width:100%;text-align:left;display:flex;flex-direction:column;gap:4px;padding:10px;margin-bottom:8px;${o}">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:8px;">\n <strong style="font-size:13px;">${t(e.name)}</strong>\n ${l}\n </div>\n <div style="font-size:11px;color:var(--text-3);">${e.enabled?"enabled":"disabled"} · ${e.stageCount||0} stage(s)</div>\n <div style="font-size:11px;color:var(--text-2);font-family:monospace;">${a}</div>\n </button>\n `}).join(""),e.querySelectorAll(".workflow-row").forEach(e=>{e.addEventListener("click",async()=>{const t=e.dataset.workflowName||"";await w(t)})})):e.innerHTML='<div class="meta" style="padding:10px;">No workflows yet.</div>'}async function w(t){if(t)try{const n=await e(`/api/workflows/item?name=${encodeURIComponent(t)}`);d.selectedName=t,d.runStatus=n.runState||{},u(),y({name:t,...n.workflow||{}},n),await async function(t){const n=document.getElementById("workflowLog");if(!n||!t)return;try{const o=(await e(`/api/workflows/log?name=${encodeURIComponent(t)}&limit=120`)).lines||[];n.textContent=o.length?o.join("\n"):"No log lines yet.",n.scrollTop=n.scrollHeight}catch(o){n.textContent=`Failed to load log: ${o.message}`}}(t)}catch(o){n(`Failed to load workflow: ${o.message}`,"error")}}function g(e){const t=String(e||"").trim();if(!t)return"No schedule set. Add a cron expression or use a preset.";return{"*/15 * * * *":"Runs every 15 minutes","0 * * * *":"Runs hourly at minute 0","0 9 * * 1-5":"Runs weekdays at 9:00","0 9 * * *":"Runs daily at 9:00","0 0 * * 1":"Runs every Monday at midnight","0 8 1 * *":"Runs monthly on day 1 at 8:00"}[t]||"Custom cron schedule"}function y(e,o={}){const a=document.getElementById("workflowEditor");if(!a)return;const l={...c(),...e},p=Array.isArray(l.stages)&&l.stages.length?l.stages:c().stages;d.editorWorkflow={...l,stages:p.map(e=>({...e}))};const m=o.cronExample?t(o.cronExample):`*/15 * * * * cd ${t(window.location.pathname||".")} && node scripts/run-scheduled-pipeline.mjs ${t(l.name||"my-workflow")}`,u={agents:s.length?s.map(e=>`<code style="font-size:11px;">${t(e)}</code>`).join(" "):'<span style="font-size:11px;color:var(--text-3);">No agents loaded</span>',skills:i.length?i.map(e=>`<div style="font-size:11px;line-height:1.4;"><code>${t(e.name)}</code> <span style="color:var(--text-3);">(${t(e.type)})</span></div>`).join(""):'<span style="font-size:11px;color:var(--text-3);">No skills loaded</span>'};a.innerHTML=`\n <div class="card" style="display:flex;flex-direction:column;gap:12px;">\n <div style="display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfOpenTemplateLibraryBtn" class="btn-ghost" style="font-size:12px;">📚 Job Library</button>\n <button id="wfOpenSkillGuideBtn" class="btn-ghost" style="font-size:12px;">🧩 Skills & Agent Options</button>\n <button id="wfOpenJsonEditorBtn" class="btn-ghost" style="font-size:12px;">{ } Advanced JSON</button>\n </div>\n\n <div style="display:flex;gap:10px;flex-wrap:wrap;">\n <div style="flex:1;min-width:260px;">\n <label style="font-size:12px;font-weight:600;">Name</label>\n <input id="wfName" type="text" value="${t(l.name||"")}" placeholder="daily-research" style="width:100%;margin-top:4px;padding:8px 10px;" />\n </div>\n <div style="flex:1;min-width:260px;">\n <label style="font-size:12px;font-weight:600;">Description</label>\n <input id="wfDescription" type="text" value="${t(l.description||"")}" placeholder="What this workflow does" style="width:100%;margin-top:4px;padding:8px 10px;" />\n </div>\n </div>\n\n <div style="display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;">\n <div style="min-width:280px;flex:1;">\n <label style="font-size:12px;font-weight:600;">Cron Schedule</label>\n <input id="wfSchedule" type="text" value="${t(l.schedule||"")}" placeholder="0 9 * * 1-5" style="width:100%;margin-top:4px;padding:8px 10px;font-family:monospace;" />\n <div style="font-size:11px;color:var(--text-3);margin-top:4px;">Format: minute hour day month weekday</div>\n <div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:8px;">${[{label:"Every 15m",cron:"*/15 * * * *"},{label:"Hourly",cron:"0 * * * *"},{label:"Daily 9am",cron:"0 9 * * *"},{label:"Weekdays 9am",cron:"0 9 * * 1-5"},{label:"Weekly Mon",cron:"0 0 * * 1"},{label:"Monthly",cron:"0 8 1 * *"}].map(e=>`<button class="btn-ghost wf-cron-preset" data-cron="${t(e.cron)}" style="font-size:11px;padding:4px 8px;">${t(e.label)}</button>`).join("")}</div>\n <div id="wfScheduleHint" style="font-size:11px;color:var(--text-2);margin-top:6px;">${t(g(l.schedule))}</div>\n </div>\n <label style="display:flex;align-items:center;gap:8px;font-size:12px;font-weight:600;padding-bottom:8px;">\n <input id="wfEnabled" type="checkbox" ${l.enabled?"checked":""} />\n Enabled\n </label>\n </div>\n\n <div id="workflowTimezoneLabel" style="font-size:11px;color:var(--text-3);"></div>\n\n <div>\n <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">\n <label style="font-size:12px;font-weight:600;">Stages (wave-like, runs top to bottom)</label>\n <button id="wfAddStageBtn" class="btn-ghost" style="font-size:12px;">+ Add Stage</button>\n </div>\n <div id="wfStagesWrap" style="display:flex;flex-direction:column;gap:8px;">\n ${p.map((e,n)=>{return`\n <div class="wf-stage-row" data-stage-index="${n}" style="border:1px solid var(--border);border-radius:8px;padding:10px;background:var(--bg-2);">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;">\n <strong style="font-size:12px;">Stage ${n+1}</strong>\n <div style="display:flex;gap:6px;flex-wrap:wrap;">\n <button class="btn-ghost wf-move-stage-up" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">↑</button>\n <button class="btn-ghost wf-move-stage-down" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">↓</button>\n <button class="btn-ghost wf-duplicate-stage" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">Duplicate</button>\n <button class="btn-red wf-remove-stage" data-stage-index="${n}" style="font-size:11px;padding:4px 8px;">Remove</button>\n </div>\n </div>\n <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px;">\n <div style="flex:1;min-width:220px;">\n <label style="font-size:11px;font-weight:600;">Agent</label>\n <select class="wf-agent" style="width:100%;margin-top:4px;padding:6px 8px;">${o=e.agent,Array.from(new Set([...s||[],"crew-main","crew-pm","crew-qa","crew-coder","crew-coder-front","crew-coder-back","crew-copywriter",o||""])).filter(Boolean).sort().map(e=>`<option value="${t(e)}" ${e===o?"selected":""}>${t(e)}</option>`).join("")}</select>\n </div>\n <div style="width:180px;">\n <label style="font-size:11px;font-weight:600;">Tool hint (optional)</label>\n <input class="wf-tool" type="text" value="${t(e.tool||"")}" placeholder="write_file" style="width:100%;margin-top:4px;padding:6px 8px;" />\n </div>\n </div>\n <div>\n <label style="font-size:11px;font-weight:600;">Task</label>\n <textarea class="wf-task" rows="3" style="width:100%;margin-top:4px;padding:8px 10px;font-family:monospace;">${t(e.task||"")}</textarea>\n </div>\n </div>\n `;var o}).join("")}\n </div>\n </div>\n\n <div style="display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfSaveBtn" class="btn">Save Workflow</button>\n <button id="wfRunBtn" class="btn-green">Run Now</button>\n <button id="wfDeleteBtn" class="btn-red">Delete</button>\n <button id="wfNewBtn" class="btn-ghost">New</button>\n <button id="wfRefreshBtn" class="btn-ghost">Refresh</button>\n </div>\n\n <div>\n <div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:4px;">Crontab example</div>\n <code style="display:block;background:var(--bg-2);border:1px solid var(--border);padding:8px 10px;border-radius:6px;overflow:auto;white-space:nowrap;">${m}</code>\n </div>\n\n <div id="wfLibraryModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:12000;align-items:center;justify-content:center;padding:18px;">\n <div style="width:min(960px,100%);max-height:85vh;overflow:auto;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:14px;">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;">\n <div style="font-size:14px;font-weight:700;">Workflow Job Library</div>\n <button id="wfCloseLibraryBtn" class="btn-ghost" style="font-size:12px;">Close</button>\n </div>\n <div style="font-size:12px;color:var(--text-2);margin-bottom:10px;">Pick a starter template, then customize stages/tasks.</div>\n <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:10px;">${r.map(e=>`\n <div style="border:1px solid var(--border);border-radius:8px;padding:10px;background:var(--bg-2);">\n <div style="font-size:12px;font-weight:700;">${t(e.name)}</div>\n <div style="font-size:11px;color:var(--text-3);margin-top:4px;">${t(e.description)}</div>\n <div style="font-size:11px;color:var(--text-2);font-family:monospace;margin-top:6px;">${t(e.schedule)}</div>\n <div style="margin-top:8px;">\n <button class="btn-ghost wf-apply-template" data-template-id="${t(e.id)}" style="font-size:11px;">Use Template</button>\n </div>\n </div>\n `).join("")}</div>\n <hr style="border:none;border-top:1px solid var(--border);margin:14px 0;" />\n <div style="font-size:12px;font-weight:700;margin-bottom:6px;">Available Agents</div>\n <div style="display:flex;gap:6px;flex-wrap:wrap;">${u.agents}</div>\n <div style="font-size:12px;font-weight:700;margin:12px 0 6px;">Available Skills</div>\n <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:6px;">${u.skills}</div>\n </div>\n </div>\n\n <div id="wfJsonModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:12000;align-items:center;justify-content:center;padding:18px;">\n <div style="width:min(920px,100%);max-height:85vh;overflow:auto;background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:14px;">\n <div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;">\n <div style="font-size:14px;font-weight:700;">Advanced Workflow JSON</div>\n <button id="wfCloseJsonBtn" class="btn-ghost" style="font-size:12px;">Close</button>\n </div>\n <div style="font-size:12px;color:var(--text-2);margin-bottom:8px;">Edit raw JSON. Supports both <code>stages</code> and <code>steps</code>.</div>\n <textarea id="wfJsonTextarea" rows="18" style="width:100%;font-family:monospace;font-size:12px;padding:10px;border:1px solid var(--border);border-radius:8px;background:var(--bg-2);"></textarea>\n <div style="margin-top:10px;display:flex;gap:8px;flex-wrap:wrap;">\n <button id="wfApplyJsonBtn" class="btn-green">Apply JSON</button>\n </div>\n </div>\n </div>\n </div>\n `;const w=document.getElementById("workflowTimezoneLabel");var k,E,B,I,z,S,$,L,A,N,D,T,J,C,O;w&&(w.textContent=`Local timezone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`),null==(k=document.getElementById("wfOpenTemplateLibraryBtn"))||k.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="flex")}),null==(E=document.getElementById("wfOpenSkillGuideBtn"))||E.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="flex")}),null==(B=document.getElementById("wfCloseLibraryBtn"))||B.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfLibraryModal");t&&(t.style.display="none")}),null==(I=document.getElementById("wfLibraryModal"))||I.addEventListener("click",e=>{var t;"wfLibraryModal"===(null==(t=e.target)?void 0:t.id)&&(e.currentTarget.style.display="none")}),null==(z=document.getElementById("wfOpenJsonEditorBtn"))||z.addEventListener("click",e=>{var t;e.preventDefault();const n={...v().workflow,...(null==(t=d.editorWorkflow)?void 0:t.steps)?{steps:d.editorWorkflow.steps}:{}},o=document.getElementById("wfJsonTextarea");o&&(o.value=JSON.stringify(n,null,2));const a=document.getElementById("wfJsonModal");a&&(a.style.display="flex")}),null==(S=document.getElementById("wfCloseJsonBtn"))||S.addEventListener("click",e=>{e.preventDefault();const t=document.getElementById("wfJsonModal");t&&(t.style.display="none")}),null==($=document.getElementById("wfJsonModal"))||$.addEventListener("click",e=>{var t;"wfJsonModal"===(null==(t=e.target)?void 0:t.id)&&(e.currentTarget.style.display="none")}),null==(L=document.getElementById("wfApplyJsonBtn"))||L.addEventListener("click",e=>{e.preventDefault();try{const e=document.getElementById("wfJsonTextarea"),t=JSON.parse((null==e?void 0:e.value)||"{}"),o=v();y({name:o.name,description:t.description||o.workflow.description,enabled:t.enabled??o.workflow.enabled,schedule:t.schedule||o.workflow.schedule,timezone:t.timezone||Intl.DateTimeFormat().resolvedOptions().timeZone,stages:Array.isArray(t.stages)&&t.stages.length?t.stages:o.workflow.stages,...Array.isArray(t.steps)?{steps:t.steps}:{}});const a=document.getElementById("wfJsonModal");a&&(a.style.display="none"),n("Applied advanced JSON","success")}catch(t){n(`Invalid JSON: ${t.message}`,"error")}}),document.querySelectorAll(".wf-apply-template").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const o=e.dataset.templateId||"",a=r.find(e=>e.id===o);if(!a)return;const l=v();y({name:l.name||a.id,description:a.description,enabled:l.workflow.enabled,schedule:a.schedule,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:a.stages.map(e=>({...e,tool:e.tool||""}))});const s=document.getElementById("wfLibraryModal");s&&(s.style.display="none"),n(`Applied template: ${a.name}`,"success")})}),document.querySelectorAll(".wf-cron-preset").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=e.dataset.cron||"",o=document.getElementById("wfSchedule"),a=document.getElementById("wfScheduleHint");o&&(o.value=n),a&&(a.textContent=g(n))})}),null==(A=document.getElementById("wfSchedule"))||A.addEventListener("input",e=>{const t=document.getElementById("wfScheduleHint");t&&(t.textContent=g(e.target.value))}),null==(N=document.getElementById("wfAddStageBtn"))||N.addEventListener("click",e=>{e.preventDefault();const t=v({includeIncompleteStages:!0});t.workflow.stages.push({agent:"crew-main",task:"",tool:""}),y({name:t.name,...t.workflow})}),document.querySelectorAll(".wf-remove-stage").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});o.workflow.stages=o.workflow.stages.filter((e,t)=>t!==n),o.workflow.stages.length||(o.workflow.stages=[{agent:"crew-main",task:"",tool:""}]),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-move-stage-up").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1");if(n<=0)return;const o=v({includeIncompleteStages:!0}),[a]=o.workflow.stages.splice(n,1);o.workflow.stages.splice(n-1,0,a),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-move-stage-down").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});if(n<0||n>=o.workflow.stages.length-1)return;const[a]=o.workflow.stages.splice(n,1);o.workflow.stages.splice(n+1,0,a),y({name:o.name,...o.workflow})})}),document.querySelectorAll(".wf-duplicate-stage").forEach(e=>{e.addEventListener("click",t=>{t.preventDefault();const n=Number(e.dataset.stageIndex||"-1"),o=v({includeIncompleteStages:!0});if(n<0||n>=o.workflow.stages.length)return;const a=o.workflow.stages[n];o.workflow.stages.splice(n+1,0,{...a}),y({name:o.name,...o.workflow})})}),null==(D=document.getElementById("wfSaveBtn"))||D.addEventListener("click",x),null==(T=document.getElementById("wfRunBtn"))||T.addEventListener("click",b),null==(J=document.getElementById("wfDeleteBtn"))||J.addEventListener("click",h),null==(C=document.getElementById("wfNewBtn"))||C.addEventListener("click",()=>{d.selectedName="",y(c());const e=document.getElementById("workflowLog");e&&(e.textContent="")}),null==(O=document.getElementById("wfRefreshBtn"))||O.addEventListener("click",async()=>{await f()})}function v(e={}){var t,n,o,a,l;const{includeIncompleteStages:s=!1}=e,i=((null==(t=document.getElementById("wfName"))?void 0:t.value)||"").trim(),r=((null==(n=document.getElementById("wfDescription"))?void 0:n.value)||"").trim(),c=((null==(o=document.getElementById("wfSchedule"))?void 0:o.value)||"").trim(),p=!!(null==(a=document.getElementById("wfEnabled"))?void 0:a.checked),m=Array.from(document.querySelectorAll(".wf-stage-row")).map(e=>{var t,n,o,a,l,s;const i=(null==(n=null==(t=e.querySelector(".wf-agent"))?void 0:t.value)?void 0:n.trim())||"",d=(null==(a=null==(o=e.querySelector(".wf-tool"))?void 0:o.value)?void 0:a.trim())||"";return{agent:i,task:(null==(s=null==(l=e.querySelector(".wf-task"))?void 0:l.value)?void 0:s.trim())||"",...d?{tool:d}:{}}}).filter(e=>s||e.agent&&e.task),f=Array.isArray(null==(l=d.editorWorkflow)?void 0:l.steps)?d.editorWorkflow.steps:[];return{name:i,workflow:{description:r,enabled:p,schedule:c,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,stages:m,...f.length?{steps:f}:{}}}}async function x(){const e=v();if(e.name)if(e.workflow.stages.length)try{await o("/api/workflows/save",e),d.selectedName=e.name,n(`Saved workflow: ${e.name}`,"success"),await f(),await w(e.name)}catch(t){n(`Save failed: ${t.message}`,"error")}else n("Add at least one stage","error");else n("Workflow name is required","error")}async function b(){const e=v();if(e.name)try{const t=await o("/api/workflows/run",{name:e.name});n(`Started ${e.name}${t.pid?` (pid ${t.pid})`:""}`,"success"),await w(e.name)}catch(t){n(`Run failed: ${t.message}`,"error")}else n("Save workflow first (name required)","warning")}async function h(){const e=v();if(e.name){if(confirm(`Delete workflow "${e.name}"?`))try{await o("/api/workflows/delete",{name:e.name}),n(`Deleted ${e.name}`,"success"),d.selectedName="",await f(),y(c());const t=document.getElementById("workflowLog");t&&(t.textContent="")}catch(t){n(`Delete failed: ${t.message}`,"error")}}else n("No workflow selected","warning")}export{p as i,m as s};
|
|
Binary file
|
|
@@ -6,31 +6,31 @@
|
|
|
6
6
|
<title>crewswarm dashboard</title>
|
|
7
7
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
8
8
|
<!-- Font: system stack only to avoid CORS when dashboard (4319) and studio (3333) both load Inter from Google -->
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/core-utils-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/setup-wizard-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/components-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-DnClJ1ee.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/core-utils-CmOkXgzi.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/setup-wizard-CA0Or47w.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/components-BS9fQjE_.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/orchestration-Ca2DLWN-.js">
|
|
14
14
|
<link rel="modulepreload" crossorigin href="/assets/cli-process-COMRNPqr.js">
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/chat-core-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-swarm-chat-tab-
|
|
15
|
+
<link rel="modulepreload" crossorigin href="/assets/chat-core-Cx4sTxDd.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-swarm-chat-tab-BNrd88-r.js">
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/assets/tab-waves-tab-SaJDkb4x.js">
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-workflows-tab-
|
|
19
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-memory-tab-
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-services-tab-
|
|
21
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-agents-tab-
|
|
22
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-prompts-tab-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-skills-tab-
|
|
24
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-contacts-tab-
|
|
25
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-engines-tab-
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-swarm-tab-
|
|
27
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-models-tab-
|
|
28
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-projects-tab-
|
|
29
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-settings-tab-
|
|
30
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-comms-tab-
|
|
31
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-usage-tab-
|
|
32
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-spending-tab-
|
|
33
|
-
<link rel="modulepreload" crossorigin href="/assets/tab-pm-loop-tab-
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-workflows-tab-B-soSy1k.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-memory-tab-Cu6u13EQ.js">
|
|
20
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-services-tab-DU_LH3uG.js">
|
|
21
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-agents-tab-BgpIsjkw.js">
|
|
22
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-prompts-tab-DVkUNaJd.js">
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-skills-tab-BpY0uZHW.js">
|
|
24
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-contacts-tab-DiOyMYth.js">
|
|
25
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-engines-tab-BsdZVvU0.js">
|
|
26
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-swarm-tab-B1AcjL1W.js">
|
|
27
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-models-tab-BLEjmd19.js">
|
|
28
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-projects-tab-DhNWnlzt.js">
|
|
29
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-settings-tab-Bn4nXtDe.js">
|
|
30
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-comms-tab-kguqTIzD.js">
|
|
31
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-usage-tab-BIOOnB-Y.js">
|
|
32
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-spending-tab-DEccQHnt.js">
|
|
33
|
+
<link rel="modulepreload" crossorigin href="/assets/tab-pm-loop-tab-Bfd449B4.js">
|
|
34
34
|
<link rel="stylesheet" crossorigin href="/assets/index-CF0aJRtC.css">
|
|
35
35
|
</head>
|
|
36
36
|
<body>
|
|
@@ -3519,7 +3519,7 @@
|
|
|
3519
3519
|
>
|
|
3520
3520
|
<input
|
|
3521
3521
|
id="tgAllowedIds"
|
|
3522
|
-
placeholder="
|
|
3522
|
+
placeholder="123456789, 987654321"
|
|
3523
3523
|
style="width: 100%; margin-bottom: 12px"
|
|
3524
3524
|
/>
|
|
3525
3525
|
<div id="tgContactNamesList" style="margin-bottom: 12px"></div>
|
|
Binary file
|
|
Binary file
|
|
@@ -3494,7 +3494,7 @@
|
|
|
3494
3494
|
>
|
|
3495
3495
|
<input
|
|
3496
3496
|
id="tgAllowedIds"
|
|
3497
|
-
placeholder="
|
|
3497
|
+
placeholder="123456789, 987654321"
|
|
3498
3498
|
style="width: 100%; margin-bottom: 12px"
|
|
3499
3499
|
/>
|
|
3500
3500
|
<div id="tgContactNamesList" style="margin-bottom: 12px"></div>
|
|
@@ -4402,6 +4402,76 @@
|
|
|
4402
4402
|
></div>
|
|
4403
4403
|
</div>
|
|
4404
4404
|
|
|
4405
|
+
<div class="card" style="margin-top: 16px">
|
|
4406
|
+
<div
|
|
4407
|
+
style="
|
|
4408
|
+
display: flex;
|
|
4409
|
+
align-items: center;
|
|
4410
|
+
justify-content: space-between;
|
|
4411
|
+
flex-wrap: wrap;
|
|
4412
|
+
gap: 12px;
|
|
4413
|
+
"
|
|
4414
|
+
>
|
|
4415
|
+
<div>
|
|
4416
|
+
<div class="card-title" style="margin-bottom: 2px">
|
|
4417
|
+
🔌 tmux-bridge Sessions
|
|
4418
|
+
</div>
|
|
4419
|
+
<div
|
|
4420
|
+
style="
|
|
4421
|
+
font-size: 11px;
|
|
4422
|
+
color: var(--text-3);
|
|
4423
|
+
line-height: 1.5;
|
|
4424
|
+
"
|
|
4425
|
+
>
|
|
4426
|
+
Enable persistent tmux sessions that survive across pipeline
|
|
4427
|
+
waves. Agents can hand off live execution context (running
|
|
4428
|
+
servers, env vars, cwd) to the next wave instead of
|
|
4429
|
+
cold-starting. Requires
|
|
4430
|
+
<code
|
|
4431
|
+
style="
|
|
4432
|
+
background: var(--bg-1);
|
|
4433
|
+
padding: 1px 4px;
|
|
4434
|
+
border-radius: 3px;
|
|
4435
|
+
"
|
|
4436
|
+
>tmux</code
|
|
4437
|
+
>
|
|
4438
|
+
+
|
|
4439
|
+
<code
|
|
4440
|
+
style="
|
|
4441
|
+
background: var(--bg-1);
|
|
4442
|
+
padding: 1px 4px;
|
|
4443
|
+
border-radius: 3px;
|
|
4444
|
+
"
|
|
4445
|
+
>smux</code
|
|
4446
|
+
>
|
|
4447
|
+
installed. One writer per session (lock enforced).
|
|
4448
|
+
</div>
|
|
4449
|
+
</div>
|
|
4450
|
+
<button
|
|
4451
|
+
id="tmuxBridgeBtn"
|
|
4452
|
+
data-action="toggleTmuxBridge"
|
|
4453
|
+
style="
|
|
4454
|
+
font-size: 12px;
|
|
4455
|
+
font-weight: 700;
|
|
4456
|
+
padding: 8px 18px;
|
|
4457
|
+
border-radius: 8px;
|
|
4458
|
+
cursor: pointer;
|
|
4459
|
+
border: 1px solid var(--border);
|
|
4460
|
+
background: var(--surface-2);
|
|
4461
|
+
color: var(--text-2);
|
|
4462
|
+
white-space: nowrap;
|
|
4463
|
+
min-width: 80px;
|
|
4464
|
+
"
|
|
4465
|
+
>
|
|
4466
|
+
Loading…
|
|
4467
|
+
</button>
|
|
4468
|
+
</div>
|
|
4469
|
+
<div
|
|
4470
|
+
id="tmuxBridgeStatus"
|
|
4471
|
+
style="margin-top: 8px; font-size: 12px; color: var(--text-3)"
|
|
4472
|
+
></div>
|
|
4473
|
+
</div>
|
|
4474
|
+
|
|
4405
4475
|
<div class="card" style="margin-top: 16px">
|
|
4406
4476
|
<div
|
|
4407
4477
|
style="
|
|
@@ -181,6 +181,8 @@ import {
|
|
|
181
181
|
loadLoopBrain,
|
|
182
182
|
saveLoopBrain,
|
|
183
183
|
loadEnvAdvanced,
|
|
184
|
+
loadTmuxBridge,
|
|
185
|
+
toggleTmuxBridge,
|
|
184
186
|
} from "./tabs/settings-tab.js";
|
|
185
187
|
import {
|
|
186
188
|
initCommsTab,
|
|
@@ -1739,6 +1741,7 @@ function showSettingsTab(tab) {
|
|
|
1739
1741
|
loadGlobalFallback();
|
|
1740
1742
|
loadConfigLockStatus();
|
|
1741
1743
|
loadCursorWaves();
|
|
1744
|
+
loadTmuxBridge();
|
|
1742
1745
|
loadAutonomousMentions();
|
|
1743
1746
|
loadClaudeCode();
|
|
1744
1747
|
loadCodexExecutor();
|
|
@@ -2181,6 +2184,7 @@ const ACTION_REGISTRY = {
|
|
|
2181
2184
|
saveGlobalFallback,
|
|
2182
2185
|
toggleBgConsciousness,
|
|
2183
2186
|
toggleCursorWaves,
|
|
2187
|
+
toggleTmuxBridge,
|
|
2184
2188
|
toggleAutonomousMentions,
|
|
2185
2189
|
toggleClaudeCode,
|
|
2186
2190
|
toggleCodexExecutor,
|
|
@@ -2772,6 +2776,7 @@ Object.assign(window, {
|
|
|
2772
2776
|
toggleAddSkill,
|
|
2773
2777
|
toggleBgConsciousness,
|
|
2774
2778
|
toggleCursorWaves,
|
|
2779
|
+
toggleTmuxBridge,
|
|
2775
2780
|
toggleClaudeCode,
|
|
2776
2781
|
toggleEmojiPicker,
|
|
2777
2782
|
updateSkillAuthFields,
|
|
@@ -172,19 +172,27 @@ export function appendChatBubble(
|
|
|
172
172
|
if (engineUsed) {
|
|
173
173
|
const engineColors = {
|
|
174
174
|
claude: "#e07a5f",
|
|
175
|
+
"claude-code": "#e07a5f",
|
|
175
176
|
codex: "#8338ec",
|
|
176
177
|
cursor: "#3d405b",
|
|
177
178
|
opencode: "#06d6a0",
|
|
178
179
|
gemini: "#4285f4",
|
|
180
|
+
"gemini-cli": "#4285f4",
|
|
179
181
|
"docker-sandbox": "#0db7ed",
|
|
182
|
+
"crew-cli": "#8b5cf6",
|
|
183
|
+
"direct-llm": "#6b7280",
|
|
180
184
|
};
|
|
181
185
|
const engineLabels = {
|
|
182
186
|
claude: "🤖 Claude Code",
|
|
187
|
+
"claude-code": "🤖 Claude Code",
|
|
183
188
|
codex: "🟣 Codex",
|
|
184
189
|
cursor: "🖱 Cursor",
|
|
185
190
|
opencode: "⚡ OpenCode",
|
|
186
191
|
gemini: "✨ Gemini",
|
|
192
|
+
"gemini-cli": "✨ Gemini",
|
|
187
193
|
"docker-sandbox": "🐳 Docker",
|
|
194
|
+
"crew-cli": "🔧 crew-cli",
|
|
195
|
+
"direct-llm": "💬 LLM Direct",
|
|
188
196
|
};
|
|
189
197
|
const engineBadge = document.createElement("span");
|
|
190
198
|
engineBadge.title =
|
|
@@ -290,6 +290,36 @@ export async function toggleCursorWaves() {
|
|
|
290
290
|
} catch(e) { showNotification('Failed: ' + e.message, 'error'); }
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
export async function loadTmuxBridge() {
|
|
294
|
+
const btn = document.getElementById('tmuxBridgeBtn');
|
|
295
|
+
const status = document.getElementById('tmuxBridgeStatus');
|
|
296
|
+
try {
|
|
297
|
+
const d = await getJSON('/api/settings/tmux-bridge');
|
|
298
|
+
const on = d.enabled;
|
|
299
|
+
if (btn) {
|
|
300
|
+
btn.textContent = on ? '🔌 ON' : '⚫ OFF';
|
|
301
|
+
btn.style.background = on ? 'rgba(52,211,153,0.15)' : 'var(--surface-2)';
|
|
302
|
+
btn.style.borderColor = on ? 'rgba(52,211,153,0.3)' : 'var(--border)';
|
|
303
|
+
btn.style.color = on ? 'var(--green)' : 'var(--text-2)';
|
|
304
|
+
}
|
|
305
|
+
if (status) status.textContent = on
|
|
306
|
+
? 'Active — agents can share persistent tmux sessions across pipeline waves. Requires tmux + smux.'
|
|
307
|
+
: 'Off — agents use standard cold-start execution (no session persistence).';
|
|
308
|
+
} catch(e) {
|
|
309
|
+
if (btn) btn.textContent = 'Error';
|
|
310
|
+
if (status) status.textContent = 'Could not load: ' + e.message;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export async function toggleTmuxBridge() {
|
|
315
|
+
try {
|
|
316
|
+
const current = await getJSON('/api/settings/tmux-bridge');
|
|
317
|
+
const d = await postJSON('/api/settings/tmux-bridge', { enabled: !current.enabled });
|
|
318
|
+
showNotification('tmux-bridge ' + (d.enabled ? 'ENABLED 🔌' : 'DISABLED'));
|
|
319
|
+
loadTmuxBridge();
|
|
320
|
+
} catch(e) { showNotification('Failed: ' + e.message, 'error'); }
|
|
321
|
+
}
|
|
322
|
+
|
|
293
323
|
export async function loadAutonomousMentions() {
|
|
294
324
|
const btn = document.getElementById('autonomousMentionsBtn');
|
|
295
325
|
const status = document.getElementById('autonomousMentionsStatus');
|
|
@@ -691,6 +721,34 @@ const ENV_GROUPS = [
|
|
|
691
721
|
{ key: 'SHARED_MEMORY_DIR', hint: 'Directory for shared memory files', default: '~/.crewswarm/memory' },
|
|
692
722
|
],
|
|
693
723
|
},
|
|
724
|
+
{
|
|
725
|
+
label: 'crew-cli — Streaming & Hooks',
|
|
726
|
+
note: 'Controls for crew-cli streaming output, tool hooks, and session token limits.',
|
|
727
|
+
vars: [
|
|
728
|
+
{ key: 'CREW_NO_STREAM', hint: 'Disable streaming output — tokens arrive after full response (true/false)', default: 'false' },
|
|
729
|
+
{ key: 'CREW_HOOKS_FILE', hint: 'Path to hooks.json for PreToolUse/PostToolUse hooks', default: '.crew/hooks.json' },
|
|
730
|
+
{ key: 'CREW_MAX_SESSION_TOKENS', hint: 'Max estimated tokens per session before oldest turns are trimmed', default: '100000' },
|
|
731
|
+
],
|
|
732
|
+
},
|
|
733
|
+
{
|
|
734
|
+
label: 'crew-cli — Codebase Index & RAG',
|
|
735
|
+
note: 'Codebase embedding index auto-builds on startup. Injects relevant file context into every worker prompt.',
|
|
736
|
+
vars: [
|
|
737
|
+
{ key: 'CREW_RAG_MODE', hint: 'RAG mode: auto (use index when ready, else keyword), semantic, keyword, import-graph, off', default: 'auto' },
|
|
738
|
+
{ key: 'CREW_EMBEDDING_PROVIDER', hint: 'Embedding provider: local (zero-cost), openai (best), gemini (free tier)', default: 'local' },
|
|
739
|
+
{ key: 'CREW_RAG_WORKER_BUDGET', hint: 'Max tokens of RAG context injected per worker (approximate)', default: '4000' },
|
|
740
|
+
{ key: 'CREW_RAG_MAX_FILES', hint: 'Max code files to index (larger repos should increase this)', default: '2000' },
|
|
741
|
+
{ key: 'CREW_RAG_BATCH_SIZE', hint: 'Files per embedding batch (higher = faster but more API calls)', default: '20' },
|
|
742
|
+
],
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
label: 'crew-cli — Checkpointing',
|
|
746
|
+
note: 'Automatic git checkpoints during pipeline execution for easy rollback.',
|
|
747
|
+
vars: [
|
|
748
|
+
{ key: 'CREW_AUTO_CHECKPOINT', hint: 'Enable auto-commit at task boundaries (true/false)', default: 'true' },
|
|
749
|
+
{ key: 'CREW_CHECKPOINT_INTERVAL_MS', hint: 'Periodic git stash snapshot interval during long tasks (ms, 0=off)', default: '60000' },
|
|
750
|
+
],
|
|
751
|
+
},
|
|
694
752
|
{
|
|
695
753
|
label: 'PM Loop',
|
|
696
754
|
vars: [
|