crewswarm 0.9.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +56 -7
  2. package/apps/dashboard/dist/assets/{index-D-sRshvg.css → index-C5-vlIwl.css} +1 -1
  3. package/apps/dashboard/dist/assets/index-CSooN9fi.js +2 -0
  4. package/apps/dashboard/dist/assets/index-CSooN9fi.js.br +0 -0
  5. package/apps/dashboard/dist/assets/tab-spending-tab-DcXD5TQY.js +1 -0
  6. package/apps/dashboard/dist/assets/tab-spending-tab-DcXD5TQY.js.br +0 -0
  7. package/apps/dashboard/dist/assets/tab-testing-tab-Ea5K-rsb.js +1 -0
  8. package/apps/dashboard/dist/index.html +83 -7
  9. package/apps/dashboard/dist/index.html.br +0 -0
  10. package/contrib/openclaw-plugin/index.ts +20 -11
  11. package/lib/autoharness/index.mjs +151 -1
  12. package/lib/chat/history.mjs +1 -1
  13. package/lib/contacts/identity-linker.mjs +24 -3
  14. package/lib/contacts/index.mjs +2 -1
  15. package/lib/crew-lead/chat-handler.mjs +56 -33
  16. package/lib/crew-lead/llm-caller.mjs +71 -14
  17. package/lib/crew-lead/prompts.mjs +4 -2
  18. package/lib/engines/rt-envelope.mjs +4 -1
  19. package/package.json +5 -3
  20. package/scripts/dashboard.mjs +216 -25
  21. package/scripts/health-check.mjs +70 -28
  22. package/scripts/restart-all-from-repo.sh +25 -21
  23. package/scripts/start.mjs +35 -15
  24. package/apps/dashboard/dist/assets/chat-core-uXb_C0GM.js.br +0 -0
  25. package/apps/dashboard/dist/assets/cli-process-CNZ_UBCt.js.br +0 -0
  26. package/apps/dashboard/dist/assets/components-BS9fQjE_.js.br +0 -0
  27. package/apps/dashboard/dist/assets/core-utils-CmOkXgzi.js.br +0 -0
  28. package/apps/dashboard/dist/assets/index-BeVllEj_.js +0 -2
  29. package/apps/dashboard/dist/assets/index-BeVllEj_.js.br +0 -0
  30. package/apps/dashboard/dist/assets/index-D-sRshvg.css.br +0 -0
  31. package/apps/dashboard/dist/assets/orchestration-Ca2DLWN-.js.br +0 -0
  32. package/apps/dashboard/dist/assets/setup-wizard-CA0Or47w.js.br +0 -0
  33. package/apps/dashboard/dist/assets/tab-agents-tab-BgpIsjkw.js.br +0 -0
  34. package/apps/dashboard/dist/assets/tab-benchmarks-tab-BHjKCPm3.js.br +0 -0
  35. package/apps/dashboard/dist/assets/tab-comms-tab-kguqTIzD.js.br +0 -0
  36. package/apps/dashboard/dist/assets/tab-contacts-tab-DiOyMYth.js.br +0 -0
  37. package/apps/dashboard/dist/assets/tab-engines-tab-BsdZVvU0.js.br +0 -0
  38. package/apps/dashboard/dist/assets/tab-memory-tab-Cu6u13EQ.js.br +0 -0
  39. package/apps/dashboard/dist/assets/tab-models-tab-dNRgsTOO.js.br +0 -0
  40. package/apps/dashboard/dist/assets/tab-pm-loop-tab-DiAPTJXu.js.br +0 -0
  41. package/apps/dashboard/dist/assets/tab-projects-tab-SFH4E--a.js.br +0 -0
  42. package/apps/dashboard/dist/assets/tab-prompts-tab-DVkUNaJd.js.br +0 -0
  43. package/apps/dashboard/dist/assets/tab-services-tab-DU_LH3uG.js.br +0 -0
  44. package/apps/dashboard/dist/assets/tab-settings-tab-CuvH_Fj_.js.br +0 -0
  45. package/apps/dashboard/dist/assets/tab-skills-tab-DR7PJ7NB.js.br +0 -0
  46. package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js +0 -1
  47. package/apps/dashboard/dist/assets/tab-spending-tab-DEccQHnt.js.br +0 -0
  48. package/apps/dashboard/dist/assets/tab-swarm-chat-tab-BNrd88-r.js.br +0 -0
  49. package/apps/dashboard/dist/assets/tab-swarm-tab-B1AcjL1W.js.br +0 -0
  50. package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js +0 -1
  51. package/apps/dashboard/dist/assets/tab-testing-tab-CezZOZcJ.js.br +0 -0
  52. package/apps/dashboard/dist/assets/tab-usage-tab-BIOOnB-Y.js.br +0 -0
  53. package/apps/dashboard/dist/assets/tab-waves-tab-SaJDkb4x.js.br +0 -0
  54. package/apps/dashboard/dist/assets/tab-workflows-tab-B-soSy1k.js.br +0 -0
  55. package/apps/dashboard/dist/index.html.gz +0 -0
@@ -1 +0,0 @@
1
- import{s as t,g as e,d as n}from"./core-utils-CmOkXgzi.js";import{e as o,l as a}from"./tab-usage-tab-BIOOnB-Y.js";var i=null,l=null;function s(){var t=i,e=l,n=document.getElementById("gtAgentCost"),o=document.getElementById("gtOcCost"),a=document.getElementById("gtTotal");n&&(null!==t&&(n.textContent="$"+t.toFixed(4)),null!==e&&(o.textContent="$"+e.toFixed(4)),null!==t&&null!==e&&(a.textContent="$"+(t+e).toFixed(4)))}function r(t){l=t,s()}async function d(){var t,e=parseInt((null==(t=document.getElementById("grandTotalDays"))?void 0:t.value)||"14"),n=document.getElementById("ocStatsDays"),o=document.getElementById("spendingDays");n&&(n.value=String(e)),o&&(o.value=String(1===e?1:e)),i=null,l=null,document.getElementById("gtAgentCost").textContent="—",document.getElementById("gtOcCost").textContent="—",document.getElementById("gtTotal").textContent="—",c(),a(r)}async function c(){var t,a,l,r,d;const c=document.getElementById("spendingWidget"),p=parseInt((null==(t=document.getElementById("spendingDays"))?void 0:t.value)||"1");try{if(p<=1){const t=await(await fetch("/api/spending")).json(),{spending:e,caps:n}=t,o=(null==(a=e.global)?void 0:a.tokens)||0,p=(null==(l=e.global)?void 0:l.costUSD)||0,g=null==(r=n.global)?void 0:r.dailyTokenLimit,m=null==(d=n.global)?void 0:d.dailyCostLimitUSD;let y='<div style="margin-bottom:10px;"><div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:4px;text-transform:uppercase;letter-spacing:.06em;">Global &middot; '+(e.date||"today")+'</div><div style="display:flex;gap:20px;"><span>'+o.toLocaleString()+" tokens"+(g?" / "+Number(g).toLocaleString():"")+'</span><span style="color:var(--yellow);font-weight:600;">$'+p.toFixed(4)+"</span>"+(m?"<span> / $"+m+"</span>":"")+"</div>";if(g){const t=Math.min(100,o/g*100);y+='<div style="margin-top:4px;height:4px;background:var(--border);border-radius:2px;"><div style="width:'+t+"%;height:100%;background:"+(t>80?"var(--red)":t>50?"var(--yellow)":"var(--green)")+';border-radius:2px;transition:width .3s;"></div></div>'}y+="</div>";const u=Object.entries(e.agents||{});u.length?(y+='<div style="font-size:11px;font-weight:600;color:var(--text-2);margin-bottom:6px;text-transform:uppercase;letter-spacing:.06em;">Per Agent</div>',y+=u.map(function(t){var e=t[0],o=t[1];const a=n.agents&&n.agents[e],i=o.tokens||0,l=(o.costUSD||0).toFixed(4),s=a&&a.dailyTokenLimit,r=s?Math.min(100,i/s*100):null;let d='<div style="display:flex;align-items:center;gap:10px;margin-bottom:4px;"><span style="min-width:140px;font-size:12px;">'+e+'</span><span style="font-size:12px;">'+i.toLocaleString()+" tok"+(s?" / "+Number(s).toLocaleString():"")+' &middot; <span style="color:var(--yellow);">$'+l+"</span></span>";if(null!==r){d+='<div style="flex:1;height:3px;background:var(--border);border-radius:2px;"><div style="width:'+r+"%;height:100%;background:"+(r>80?"var(--red)":"var(--accent)")+';border-radius:2px;"></div></div>'}return d+"</div>"}).join("")):y+='<div style="color:var(--text-3);">No per-agent data yet for today.</div>',g&&(document.getElementById("gcapTokens").value=g),m&&(document.getElementById("gcapCost").value=m),i=p,s(),c.innerHTML=y}else{const t=(await e("/api/token-usage").catch(function(){return{}})).byDay||{},n=new Date(Date.now()-864e5*p).toISOString().slice(0,10),a=Object.keys(t).filter(function(t){return t>=n}).sort().reverse();if(!a.length)return c.innerHTML='<div style="color:var(--text-3);">No data for this period.</div>',i=0,void s();const l={};var g=0;a.forEach(function(e){const n=t[e].byModel||{};Object.entries(n).forEach(function(t){var e=t[0],n=t[1];l[e]||(l[e]={prompt:0,completion:0}),l[e].prompt+=n.prompt||0,l[e].completion+=n.completion||0,(n.prompt||0)+(n.completion||0)})}),g=o(l);let r='<div style="margin-bottom:10px;display:flex;justify-content:space-between;align-items:center;"><span style="font-size:12px;color:var(--text-3);">Last '+p+" days &middot; "+a.length+' days of data</span><span style="font-size:16px;font-weight:700;color:var(--yellow);">$'+g.toFixed(4)+"</span></div>";const d=Math.max(...a.map(function(e){return o(t[e].byModel||{})}),1e-4),m=(new Date).toISOString().slice(0,10);r+='<div style="display:flex;flex-direction:column;gap:3px;margin-bottom:12px;">',a.forEach(function(e){const n=o(t[e].byModel||{}),a=Math.max(n/d*100,n>0?2:0),i=e===m,l=((t[e].prompt||0)+(t[e].completion||0))/1e3;r+='<div style="display:flex;align-items:center;gap:8px;font-size:11px;"><span style="width:64px;color:var(--text-3);flex-shrink:0;">'+(i?"today":e.slice(5))+'</span><div style="flex:1;background:var(--bg-1);border-radius:3px;height:12px;overflow:hidden;"><div style="width:'+a.toFixed(1)+"%;height:100%;background:"+(i?"var(--accent)":"var(--green)")+';border-radius:3px;opacity:.8;"></div></div><span style="width:58px;text-align:right;color:var(--yellow);font-weight:600;">$'+n.toFixed(4)+'</span><span style="width:40px;text-align:right;color:var(--text-3);">'+l.toFixed(0)+"k</span></div>"}),r+="</div>";const y=Object.entries(l).sort(function(t,e){return o({b:e[1]})-o({a:t[1]})});y.length&&(r+='<div style="font-size:11px;color:var(--text-3);margin-bottom:4px;">By model</div>',y.slice(0,8).forEach(function(t){var e=t[0],n=t[1];const a=o({x:n}),i=((n.prompt||0)+(n.completion||0))/1e3;r+='<div style="display:flex;justify-content:space-between;font-size:11px;padding:2px 0;border-bottom:1px solid var(--border);"><code style="color:var(--accent);">'+e+'</code><span style="color:var(--text-2);">'+i.toFixed(1)+'k tok &middot; <span style="color:var(--yellow);">$'+a.toFixed(4)+"</span></span></div>"})),i=g,s(),c.innerHTML=r}}catch(m){n(c,"Error: "+m.message)}}async function p(){if(confirm("Reset today's spending counters?"))try{await fetch("/api/spending/reset",{method:"POST",headers:{"content-type":"application/json"},body:"{}"}),c(),t("Spending reset")}catch(e){t("Reset failed",!0)}}async function g(){const e=parseInt(document.getElementById("gcapTokens").value)||null,n=parseFloat(document.getElementById("gcapCost").value)||null;t('Add to ~/.crewswarm/crewswarm.json: "globalSpendingCaps": {"dailyTokenLimit":'+(e||"null")+',"dailyCostLimitUSD":'+(n||"null")+"}","warning")}export{d as a,r as b,c as l,p as r,g as s};
@@ -1 +0,0 @@
1
- import{a as s,b as t,g as e,e as a,s as n,p as i}from"./core-utils-CmOkXgzi.js";let l=()=>{},r=()=>{};function o(s={}){l=s.hideAllViews||l,r=s.setNavActive||r}let d=null;function c(){l(),document.getElementById("testingView").classList.add("active"),r("navTesting"),s.activeTab="testing",t(),m(),g(),e("/api/tests/progress").then(s=>{s.running&&!y&&(b(),y=setInterval(b,2e3))}).catch(()=>{}),d&&clearInterval(d),d=setInterval(()=>{document.getElementById("testingView").classList.contains("active")?(m(),g()):(clearInterval(d),d=null)},3e4)}function u(s){return!s||s<=0?"-":s>=6e4?(s/6e4).toFixed(1)+"m":s>=1e3?(s/1e3).toFixed(1)+"s":Math.round(s)+"ms"}function p(s){if(!s)return"-";const t=new Date(s);return t.toLocaleDateString(void 0,{month:"short",day:"numeric"})+" "+t.toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"})}function v(s,t){const e=s+t;return 0===e?"-":(s/e*100).toFixed(0)+"%"}const f={unit:"Unit",integration:"Integration",e2e:"E2E",all:"All",unknown:"Other"},h={unit:"#818cf8",integration:"#34d399",e2e:"#fbbf24",all:"#60a5fa",unknown:"#94a3b8"};async function m(){var s;const t=document.getElementById("testingContent");if(t)try{const n=await e("/api/tests/summary");if(!n.latest&&!n.fileCounts)return void(t.innerHTML='<div class="empty-state">No test results found. Run tests to see results here.</div>');let i="";const l=n.fileCounts||{},r=n.testCounts||{};i+='<div class="test-launch-grid">';const o=[{key:"unit",label:"Unit",files:l.unit,tests:r.unit,cmd:"test:unit",color:h.unit},{key:"integration",label:"Integration",files:l.integration,tests:r.integration,cmd:"test:integration",color:h.integration},{key:"e2e",label:"E2E",files:l.e2e,tests:r.e2e,cmd:"test:e2e",color:h.e2e},{key:"playwright",label:"Playwright",files:l.playwright,tests:r.playwright,cmd:"test:e2e:vibe",color:"#f472b6"},{key:"crew-cli",label:"crew-cli",files:l["crew-cli"],tests:r["crew-cli"],cmd:"test",color:"#10b981"}];for(const s of o){const t=s.tests?`<span class="test-launch-tests">${s.tests} tests</span>`:"",e=s.cmd?`<button class="test-launch-btn" data-action="runTests" data-arg="${s.cmd}">▶ Run</button>`:'<span class="meta" style="font-size:10px">npx playwright test</span>';i+=`\n <div class="test-launch-card" style="border-color:${s.color}30">\n <div class="test-launch-header">\n <span class="test-launch-name" style="color:${s.color}">${s.label}</span>\n ${e}\n </div>\n <div class="test-launch-counts">\n <span class="test-launch-files">${s.files||0} files</span>\n ${t}\n </div>\n </div>`}const d=Object.values(r).reduce((s,t)=>s+(t||0),0);i+=`\n <div class="test-launch-card test-launch-total" style="border-color:var(--accent)">\n <div class="test-launch-header">\n <span class="test-launch-name" style="color:var(--accent)">All</span>\n <button class="test-launch-btn" data-action="runTests" data-arg="test:all" style="background:var(--accent);color:#fff">▶ Run All</button>\n </div>\n <div class="test-launch-counts">\n <span class="test-launch-files">${l.total||0} files</span>\n ${d?`<span class="test-launch-tests">${d}+ tests</span>`:""}\n </div>\n </div>`,i+="</div>",i+='<div class="test-section-title">Latest Results by Suite</div>',i+='<div class="test-suite-grid">';for(const t of["unit","integration","e2e","all"]){const e=null==(s=n.suites)?void 0:s[t];if(!e||!e.total&&!e.passed&&!e.failed)continue;const a=(e.passed||0)+(e.failed||0),l=e.failed>0?"test-status-fail":"test-status-pass",r=e.failed>0?"FAIL":"PASS";i+=`\n <div class="test-suite-card">\n <div class="test-suite-header">\n <span class="test-suite-name" style="color:${h[t]}">${f[t]}</span>\n <span class="test-summary-status ${l}">${r}</span>\n </div>\n <div class="test-suite-stats">\n <div><span class="test-color-pass">${e.passed||0}</span> pass</div>\n <div><span class="${e.failed>0?"test-color-fail":""}">${e.failed||0}</span> fail</div>\n <div><span class="${e.skipped>0?"test-color-skip":""}">${e.skipped||0}</span> skip</div>\n <div><strong>${e.total||0}</strong> total</div>\n </div>\n <div class="test-suite-meta">\n ${v(e.passed||0,e.failed||0)} pass rate · ${u(e.duration_ms)} · ${p(e.timestamp)}\n </div>\n <div class="test-progress-bar">\n <div class="test-progress-pass" style="width:${a>0?(e.passed||0)/a*100:0}%"></div>\n <div class="test-progress-fail" style="width:${a>0?(e.failed||0)/a*100:0}%"></div>\n </div>\n </div>`}i+="</div>";const c=[];for(const s of Object.values(n.suites||{}))s.failures&&c.push(...s.failures);if(c.length>0){i+=`<div class="test-section-title">Failures (${c.length})</div>`;for(const s of c)i+=`\n <div class="test-failure-card">\n <div class="test-failure-name">${a(s.name)}</div>\n <div class="test-failure-file">${a(s.file)}</div>\n ${s.classification&&"unknown"!==s.classification?`<span class="test-failure-class">${a(s.classification)}</span>`:""}\n ${s.error?`<pre class="test-failure-error">${a(String(s.error).slice(0,500))}</pre>`:""}\n ${s.rerun_command?`<div class="test-failure-rerun"><code>${a(s.rerun_command)}</code></div>`:""}\n </div>`}const m=[];for(const[s,t]of Object.entries(n.suites||{}))t.skips&&m.push(...t.skips.map(t=>({...t,suite:s})));if(m.length>0){i+='<details class="test-skips-section">',i+=`<summary class="test-section-title" style="cursor:pointer">Skipped (${m.length}) — click to expand</summary>`,i+='<table class="test-groups-table"><thead><tr><th>Test</th><th>File</th><th>Suite</th></tr></thead><tbody>';for(const s of m.slice(0,50))i+=`<tr><td>${a(s.name)}</td><td class="meta">${a(s.file)}</td><td><span class="test-cat-badge test-cat-${a(s.suite)}">${a(s.suite)}</span></td></tr>`;m.length>50&&(i+=`<tr><td colspan="3" class="meta">...and ${m.length-50} more</td></tr>`),i+="</tbody></table></details>"}t.innerHTML=i}catch(n){t.innerHTML=`<div class="empty-state">Failed to load test results: ${a(n.message)}</div>`}}async function g(){const s=document.getElementById("testingHistory");if(s)try{const t=await e("/api/tests/history");if(!t.history||0===t.history.length)return void(s.innerHTML='<div class="meta">No run history yet.</div>');let n='<div class="test-section-title">Run History</div>';n+='\n <table class="test-history-table">\n <thead>\n <tr>\n <th>When</th>\n <th>Suite</th>\n <th>Status</th>\n <th class="num">Pass</th>\n <th class="num">Fail</th>\n <th class="num">Skip</th>\n <th class="num">Total</th>\n <th class="num">Duration</th>\n <th class="num">Rate</th>\n </tr>\n </thead>\n <tbody>';for(const s of t.history.slice(0,25)){const t=s.failed>0?"test-color-fail":"test-color-pass",e=f[s.suite]||s.suite||"?",i=h[s.suite]||h.unknown;n+=`\n <tr data-action="loadRunDetail" data-arg="${a(s.runId)}" style="cursor:pointer" class="${s.failed>0?"test-row-fail":""}">\n <td class="meta" style="white-space:nowrap">${p(s.timestamp)}</td>\n <td><span class="test-cat-badge" style="background:${i}20;color:${i}">${e}</span></td>\n <td class="${t}" style="font-weight:600">${s.failed>0?"FAIL":"PASS"} ▸</td>\n <td class="num">${s.passed}</td>\n <td class="num ${s.failed>0?"test-color-fail":""}">${s.failed}</td>\n <td class="num ${s.skipped>0?"test-color-skip":""}">${s.skipped}</td>\n <td class="num"><strong>${s.total}</strong></td>\n <td class="num">${u(s.duration_ms)}</td>\n <td class="num">${v(s.passed,s.failed)}</td>\n </tr>`}n+="</tbody></table>",n+='<div id="testingRunDetail"></div>',s.innerHTML=n}catch(t){s.innerHTML=`<div class="meta">Failed to load history: ${a(t.message)}</div>`}}async function $(s){var t,n;const i=document.getElementById("testingRunDetail");if(i){i.innerHTML='<div class="meta" style="padding:12px">Loading run detail...</div>';try{const l=await e("/api/tests/run-detail?runId="+encodeURIComponent(s));if(l.error)return void(i.innerHTML=`<div class="meta">${a(l.error)}</div>`);let r=`<div class="test-section-title">Run Detail: ${a(s)} <span class="meta" style="font-weight:400;font-size:11px;text-transform:none">${p(l.timestamp)}</span></div>`;r+=`<div class="test-suite-meta" style="margin-bottom:12px">${l.passed} pass, ${l.failed} fail, ${l.skipped} skip, ${l.total} total · ${u(l.duration_ms)} · ${v(l.passed,l.failed)} pass rate</div>`;if(!((null==(t=l.failures)?void 0:t.length)>0||(null==(n=l.skips)?void 0:n.length)>0)&&l.total>0&&(r+='<div class="meta" style="padding:8px 0;color:var(--text-2)">No detailed failure/skip data saved for this run. Run with <code>npm run test:all</code> to generate full reports.</div>'),l.failures&&l.failures.length>0){r+=`<div class="test-section-title">Failures (${l.failures.length})</div>`;for(const s of l.failures)r+=`\n <div class="test-failure-card">\n <div class="test-failure-name">${a(s.name)}</div>\n <div class="test-failure-file">${a(s.file)}</div>\n ${s.error?`<pre class="test-failure-error">${a(String(s.error).slice(0,500))}</pre>`:""}\n ${s.rerun_command?`<div class="test-failure-rerun"><code>${a(s.rerun_command)}</code></div>`:""}\n </div>`}if(l.skips&&l.skips.length>0){r+=`<details><summary class="test-section-title" style="cursor:pointer">Skipped (${l.skips.length})</summary>`,r+='<table class="test-groups-table"><thead><tr><th>Test</th><th>File</th></tr></thead><tbody>';for(const s of l.skips.slice(0,50))r+=`<tr><td>${a(s.name)}</td><td class="meta">${a(s.file)}</td></tr>`;l.skips.length>50&&(r+=`<tr><td colspan="2" class="meta">...and ${l.skips.length-50} more</td></tr>`),r+="</tbody></table></details>"}i.innerHTML=r,i.scrollIntoView({behavior:"smooth",block:"nearest"})}catch(l){i.innerHTML=`<div class="meta">Failed: ${a(l.message)}</div>`}}}let y=null;function b(){const s=document.getElementById("testProgressBar");s&&e("/api/tests/progress").then(t=>{var e;if(!t.running&&!t.finished)return void(s.innerHTML="");const n=((t.finished||Date.now())-t.started)/1e3,i=n>=60?(n/60).toFixed(1)+"m":Math.round(n)+"s",l=t.passed+t.failed+t.skipped,r=f[null==(e=t.suite)?void 0:e.replace("test:","")]||t.suite||"Tests";if(t.running){const e=t.current_file?t.current_file.split("/").pop():"";s.innerHTML=`\n <div class="test-progress-live">\n <div class="test-progress-live-header">\n <span class="test-progress-live-status">⏳ Running ${a(r)}...</span>\n <span class="meta">${i}</span>\n </div>\n <div class="test-progress-live-stats">\n <span class="test-color-pass">${t.passed} pass</span>\n <span class="test-color-fail">${t.failed} fail</span>\n <span class="test-color-skip">${t.skipped} skip</span>\n <span>${t.files_done} files</span>\n <span>${l} tests</span>\n </div>\n ${e?`<div class="test-progress-live-file">${a(e)}</div>`:""}\n <div class="test-progress-bar" style="margin-top:6px">\n <div class="test-progress-pass" style="width:${l>0?t.passed/l*100:0}%;transition:width 0.3s"></div>\n <div class="test-progress-fail" style="width:${l>0?t.failed/l*100:0}%;transition:width 0.3s"></div>\n </div>\n </div>`}else{const e=t.failed>0?"test-color-fail":"test-color-pass",n=t.failed>0?"FAILED":"PASSED";s.innerHTML=`\n <div class="test-progress-live test-progress-done">\n <div class="test-progress-live-header">\n <span class="${e}" style="font-weight:700">✓ ${a(r)} ${n}</span>\n <span class="meta">${i}</span>\n </div>\n <div class="test-progress-live-stats">\n <span class="test-color-pass">${t.passed} pass</span>\n <span class="test-color-fail">${t.failed} fail</span>\n <span class="test-color-skip">${t.skipped} skip</span>\n <span>${t.files_done} files</span>\n </div>\n </div>`,y&&(clearInterval(y),y=null),m(),g(),setTimeout(()=>{s&&(s.innerHTML="")},1e4)}}).catch(()=>{})}async function k(s){try{n(`Starting ${s}...`),await i("/api/tests/run",{suite:s}),y&&clearInterval(y),b(),y=setInterval(b,2e3)}catch(t){n("Failed to start tests: "+t.message,!0)}}export{o as i,$ as l,k as r,c as s};
Binary file