botmux 2.98.4-canary.2 → 2.99.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 (205) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/adapters/cli/genius.d.ts +4 -0
  4. package/dist/adapters/cli/genius.d.ts.map +1 -0
  5. package/dist/adapters/cli/genius.js +216 -0
  6. package/dist/adapters/cli/genius.js.map +1 -0
  7. package/dist/adapters/cli/registry.d.ts +2 -1
  8. package/dist/adapters/cli/registry.d.ts.map +1 -1
  9. package/dist/adapters/cli/registry.js +3 -1
  10. package/dist/adapters/cli/registry.js.map +1 -1
  11. package/dist/adapters/cli/types.d.ts +1 -1
  12. package/dist/adapters/cli/types.d.ts.map +1 -1
  13. package/dist/core/dashboard-rows.d.ts +1 -1
  14. package/dist/core/dashboard-rows.d.ts.map +1 -1
  15. package/dist/core/dashboard-rows.js +2 -1
  16. package/dist/core/dashboard-rows.js.map +1 -1
  17. package/dist/dashboard/session-card-model.d.ts +2 -2
  18. package/dist/dashboard/session-card-model.d.ts.map +1 -1
  19. package/dist/dashboard/session-card-model.js +5 -2
  20. package/dist/dashboard/session-card-model.js.map +1 -1
  21. package/dist/dashboard/web/app.d.ts.map +1 -1
  22. package/dist/dashboard/web/app.js +28 -63
  23. package/dist/dashboard/web/app.js.map +1 -1
  24. package/dist/dashboard/web/bot-defaults-page.d.ts +3 -0
  25. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -0
  26. package/dist/dashboard/web/bot-defaults-page.js +23 -0
  27. package/dist/dashboard/web/bot-defaults-page.js.map +1 -0
  28. package/dist/dashboard/web/bot-defaults.d.ts +2 -1
  29. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  30. package/dist/dashboard/web/bot-defaults.js +30 -30
  31. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  32. package/dist/dashboard/web/connectors-page.d.ts +14 -0
  33. package/dist/dashboard/web/connectors-page.d.ts.map +1 -0
  34. package/dist/dashboard/web/connectors-page.js +303 -0
  35. package/dist/dashboard/web/connectors-page.js.map +1 -0
  36. package/dist/dashboard/web/connectors.d.ts +1 -12
  37. package/dist/dashboard/web/connectors.d.ts.map +1 -1
  38. package/dist/dashboard/web/connectors.js +1 -325
  39. package/dist/dashboard/web/connectors.js.map +1 -1
  40. package/dist/dashboard/web/dashboard-routes.d.ts +14 -0
  41. package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -0
  42. package/dist/dashboard/web/dashboard-routes.js +176 -0
  43. package/dist/dashboard/web/dashboard-routes.js.map +1 -0
  44. package/dist/dashboard/web/groups-page.d.ts +3 -0
  45. package/dist/dashboard/web/groups-page.d.ts.map +1 -0
  46. package/dist/dashboard/web/groups-page.js +26 -0
  47. package/dist/dashboard/web/groups-page.js.map +1 -0
  48. package/dist/dashboard/web/groups.d.ts +1 -1
  49. package/dist/dashboard/web/groups.d.ts.map +1 -1
  50. package/dist/dashboard/web/groups.js +113 -52
  51. package/dist/dashboard/web/groups.js.map +1 -1
  52. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  53. package/dist/dashboard/web/i18n.js +18 -0
  54. package/dist/dashboard/web/i18n.js.map +1 -1
  55. package/dist/dashboard/web/insights-page.d.ts +3 -0
  56. package/dist/dashboard/web/insights-page.d.ts.map +1 -0
  57. package/dist/dashboard/web/insights-page.js +26 -0
  58. package/dist/dashboard/web/insights-page.js.map +1 -0
  59. package/dist/dashboard/web/insights.d.ts +18 -1
  60. package/dist/dashboard/web/insights.d.ts.map +1 -1
  61. package/dist/dashboard/web/insights.js +25 -61
  62. package/dist/dashboard/web/insights.js.map +1 -1
  63. package/dist/dashboard/web/office-page.d.ts +3 -0
  64. package/dist/dashboard/web/office-page.d.ts.map +1 -0
  65. package/dist/dashboard/web/office-page.js +149 -0
  66. package/dist/dashboard/web/office-page.js.map +1 -0
  67. package/dist/dashboard/web/office.d.ts +1 -1
  68. package/dist/dashboard/web/office.d.ts.map +1 -1
  69. package/dist/dashboard/web/office.js +1 -139
  70. package/dist/dashboard/web/office.js.map +1 -1
  71. package/dist/dashboard/web/overview-page.d.ts +3 -0
  72. package/dist/dashboard/web/overview-page.d.ts.map +1 -0
  73. package/dist/dashboard/web/overview-page.js +149 -0
  74. package/dist/dashboard/web/overview-page.js.map +1 -0
  75. package/dist/dashboard/web/overview.d.ts +2 -2
  76. package/dist/dashboard/web/overview.d.ts.map +1 -1
  77. package/dist/dashboard/web/overview.js +14 -3
  78. package/dist/dashboard/web/overview.js.map +1 -1
  79. package/dist/dashboard/web/react-hooks.d.ts +8 -0
  80. package/dist/dashboard/web/react-hooks.d.ts.map +1 -0
  81. package/dist/dashboard/web/react-hooks.js +43 -0
  82. package/dist/dashboard/web/react-hooks.js.map +1 -0
  83. package/dist/dashboard/web/react-mount.d.ts +4 -0
  84. package/dist/dashboard/web/react-mount.d.ts.map +1 -0
  85. package/dist/dashboard/web/react-mount.js +7 -0
  86. package/dist/dashboard/web/react-mount.js.map +1 -0
  87. package/dist/dashboard/web/roles-page.d.ts +4 -0
  88. package/dist/dashboard/web/roles-page.d.ts.map +1 -0
  89. package/dist/dashboard/web/roles-page.js +26 -0
  90. package/dist/dashboard/web/roles-page.js.map +1 -0
  91. package/dist/dashboard/web/roles.d.ts +1 -2
  92. package/dist/dashboard/web/roles.d.ts.map +1 -1
  93. package/dist/dashboard/web/roles.js +189 -135
  94. package/dist/dashboard/web/roles.js.map +1 -1
  95. package/dist/dashboard/web/route-lifecycle.d.ts +14 -0
  96. package/dist/dashboard/web/route-lifecycle.d.ts.map +1 -0
  97. package/dist/dashboard/web/route-lifecycle.js +29 -0
  98. package/dist/dashboard/web/route-lifecycle.js.map +1 -0
  99. package/dist/dashboard/web/schedules-page.d.ts +14 -0
  100. package/dist/dashboard/web/schedules-page.d.ts.map +1 -0
  101. package/dist/dashboard/web/schedules-page.js +84 -0
  102. package/dist/dashboard/web/schedules-page.js.map +1 -0
  103. package/dist/dashboard/web/schedules.d.ts +1 -1
  104. package/dist/dashboard/web/schedules.d.ts.map +1 -1
  105. package/dist/dashboard/web/schedules.js +1 -115
  106. package/dist/dashboard/web/schedules.js.map +1 -1
  107. package/dist/dashboard/web/sessions-page.d.ts +3 -0
  108. package/dist/dashboard/web/sessions-page.d.ts.map +1 -0
  109. package/dist/dashboard/web/sessions-page.js +28 -0
  110. package/dist/dashboard/web/sessions-page.js.map +1 -0
  111. package/dist/dashboard/web/sessions.d.ts +4 -1
  112. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  113. package/dist/dashboard/web/sessions.js +43 -10
  114. package/dist/dashboard/web/sessions.js.map +1 -1
  115. package/dist/dashboard/web/settings-page.d.ts +3 -0
  116. package/dist/dashboard/web/settings-page.d.ts.map +1 -0
  117. package/dist/dashboard/web/settings-page.js +387 -0
  118. package/dist/dashboard/web/settings-page.js.map +1 -0
  119. package/dist/dashboard/web/settings.d.ts +1 -1
  120. package/dist/dashboard/web/settings.d.ts.map +1 -1
  121. package/dist/dashboard/web/settings.js +1 -534
  122. package/dist/dashboard/web/settings.js.map +1 -1
  123. package/dist/dashboard/web/skills-page.d.ts +33 -0
  124. package/dist/dashboard/web/skills-page.d.ts.map +1 -0
  125. package/dist/dashboard/web/skills-page.js +515 -0
  126. package/dist/dashboard/web/skills-page.js.map +1 -0
  127. package/dist/dashboard/web/skills.d.ts +1 -1
  128. package/dist/dashboard/web/skills.d.ts.map +1 -1
  129. package/dist/dashboard/web/skills.js +1 -711
  130. package/dist/dashboard/web/skills.js.map +1 -1
  131. package/dist/dashboard/web/store.d.ts +9 -0
  132. package/dist/dashboard/web/store.d.ts.map +1 -1
  133. package/dist/dashboard/web/store.js +19 -2
  134. package/dist/dashboard/web/store.js.map +1 -1
  135. package/dist/dashboard/web/team-federation-page.d.ts +4 -0
  136. package/dist/dashboard/web/team-federation-page.d.ts.map +1 -0
  137. package/dist/dashboard/web/team-federation-page.js +47 -0
  138. package/dist/dashboard/web/team-federation-page.js.map +1 -0
  139. package/dist/dashboard/web/team-federation.d.ts +2 -2
  140. package/dist/dashboard/web/team-federation.d.ts.map +1 -1
  141. package/dist/dashboard/web/team-federation.js +104 -97
  142. package/dist/dashboard/web/team-federation.js.map +1 -1
  143. package/dist/dashboard/web/v3-page.d.ts +3 -0
  144. package/dist/dashboard/web/v3-page.d.ts.map +1 -0
  145. package/dist/dashboard/web/v3-page.js +27 -0
  146. package/dist/dashboard/web/v3-page.js.map +1 -0
  147. package/dist/dashboard/web/v3.d.ts +2 -1
  148. package/dist/dashboard/web/v3.d.ts.map +1 -1
  149. package/dist/dashboard/web/v3.js +18 -43
  150. package/dist/dashboard/web/v3.js.map +1 -1
  151. package/dist/dashboard/web/whiteboards-page.d.ts +3 -0
  152. package/dist/dashboard/web/whiteboards-page.d.ts.map +1 -0
  153. package/dist/dashboard/web/whiteboards-page.js +203 -0
  154. package/dist/dashboard/web/whiteboards-page.js.map +1 -0
  155. package/dist/dashboard/web/whiteboards.d.ts +1 -1
  156. package/dist/dashboard/web/whiteboards.d.ts.map +1 -1
  157. package/dist/dashboard/web/whiteboards.js +1 -275
  158. package/dist/dashboard/web/whiteboards.js.map +1 -1
  159. package/dist/dashboard-web/app.js +36 -2550
  160. package/dist/dashboard-web/chunks/bot-defaults-page-3EV7K6LJ.js +358 -0
  161. package/dist/dashboard-web/chunks/chunk-5E3MJJL4.js +1 -0
  162. package/dist/dashboard-web/chunks/chunk-76J7PNZI.js +1 -0
  163. package/dist/dashboard-web/chunks/chunk-7SZRL6FY.js +1 -0
  164. package/dist/dashboard-web/chunks/chunk-JTSE5VP6.js +54 -0
  165. package/dist/dashboard-web/chunks/chunk-JXLHRRJD.js +31 -0
  166. package/dist/dashboard-web/chunks/chunk-NASYW5FD.js +1 -0
  167. package/dist/dashboard-web/chunks/connectors-XPZKEHF6.js +1 -0
  168. package/dist/dashboard-web/chunks/groups-page-C54PVKYP.js +207 -0
  169. package/dist/dashboard-web/chunks/insights-page-BBQYR7WY.js +309 -0
  170. package/dist/dashboard-web/chunks/office-page-6DXYOG55.js +1 -0
  171. package/dist/dashboard-web/chunks/overview-page-5PJCAMID.js +1 -0
  172. package/dist/dashboard-web/chunks/roles-page-APUDLPVM.js +98 -0
  173. package/dist/dashboard-web/chunks/schedules-WG2UKHSO.js +1 -0
  174. package/dist/dashboard-web/chunks/sessions-page-F3U5NFPD.js +238 -0
  175. package/dist/dashboard-web/chunks/settings-page-OSBZNCXL.js +2 -0
  176. package/dist/dashboard-web/chunks/skills-page-Y3VUAOYG.js +2 -0
  177. package/dist/dashboard-web/chunks/team-federation-page-CRH3WZPH.js +10 -0
  178. package/dist/dashboard-web/chunks/v3-page-FVPUL665.js +149 -0
  179. package/dist/dashboard-web/chunks/whiteboards-page-HLCTYSSV.js +1 -0
  180. package/dist/dashboard-web/chunks/workflows-UB7OPYGI.js +184 -0
  181. package/dist/dashboard-web/index.html +1 -1
  182. package/dist/dashboard-web/style.css +82 -1
  183. package/dist/dashboard.js +5 -6
  184. package/dist/dashboard.js.map +1 -1
  185. package/dist/i18n/en.d.ts.map +1 -1
  186. package/dist/i18n/en.js +1 -0
  187. package/dist/i18n/en.js.map +1 -1
  188. package/dist/i18n/zh.d.ts.map +1 -1
  189. package/dist/i18n/zh.js +1 -0
  190. package/dist/i18n/zh.js.map +1 -1
  191. package/dist/im/lark/card-builder.d.ts.map +1 -1
  192. package/dist/im/lark/card-builder.js +1 -0
  193. package/dist/im/lark/card-builder.js.map +1 -1
  194. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  195. package/dist/im/lark/event-dispatcher.js +7 -0
  196. package/dist/im/lark/event-dispatcher.js.map +1 -1
  197. package/dist/im/lark/sessions-card.d.ts.map +1 -1
  198. package/dist/im/lark/sessions-card.js +4 -1
  199. package/dist/im/lark/sessions-card.js.map +1 -1
  200. package/dist/setup/bot-config-editor.d.ts.map +1 -1
  201. package/dist/setup/bot-config-editor.js +16 -14
  202. package/dist/setup/bot-config-editor.js.map +1 -1
  203. package/dist/worker.js +1 -1
  204. package/dist/worker.js.map +1 -1
  205. package/package.json +8 -2
@@ -0,0 +1,184 @@
1
+ import{m as i}from"./chunk-JXLHRRJD.js";import"./chunk-7SZRL6FY.js";function Rt(){let t=[["",i("workflow.filter.nonTerminal")],["all",i("workflow.filter.all")],["pending",C("pending")],["running",C("running")],["waiting",C("waiting")],["succeeded",C("succeeded")],["failed",C("failed")],["cancelled",C("cancelled")]];return`
2
+ <nav class="wf-subnav">
3
+ <a href="#/legacy-workflow" class="active" data-i18n="workflow.subnav.runs">${r(i("workflow.subnav.runs"))}</a>
4
+ <a href="#/workflows" data-i18n="workflow.subnav.v3">${r(i("workflow.subnav.v3"))}</a>
5
+ </nav>
6
+ <form id="wf-filters" class="filters">
7
+ <input type="search" name="q" placeholder="${r(i("workflow.searchPlaceholder"))}" />
8
+ <select name="status">
9
+ ${t.map(([e,n])=>`<option value="${r(e)}">${r(n)}</option>`).join("")}
10
+ </select>
11
+ <span id="wf-last-load" class="muted"></span>
12
+ </form>
13
+ <table>
14
+ <thead><tr>
15
+ <th>${r(i("workflow.table.run"))}</th><th>${r(i("workflow.table.workflow"))}</th><th>${r(i("workflow.table.status"))}</th>
16
+ <th>${r(i("workflow.table.lastSeq"))}</th><th>${r(i("workflow.table.dangling"))}</th><th>${r(i("workflow.table.updated"))}</th>
17
+ <th>${r(i("workflow.table.chatApp"))}</th>
18
+ </tr></thead>
19
+ <tbody id="wf-tbody"></tbody>
20
+ </table>
21
+ `}var Ct=5e3,Ht=2e3,B=new Set(["succeeded","failed","cancelled"]);function r(t){return t.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function qt(t){let e=new Date(t),a=Date.now()-t;return a<6e4?i("time.secondsAgo",{value:Math.max(1,Math.floor(a/1e3))}):a<36e5?i("time.minutesAgo",{value:Math.floor(a/6e4)}):a<864e5?i("time.hoursAgo",{value:Math.floor(a/36e5)}):e.toISOString().slice(0,19).replace("T"," ")}function M(t){return`<span class="${B.has(t)?"wf-status terminal":"wf-status live"} wf-status-${r(t)}">${r(C(t))}</span>`}function C(t){let e=`workflow.status.${t}`,n=i(e);return n===e?t:n}function Te(t){let e=location.hash.match(/^#\/legacy-workflow\/([^?#]+)(?:\?([^#]*))?$/);if(e){let n=new URLSearchParams(e[2]??"");return Ot(t,decodeURIComponent(e[1]),{focusAttemptId:n.get("attempt")??void 0})}return Pt(t)}function Pt(t){t.innerHTML=Rt();let e=t.querySelector("#wf-tbody"),n=t.querySelector("#wf-filters"),a=t.querySelector("#wf-last-load"),o=[],s=null,d=!1,c=null,f=!1;function h($){let I=(new FormData(n).get("q")??"").trim().toLowerCase();return I?$.filter(g=>g.runId.toLowerCase().includes(I)||g.workflowId.toLowerCase().includes(I)||(g.chatId??"").toLowerCase().includes(I)):$}function v(){let $=h(o);if($.length===0){e.innerHTML=`<tr><td colspan="7" class="empty">${c?r(i("workflow.list.failedLoad",{error:c})):o.length===0?r(i("workflow.list.noRuns")):r(i("workflow.list.noFilterMatch"))}</td></tr>`;return}e.innerHTML=$.map(m=>{let I=`${m.dEf}/${m.dAct}/${m.dWait}`,g=m.dEf+m.dAct+m.dWait>0?"wf-dangling has":"wf-dangling none",b=[];m.chatId&&b.push(r(m.chatId)),m.larkAppId&&b.push(`<span class="muted">${r(m.larkAppId)}</span>`);let O=b.length>0?b.join("<br/>"):"\u2014",L=xt(m);return`<tr data-runid="${r(m.runId)}">
22
+ <td><a href="#/legacy-workflow/${encodeURIComponent(m.runId)}"><code>${r(m.runId)}</code></a></td>
23
+ <td>${r(m.workflowId)}</td>
24
+ <td>${M(m.status)}${m.failedNodeId?` <span class="muted">(${r(m.failedNodeId)})</span>`:""}${L}</td>
25
+ <td>${m.lastSeq}</td>
26
+ <td class="${g}">${I}</td>
27
+ <td title="${r(new Date(m.updatedAt).toISOString())}">${qt(m.updatedAt)}</td>
28
+ <td>${O}</td>
29
+ </tr>`}).join("")}function k(){c?(a.textContent=i("workflow.list.error",{error:c}),a.classList.add("error")):(a.textContent=i("workflow.list.loaded",{count:o.length,time:new Date().toLocaleTimeString()}),a.classList.remove("error"))}async function u(){if(!(f||d)&&!document.hidden){d=!0;try{let $=n.elements.namedItem("status")?.value??"",m=new URLSearchParams;$==="all"?m.set("all","1"):$&&m.set("status",$);let I="/api/workflows/runs"+(m.toString()?`?${m}`:""),g=await fetch(I);g.ok?(o=(await g.json()).runs??[],c=null):(c=`HTTP ${g.status}`,o=[])}catch($){c=$?.message??String($),o=[]}finally{d=!1,f||(v(),k())}}}function y(){s!==null&&window.clearTimeout(s),s=window.setTimeout(async()=>{await u(),f||y()},Ct)}function P(){document.hidden||u()}return n.addEventListener("input",()=>{v()}),n.addEventListener("change",$=>{$.target.getAttribute("name")==="status"&&u()}),document.addEventListener("visibilitychange",P),u().then(()=>{f||y()}),()=>{f=!0,s!==null&&window.clearTimeout(s),document.removeEventListener("visibilitychange",P)}}function Ot(t,e,n={}){t.innerHTML=`
30
+ <div class="wf-detail-head">
31
+ <a class="btn-link" href="#/legacy-workflow">${r(i("workflow.detail.back"))}</a>
32
+ <div>
33
+ <h2><code>${r(e)}</code></h2>
34
+ <div id="wf-detail-subtitle" class="muted">${r(i("workflow.detail.loading"))}</div>
35
+ </div>
36
+ <button id="wf-cancel-run" type="button" class="contrast" hidden>${r(i("workflow.detail.cancel"))}</button>
37
+ <span id="wf-detail-refresh" class="muted"></span>
38
+ </div>
39
+ <section id="wf-detail-error" class="hint-warn" hidden></section>
40
+ <section id="wf-cancel-status" class="hint-ok" hidden></section>
41
+ <section id="wf-summary" class="wf-summary-grid"></section>
42
+ <section id="wf-dangling-panel"></section>
43
+ <section class="wf-panel">
44
+ <div class="wf-panel-title">
45
+ <h3>${r(i("workflow.detail.parallel"))}</h3>
46
+ <span id="wf-parallel-meta" class="muted"></span>
47
+ </div>
48
+ <div id="wf-parallel-view"></div>
49
+ </section>
50
+ <section class="wf-panel">
51
+ <div class="wf-panel-title">
52
+ <h3>${r(i("workflow.detail.nodes"))}</h3>
53
+ </div>
54
+ <div class="wf-table-scroll">
55
+ <table>
56
+ <thead><tr>
57
+ <th>${r(i("workflow.detail.node"))}</th><th>${r(i("workflow.detail.nodeStatus"))}</th><th>${r(i("workflow.detail.activity"))}</th><th>${r(i("workflow.detail.activityStatus"))}</th>
58
+ <th>${r(i("workflow.detail.attempts"))}</th><th>${r(i("workflow.detail.current"))}</th><th>${r(i("workflow.detail.detail"))}</th>
59
+ </tr></thead>
60
+ <tbody id="wf-node-tbody"></tbody>
61
+ </table>
62
+ </div>
63
+ </section>
64
+ <section class="wf-panel">
65
+ <div class="wf-panel-title">
66
+ <h3>${r(i("workflow.detail.nodeIO"))}</h3>
67
+ </div>
68
+ <div id="wf-io-list" class="wf-io-list"></div>
69
+ </section>
70
+ <section class="wf-panel">
71
+ <div class="wf-panel-title">
72
+ <h3>${r(i("workflow.detail.timeline"))}</h3>
73
+ <button id="wf-load-older" type="button" hidden>${r(i("workflow.detail.loadOlder"))}</button>
74
+ </div>
75
+ <div class="wf-table-scroll wf-timeline-scroll">
76
+ <table>
77
+ <thead><tr>
78
+ <th>${r(i("workflow.detail.seq"))}</th><th>${r(i("workflow.detail.event"))}</th><th>${r(i("workflow.detail.actor"))}</th><th>${r(i("workflow.detail.node"))}</th><th>${r(i("workflow.detail.activity"))}</th><th>${r(i("workflow.detail.error"))}</th><th>${r(i("workflow.detail.time"))}</th>
79
+ </tr></thead>
80
+ <tbody id="wf-event-tbody"></tbody>
81
+ </table>
82
+ </div>
83
+ <div id="wf-event-meta" class="muted"></div>
84
+ </section>
85
+ `;let a=t.querySelector("#wf-detail-subtitle"),o=t.querySelector("#wf-detail-refresh"),s=t.querySelector("#wf-detail-error"),d=t.querySelector("#wf-cancel-status"),c=t.querySelector("#wf-summary"),f=t.querySelector("#wf-dangling-panel"),h=t.querySelector("#wf-parallel-view"),v=t.querySelector("#wf-parallel-meta"),k=t.querySelector("#wf-node-tbody"),u=t.querySelector("#wf-io-list"),y=t.querySelector(".wf-timeline-scroll"),P=t.querySelector("#wf-event-tbody"),$=t.querySelector("#wf-event-meta"),m=t.querySelector("#wf-cancel-run"),I=t.querySelector("#wf-load-older"),g=null,b=[],O=new Set,L=null,N=null,x=!1,U=0,H=null,j=!1,Z=!1,_=!1,St=new Set,$t=new Map,rt=new Map,F=new Map,K=new Set,V=new Map,q=new Set,D=new Map,bt=new Map,it=0,ot=n.focusAttemptId;function T(l){if(!l){s.hidden=!0,s.textContent="";return}s.hidden=!1,s.textContent=l}function at(l){if(!l){d.hidden=!0,d.textContent="";return}d.hidden=!1,d.textContent=l}async function st(){let l=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/snapshot`);if(l.status===404)throw new Error(i("workflow.detail.unknownRun"));if(!l.ok)throw new Error(i("workflow.detail.snapshotHttp",{status:l.status}));g=await l.json()}async function J(l){let S=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/events?${l}`);if(S.status===404)throw new Error(i("workflow.detail.unknownRun"));if(!S.ok)throw new Error(i("workflow.detail.eventsHttp",{status:S.status}));return await S.json()}function z(l,S){let p=l.filter(w=>O.has(w.eventId)?!1:(O.add(w.eventId),!0));p.length!==0&&(b=S==="prepend"?[...p,...b]:[...b,...p],b.sort((w,R)=>W(w.eventId)-W(R.eventId)))}async function It(){await st();let l=await J(new URLSearchParams({tail:"100"}));b=[],O=new Set,z(l.events,"append"),L=l.oldestSeq,N=l.newestSeq,x=l.hasOlder,U=l.totalCount,A()}async function G(){if(!(j||Z||document.hidden)){Z=!0;try{if(await st(),N!==null){let l=await J(new URLSearchParams({afterSeq:String(N),limit:"200"}));z(l.events,"append"),l.newestSeq!==null&&(N=l.newestSeq),L===null&&l.oldestSeq!==null&&(L=l.oldestSeq),U=l.totalCount}else{let l=await J(new URLSearchParams({tail:"1"}));z(l.events,"append"),L=l.oldestSeq,N=l.newestSeq,x=l.hasOlder,U=l.totalCount}T(null),A()}catch(l){T(l?.message??String(l))}finally{Z=!1}}}async function Tt(){if(!(L===null||!x)){I.disabled=!0;try{let l=await J(new URLSearchParams({beforeSeq:String(L),limit:"100"}));z(l.events,"prepend"),l.oldestSeq!==null&&(L=l.oldestSeq),x=l.hasOlder,U=l.totalCount,T(null),A()}catch(l){T(l?.message??String(l))}finally{I.disabled=!1}}}async function At(){if(!g||B.has(g.run.status)||_)return;if(!g.chatBinding?.larkAppId){T(i("workflow.detail.cancelUnavailable",{runId:e}));return}let l=Ut(g),S=i("workflow.detail.cancelConfirm",{runId:e,...l});if(window.confirm(S)){_=!0,m.disabled=!0;try{let p=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/cancel`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"cancelled via dashboard"})});if(p.status===401)throw new Error(i("workflow.detail.writeAccessCancel"));let w=await p.json().catch(()=>({}));if(!p.ok||!w.ok)throw new Error(w.hint??w.error??i("workflow.detail.cancelHttp",{status:p.status}));at(w.pending?i("workflow.detail.cancelPending"):null),T(null),await G()}catch(p){T(p?.message??String(p))}finally{_=!1,m.disabled=!1,A()}}}async function Et(l,S){if(!q.has(l)){q.add(l),D.delete(l),A();try{let p=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(S)}/${encodeURIComponent(l)}/resume`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});if(p.status===401)throw new Error(i("workflow.detail.writeAccessResume"));let w=await p.json().catch(()=>({}));if(!p.ok||!w.ok||!w.resumeId||!w.url)throw new Error(w.hint??w.message??w.error??i("workflow.detail.resumeStartFailed",{status:p.status}));V.set(l,{resumeId:w.resumeId,url:w.url})}catch(p){let w=p?.message??String(p);D.set(l,w)}finally{q.delete(l),A()}}}async function Lt(l,S){if(!q.has(l)){q.add(l),D.delete(l),A();try{let p=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/attempts/${encodeURIComponent(S)}/${encodeURIComponent(l)}/resume/end`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({reason:"ended_by_dashboard"})});if(p.status===401)throw new Error(i("workflow.detail.writeAccessResume"));let w=await p.json().catch(()=>({}));if(!p.ok||!w.ok)if(w.error==="resume_not_running")V.delete(l);else throw new Error(w.hint??w.message??w.error??i("workflow.detail.resumeEndFailed",{status:p.status}));else V.delete(l)}catch(p){let w=p?.message??String(p);D.set(l,w)}finally{q.delete(l),A()}}}async function Mt(l,S){if(!K.has(l)){K.add(l),F.delete(l),A();try{let p=rt.get(l)?.trim()||void 0,w=await fetch(`/api/workflows/runs/${encodeURIComponent(e)}/${S}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({comment:p})});if(w.status===401)throw new Error(i("workflow.detail.writeAccessApproval"));let R=await w.json().catch(()=>({}));if(!w.ok||!R.ok)throw new Error(R.hint??R.message??R.error??i("workflow.detail.actionHttp",{action:S,status:w.status}));let et=S==="approve"?i("workflow.detail.approved"):i("workflow.detail.rejected");F.set(l,{kind:"ok",text:R.alreadyTerminal?i("workflow.detail.alreadyTerminal",{label:et}):R.pending?i("workflow.detail.workflowContinue",{label:et}):i("workflow.detail.workflowRefreshing",{label:et})}),T(null),await G()}catch(p){let w=p?.message??String(p);F.set(l,{kind:"error",text:w}),T(w)}finally{K.delete(l),A()}}}function A(){if(!g)return;it=y.scrollTop;let l=g.run;B.has(l.status)&&at(null),a.innerHTML=`${r(l.workflowId??"?")} \xB7 ${M(l.status)} \xB7 lastSeq ${g.lastSeq}`,o.textContent=i("workflow.detail.refreshed",{time:new Date().toLocaleTimeString()}),m.hidden=B.has(l.status),m.disabled=_||!g.chatBinding?.larkAppId,m.textContent=g.chatBinding?.larkAppId?i("workflow.detail.cancel"):i("workflow.detail.cliCancelOnly"),m.title=g.chatBinding?.larkAppId?i("workflow.detail.cancelTitle"):i("workflow.detail.cliCancelTitle",{runId:e}),Nt(c,g),jt(f,g),Dt(h,v,g,b),Vt(k,g),Jt(u,g,St,$t,{comments:rt,statuses:F,resolving:K,onResolve:Mt},{sessions:V,pending:q,errors:D,onStart:Et,onEnd:Lt},ot,bt)&&(ot=void 0),he(P,b),y.scrollTop=it,I.hidden=!x,$.textContent=i("workflow.detail.eventsLoaded",{loaded:b.length,total:U})}function tt(){if(H!==null&&window.clearTimeout(H),g&&B.has(g.run.status)){H=null;return}H=window.setTimeout(async()=>{await G(),j||tt()},Ht)}function lt(){document.hidden||G().then(()=>{!j&&H===null&&tt()})}return I.addEventListener("click",()=>{Tt()}),m.addEventListener("click",()=>{At()}),document.addEventListener("visibilitychange",lt),It().then(()=>{T(null),j||tt()}).catch(l=>{T(l?.message??String(l)),a.textContent=i("workflow.detail.loadFailed")}),()=>{j=!0,H!==null&&window.clearTimeout(H),document.removeEventListener("visibilitychange",lt)}}function Nt(t,e){let n=e.run,a=[[i("workflow.summary.workflow"),r(n.workflowId??"?")],[i("workflow.summary.status"),M(n.status)],[i("workflow.summary.lastSeq"),String(e.lastSeq)],[i("workflow.summary.updated"),r(new Date(e.updatedAt).toLocaleString())],[i("workflow.summary.revision"),r(Y(n.revisionId))],[i("workflow.summary.initiator"),r(n.initiator??"-")]];n.failedNodeId&&a.push([i("workflow.summary.failedNode"),r(n.failedNodeId)]),n.cancelOriginEventId&&a.push([i("workflow.summary.cancelOrigin"),r(n.cancelOriginEventId)]),e.chatBinding&&(a.push([i("workflow.summary.chat"),`<code>${r(e.chatBinding.chatId)}</code>`]),a.push([i("workflow.summary.app"),`<code>${r(e.chatBinding.larkAppId)}</code>`])),t.innerHTML=a.map(([o,s])=>`<div class="wf-summary-item"><span>${o}</span><strong>${s}</strong></div>`).join("")}function xt(t){if(!t.errorCode)return"";let e=t.errorMessage?` \u2014 ${be(t.errorMessage,96)}`:"";return`<div class="wf-run-error">
86
+ <span class="muted error">${r(t.errorCode)}</span>${r(e)}
87
+ </div>`}function Ut(t){let e=t.dangling;return{total:new Set([...e.activities,...e.effectAttempted,...e.waits,...e.cancels]).size,effects:e.effectAttempted.length,activities:e.activities.length,waits:e.waits.length,cancels:e.cancels.length}}function jt(t,e){let n=e.dangling,a=[[i("workflow.dangling.activities"),n.activities],[i("workflow.dangling.effects"),n.effectAttempted],[i("workflow.dangling.waits"),n.waits],[i("workflow.dangling.cancels"),n.cancels]],o=new Set(a.flatMap(([,s])=>s)).size;if(t.className=o>0?"wf-panel wf-dangling-panel has":"wf-panel wf-dangling-panel",o===0){t.innerHTML=`<div class="wf-panel-title"><h3>${r(i("workflow.detail.dangling"))}</h3></div><div class="muted">${r(i("workflow.detail.noDangling"))}</div>`;return}t.innerHTML=`<div class="wf-panel-title"><h3>${r(i("workflow.detail.dangling"))}</h3><span class="wf-dangling has">${o}</span></div>
88
+ <div class="wf-dangling-grid">
89
+ ${a.map(([s,d])=>`<div><strong>${s}</strong>${d.length===0?`<div class="muted">${r(i("workflow.detail.none"))}</div>`:`<ul>${d.map(c=>`<li><code>${r(c)}</code></li>`).join("")}</ul>`}</div>`).join("")}
90
+ </div>`}function Dt(t,e,n,a){let o=Bt(a,n);if(o.length===0){e.textContent="",t.innerHTML=`<div class="empty">${r(i("workflow.detail.noParallelData"))}</div>`;return}let s=Date.now(),d=Math.min(...o.map(u=>u.startedAt)),c=Math.max(...o.map(u=>u.endedAt??s),d+1e3),f=Math.max(1,c-d),h=_t(o,s),v=o.filter(u=>!u.endedAt&&(u.status==="running"||u.status==="effectAttempting")).length;e.textContent=i("workflow.detail.parallelMeta",{count:o.length,max:h,running:v});let k=o.sort((u,y)=>u.startedAt-y.startedAt||u.activityId.localeCompare(y.activityId)).map(u=>Wt(u,d,f,s)).join("");t.innerHTML=`<div class="wf-parallel-axis">
91
+ <span title="${r(new Date(d).toISOString())}">${r(X(d))}</span>
92
+ <span title="${r(new Date(c).toISOString())}">${r(X(c))}</span>
93
+ </div>
94
+ <div class="wf-parallel-list">${k}</div>`}function Bt(t,e){let n=new Map,a=new Map(e.activities.map(o=>[o.activityId,o.ownerNodeId]));for(let o of[...t].sort((s,d)=>W(s.eventId)-W(d.eventId))){let s=$e(o);if(!s)continue;let d=typeof s.activityId=="string"?s.activityId:void 0,c=typeof s.attemptId=="string"?s.attemptId:void 0;if(!d||!c)continue;let f=n.get(c);if(o.type==="attemptCreated"){let h=typeof s.attemptNumber=="number"?s.attemptNumber:void 0;f={nodeId:typeof s.nodeId=="string"?s.nodeId:a.get(d),activityId:d,attemptId:c,attemptNumber:h,status:"pending",startedAt:o.timestamp},n.set(c,f);continue}f||(f={nodeId:a.get(d),activityId:d,attemptId:c,status:"pending",startedAt:o.timestamp},n.set(c,f)),o.type==="activityRunning"?(f.status="running",f.runningAt=o.timestamp):o.type==="effectAttempted"?f.status="effectAttempting":o.type==="activityWaiting"||o.type==="waitCreated"?f.status="waiting":Ft(o.type)&&(f.status=Kt(o.type),f.endedAt=o.timestamp,f.endType=o.type)}return[...n.values()]}function Wt(t,e,n,a){let o=t.endedAt??a,s=ut((t.startedAt-e)/n*100,0,100),d=ut((Math.max(o,t.startedAt+1)-t.startedAt)/n*100,.7,100-s),c=t.nodeId??t.activityId,f=t.attemptNumber!==void 0?`#${t.attemptNumber}`:Y(t.attemptId),h=[`${c} ${t.status}`,`${new Date(t.startedAt).toISOString()} \u2192 ${t.endedAt?new Date(t.endedAt).toISOString():i("workflow.detail.parallelNow")}`,t.endType?`end: ${t.endType}`:void 0].filter(Boolean).join(`
95
+ `);return`<div class="wf-parallel-row">
96
+ <div class="wf-parallel-label">
97
+ <code>${r(c)}</code>
98
+ <span class="muted">${r(t.activityId)} \xB7 ${r(f)}</span>
99
+ </div>
100
+ <div class="wf-parallel-track">
101
+ <div class="wf-parallel-bar wf-parallel-${r(t.status)}" style="left:${s.toFixed(3)}%;width:${d.toFixed(3)}%;" title="${r(h)}">
102
+ <span>${r(C(t.status))}</span>
103
+ </div>
104
+ </div>
105
+ </div>`}function _t(t,e){let n=[];for(let s of t)n.push({time:s.startedAt,delta:1}),n.push({time:s.endedAt??e,delta:-1});n.sort((s,d)=>s.time-d.time||d.delta-s.delta);let a=0,o=0;for(let s of n)a+=s.delta,o=Math.max(o,a);return o}function Ft(t){return t==="activitySucceeded"||t==="activityFailed"||t==="activityTimedOut"||t==="activityCanceled"}function Kt(t){return t==="activitySucceeded"?"succeeded":t==="activityCanceled"?"cancelled":t==="activityTimedOut"?"timedOut":"failed"}function Vt(t,e){let n=new Map(e.activities.map(s=>[s.activityId,s])),a=new Set,o=[];for(let s of e.nodes){let d=(s.activityId?n.get(s.activityId):void 0)??e.activities.find(c=>c.ownerNodeId===s.nodeId);d&&a.add(d.activityId),o.push(dt(s,d))}for(let s of e.activities)a.has(s.activityId)||o.push(dt(void 0,s));t.innerHTML=o.length>0?o.join(""):`<tr><td colspan="7" class="empty">${r(i("workflow.detail.noNodes"))}</td></tr>`}function dt(t,e){let n=e?.attempts[e.attempts.length-1];return`<tr>
106
+ <td>${t?`<code>${r(t.nodeId)}</code>`:'<span class="muted">-</span>'}</td>
107
+ <td>${t?M(t.status):'<span class="muted">-</span>'}</td>
108
+ <td>${e?`<code>${r(e.activityId)}</code>`:'<span class="muted">-</span>'}</td>
109
+ <td>${e?M(e.status):'<span class="muted">-</span>'}</td>
110
+ <td>${e?.attempts.length??0}</td>
111
+ <td>${n?`<code>${r(n.attemptId)}</code>`:'<span class="muted">-</span>'}</td>
112
+ <td>${n?ye(n):`<span class="muted">${r(i("workflow.detail.idle"))}</span>`}</td>
113
+ </tr>`}function Jt(t,e,n,a,o,s,d,c){fe(t,n,a),le(t,o.comments);let f=!!(d&&e.attemptIO?.[d]?.terminal);f&&d&&n.add(nt(d,i("workflow.detail.liveTerminal")));let h=zt(e),v=new Set;if(c){for(let u of h){v.add(u.key);let y=c.get(u.key);y||(y=Gt(u.key),c.set(u.key,y),t.appendChild(y.article)),Qt(y,u,n,o,s,d)}for(let[u,y]of Array.from(c))v.has(u)||(y.article.remove(),c.delete(u));if(h.length===0){if(!t.querySelector(".wf-io-empty-placeholder")){let u=document.createElement("div");u.className="empty wf-io-empty-placeholder",u.textContent=i("workflow.detail.noNodeIO"),t.appendChild(u)}}else t.querySelector(".wf-io-empty-placeholder")?.remove()}else{let u=[];for(let y of h)u.push(ee(y,n,o,s,d));t.innerHTML=u.length>0?u.join(""):`<div class="empty">${r(i("workflow.detail.noNodeIO"))}</div>`}me(t,a);let k=ue(t,d);return we(t,n),pe(t,a),ce(t,o),kt(t,s),k&&f}function zt(t){let e=new Map(t.activities.map(o=>[o.activityId,o])),n=new Set,a=[];for(let o of t.nodes){let s=(o.activityId?e.get(o.activityId):void 0)??t.activities.find(d=>d.ownerNodeId===o.nodeId);if(!s){a.push({key:`node:${o.nodeId}`,node:o});continue}n.add(s.activityId),a.push({key:`activity:${s.activityId}`,node:o,activity:s,io:t.attemptIO?.[Q(s)?.attemptId??""]})}for(let o of t.activities)n.has(o.activityId)||a.push({key:`activity:${o.activityId}`,activity:o,io:t.attemptIO?.[Q(o)?.attemptId??""]});return a}function Gt(t){let e=document.createElement("article");e.className="wf-io-card",e.dataset.wfCardKey=t;let n=document.createElement("div");n.className="wf-io-card-head";let a=document.createElement("div");a.className="wf-io-terminal-slot";let o=document.createElement("div");return o.className="wf-io-grid",e.appendChild(n),e.appendChild(a),e.appendChild(o),{article:e,head:n,terminalSlot:a,grid:o,currentTerminalUrl:null}}function Qt(t,e,n,a,o,s){let d=Q(e.activity),c=e.node?.nodeId??e.activity?.ownerNodeId??e.activity?.activityId??"unknown",f=!!(d&&d.attemptId===s);t.article.classList.toggle("is-focused",f),d?t.article.dataset.wfAttemptCard=d.attemptId:delete t.article.dataset.wfAttemptCard;let h=ht(d,a);t.head.innerHTML=`
114
+ <header>
115
+ <div>
116
+ <strong><code>${r(c)}</code></strong>
117
+ <span class="muted">${e.activity?r(e.activity.activityId):r(i("workflow.detail.notDispatched"))}</span>
118
+ </div>
119
+ <div>${e.node?M(e.node.status):""} ${e.activity?M(e.activity.status):""}</div>
120
+ </header>
121
+ <div class="wf-io-meta">
122
+ ${d?`${r(i("workflow.detail.attempt"))} <code>${r(d.attemptId)}</code>`:r(i("workflow.detail.noAttempt"))}
123
+ </div>
124
+ ${h}
125
+ `;let v=ft(d,e.activity,e.io?.terminal,o),k=v?.url??null;if(k!==t.currentTerminalUrl)v===null?t.terminalSlot.innerHTML="":t.terminalSlot.innerHTML=wt(e.key,d,e.activity,e.io?.terminal,v,n,o),t.currentTerminalUrl=k;else if(v!==null&&e.io?.terminal){let y=t.terminalSlot.querySelector("details.wf-terminal-block > summary");if(y){let P=mt(v.kind);y.innerHTML=`${r(P)} ${yt(d,e.io.terminal)}`}d&&de(t.terminalSlot,d,e.activity,e.io.terminal,v,o)}let u=d?.attemptId??e.activity?.activityId??e.node?.nodeId??"unknown";t.grid.innerHTML=`
126
+ ${E(u,i("workflow.detail.authoredInput"),e.io?.input,n)}
127
+ ${E(u,i("workflow.detail.resolvedInput"),e.io?.resolvedInput,n)}
128
+ ${E(u,i("workflow.detail.output"),e.io?.output,n)}
129
+ ${E(u,i("workflow.detail.executionLog"),e.io?.log,n)}
130
+ ${e.io?.waitPrompt?E(u,i("workflow.detail.waitPrompt"),e.io.waitPrompt,n):""}
131
+ `}function ft(t,e,n,a){if(!n||n.error)return null;if(ne(t,n))return{kind:"live",url:ie(n)};if(!t||!e||!re(t,n))return null;let o=ae();if(!o)return null;let s=a?.sessions.get(t.attemptId);return s?{kind:"resume",url:s.url,resumeId:s.resumeId,downloadUrl:ct(o,e.activityId,t.attemptId)}:{kind:"replay",url:oe(o,e.activityId,t.attemptId,!!n.hasPtyLog),downloadUrl:ct(o,e.activityId,t.attemptId)}}function wt(t,e,n,a,o,s,d){if(!a)return"";let c=mt(o.kind),f=nt(t,c),h=yt(e,a),v=Xt(o.kind),k=o.kind==="replay"||o.kind==="resume"?`<a class="btn-link" href="${r(o.downloadUrl)}" download>${r(i("workflow.detail.downloadFullLog"))}</a>`:"",u=e?gt(e,n,a,o,d):"",y=e?vt(e.attemptId,d):"";return`<details class="wf-io-block wf-terminal-block" data-io-key="${r(f)}"${s.has(f)?" open":""}>
132
+ <summary>${r(c)} ${h}</summary>
133
+ <div class="wf-terminal-actions">
134
+ <a class="btn-link" href="${r(o.url)}" target="_blank" rel="noreferrer">${r(v)}</a>
135
+ ${k}
136
+ ${u}
137
+ </div>
138
+ ${y}
139
+ <iframe class="wf-terminal-frame" src="${r(o.url)}" title="${r(c)}" loading="lazy"></iframe>
140
+ </details>`}function mt(t){return t==="live"?i("workflow.detail.liveTerminal"):t==="resume"?i("workflow.detail.terminalResume"):i("workflow.detail.terminalReplay")}function Xt(t){return t==="live"?i("workflow.detail.openTerminalNewTab"):t==="resume"?i("workflow.detail.openResumeNewTab"):i("workflow.detail.openReplayNewTab")}var pt=new Set(["antigravity","codex-app","cursor","mira"]),Yt=new Set(["aiden","coco","claude-code","seed","relay","codex","mtr","hermes","pi","mir"]);function Zt(t){return!!t&&(Yt.has(t)||pt.has(t))}function te(t){return!!t&&pt.has(t)}function gt(t,e,n,a,o){if(!o||a.kind==="live"||!e)return"";let s=a.kind==="resume",d=o.pending.has(t.attemptId),c=`data-wf-resume-attempt="${r(t.attemptId)}" data-wf-resume-activity="${r(e.activityId)}"`;return s?`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="end" ${c}${d?" disabled":""}>${r(d?i("workflow.detail.resumeEnding"):i("workflow.detail.endResumeSession"))}</button>`:Zt(n.cliId)?te(n.cliId)&&!n.cliSessionId?`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${r(i("workflow.detail.resumeMissingCliSession"))}">${r(i("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" data-wf-resume-action="start" ${c}${d?" disabled":""}>${r(d?i("workflow.detail.resumeStarting"):i("workflow.detail.resumeSession"))}</button>`:`<button type="button" class="btn-link" data-wf-resume-button="1" disabled title="${r(i("workflow.detail.resumeUnsupportedCli",{cliId:n.cliId??"?"}))}">${r(i("workflow.detail.resumeSession"))}</button>`}function vt(t,e){if(!e)return"";let n=e.errors.get(t);return n?`<div class="hint-warn wf-resume-status" data-wf-resume-status="${r(t)}">${r(n)}</div>`:""}function ee(t,e,n,a,o){let s=Q(t.activity),d=t.node?.nodeId??t.activity?.ownerNodeId??t.activity?.activityId??"unknown",c=s?.attemptId??t.activity?.activityId??t.node?.nodeId??"unknown",f=ht(s,n),h=s?.attemptId===o?" is-focused":"",v=s?` data-wf-attempt-card="${r(s.attemptId)}"`:"",k=ft(s,t.activity,t.io?.terminal,a),u=k?wt(c,s,t.activity,t.io?.terminal,k,e,a):"";return`<article class="wf-io-card${h}" data-wf-card-key="${r(t.key)}"${v}>
141
+ <div class="wf-io-card-head">
142
+ <header>
143
+ <div>
144
+ <strong><code>${r(d)}</code></strong>
145
+ <span class="muted">${t.activity?r(t.activity.activityId):r(i("workflow.detail.notDispatched"))}</span>
146
+ </div>
147
+ <div>${t.node?M(t.node.status):""} ${t.activity?M(t.activity.status):""}</div>
148
+ </header>
149
+ <div class="wf-io-meta">
150
+ ${s?`${r(i("workflow.detail.attempt"))} <code>${r(s.attemptId)}</code>`:r(i("workflow.detail.noAttempt"))}
151
+ </div>
152
+ ${f}
153
+ </div>
154
+ <div class="wf-io-terminal-slot">${u}</div>
155
+ <div class="wf-io-grid">
156
+ ${E(c,i("workflow.detail.authoredInput"),t.io?.input,e)}
157
+ ${E(c,i("workflow.detail.resolvedInput"),t.io?.resolvedInput,e)}
158
+ ${E(c,i("workflow.detail.output"),t.io?.output,e)}
159
+ ${E(c,i("workflow.detail.executionLog"),t.io?.log,e)}
160
+ ${t.io?.waitPrompt?E(c,i("workflow.detail.waitPrompt"),t.io.waitPrompt,e):""}
161
+ </div>
162
+ </article>`}function Q(t){return t?.attempts[t.attempts.length-1]}function yt(t,e){let n=[];return e.error?n.push(i("workflow.detail.error")):n.push(e.status==="live"?i("workflow.detail.terminalLive"):i("workflow.detail.terminalClosedShort")),t?.status&&n.push(t.status),e.webPort>0&&n.push(`:${e.webPort}`),`<span class="muted">${r(n.join(" \xB7 "))}</span>`}function ne(t,e){return e.status==="live"&&e.webPort>0&&(t?.status==="pending"||t?.status==="running"||t?.status==="effectAttempting")}function re(t,e){return t.status==="succeeded"||t.status==="failed"||t.status==="cancelled"||t.status==="timedOut"?!!(e.sessionId||e.startedAt):!1}function ie(t){return`http://${window.location.hostname||"127.0.0.1"}:${t.webPort}`}function oe(t,e,n,a){let o=new URLSearchParams({runId:t,activityId:e,attemptId:n});return a&&o.set("hasPtyLog","1"),`/assets/terminal-replay.html?${o.toString()}`}function ct(t,e,n){return`/api/workflows/runs/${encodeURIComponent(t)}/attempts/${encodeURIComponent(e)}/${encodeURIComponent(n)}/terminal-log/raw?download=1`}function ae(){let t=window.location.hash.match(/^#\/legacy-workflow\/([^/?#]+)/);if(!t)return null;try{return decodeURIComponent(t[1])}catch{return null}}function ht(t,e){if(!se(t))return"";let n=t.attemptId,a=e.comments.get(n)??"",o=e.resolving.has(n),s=e.statuses.get(n),d=s?.kind==="error"?"hint-warn":"hint-ok";return`<div class="wf-approval-box" data-wf-approval="${r(n)}">
163
+ <label>
164
+ <span>${r(i("workflow.detail.approvalComment"))}</span>
165
+ <textarea class="wf-approval-comment" data-wf-approval-comment="${r(n)}" rows="2" placeholder="${r(i("workflow.detail.optionalComment"))}"${o?" disabled":""}>${r(a)}</textarea>
166
+ </label>
167
+ <div class="wf-approval-actions">
168
+ <button type="button" class="primary" data-wf-approval-action="approve" data-wf-attempt-id="${r(n)}"${o?" disabled":""}>${r(i("workflow.detail.approve"))}</button>
169
+ <button type="button" data-wf-approval-action="reject" data-wf-attempt-id="${r(n)}"${o?" disabled":""}>${r(i("workflow.detail.reject"))}</button>
170
+ ${o?`<span class="muted">${r(i("workflow.detail.submitting"))}</span>`:""}
171
+ </div>
172
+ ${s?`<div class="${d} wf-approval-status">${r(s.text)}</div>`:""}
173
+ </div>`}function se(t){return!!t&&t.status==="waiting"&&t.wait?.waitKind==="human-gate"&&!t.wait.resolution}function le(t,e){t.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let a=n.dataset.wfApprovalComment;a&&e.set(a,n.value)})}function kt(t,e){t.querySelectorAll("button[data-wf-resume-action][data-wf-resume-attempt][data-wf-resume-activity]").forEach(n=>{n.dataset.wfResumeBound!=="1"&&(n.dataset.wfResumeBound="1",n.addEventListener("click",()=>{let a=n.dataset.wfResumeAttempt,o=n.dataset.wfResumeActivity,s=n.dataset.wfResumeAction;!a||!o||(s==="start"?e.onStart(a,o):s==="end"&&e.onEnd(a,o))}))})}function de(t,e,n,a,o,s){let d=t.querySelector(".wf-terminal-actions");if(!d)return;let c=d.querySelector('button[data-wf-resume-button="1"]'),f=gt(e,n,a,o,s);c?c.outerHTML=f:f&&d.insertAdjacentHTML("beforeend",f);let h=t.querySelector("details.wf-terminal-block");if(h){let v=h.querySelector(".wf-resume-status"),k=vt(e.attemptId,s);v?v.outerHTML=k:k&&d.insertAdjacentHTML("afterend",k)}kt(t,s)}function ce(t,e){t.querySelectorAll("textarea[data-wf-approval-comment]").forEach(n=>{let a=n.dataset.wfApprovalComment;a&&n.addEventListener("input",()=>{e.comments.set(a,n.value)})}),t.querySelectorAll("button[data-wf-approval-action][data-wf-attempt-id]").forEach(n=>{n.addEventListener("click",()=>{let a=n.dataset.wfAttemptId,o=n.dataset.wfApprovalAction;!a||o!=="approve"&&o!=="reject"||e.onResolve(a,o)})})}function E(t,e,n,a){let o=nt(t,e);return`<details class="wf-io-block" data-io-key="${r(o)}"${a.has(o)?" open":""}>
174
+ <summary>${r(e)} ${ge(n)}</summary>
175
+ ${ve(n)}
176
+ </details>`}function nt(t,e){return`${t}:${e}`}function ue(t,e){if(!e)return!1;for(let n of t.querySelectorAll("[data-wf-attempt-card]"))if(n.dataset.wfAttemptCard===e)return n.scrollIntoView({block:"center"}),!0;return!1}function fe(t,e,n){t.querySelectorAll("details.wf-io-block[data-io-key]").forEach(a=>{let o=a.dataset.ioKey;if(!o)return;a.open?e.add(o):e.delete(o);let s=a.querySelector(".wf-io-pre");s&&n.set(o,s.scrollTop)})}function we(t,e){t.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{n.dataset.ioToggleBound!=="1"&&(n.dataset.ioToggleBound="1",n.addEventListener("toggle",()=>{let a=n.dataset.ioKey;a&&(n.open?e.add(a):e.delete(a))}))})}function me(t,e){t.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let a=n.dataset.ioKey;if(!a)return;let o=e.get(a);if(o===void 0)return;let s=n.querySelector(".wf-io-pre");s&&(s.scrollTop=o)})}function pe(t,e){t.querySelectorAll("details.wf-io-block[data-io-key]").forEach(n=>{let a=n.dataset.ioKey;if(!a)return;let o=n.querySelector(".wf-io-pre");o&&o.dataset.ioScrollBound!=="1"&&(o.dataset.ioScrollBound="1",o.addEventListener("scroll",()=>{e.set(a,o.scrollTop)}))})}function ge(t){if(!t)return`<span class="muted">${r(i("workflow.detail.empty"))}</span>`;let e=[];return t.outputBytes!==void 0&&e.push(`${t.outputBytes}B`),t.truncated&&e.push(i("workflow.detail.truncated")),t.error&&e.push(i("workflow.detail.error")),t.outputHash&&e.push(Y(t.outputHash)),e.length?`<span class="muted">${r(e.join(" \xB7 "))}</span>`:""}function ve(t){if(!t)return`<div class="muted wf-io-empty">${r(i("workflow.detail.noData"))}</div>`;let e=t.value!==void 0?JSON.stringify(t.value,null,2):t.text??"",n=t.error?`<div class="muted error">${r(t.error)}</div>`:"";return e?`${n}<pre class="wf-io-pre">${r(e)}</pre>`:`${n}<div class="muted wf-io-empty">${r(i("workflow.detail.noPreview"))}</div>`}function ye(t){let e=[];if(t.effectAttempted&&e.push(`${r(i("workflow.detail.effect"))} ${r(t.effectAttempted.provider)}`),t.wait){let n=t.wait.resolution?`${t.wait.resolution.kind}${t.wait.resolution.resolution?":"+t.wait.resolution.resolution:""}`:i("workflow.detail.open");e.push(`${r(i("workflow.detail.wait"))} ${r(t.wait.waitKind)} ${r(n)}`),t.wait.deadlineAt!==void 0&&e.push(`${r(i("workflow.detail.deadline"))} ${r(X(t.wait.deadlineAt))}`)}if(t.error){let n=`${t.error.errorCode}${t.error.errorClass?` \xB7 ${t.error.errorClass}`:""}`;e.push(`<span class="muted error">${r(n)}</span>`),t.error.errorMessage&&e.push(`<span class="error wf-error-msg">${r(t.error.errorMessage)}</span>`)}return t.output&&e.push(`${r(i("workflow.detail.output"))} ${r(Y(t.output.outputHash))}`),t.runningMs!==void 0&&e.push(`${t.runningMs}ms`),e.length>0?e.join("<br/>"):'<span class="muted">-</span>'}function he(t,e){t.innerHTML=e.length>0?e.map(ke).join(""):`<tr><td colspan="7" class="empty">${r(i("workflow.detail.noEvents"))}</td></tr>`}function ke(t){let e=Se(t.payload);return`<tr>
177
+ <td>${W(t.eventId)}</td>
178
+ <td><code>${r(t.type)}</code></td>
179
+ <td>${r(t.actor)}</td>
180
+ <td>${e.nodeId?`<code>${r(e.nodeId)}</code>`:"-"}</td>
181
+ <td>${e.activityId?`<code>${r(e.activityId)}</code>`:"-"}</td>
182
+ <td>${e.errorCode?`<span class="muted error">${r(e.errorCode)}</span>`:"-"}</td>
183
+ <td title="${r(new Date(t.timestamp).toISOString())}">${r(X(t.timestamp))}</td>
184
+ </tr>`}function W(t){let e=t.lastIndexOf("-");if(e<0)return 0;let n=Number(t.slice(e+1));return Number.isFinite(n)?n:0}function Se(t){if(!t||typeof t!="object"||"ref"in t)return{};let e=t,n={};typeof e.nodeId=="string"&&(n.nodeId=e.nodeId),typeof e.activityId=="string"&&(n.activityId=e.activityId),typeof e.failedNodeId=="string"&&(n.nodeId=e.failedNodeId);let a=e.error;return a&&typeof a=="object"&&"errorCode"in a&&(n.errorCode=String(a.errorCode)),n}function $e(t){return!t.payload||typeof t.payload!="object"||"ref"in t.payload?null:t.payload}function ut(t,e,n){return Math.min(n,Math.max(e,t))}function Y(t){return t?t.length>18?t.slice(0,10)+"..."+t.slice(-6):t:"-"}function be(t,e){return t.length>e?t.slice(0,e-1)+"\u2026":t}function X(t){return new Date(t).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"})}export{Te as renderWorkflowsPage};
@@ -67,6 +67,6 @@
67
67
  <main id="root"></main>
68
68
  </div>
69
69
  </div>
70
- <script src="/assets/app.js"></script>
70
+ <script type="module" src="/assets/app.js"></script>
71
71
  </body>
72
72
  </html>
@@ -773,6 +773,12 @@ th {
773
773
 
774
774
  tbody tr:last-child td { border-bottom: 0; }
775
775
 
776
+ .schedules-table .schedule-actions {
777
+ display: flex;
778
+ gap: 6px;
779
+ flex-wrap: wrap;
780
+ }
781
+
776
782
  /* ── 首尾列固定的横向滚动矩阵(群组与 Bot)─────────────────────────────
777
783
  bot 一多中间的成员列就溢出视口,操作按钮被顶出屏幕。把圆角/阴影挪到
778
784
  滚动容器上,表格本体放开宽度横向滚,首列(群)和尾列(操作)sticky 钉住。 */
@@ -969,6 +975,7 @@ button.primary {
969
975
  .status-working,
970
976
  .status-active { background: var(--accent-soft); color: var(--accent-strong); }
971
977
  .status-idle { background: var(--surface-muted); color: var(--muted); }
978
+ .status-dormant { background: var(--surface-muted); color: var(--muted); }
972
979
  .status-closed { background: var(--danger-soft); color: var(--danger); }
973
980
  .status-analyzing { background: var(--warning-soft); color: var(--warning); }
974
981
  .status-starting { background: var(--success-soft); color: var(--success); }
@@ -1572,6 +1579,14 @@ button.primary {
1572
1579
  background: var(--danger);
1573
1580
  }
1574
1581
 
1582
+ .kanban-card-dot[data-status="idle"] {
1583
+ background: var(--success);
1584
+ }
1585
+
1586
+ .kanban-card-dot[data-status="dormant"] {
1587
+ background: var(--muted);
1588
+ }
1589
+
1575
1590
  .kanban-card-dot[data-status="closed"] {
1576
1591
  background: var(--border);
1577
1592
  }
@@ -2111,6 +2126,9 @@ fieldset legend {
2111
2126
  }
2112
2127
 
2113
2128
  .bulk-bar[hidden] { display: none; }
2129
+ /* Mobile table rules are author-level and can override the UA hidden style;
2130
+ keep hidden tables invisible across view toggles such as sessions board/table. */
2131
+ table[hidden] { display: none !important; }
2114
2132
  .bulk-bar #bulk-count { font-weight: 800; margin-right: 4px; }
2115
2133
  .idle-cleanup-bar {
2116
2134
  display: grid;
@@ -2601,6 +2619,66 @@ input.row-select,
2601
2619
  display: block;
2602
2620
  overflow-x: auto;
2603
2621
  }
2622
+ .schedules-table {
2623
+ display: block;
2624
+ overflow: visible;
2625
+ border: 0;
2626
+ border-radius: 0;
2627
+ background: transparent;
2628
+ box-shadow: none;
2629
+ }
2630
+ .schedules-table thead {
2631
+ display: none;
2632
+ }
2633
+ .schedules-table tbody {
2634
+ display: grid;
2635
+ gap: 10px;
2636
+ }
2637
+ .schedules-table tr {
2638
+ display: grid;
2639
+ gap: 8px;
2640
+ padding: 14px;
2641
+ border: 1px solid var(--border-soft);
2642
+ border-radius: var(--radius);
2643
+ background: var(--surface);
2644
+ box-shadow: var(--shadow);
2645
+ }
2646
+ .schedules-table td {
2647
+ display: grid;
2648
+ grid-template-columns: minmax(84px, 0.36fr) minmax(0, 1fr);
2649
+ gap: 10px;
2650
+ align-items: baseline;
2651
+ min-width: 0;
2652
+ padding: 0;
2653
+ border-bottom: 0;
2654
+ white-space: normal;
2655
+ overflow-wrap: anywhere;
2656
+ }
2657
+ .schedules-table td[data-label]::before {
2658
+ content: attr(data-label);
2659
+ color: var(--muted);
2660
+ font-size: 11px;
2661
+ font-weight: 800;
2662
+ line-height: 1.35;
2663
+ text-transform: uppercase;
2664
+ }
2665
+ .schedules-table td.actions-cell {
2666
+ grid-template-columns: 1fr;
2667
+ }
2668
+ .schedules-table .schedule-actions {
2669
+ gap: 8px;
2670
+ }
2671
+ .schedules-table .schedule-actions button {
2672
+ flex: 1 1 120px;
2673
+ }
2674
+ .schedules-table tr.schedule-empty-row {
2675
+ padding: 0;
2676
+ }
2677
+ .schedules-table tr.schedule-empty-row td {
2678
+ display: block;
2679
+ padding: 18px;
2680
+ text-align: center;
2681
+ }
2604
2682
  }
2605
2683
 
2606
2684
  /* ─── Roles Page ─── */
@@ -3414,6 +3492,7 @@ button.contrast:hover { background: var(--danger-soft); border-color: var(--dang
3414
3492
  .status-analyzing { background: var(--accent-soft); color: var(--accent); }
3415
3493
  .status-starting { background: var(--info-soft); color: var(--info); }
3416
3494
  .status-idle { background: var(--success-soft); color: var(--success); }
3495
+ .status-dormant { background: var(--surface-muted); color: var(--muted); }
3417
3496
  .status-limited { background: var(--danger-soft); color: var(--danger); }
3418
3497
 
3419
3498
  /* ── 玻璃面板(dark 下生效;light 保持实底)─────────────────────────────── */
@@ -4388,6 +4467,7 @@ button.contrast:hover { background: var(--danger-soft); border-color: var(--dang
4388
4467
  }
4389
4468
 
4390
4469
  .skills-install-grid label:first-child,
4470
+ .skills-install-grid .skills-source-label,
4391
4471
  .skills-install-field-wide,
4392
4472
  .skills-install-note {
4393
4473
  grid-column: 1 / -1;
@@ -4408,7 +4488,8 @@ button.contrast:hover { background: var(--danger-soft); border-color: var(--dang
4408
4488
  font-weight: 700;
4409
4489
  }
4410
4490
 
4411
- .skills-install-grid label {
4491
+ .skills-install-grid label,
4492
+ .skills-install-grid .skills-source-label {
4412
4493
  display: grid;
4413
4494
  gap: 5px;
4414
4495
  color: var(--muted);
package/dist/dashboard.js CHANGED
@@ -421,15 +421,14 @@ function serveStatic(req, res, pathname) {
421
421
  const st = statSync(fp);
422
422
  if (!st.isFile())
423
423
  return false;
424
- // Bundle filenames are fixed (app.js/style.css), so without revalidation
425
- // browsers heuristic-cache them and serve a stale build after a deploy
426
- // (new JS + old CSS broken layout). `no-cache` + an mtime/size ETag makes
427
- // the browser revalidate every load: 304 when unchanged (cheap), fresh 200
428
- // when the build changed. No manual hard-refresh needed after deploy.
424
+ // Fixed entry filenames (index.html/app.js/style.css) need revalidation so
425
+ // a deploy never serves new JS with old CSS. Lazy chunks are content-hashed
426
+ // and can be cached immutably once the current app.js points at them.
427
+ const immutableChunk = relToRoot.startsWith('chunks/') || relToRoot.startsWith('chunks\\');
429
428
  const etag = `W/"${st.size.toString(16)}-${Math.floor(st.mtimeMs).toString(16)}"`;
430
429
  const headers = {
431
430
  'content-type': MIME[extname(fp)] ?? 'application/octet-stream',
432
- 'cache-control': 'no-cache',
431
+ 'cache-control': immutableChunk ? 'public, max-age=31536000, immutable' : 'no-cache',
433
432
  etag,
434
433
  };
435
434
  if (req.headers['if-none-match'] === etag) {