cli-jaw 2.2.0 → 2.2.1

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 (123) hide show
  1. package/README.ko.md +1 -1
  2. package/README.md +22 -3
  3. package/README.zh-CN.md +1 -1
  4. package/dist/bin/cli-jaw.js +5 -1
  5. package/dist/bin/cli-jaw.js.map +1 -1
  6. package/dist/bin/commands/bgtask.js +2 -1
  7. package/dist/bin/commands/bgtask.js.map +1 -1
  8. package/dist/bin/commands/dispatch-batch-summary.js +38 -0
  9. package/dist/bin/commands/dispatch-batch-summary.js.map +1 -0
  10. package/dist/bin/commands/dispatch.js +91 -52
  11. package/dist/bin/commands/dispatch.js.map +1 -1
  12. package/dist/bin/commands/jwc.js +237 -0
  13. package/dist/bin/commands/jwc.js.map +1 -0
  14. package/dist/bin/commands/skill.js +17 -4
  15. package/dist/bin/commands/skill.js.map +1 -1
  16. package/dist/bin/commands/worker.js +162 -4
  17. package/dist/bin/commands/worker.js.map +1 -1
  18. package/dist/lib/mcp/skills-distribution.js +17 -19
  19. package/dist/lib/mcp/skills-distribution.js.map +1 -1
  20. package/dist/server.js +2 -1
  21. package/dist/server.js.map +1 -1
  22. package/dist/src/agent/jwc-runtime.js +12 -3
  23. package/dist/src/agent/jwc-runtime.js.map +1 -1
  24. package/dist/src/bgtask/registry.js +12 -2
  25. package/dist/src/bgtask/registry.js.map +1 -1
  26. package/dist/src/browser/adaptive-fetch/browser-escalation.js +122 -0
  27. package/dist/src/browser/adaptive-fetch/browser-escalation.js.map +1 -1
  28. package/dist/src/browser/adaptive-fetch/browser-flow.js +57 -0
  29. package/dist/src/browser/adaptive-fetch/browser-flow.js.map +1 -0
  30. package/dist/src/browser/adaptive-fetch/candidate-discovery.js +116 -0
  31. package/dist/src/browser/adaptive-fetch/candidate-discovery.js.map +1 -0
  32. package/dist/src/browser/adaptive-fetch/feed-parser.js +152 -0
  33. package/dist/src/browser/adaptive-fetch/feed-parser.js.map +1 -0
  34. package/dist/src/browser/adaptive-fetch/index.js +9 -59
  35. package/dist/src/browser/adaptive-fetch/index.js.map +1 -1
  36. package/dist/src/browser/adaptive-fetch/live-smoke-manifest.js +43 -0
  37. package/dist/src/browser/adaptive-fetch/live-smoke-manifest.js.map +1 -0
  38. package/dist/src/browser/adaptive-fetch/metadata.js +74 -5
  39. package/dist/src/browser/adaptive-fetch/metadata.js.map +1 -1
  40. package/dist/src/browser/adaptive-fetch/public-endpoint-normalizers.js +414 -0
  41. package/dist/src/browser/adaptive-fetch/public-endpoint-normalizers.js.map +1 -0
  42. package/dist/src/browser/adaptive-fetch/reader-adapters.js +36 -0
  43. package/dist/src/browser/adaptive-fetch/reader-adapters.js.map +1 -1
  44. package/dist/src/cli/commands.js +2 -0
  45. package/dist/src/cli/commands.js.map +1 -1
  46. package/dist/src/cli/handlers-search.js +28 -0
  47. package/dist/src/cli/handlers-search.js.map +1 -0
  48. package/dist/src/cli/handlers.js +12 -1
  49. package/dist/src/cli/handlers.js.map +1 -1
  50. package/dist/src/code-mode/acp-host.js +1 -8
  51. package/dist/src/code-mode/acp-host.js.map +1 -1
  52. package/dist/src/orchestrator/pipeline.js +2 -4
  53. package/dist/src/orchestrator/pipeline.js.map +1 -1
  54. package/dist/src/orchestrator/worker-output-store.js +64 -0
  55. package/dist/src/orchestrator/worker-output-store.js.map +1 -0
  56. package/dist/src/orchestrator/worker-progress.js.map +1 -1
  57. package/dist/src/orchestrator/worker-registry.js +91 -10
  58. package/dist/src/orchestrator/worker-registry.js.map +1 -1
  59. package/dist/src/orchestrator/worker-replay-notice.js +28 -0
  60. package/dist/src/orchestrator/worker-replay-notice.js.map +1 -0
  61. package/dist/src/orchestrator/worker-run-store.js +142 -0
  62. package/dist/src/orchestrator/worker-run-store.js.map +1 -0
  63. package/dist/src/routes/bgtask.js +13 -4
  64. package/dist/src/routes/bgtask.js.map +1 -1
  65. package/dist/src/routes/orchestrate.js +53 -4
  66. package/dist/src/routes/orchestrate.js.map +1 -1
  67. package/dist/src/shared/runtime-observability.js +20 -0
  68. package/dist/src/shared/runtime-observability.js.map +1 -0
  69. package/dist/src/workflows/search.js +34 -0
  70. package/dist/src/workflows/search.js.map +1 -0
  71. package/package.json +6 -7
  72. package/public/dist/assets/{app-BsVpXeLC.js → app-BbBXyLe3.js} +4 -4
  73. package/public/dist/assets/{bgtask-badge-DqMU3pM3.js → bgtask-badge-BioRIkPz.js} +1 -1
  74. package/public/dist/assets/bgtask-badge-BwMVGFG_.js +1 -0
  75. package/public/dist/assets/{employees-BhkR2-xi.js → employees-B8cUYBRx.js} +1 -1
  76. package/public/dist/assets/manager-Ceg2x8D0.js +13 -0
  77. package/public/dist/assets/{manager-U147AWWu.css → manager-CwAlpgV7.css} +1 -1
  78. package/public/dist/assets/{memory-DERWDVjI.js → memory-3J4rzlxy.js} +1 -1
  79. package/public/dist/assets/memory-B5CQnDFI.js +1 -0
  80. package/public/dist/assets/message-history-BYswFI5p.js +1 -0
  81. package/public/dist/assets/{message-history-CK0ah3pB.js → message-history-Vv3aIRWS.js} +2 -2
  82. package/public/dist/assets/{render-CqzsW5KN.js → render-BVZ1xMEu.js} +1 -1
  83. package/public/dist/assets/{settings-DdwmhI5a.js → settings-C5FVzFpn.js} +1 -1
  84. package/public/dist/assets/settings-DZ4wz5SY.js +1 -0
  85. package/public/dist/assets/{settings-core-AiF7o3Ns.js → settings-core-5lL6lIyu.js} +1 -1
  86. package/public/dist/assets/settings-core-DYnePZHe.js +1 -0
  87. package/public/dist/assets/{sidebar-Bhtk2fPc.js → sidebar-jRPFidCd.js} +3 -3
  88. package/public/dist/assets/{skills-Cs8byPIx.js → skills-BjOjT5sG.js} +1 -1
  89. package/public/dist/assets/skills-CH0wHfkw.js +1 -0
  90. package/public/dist/assets/{slash-commands-C5erv0KS.js → slash-commands-B2oqpz-B.js} +1 -1
  91. package/public/dist/assets/slash-commands-C_9y_-8B.js +1 -0
  92. package/public/dist/assets/{trace-drawer-CtmD6jwj.js → trace-drawer-BQIdKFZx.js} +1 -1
  93. package/public/dist/assets/{ui-DaFl446W.js → ui-B9KmU-Qr.js} +1 -1
  94. package/public/dist/assets/ui-BCJ4lcQ4.js +1 -0
  95. package/public/dist/index.html +1 -1
  96. package/public/dist/manager/index.html +2 -2
  97. package/public/js/features/command-info.ts +1 -0
  98. package/public/locales/en.json +2 -0
  99. package/public/locales/ja.json +2 -0
  100. package/public/locales/ko.json +2 -0
  101. package/public/locales/zh.json +2 -0
  102. package/public/manager/src/SidebarRailRouter.tsx +7 -3
  103. package/public/manager/src/background-tasks/background-task-client.ts +21 -1
  104. package/public/manager/src/main.tsx +2 -0
  105. package/public/manager/src/workers/WorkerProgressMonitorPanel.tsx +2 -0
  106. package/public/manager/src/workers/WorkerRunsPanel.tsx +152 -0
  107. package/public/manager/src/workers/useWorkerRuns.ts +138 -0
  108. package/public/manager/src/workers/worker-runs-client.ts +112 -0
  109. package/public/manager/src/workers/worker-runs.css +208 -0
  110. package/scripts/bundle-sidecar.sh +2 -64
  111. package/scripts/check-electron-sidecar-no-jwc.cjs +57 -0
  112. package/scripts/install-risk-gate.mjs +3 -2
  113. package/scripts/jwc-no-global-smoke.mjs +14 -22
  114. package/public/dist/assets/bgtask-badge-YR8SMYrp.js +0 -1
  115. package/public/dist/assets/manager-ycX0r7uL.js +0 -13
  116. package/public/dist/assets/memory-CfeG2ViL.js +0 -1
  117. package/public/dist/assets/message-history-BaI36ciH.js +0 -1
  118. package/public/dist/assets/settings-VeoQiKpd.js +0 -1
  119. package/public/dist/assets/settings-core-DlfGtuWD.js +0 -1
  120. package/public/dist/assets/skills-Z0rMlwnf.js +0 -1
  121. package/public/dist/assets/slash-commands-CZKlw4A6.js +0 -1
  122. package/public/dist/assets/ui-WRcA4tUT.js +0 -1
  123. package/scripts/check-electron-sidecar-jwc.cjs +0 -117
@@ -1,2 +1,2 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/vendor-render-Bjnw0wQ6.css"])))=>i.map(i=>d[i]);
2
- import{t as e}from"./state-DxpgDKMO.js";import{t}from"./preload-helper-DFYRRz9w.js";import{E as n,S as r,t as i,v as a,w as o}from"./render-CqzsW5KN.js";import{B as s,C as c,D as l,E as u,G as d,H as f,I as p,J as m,K as h,O as g,R as _,S as v,U as y,V as ee,W as b,X as te,_ as x,b as S,f as C,g as w,h as ne,l as re,m as T,p as ie,q as E,u as D,v as ae,w as O,x as k,y as A,z as j}from"./message-history-CK0ah3pB.js";import{o as oe}from"./idb-cache-DTKWSF12.js";var se=2e3,ce=80;function M(e){return{chunks:[],fullText:``,textDirty:!1,element:e,pendingRAF:null,isFinalized:!1,lastRenderTime:0}}function le(e,t=``){let n=M(e);return t?(n.chunks=[t],n.fullText=t,n.textDirty=!1,n.element.innerHTML=i(t,!0)+`<span class="stream-cursor" aria-hidden="true"></span>`):n.element.innerHTML=`<span class="stream-cursor" aria-hidden="true"></span>`,n}function N(e){return e.textDirty&&=(e.fullText=e.chunks.join(``),!1),e.fullText}function P(e,t){e.chunks.push(t),e.textDirty=!0,!e.pendingRAF&&!e.isFinalized&&(e.pendingRAF=requestAnimationFrame(()=>{if(e.pendingRAF=null,e.isFinalized)return;let t=performance.now(),n=N(e);n.length<se||t-e.lastRenderTime>ce?(e.element.innerHTML=i(n,!0)+`<span class="stream-cursor" aria-hidden="true"></span>`,e.lastRenderTime=t):e.pendingRAF=requestAnimationFrame(()=>{e.pendingRAF=null,!e.isFinalized&&(e.element.innerHTML=i(N(e),!0)+`<span class="stream-cursor" aria-hidden="true"></span>`,e.lastRenderTime=performance.now())})}))}function F(e,t=!1){e.isFinalized=!0,e.pendingRAF&&=(cancelAnimationFrame(e.pendingRAF),null);let n=N(e);return t||(e.element.innerHTML=i(n)),n}function I(e){return typeof e.traceSeq==`number`&&Number.isFinite(e.traceSeq)&&e.traceSeq>0}function L(e,t){return!!t.traceRunId&&!!e.traceRunId&&t.traceRunId===e.traceRunId&&I(t)&&I(e)&&t.traceSeq===e.traceSeq&&t.type===e.type&&t.label===e.label&&!!t.isEmployee==!!e.isEmployee}function R(e,t){return t.stepRef&&e.stepRef===t.stepRef?!0:L(e,t)}function z(e,t,n={}){return[...e].reverse().filter(e=>n.includeDone||e.status===`running`).find(e=>R(e,t))??null}function B(e,t){let n=e.filter(e=>e.status===`running`&&!e.stepRef&&e.label===t.label&&e.type===t.type&&!!e.isEmployee==!!t.isEmployee);return n.length===1?n[0]:null}function V(e,t){let n=[...e].reverse().filter(e=>e.status===`running`);return z(n,t)||B(n,t)}function H(){e.currentProcessBlock&&d(e.currentProcessBlock),e.currentAgentDiv instanceof HTMLElement&&d(e.currentAgentDiv),l(),m(),e.currentAgentDiv=null,e.currentProcessBlock=null,q=null}var U=0;function W(){U=Date.now()}function ue(){U=0}function de(){return Date.now()-U<8e3}function G(e){for(let t of document.querySelectorAll(`.msg-user`))if(e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING)return!0;return!1}function K(){let t=e.currentAgentDiv&&e.currentAgentDiv.isConnected?e.currentAgentDiv:null;return t?G(t)?(e.currentAgentDiv=null,e.currentProcessBlock=null,q=null,null):t:null}function fe(){let e=Array.from(document.querySelectorAll(`.msg-agent`)).at(-1)??null;return!e||G(e)?null:e}function pe(t){A();let n=K();if(n||(n=x(`agent`,``),e.currentAgentDiv=n,e.currentProcessBlock=null),v(n),!e.currentProcessBlock){let t=n.querySelector(`.agent-body`);t&&(e.currentProcessBlock=S(n)),!e.currentProcessBlock&&t&&(c(n),e.currentProcessBlock=f(t))}if(e.currentProcessBlock){let n=t.rawIcon||t.icon,i=t.status||r(t.icon)||`running`;if(i===`done`||i===`error`){let r=V(e.currentProcessBlock.steps,t);if(r){t.icon=o(t.icon);let a=t.type===`thinking`?E(r.id,t.detail):b(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,detail:a,detailPreview:a,label:t.label||r.label,status:i}),p();return}if(t.stepRef&&(i===`done`||i===`error`)){let r=[...e.currentProcessBlock.steps].reverse().find(e=>e.stepRef===t.stepRef&&(e.status===`done`||e.status===`error`));if(r){t.icon=o(t.icon);let a=t.type===`thinking`?E(r.id,t.detail):b(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,status:i,detail:a,detailPreview:a}),p();return}}}if(t.stepRef&&i===`running`){let r=[...e.currentProcessBlock.steps].reverse().find(e=>e.stepRef===t.stepRef&&e.status===`running`);if(r){t.rawIcon=n,t.icon=o(t.icon);let i=E(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,status:`running`,detail:i,detailPreview:i,label:t.label||r.label}),p();return}}let a=z(e.currentProcessBlock.steps,t,{includeDone:!0});if(a){t.rawIcon=n,t.icon=o(t.icon);let r=t.detail||``,s=y(a.id)||a.detail||a.detailPreview||``,c=r.length>=s.length?r:s,l=E(a.id,c),u=(a.status===`done`||a.status===`error`)&&i===`running`?a.status:i;h(e.currentProcessBlock,a.id,{...a,...t,id:a.id,rawIcon:n,status:u,detail:l,detailPreview:l,label:t.label||a.label}),p();return}if(t.detail){let n=[...e.currentProcessBlock.steps].reverse().find(e=>e.status===`running`&&e.label===t.label&&e.type===t.type&&!!e.isEmployee==!!t.isEmployee&&!e.detail);if(n){h(e.currentProcessBlock,n.id,t),p();return}}t.rawIcon=n,t.icon=o(t.icon),j(e.currentProcessBlock,t)}p()}var q=null,J=`data-active-run-hydrated`;function Y(e){document.querySelectorAll(`[${J}="true"]`).forEach(t=>{e&&t===e||t.remove()})}function me(e){let t=K()??fe();Y(t);let n=t||x(`agent`,``,e||null);return n.setAttribute(J,`true`),n}function he(e,t){let n=y(e.id)||e.detail||e.detailPreview||``,r=t.detail||t.detailPreview||``;return r.length>=n.length?r:n}function X(e){return e.stepRef?!0:!!e.traceRunId&&typeof e.traceSeq==`number`&&Number.isFinite(e.traceSeq)&&e.traceSeq>0}function ge(e,t){let n=e.steps.filter(e=>!X(e)),r=0,i=!0;for(let a of t){let t=e.steps.find(e=>R(e,a))??null;if(!t&&!X(a)&&i){let e=n[r]??null;e?e.type===a.type&&!!e.isEmployee==!!a.isEmployee?(t=e,r++):i=!1:r++}if(!t){let n=e.steps.filter(e=>e.label===a.label&&e.type===a.type&&!!e.isEmployee==!!a.isEmployee);t=n.length===1?n[0]:null}if(!t){if(j(e,a),!X(a)&&i){let t=e.steps[e.steps.length-1];t&&n.push(t)}continue}let o=E(t.id,he(t,a));h(e,t.id,{...t,...a,id:t.id,detail:o,detailPreview:o,label:a.label||t.label})}}function _e(e=[]){document.querySelectorAll(`[data-queued-overlay="true"]`).forEach(e=>e.remove())}var Z=``;function ve(e){let t=Array.isArray(e.toolLog)?e.toolLog:[],n=t.map(e=>`${e.stepRef||``}~${e.traceRunId||``}~${e.traceSeq??``}~${e.status||``}~${e.label||``}~${(e.detail||``).length}`).join(`|`);return`${e.traceRunId||``}:${e.cli||``}:${(e.text||``).length}:${t.length}:${n}`}function Q(t){if(!t?.running){Z=``,Y();return}let n=ve(t);if(n===Z&&K())return;l(),A(),e.currentAgentDiv=me(t.cli||null);let r=e.currentAgentDiv.querySelector(`.agent-body`),i=T(t.toolLog||[]);v(e.currentAgentDiv),e.currentProcessBlock=S(e.currentAgentDiv),r&&i.length?(e.currentProcessBlock||=(c(e.currentAgentDiv),f(r)),ge(e.currentProcessBlock,w(i,t.startedAt))):e.currentProcessBlock=S(e.currentAgentDiv);let a=e.currentAgentDiv.querySelector(`.msg-content`);a&&(q=le(a,t.text||``)),Z=n}function ye(t){if(!t)return;A(),K()||(e.currentAgentDiv=x(`agent`,``),q=null);let n=e.currentAgentDiv?.querySelector(`.msg-content`);n&&(q||=M(n),P(q,t)),p()}var $=0;function be(e){e.querySelectorAll(`.mermaid-pending`).forEach(e=>{delete e.dataset.mermaidQueued,delete e.dataset.mermaidQueuedAt})}function xe(t,r){let o=Date.now();if(!e.currentAgentDiv&&o-$<500)return;Z=``,l(),A(),e.currentAgentDiv&&v(e.currentAgentDiv);let c=O(e.currentProcessBlock??e.currentAgentDiv,!0),u=T(ie(Array.isArray(r)?r:[],c)),f=ne(u),p=!!e.currentProcessBlock||!!(e.currentAgentDiv&&k(e.currentAgentDiv));e.currentProcessBlock&&=(ee(e.currentProcessBlock),null);let m=u.length>0;if(t||m){(!e.currentAgentDiv||!e.currentAgentDiv.isConnected)&&(e.currentAgentDiv=x(`agent`,``)),e.currentAgentDiv.removeAttribute(J);let r=e.currentAgentDiv?.querySelector(`.msg-content`),o=q?F(q,!0):``,c=t||o;if(q=null,r&&(r.innerHTML=i(c)),m&&e.currentAgentDiv&&!p&&!k(e.currentAgentDiv)){let t=e.currentAgentDiv.querySelector(`.msg-content`);t&&t.insertAdjacentHTML(`beforebegin`,s(w(u),!0))}e.currentAgentDiv&&v(e.currentAgentDiv),r&&r.setAttribute(`data-raw`,n(c)),r&&g(r);let l=_(),h=!!(l.active&&e.currentAgentDiv&&e.currentAgentDiv.isConnected);if(r&&!h&&a(r,{immediate:!0}),h){let t=e.currentAgentDiv;be(t),t.querySelectorAll(`.diagram-widget`).forEach(e=>{let t=e.dataset.widgetHtml;if(!t)return;let n=document.createElement(`div`);n.className=`diagram-widget-pending`,n.dataset.diagramHtml=t,e.replaceWith(n)}),f?(l.appendItem(C({role:`assistant`,content:c,cli:null,tool_log:f},l.count)),d(t),l.scrollToBottom()):(t.dataset.turnIndex=String(l.count),t.dataset.messageId||(t.dataset.messageId=te()),l.appendLiveItem(t)),t.remove()}c&&oe({role:`assistant`,content:c,tool_log:f,timestamp:Date.now()}).catch(()=>{})}q=null,e.currentAgentDiv=null,$=Date.now(),D(`idle`),re()}function Se(e,n){document.querySelectorAll(`.tab-btn`).forEach(e=>{e.classList.remove(`active`),e.setAttribute(`aria-selected`,`false`)}),document.querySelectorAll(`.tab-content`).forEach(e=>e.classList.remove(`active`)),document.getElementById({agents:`tabAgents`,settings:`tabSettings`,skills:`tabSkills`}[e])?.classList.add(`active`),n&&(n.classList.add(`active`),n.setAttribute(`aria-selected`,`true`)),e===`settings`&&t(()=>import(`./settings-VeoQiKpd.js`).then(e=>e.loadSettings()),__vite__mapDeps([0])),e===`agents`&&t(()=>import(`./employees-BhkR2-xi.js`).then(e=>e.loadEmployees()),__vite__mapDeps([0])),e===`skills`&&t(()=>import(`./skills-Z0rMlwnf.js`).then(e=>e.loadSkills()),__vite__mapDeps([0]))}function Ce(){let e=document.getElementById(`tabSettings`)?.classList.contains(`active`);t(()=>import(`./settings-VeoQiKpd.js`).then(t=>e?t.savePerCli():t.updateSettings()),__vite__mapDeps([0]))}function we(){u({onStatus:ae})}export{xe as a,we as c,pe as d,Se as f,ue as i,de as l,_e as n,Ce as o,H as r,Q as s,ye as t,W as u};
2
+ import{t as e}from"./state-DxpgDKMO.js";import{t}from"./preload-helper-DFYRRz9w.js";import{E as n,S as r,t as i,v as a,w as o}from"./render-BVZ1xMEu.js";import{B as s,C as c,D as l,E as u,G as d,H as f,I as p,J as m,K as h,O as g,R as _,S as v,U as y,V as ee,W as b,X as te,_ as x,b as S,f as C,g as w,h as ne,l as re,m as T,p as ie,q as E,u as D,v as ae,w as O,x as k,y as A,z as j}from"./message-history-Vv3aIRWS.js";import{o as oe}from"./idb-cache-DTKWSF12.js";var se=2e3,ce=80;function M(e){return{chunks:[],fullText:``,textDirty:!1,element:e,pendingRAF:null,isFinalized:!1,lastRenderTime:0}}function le(e,t=``){let n=M(e);return t?(n.chunks=[t],n.fullText=t,n.textDirty=!1,n.element.innerHTML=i(t,!0)+`<span class="stream-cursor" aria-hidden="true"></span>`):n.element.innerHTML=`<span class="stream-cursor" aria-hidden="true"></span>`,n}function N(e){return e.textDirty&&=(e.fullText=e.chunks.join(``),!1),e.fullText}function P(e,t){e.chunks.push(t),e.textDirty=!0,!e.pendingRAF&&!e.isFinalized&&(e.pendingRAF=requestAnimationFrame(()=>{if(e.pendingRAF=null,e.isFinalized)return;let t=performance.now(),n=N(e);n.length<se||t-e.lastRenderTime>ce?(e.element.innerHTML=i(n,!0)+`<span class="stream-cursor" aria-hidden="true"></span>`,e.lastRenderTime=t):e.pendingRAF=requestAnimationFrame(()=>{e.pendingRAF=null,!e.isFinalized&&(e.element.innerHTML=i(N(e),!0)+`<span class="stream-cursor" aria-hidden="true"></span>`,e.lastRenderTime=performance.now())})}))}function F(e,t=!1){e.isFinalized=!0,e.pendingRAF&&=(cancelAnimationFrame(e.pendingRAF),null);let n=N(e);return t||(e.element.innerHTML=i(n)),n}function I(e){return typeof e.traceSeq==`number`&&Number.isFinite(e.traceSeq)&&e.traceSeq>0}function L(e,t){return!!t.traceRunId&&!!e.traceRunId&&t.traceRunId===e.traceRunId&&I(t)&&I(e)&&t.traceSeq===e.traceSeq&&t.type===e.type&&t.label===e.label&&!!t.isEmployee==!!e.isEmployee}function R(e,t){return t.stepRef&&e.stepRef===t.stepRef?!0:L(e,t)}function z(e,t,n={}){return[...e].reverse().filter(e=>n.includeDone||e.status===`running`).find(e=>R(e,t))??null}function B(e,t){let n=e.filter(e=>e.status===`running`&&!e.stepRef&&e.label===t.label&&e.type===t.type&&!!e.isEmployee==!!t.isEmployee);return n.length===1?n[0]:null}function V(e,t){let n=[...e].reverse().filter(e=>e.status===`running`);return z(n,t)||B(n,t)}function H(){e.currentProcessBlock&&d(e.currentProcessBlock),e.currentAgentDiv instanceof HTMLElement&&d(e.currentAgentDiv),l(),m(),e.currentAgentDiv=null,e.currentProcessBlock=null,q=null}var U=0;function W(){U=Date.now()}function ue(){U=0}function de(){return Date.now()-U<8e3}function G(e){for(let t of document.querySelectorAll(`.msg-user`))if(e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_FOLLOWING)return!0;return!1}function K(){let t=e.currentAgentDiv&&e.currentAgentDiv.isConnected?e.currentAgentDiv:null;return t?G(t)?(e.currentAgentDiv=null,e.currentProcessBlock=null,q=null,null):t:null}function fe(){let e=Array.from(document.querySelectorAll(`.msg-agent`)).at(-1)??null;return!e||G(e)?null:e}function pe(t){A();let n=K();if(n||(n=x(`agent`,``),e.currentAgentDiv=n,e.currentProcessBlock=null),v(n),!e.currentProcessBlock){let t=n.querySelector(`.agent-body`);t&&(e.currentProcessBlock=S(n)),!e.currentProcessBlock&&t&&(c(n),e.currentProcessBlock=f(t))}if(e.currentProcessBlock){let n=t.rawIcon||t.icon,i=t.status||r(t.icon)||`running`;if(i===`done`||i===`error`){let r=V(e.currentProcessBlock.steps,t);if(r){t.icon=o(t.icon);let a=t.type===`thinking`?E(r.id,t.detail):b(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,detail:a,detailPreview:a,label:t.label||r.label,status:i}),p();return}if(t.stepRef&&(i===`done`||i===`error`)){let r=[...e.currentProcessBlock.steps].reverse().find(e=>e.stepRef===t.stepRef&&(e.status===`done`||e.status===`error`));if(r){t.icon=o(t.icon);let a=t.type===`thinking`?E(r.id,t.detail):b(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,status:i,detail:a,detailPreview:a}),p();return}}}if(t.stepRef&&i===`running`){let r=[...e.currentProcessBlock.steps].reverse().find(e=>e.stepRef===t.stepRef&&e.status===`running`);if(r){t.rawIcon=n,t.icon=o(t.icon);let i=E(r.id,t.detail);h(e.currentProcessBlock,r.id,{...r,...t,id:r.id,rawIcon:n,status:`running`,detail:i,detailPreview:i,label:t.label||r.label}),p();return}}let a=z(e.currentProcessBlock.steps,t,{includeDone:!0});if(a){t.rawIcon=n,t.icon=o(t.icon);let r=t.detail||``,s=y(a.id)||a.detail||a.detailPreview||``,c=r.length>=s.length?r:s,l=E(a.id,c),u=(a.status===`done`||a.status===`error`)&&i===`running`?a.status:i;h(e.currentProcessBlock,a.id,{...a,...t,id:a.id,rawIcon:n,status:u,detail:l,detailPreview:l,label:t.label||a.label}),p();return}if(t.detail){let n=[...e.currentProcessBlock.steps].reverse().find(e=>e.status===`running`&&e.label===t.label&&e.type===t.type&&!!e.isEmployee==!!t.isEmployee&&!e.detail);if(n){h(e.currentProcessBlock,n.id,t),p();return}}t.rawIcon=n,t.icon=o(t.icon),j(e.currentProcessBlock,t)}p()}var q=null,J=`data-active-run-hydrated`;function Y(e){document.querySelectorAll(`[${J}="true"]`).forEach(t=>{e&&t===e||t.remove()})}function me(e){let t=K()??fe();Y(t);let n=t||x(`agent`,``,e||null);return n.setAttribute(J,`true`),n}function he(e,t){let n=y(e.id)||e.detail||e.detailPreview||``,r=t.detail||t.detailPreview||``;return r.length>=n.length?r:n}function X(e){return e.stepRef?!0:!!e.traceRunId&&typeof e.traceSeq==`number`&&Number.isFinite(e.traceSeq)&&e.traceSeq>0}function ge(e,t){let n=e.steps.filter(e=>!X(e)),r=0,i=!0;for(let a of t){let t=e.steps.find(e=>R(e,a))??null;if(!t&&!X(a)&&i){let e=n[r]??null;e?e.type===a.type&&!!e.isEmployee==!!a.isEmployee?(t=e,r++):i=!1:r++}if(!t){let n=e.steps.filter(e=>e.label===a.label&&e.type===a.type&&!!e.isEmployee==!!a.isEmployee);t=n.length===1?n[0]:null}if(!t){if(j(e,a),!X(a)&&i){let t=e.steps[e.steps.length-1];t&&n.push(t)}continue}let o=E(t.id,he(t,a));h(e,t.id,{...t,...a,id:t.id,detail:o,detailPreview:o,label:a.label||t.label})}}function _e(e=[]){document.querySelectorAll(`[data-queued-overlay="true"]`).forEach(e=>e.remove())}var Z=``;function ve(e){let t=Array.isArray(e.toolLog)?e.toolLog:[],n=t.map(e=>`${e.stepRef||``}~${e.traceRunId||``}~${e.traceSeq??``}~${e.status||``}~${e.label||``}~${(e.detail||``).length}`).join(`|`);return`${e.traceRunId||``}:${e.cli||``}:${(e.text||``).length}:${t.length}:${n}`}function Q(t){if(!t?.running){Z=``,Y();return}let n=ve(t);if(n===Z&&K())return;l(),A(),e.currentAgentDiv=me(t.cli||null);let r=e.currentAgentDiv.querySelector(`.agent-body`),i=T(t.toolLog||[]);v(e.currentAgentDiv),e.currentProcessBlock=S(e.currentAgentDiv),r&&i.length?(e.currentProcessBlock||=(c(e.currentAgentDiv),f(r)),ge(e.currentProcessBlock,w(i,t.startedAt))):e.currentProcessBlock=S(e.currentAgentDiv);let a=e.currentAgentDiv.querySelector(`.msg-content`);a&&(q=le(a,t.text||``)),Z=n}function ye(t){if(!t)return;A(),K()||(e.currentAgentDiv=x(`agent`,``),q=null);let n=e.currentAgentDiv?.querySelector(`.msg-content`);n&&(q||=M(n),P(q,t)),p()}var $=0;function be(e){e.querySelectorAll(`.mermaid-pending`).forEach(e=>{delete e.dataset.mermaidQueued,delete e.dataset.mermaidQueuedAt})}function xe(t,r){let o=Date.now();if(!e.currentAgentDiv&&o-$<500)return;Z=``,l(),A(),e.currentAgentDiv&&v(e.currentAgentDiv);let c=O(e.currentProcessBlock??e.currentAgentDiv,!0),u=T(ie(Array.isArray(r)?r:[],c)),f=ne(u),p=!!e.currentProcessBlock||!!(e.currentAgentDiv&&k(e.currentAgentDiv));e.currentProcessBlock&&=(ee(e.currentProcessBlock),null);let m=u.length>0;if(t||m){(!e.currentAgentDiv||!e.currentAgentDiv.isConnected)&&(e.currentAgentDiv=x(`agent`,``)),e.currentAgentDiv.removeAttribute(J);let r=e.currentAgentDiv?.querySelector(`.msg-content`),o=q?F(q,!0):``,c=t||o;if(q=null,r&&(r.innerHTML=i(c)),m&&e.currentAgentDiv&&!p&&!k(e.currentAgentDiv)){let t=e.currentAgentDiv.querySelector(`.msg-content`);t&&t.insertAdjacentHTML(`beforebegin`,s(w(u),!0))}e.currentAgentDiv&&v(e.currentAgentDiv),r&&r.setAttribute(`data-raw`,n(c)),r&&g(r);let l=_(),h=!!(l.active&&e.currentAgentDiv&&e.currentAgentDiv.isConnected);if(r&&!h&&a(r,{immediate:!0}),h){let t=e.currentAgentDiv;be(t),t.querySelectorAll(`.diagram-widget`).forEach(e=>{let t=e.dataset.widgetHtml;if(!t)return;let n=document.createElement(`div`);n.className=`diagram-widget-pending`,n.dataset.diagramHtml=t,e.replaceWith(n)}),f?(l.appendItem(C({role:`assistant`,content:c,cli:null,tool_log:f},l.count)),d(t),l.scrollToBottom()):(t.dataset.turnIndex=String(l.count),t.dataset.messageId||(t.dataset.messageId=te()),l.appendLiveItem(t)),t.remove()}c&&oe({role:`assistant`,content:c,tool_log:f,timestamp:Date.now()}).catch(()=>{})}q=null,e.currentAgentDiv=null,$=Date.now(),D(`idle`),re()}function Se(e,n){document.querySelectorAll(`.tab-btn`).forEach(e=>{e.classList.remove(`active`),e.setAttribute(`aria-selected`,`false`)}),document.querySelectorAll(`.tab-content`).forEach(e=>e.classList.remove(`active`)),document.getElementById({agents:`tabAgents`,settings:`tabSettings`,skills:`tabSkills`}[e])?.classList.add(`active`),n&&(n.classList.add(`active`),n.setAttribute(`aria-selected`,`true`)),e===`settings`&&t(()=>import(`./settings-DZ4wz5SY.js`).then(e=>e.loadSettings()),__vite__mapDeps([0])),e===`agents`&&t(()=>import(`./employees-B8cUYBRx.js`).then(e=>e.loadEmployees()),__vite__mapDeps([0])),e===`skills`&&t(()=>import(`./skills-CH0wHfkw.js`).then(e=>e.loadSkills()),__vite__mapDeps([0]))}function Ce(){let e=document.getElementById(`tabSettings`)?.classList.contains(`active`);t(()=>import(`./settings-DZ4wz5SY.js`).then(t=>e?t.savePerCli():t.updateSettings()),__vite__mapDeps([0]))}function we(){u({onStatus:ae})}export{xe as a,we as c,pe as d,Se as f,ue as i,de as l,_e as n,Ce as o,H as r,Q as s,ye as t,W as u};
@@ -0,0 +1 @@
1
+ import{F as e,d as t,o as n}from"./message-history-Vv3aIRWS.js";import{r}from"./ui-B9KmU-Qr.js";export{r as cleanupToolActivity,n as loadMessages,e as reconcileChatBottomAfterRestore,t as updateQueueBadge};
@@ -31,7 +31,7 @@
31
31
  href="https://fonts.googleapis.com/css2?family=Chakra+Petch:wght@400;500;600;700&family=Outfit:wght@400;500;600;700&display=swap"
32
32
  rel="stylesheet">
33
33
  <!-- Vite handles module bundling in dev (HMR) and production (build) -->
34
- <script type="module" crossorigin src="/dist/assets/app-BsVpXeLC.js"></script>
34
+ <script type="module" crossorigin src="/dist/assets/app-BbBXyLe3.js"></script>
35
35
  <link rel="stylesheet" crossorigin href="/dist/assets/vendor-render-Bjnw0wQ6.css">
36
36
  <link rel="stylesheet" crossorigin href="/dist/assets/app-BPsa7jSJ.css">
37
37
  </head>
@@ -6,9 +6,9 @@
6
6
  <link rel="icon" type="image/png" href="/dist/assets/icon-192-CwXPIYF5.png">
7
7
  <title>Jaw Manager</title>
8
8
  <script src="/manager/theme-boot.js"></script>
9
- <script type="module" crossorigin src="/dist/assets/manager-ycX0r7uL.js"></script>
9
+ <script type="module" crossorigin src="/dist/assets/manager-Ceg2x8D0.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/dist/assets/vendor-render-Bjnw0wQ6.css">
11
- <link rel="stylesheet" crossorigin href="/dist/assets/manager-U147AWWu.css">
11
+ <link rel="stylesheet" crossorigin href="/dist/assets/manager-CwAlpgV7.css">
12
12
  </head>
13
13
  <body>
14
14
  <div id="manager-root"></div>
@@ -41,6 +41,7 @@ export const COMMAND_TOPIC_MAP: Record<string, HelpTopicId> = {
41
41
  deliberate: 'goals',
42
42
  planaudit: 'goals',
43
43
  review: 'goals',
44
+ search: 'mcp',
44
45
  team: 'goals',
45
46
  task: 'goals',
46
47
  help: 'keyboardShortcuts',
@@ -45,6 +45,8 @@
45
45
  "cmd.artifact.action.startPabcd": "Use in PABCD P",
46
46
  "cmd.workflow.planAudit.desc": "Create a read-only plan audit task",
47
47
  "cmd.workflow.planAudit.tg_desc": "Create plan audit task",
48
+ "cmd.workflow.search.desc": "Route search through the search skill",
49
+ "cmd.workflow.search.tg_desc": "Search through the search skill",
48
50
  "cmd.workflow.goal.desc": "Goal state and bounded run workflow",
49
51
  "cmd.workflow.goal.tg_desc": "Check goal or run state",
50
52
  "cmd.workflow.team.desc": "Parallel team orchestration",
@@ -45,6 +45,8 @@
45
45
  "cmd.artifact.action.startPabcd": "PABCD Pで使う",
46
46
  "cmd.workflow.planAudit.desc": "読み取り専用の計画監査タスクを作成",
47
47
  "cmd.workflow.planAudit.tg_desc": "計画監査タスクを作成",
48
+ "cmd.workflow.search.desc": "検索スキル経由で検索を実行",
49
+ "cmd.workflow.search.tg_desc": "検索スキルで検索",
48
50
  "cmd.workflow.goal.desc": "ゴール状態と制限付き実行ワークフロー",
49
51
  "cmd.workflow.goal.tg_desc": "ゴールまたは実行状態を確認",
50
52
  "cmd.workflow.team.desc": "並列チームオーケストレーション",
@@ -45,6 +45,8 @@
45
45
  "cmd.artifact.action.startPabcd": "PABCD P로 사용",
46
46
  "cmd.workflow.planAudit.desc": "읽기 전용 계획 감사 작업 생성",
47
47
  "cmd.workflow.planAudit.tg_desc": "계획 감사 작업 생성",
48
+ "cmd.workflow.search.desc": "검색 스킬로 검색 요청 라우팅",
49
+ "cmd.workflow.search.tg_desc": "검색 스킬로 검색",
48
50
  "cmd.workflow.goal.desc": "목표 상태와 제한 실행 워크플로우",
49
51
  "cmd.workflow.goal.tg_desc": "목표 또는 실행 상태 확인",
50
52
  "cmd.workflow.team.desc": "병렬 팀 오케스트레이션",
@@ -45,6 +45,8 @@
45
45
  "cmd.artifact.action.startPabcd": "用于 PABCD P",
46
46
  "cmd.workflow.planAudit.desc": "创建只读计划审计任务",
47
47
  "cmd.workflow.planAudit.tg_desc": "创建计划审计任务",
48
+ "cmd.workflow.search.desc": "通过搜索技能路由搜索请求",
49
+ "cmd.workflow.search.tg_desc": "通过搜索技能搜索",
48
50
  "cmd.workflow.goal.desc": "目标状态和受限运行工作流",
49
51
  "cmd.workflow.goal.tg_desc": "查看目标或运行状态",
50
52
  "cmd.workflow.team.desc": "并行团队编排",
@@ -65,6 +65,7 @@ import { ModeSwitch } from './code/ModeSwitch';
65
65
  const CodeCanvas = lazy(() => import('./code/CodeCanvas').then(m => ({ default: m.CodeCanvas })));
66
66
  import './code/code.css';
67
67
  import { useWorkbenchResourceState } from './workbench/useWorkbenchResourceState';
68
+ import { WorkerProgressMonitorPanel } from './workers/WorkerProgressMonitorPanel';
68
69
 
69
70
  type WorkspaceSurfaceProps = {
70
71
  active: boolean;
@@ -399,9 +400,12 @@ export function SidebarRailRouter(props: Props) {
399
400
  <div id="code-session-sidebar-host" className="code-session-sidebar-host" />
400
401
  </section>
401
402
  ) : (
402
- <InstanceNavigator active={props.selectedInstance} hiddenCount={props.instances.filter(instance => instance.hidden).length} collapsed={props.sidebarCollapsed}>
403
- {props.instanceListContent}
404
- </InstanceNavigator>
403
+ <>
404
+ <InstanceNavigator active={props.selectedInstance} hiddenCount={props.instances.filter(instance => instance.hidden).length} collapsed={props.sidebarCollapsed}>
405
+ {props.instanceListContent}
406
+ </InstanceNavigator>
407
+ <WorkerProgressMonitorPanel />
408
+ </>
405
409
  )}
406
410
  </div>
407
411
  </>
@@ -1,4 +1,5 @@
1
1
  export type BackgroundTaskStatus = 'running' | 'complete' | 'failed' | 'cancelled' | 'orphaned';
2
+ export type RuntimeStatusCategory = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'orphaned';
2
3
 
3
4
  export type BackgroundTaskCompletion =
4
5
  | { type: 'exit' }
@@ -46,11 +47,14 @@ export interface BackgroundTaskRow {
46
47
  completedAt: string | null;
47
48
  notifiedAt: string | null;
48
49
  runnerActive?: boolean;
50
+ statusCategory?: RuntimeStatusCategory;
49
51
  }
50
52
 
51
53
  export interface BackgroundTaskRunningSnapshot {
52
54
  id: string;
53
55
  kind: string;
56
+ status?: BackgroundTaskStatus;
57
+ statusCategory?: RuntimeStatusCategory;
54
58
  startedAt?: string | null;
55
59
  }
56
60
 
@@ -58,6 +62,7 @@ export interface BackgroundTaskChangedSnapshot {
58
62
  id: string;
59
63
  kind: string;
60
64
  status: BackgroundTaskStatus;
65
+ statusCategory?: RuntimeStatusCategory;
61
66
  }
62
67
 
63
68
  export interface BackgroundTaskUpdate {
@@ -206,6 +211,14 @@ function isStatus(value: unknown): value is BackgroundTaskStatus {
206
211
  || value === 'orphaned';
207
212
  }
208
213
 
214
+ function isStatusCategory(value: unknown): value is RuntimeStatusCategory {
215
+ return value === 'running'
216
+ || value === 'succeeded'
217
+ || value === 'failed'
218
+ || value === 'cancelled'
219
+ || value === 'orphaned';
220
+ }
221
+
209
222
  function normalizeRunning(value: unknown): BackgroundTaskRunningSnapshot[] {
210
223
  if (!Array.isArray(value)) return [];
211
224
  return value.flatMap((entry) => {
@@ -213,6 +226,8 @@ function normalizeRunning(value: unknown): BackgroundTaskRunningSnapshot[] {
213
226
  return [{
214
227
  id: entry['id'],
215
228
  kind: entry['kind'],
229
+ ...(isStatus(entry['status']) ? { status: entry['status'] } : {}),
230
+ ...(isStatusCategory(entry['statusCategory']) ? { statusCategory: entry['statusCategory'] } : {}),
216
231
  ...(typeof entry['startedAt'] === 'string' || entry['startedAt'] === null ? { startedAt: entry['startedAt'] } : {}),
217
232
  }];
218
233
  });
@@ -221,7 +236,12 @@ function normalizeRunning(value: unknown): BackgroundTaskRunningSnapshot[] {
221
236
  function normalizeChanged(value: unknown): BackgroundTaskChangedSnapshot | null {
222
237
  if (!isObject(value)) return null;
223
238
  if (typeof value['id'] !== 'string' || typeof value['kind'] !== 'string' || !isStatus(value['status'])) return null;
224
- return { id: value['id'], kind: value['kind'], status: value['status'] };
239
+ return {
240
+ id: value['id'],
241
+ kind: value['kind'],
242
+ status: value['status'],
243
+ ...(isStatusCategory(value['statusCategory']) ? { statusCategory: value['statusCategory'] } : {}),
244
+ };
225
245
  }
226
246
 
227
247
  export function normalizeBackgroundTaskUpdate(frame: unknown): BackgroundTaskUpdate | null {
@@ -26,6 +26,8 @@ import './manager-dashboard-reminders.css';
26
26
  import './manager-dashboard-reminders-priority.css';
27
27
  import './manager-dashboard-reminders-parity.css';
28
28
  import './manager-tray-reminders.css';
29
+ import './workers/worker-progress-monitor.css';
30
+ import './workers/worker-runs.css';
29
31
  import './settings-shell.css';
30
32
  import './settings-controls.css';
31
33
  import './settings-agent.css';
@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
2
2
  import type { WorkerProgressRun, WorkerProgressSnapshot } from './worker-progress-client';
3
3
  import { buildWorkerActivityTimeline } from './worker-activity-timeline';
4
4
  import { countWorkerProgress, useWorkerProgress } from './useWorkerProgress';
5
+ import { WorkerRunsPanel } from './WorkerRunsPanel';
5
6
 
6
7
  function runOf(snapshot: WorkerProgressSnapshot): WorkerProgressRun | null {
7
8
  return snapshot.current ?? snapshot.previous;
@@ -155,6 +156,7 @@ export function WorkerProgressMonitorPanel() {
155
156
  <span>{workers.length} tracked</span>
156
157
  <span>{lastReason}</span>
157
158
  </div>
159
+ <WorkerRunsPanel />
158
160
  </section>
159
161
  );
160
162
  }
@@ -0,0 +1,152 @@
1
+ import { useMemo, useState } from 'react';
2
+ import type { WorkerRunEvent, WorkerRunRecord, WorkerRunsClient } from './worker-runs-client';
3
+ import { useWorkerRuns } from './useWorkerRuns';
4
+
5
+ type WorkerRunsPanelProps = {
6
+ client?: WorkerRunsClient;
7
+ };
8
+
9
+ function formatTime(value: number | null | undefined): string {
10
+ if (!value) return 'unknown';
11
+ return new Intl.DateTimeFormat(undefined, {
12
+ hour: '2-digit',
13
+ minute: '2-digit',
14
+ second: '2-digit',
15
+ }).format(new Date(value));
16
+ }
17
+
18
+ function byteLabel(value: number): string {
19
+ if (value < 1024) return `${value} B`;
20
+ if (value < 1024 * 1024) return `${Math.round(value / 1024)} KB`;
21
+ return `${(value / 1024 / 1024).toFixed(1)} MB`;
22
+ }
23
+
24
+ function taskPreview(value: string): string {
25
+ const text = value.trim();
26
+ if (!text) return 'No task preview';
27
+ return text.length > 96 ? `${text.slice(0, 96)}...` : text;
28
+ }
29
+
30
+ function runDetail(run: WorkerRunRecord): string {
31
+ return [
32
+ run.runId,
33
+ `updated ${formatTime(run.updatedAt)}`,
34
+ run.hasOutput ? byteLabel(run.outputBytes) : 'no output',
35
+ ].join(' · ');
36
+ }
37
+
38
+ function eventDetail(event: WorkerRunEvent): string {
39
+ const data = event.data || {};
40
+ if (typeof data['safeSummary'] === 'string') return data['safeSummary'];
41
+ if (typeof data['toolCount'] === 'number') return `${data['toolCount']} tool updates`;
42
+ if (data['attention'] && typeof data['attention'] === 'object') return 'attention metadata';
43
+ return `seq ${event.seq}`;
44
+ }
45
+
46
+ function countRuns(runs: WorkerRunRecord[]): { running: number; done: number; failed: number; attention: number } {
47
+ return runs.reduce((counts, run) => {
48
+ if (run.status === 'running') counts.running += 1;
49
+ if (run.status === 'done') counts.done += 1;
50
+ if (run.status === 'failed' || run.status === 'cancelled') counts.failed += 1;
51
+ if (run.hasOutput || run.outputBytes > 0) counts.attention += 1;
52
+ return counts;
53
+ }, { running: 0, done: 0, failed: 0, attention: 0 });
54
+ }
55
+
56
+ export function WorkerRunsPanel(props: WorkerRunsPanelProps) {
57
+ const { runs, loading, error, lastReason, eventsByRunId, outputByRunId, refresh, loadEvents, loadOutput } = useWorkerRuns(props.client);
58
+ const [expandedRunId, setExpandedRunId] = useState<string | null>(null);
59
+ const visibleRuns = runs.slice(0, 8);
60
+ const counts = useMemo(() => countRuns(runs), [runs]);
61
+
62
+ const toggleRun = (run: WorkerRunRecord) => {
63
+ setExpandedRunId(prev => prev === run.runId ? null : run.runId);
64
+ if (expandedRunId !== run.runId) void loadEvents(run.runId);
65
+ };
66
+
67
+ return (
68
+ <section className="code-worker-runs" aria-label="Worker runs">
69
+ <div className="code-worker-runs-header">
70
+ <div>
71
+ <span className="code-worker-kicker">Runs</span>
72
+ <strong>Recent worker runs</strong>
73
+ </div>
74
+ <div className="code-worker-runs-summary" aria-live="polite">
75
+ <span className={counts.running > 0 ? 'is-active' : ''}>{counts.running} running</span>
76
+ <span>{counts.done} done</span>
77
+ <span className={counts.failed > 0 ? 'is-attention' : ''}>{counts.failed} failed</span>
78
+ <span>{counts.attention} output</span>
79
+ </div>
80
+ <button type="button" className="code-worker-refresh" onClick={() => void refresh()} disabled={loading}>
81
+ Refresh
82
+ </button>
83
+ </div>
84
+ {error && <div className="code-worker-error" role="status">{error}</div>}
85
+ {loading ? (
86
+ <div className="code-worker-empty">Loading worker runs...</div>
87
+ ) : visibleRuns.length === 0 ? (
88
+ <div className="code-worker-empty">No worker runs.</div>
89
+ ) : (
90
+ <ul className="code-worker-run-list">
91
+ {visibleRuns.map(run => {
92
+ const expanded = expandedRunId === run.runId;
93
+ const eventsState = eventsByRunId[run.runId];
94
+ const outputState = outputByRunId[run.runId];
95
+ const output = outputState?.output ?? null;
96
+ return (
97
+ <li key={run.runId} className={`code-worker-run-item is-${run.status}`}>
98
+ <button type="button" className="code-worker-run-main" onClick={() => toggleRun(run)} aria-expanded={expanded}>
99
+ <span className={`code-worker-status is-${run.status}`}>{run.status}</span>
100
+ <span className="code-worker-title">{run.employeeName || run.agentId}</span>
101
+ <span className="code-worker-meta">{runDetail(run)}</span>
102
+ <span className="code-worker-run-task">{taskPreview(run.taskPreview)}</span>
103
+ </button>
104
+ {expanded && (
105
+ <div className="code-worker-run-detail">
106
+ {eventsState?.error && <div className="code-worker-error" role="status">{eventsState.error}</div>}
107
+ {eventsState?.loading ? (
108
+ <div className="code-worker-empty">Loading safe events...</div>
109
+ ) : (
110
+ <ol className="code-worker-run-events">
111
+ {(eventsState?.events ?? []).slice(-12).map(event => (
112
+ <li key={`${event.runId}:${event.seq}`}>
113
+ <b>{event.event.replace('worker_run_', '')}</b>
114
+ <span>{formatTime(event.ts)}</span>
115
+ <code>{eventDetail(event)}</code>
116
+ </li>
117
+ ))}
118
+ </ol>
119
+ )}
120
+ {run.hasOutput && !output && (
121
+ <button type="button" className="code-worker-output-action" onClick={() => void loadOutput(run.runId, { offset: 0 })} disabled={outputState?.loading}>
122
+ {outputState?.loading ? 'Loading output...' : 'Load output'}
123
+ </button>
124
+ )}
125
+ {outputState?.error && <div className="code-worker-error" role="status">{outputState.error}</div>}
126
+ {output && (
127
+ <div className="code-worker-output">
128
+ <div>
129
+ <span>{byteLabel(output.offset)}-{byteLabel(output.nextOffset)} of {byteLabel(output.outputBytes)}</span>
130
+ {!output.eof && (
131
+ <button type="button" className="code-worker-output-action" onClick={() => void loadOutput(run.runId, { offset: output.nextOffset })} disabled={outputState?.loading}>
132
+ Load next chunk
133
+ </button>
134
+ )}
135
+ </div>
136
+ <pre>{output.text || 'No output text.'}</pre>
137
+ </div>
138
+ )}
139
+ </div>
140
+ )}
141
+ </li>
142
+ );
143
+ })}
144
+ </ul>
145
+ )}
146
+ <div className="code-worker-footer">
147
+ <span>{runs.length} runs</span>
148
+ <span>{lastReason}</span>
149
+ </div>
150
+ </section>
151
+ );
152
+ }
@@ -0,0 +1,138 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import {
3
+ createWorkerRunsClient,
4
+ type WorkerRunEvent,
5
+ type WorkerRunOutput,
6
+ type WorkerRunRecord,
7
+ type WorkerRunsClient,
8
+ } from './worker-runs-client';
9
+ import { subscribeToWorkerProgressEvents } from './worker-progress-client';
10
+
11
+ export type WorkerRunEventState = {
12
+ events: WorkerRunEvent[];
13
+ loading: boolean;
14
+ error: string;
15
+ };
16
+
17
+ export type WorkerRunOutputState = {
18
+ output: WorkerRunOutput | null;
19
+ loading: boolean;
20
+ error: string;
21
+ };
22
+
23
+ type WorkerRunsState = {
24
+ runs: WorkerRunRecord[];
25
+ loading: boolean;
26
+ error: string;
27
+ lastReason: string;
28
+ eventsByRunId: Record<string, WorkerRunEventState>;
29
+ outputByRunId: Record<string, WorkerRunOutputState>;
30
+ refresh: () => Promise<void>;
31
+ loadEvents: (runId: string) => Promise<void>;
32
+ loadOutput: (runId: string, input?: { offset?: number; limit?: number }) => Promise<void>;
33
+ };
34
+
35
+ function errorText(err: unknown): string {
36
+ return err instanceof Error ? err.message : String(err);
37
+ }
38
+
39
+ export function sortWorkerRuns(runs: WorkerRunRecord[]): WorkerRunRecord[] {
40
+ return [...runs].sort((left, right) => right.updatedAt - left.updatedAt);
41
+ }
42
+
43
+ export function useWorkerRuns(clientOverride?: WorkerRunsClient): WorkerRunsState {
44
+ const client = useMemo(() => clientOverride ?? createWorkerRunsClient(), [clientOverride]);
45
+ const [runs, setRuns] = useState<WorkerRunRecord[]>([]);
46
+ const [loading, setLoading] = useState(true);
47
+ const [error, setError] = useState('');
48
+ const [lastReason, setLastReason] = useState('hydrated');
49
+ const [eventsByRunId, setEventsByRunId] = useState<Record<string, WorkerRunEventState>>({});
50
+ const [outputByRunId, setOutputByRunId] = useState<Record<string, WorkerRunOutputState>>({});
51
+
52
+ const refresh = useCallback(async () => {
53
+ try {
54
+ const next = await client.listRuns();
55
+ setRuns(sortWorkerRuns(next));
56
+ setError('');
57
+ } catch (err) {
58
+ setError(errorText(err));
59
+ } finally {
60
+ setLoading(false);
61
+ }
62
+ }, [client]);
63
+
64
+ const loadEvents = useCallback(async (runId: string) => {
65
+ setEventsByRunId(prev => ({
66
+ ...prev,
67
+ [runId]: { events: prev[runId]?.events ?? [], loading: true, error: '' },
68
+ }));
69
+ try {
70
+ const events = await client.getRunEvents(runId);
71
+ setEventsByRunId(prev => ({
72
+ ...prev,
73
+ [runId]: { events, loading: false, error: '' },
74
+ }));
75
+ } catch (err) {
76
+ setEventsByRunId(prev => ({
77
+ ...prev,
78
+ [runId]: { events: prev[runId]?.events ?? [], loading: false, error: errorText(err) },
79
+ }));
80
+ }
81
+ }, [client]);
82
+
83
+ const loadOutput = useCallback(async (runId: string, input: { offset?: number; limit?: number } = {}) => {
84
+ setOutputByRunId(prev => ({
85
+ ...prev,
86
+ [runId]: { output: prev[runId]?.output ?? null, loading: true, error: '' },
87
+ }));
88
+ try {
89
+ const output = await client.readRunOutput(runId, input);
90
+ setOutputByRunId(prev => ({
91
+ ...prev,
92
+ [runId]: { output, loading: false, error: '' },
93
+ }));
94
+ } catch (err) {
95
+ setOutputByRunId(prev => ({
96
+ ...prev,
97
+ [runId]: { output: prev[runId]?.output ?? null, loading: false, error: errorText(err) },
98
+ }));
99
+ }
100
+ }, [client]);
101
+
102
+ useEffect(() => {
103
+ let cancelled = false;
104
+ setLoading(true);
105
+ void client.listRuns().then(
106
+ next => {
107
+ if (cancelled) return;
108
+ setRuns(sortWorkerRuns(next));
109
+ setError('');
110
+ setLoading(false);
111
+ },
112
+ err => {
113
+ if (cancelled) return;
114
+ setError(errorText(err));
115
+ setLoading(false);
116
+ },
117
+ );
118
+ return () => { cancelled = true; };
119
+ }, [client]);
120
+
121
+ useEffect(() => {
122
+ const sub = subscribeToWorkerProgressEvents({
123
+ onRefreshNeeded: reason => {
124
+ setLastReason(reason);
125
+ if (reason.startsWith('worker_run_') || reason === 'replay_gap') void refresh();
126
+ },
127
+ onReplayGap: () => {
128
+ setLastReason('replay_gap');
129
+ },
130
+ onError: () => {
131
+ setError('Worker run event stream disconnected; retrying.');
132
+ },
133
+ });
134
+ return () => sub.close();
135
+ }, [refresh]);
136
+
137
+ return { runs, loading, error, lastReason, eventsByRunId, outputByRunId, refresh, loadEvents, loadOutput };
138
+ }
@@ -0,0 +1,112 @@
1
+ export type WorkerRunStatus = 'running' | 'done' | 'failed' | 'cancelled';
2
+ export type RuntimeStatusCategory = 'running' | 'succeeded' | 'failed' | 'cancelled' | 'orphaned';
3
+
4
+ export type WorkerRunEventType =
5
+ | 'worker_run_started'
6
+ | 'worker_run_progress'
7
+ | 'worker_run_attention'
8
+ | 'worker_run_done'
9
+ | 'worker_run_failed'
10
+ | 'worker_run_cancelled';
11
+
12
+ export interface WorkerRunRecord {
13
+ runId: string;
14
+ agentId: string;
15
+ employeeName: string;
16
+ taskPreview: string;
17
+ startedAt: number;
18
+ status: WorkerRunStatus;
19
+ updatedAt: number;
20
+ completedAt: number | null;
21
+ outputBytes: number;
22
+ eventSeq: number;
23
+ safeSummary?: string;
24
+ hasOutput: boolean;
25
+ statusCategory: RuntimeStatusCategory;
26
+ }
27
+
28
+ export interface WorkerRunEvent {
29
+ runId: string;
30
+ seq: number;
31
+ event: WorkerRunEventType;
32
+ ts: number;
33
+ data: Record<string, unknown>;
34
+ }
35
+
36
+ export interface WorkerRunOutput {
37
+ runId: string;
38
+ offset: number;
39
+ limit: number;
40
+ nextOffset: number;
41
+ outputBytes: number;
42
+ eof: boolean;
43
+ text: string;
44
+ }
45
+
46
+ export interface WorkerRunsClient {
47
+ listRuns(): Promise<WorkerRunRecord[]>;
48
+ getRunEvents(runId: string): Promise<WorkerRunEvent[]>;
49
+ readRunOutput(runId: string, input?: { offset?: number; limit?: number }): Promise<WorkerRunOutput>;
50
+ }
51
+
52
+ type FetchImpl = typeof fetch;
53
+
54
+ function workerRunUrl(baseUrl: string, path: string): string {
55
+ return `${baseUrl}${path}`;
56
+ }
57
+
58
+ async function parseResponse<T>(response: Response, fallback: string): Promise<T> {
59
+ const text = await response.text();
60
+ let body: unknown = {};
61
+ if (text.trim()) {
62
+ try {
63
+ body = JSON.parse(text) as unknown;
64
+ } catch {
65
+ throw new Error(`${fallback}: response was not JSON`);
66
+ }
67
+ }
68
+ if (!response.ok) {
69
+ const message = typeof body === 'object' && body && 'error' in body
70
+ ? String((body as { error?: unknown }).error)
71
+ : fallback;
72
+ throw new Error(message || fallback);
73
+ }
74
+ return body as T;
75
+ }
76
+
77
+ function outputPath(runId: string, input: { offset?: number; limit?: number } = {}): string {
78
+ const params = new URLSearchParams();
79
+ if (input.offset !== undefined) params.set('offset', String(input.offset));
80
+ if (input.limit !== undefined) params.set('limit', String(input.limit));
81
+ const suffix = params.toString();
82
+ return `/api/orchestrate/worker-runs/${encodeURIComponent(runId)}/output${suffix ? `?${suffix}` : ''}`;
83
+ }
84
+
85
+ export function createWorkerRunsClient(options: { baseUrl?: string; fetchImpl?: FetchImpl } = {}): WorkerRunsClient {
86
+ const baseUrl = options.baseUrl ?? '';
87
+ const fetchImpl = options.fetchImpl ?? fetch;
88
+
89
+ return {
90
+ async listRuns() {
91
+ const body = await parseResponse<{ runs: WorkerRunRecord[] }>(
92
+ await fetchImpl(workerRunUrl(baseUrl, '/api/orchestrate/worker-runs')),
93
+ 'worker runs list failed',
94
+ );
95
+ return body.runs;
96
+ },
97
+ async getRunEvents(runId: string) {
98
+ const body = await parseResponse<{ events: WorkerRunEvent[] }>(
99
+ await fetchImpl(workerRunUrl(baseUrl, `/api/orchestrate/worker-runs/${encodeURIComponent(runId)}/events`)),
100
+ 'worker run events read failed',
101
+ );
102
+ return body.events;
103
+ },
104
+ async readRunOutput(runId: string, input = {}) {
105
+ const body = await parseResponse<{ output: WorkerRunOutput }>(
106
+ await fetchImpl(workerRunUrl(baseUrl, outputPath(runId, input))),
107
+ 'worker run output read failed',
108
+ );
109
+ return body.output;
110
+ },
111
+ };
112
+ }