botmux 2.93.0 → 2.94.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 (227) hide show
  1. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  2. package/dist/adapters/cli/claude-code.js +6 -1
  3. package/dist/adapters/cli/claude-code.js.map +1 -1
  4. package/dist/bot-registry.d.ts +10 -1
  5. package/dist/bot-registry.d.ts.map +1 -1
  6. package/dist/bot-registry.js +2 -0
  7. package/dist/bot-registry.js.map +1 -1
  8. package/dist/cli/dashboard-endpoint.d.ts +1 -1
  9. package/dist/cli/dashboard-endpoint.d.ts.map +1 -1
  10. package/dist/cli/dashboard-endpoint.js +3 -0
  11. package/dist/cli/dashboard-endpoint.js.map +1 -1
  12. package/dist/cli/workflow.d.ts.map +1 -1
  13. package/dist/cli/workflow.js +11 -4
  14. package/dist/cli/workflow.js.map +1 -1
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +133 -1
  17. package/dist/cli.js.map +1 -1
  18. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  19. package/dist/core/dashboard-ipc-server.js +3 -0
  20. package/dist/core/dashboard-ipc-server.js.map +1 -1
  21. package/dist/core/inherit-peer.d.ts +5 -0
  22. package/dist/core/inherit-peer.d.ts.map +1 -1
  23. package/dist/core/inherit-peer.js +3 -0
  24. package/dist/core/inherit-peer.js.map +1 -1
  25. package/dist/core/trigger-session.d.ts +10 -0
  26. package/dist/core/trigger-session.d.ts.map +1 -1
  27. package/dist/core/trigger-session.js +22 -2
  28. package/dist/core/trigger-session.js.map +1 -1
  29. package/dist/core/worker-pool.d.ts +6 -0
  30. package/dist/core/worker-pool.d.ts.map +1 -1
  31. package/dist/core/worker-pool.js +49 -6
  32. package/dist/core/worker-pool.js.map +1 -1
  33. package/dist/daemon.d.ts.map +1 -1
  34. package/dist/daemon.js +297 -13
  35. package/dist/daemon.js.map +1 -1
  36. package/dist/dashboard/auth.d.ts.map +1 -1
  37. package/dist/dashboard/auth.js +7 -1
  38. package/dist/dashboard/auth.js.map +1 -1
  39. package/dist/dashboard/bot-payload.d.ts +1 -0
  40. package/dist/dashboard/bot-payload.d.ts.map +1 -1
  41. package/dist/dashboard/bot-payload.js +1 -0
  42. package/dist/dashboard/bot-payload.js.map +1 -1
  43. package/dist/dashboard/federation-spoke-api.d.ts +31 -0
  44. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
  45. package/dist/dashboard/federation-spoke-api.js +36 -14
  46. package/dist/dashboard/federation-spoke-api.js.map +1 -1
  47. package/dist/dashboard/v3-runs-api.d.ts +26 -0
  48. package/dist/dashboard/v3-runs-api.d.ts.map +1 -0
  49. package/dist/dashboard/v3-runs-api.js +67 -0
  50. package/dist/dashboard/v3-runs-api.js.map +1 -0
  51. package/dist/dashboard/web/app.js +21 -9
  52. package/dist/dashboard/web/app.js.map +1 -1
  53. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  54. package/dist/dashboard/web/bot-defaults.js +24 -1
  55. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  56. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  57. package/dist/dashboard/web/i18n.js +12 -4
  58. package/dist/dashboard/web/i18n.js.map +1 -1
  59. package/dist/dashboard/web/legacy-workflow-link.d.ts +2 -0
  60. package/dist/dashboard/web/legacy-workflow-link.d.ts.map +1 -0
  61. package/dist/dashboard/web/legacy-workflow-link.js +12 -0
  62. package/dist/dashboard/web/legacy-workflow-link.js.map +1 -0
  63. package/dist/dashboard/web/v3-terminal.d.ts +11 -0
  64. package/dist/dashboard/web/v3-terminal.d.ts.map +1 -0
  65. package/dist/dashboard/web/v3-terminal.js +143 -0
  66. package/dist/dashboard/web/v3-terminal.js.map +1 -0
  67. package/dist/dashboard/web/v3.d.ts +2 -0
  68. package/dist/dashboard/web/v3.d.ts.map +1 -0
  69. package/dist/dashboard/web/v3.js +564 -0
  70. package/dist/dashboard/web/v3.js.map +1 -0
  71. package/dist/dashboard/web/workflows.d.ts.map +1 -1
  72. package/dist/dashboard/web/workflows.js +12 -8
  73. package/dist/dashboard/web/workflows.js.map +1 -1
  74. package/dist/dashboard-web/app.js +787 -699
  75. package/dist/dashboard-web/index.html +1 -1
  76. package/dist/dashboard-web/style.css +223 -0
  77. package/dist/dashboard.js +61 -40
  78. package/dist/dashboard.js.map +1 -1
  79. package/dist/i18n/en.d.ts.map +1 -1
  80. package/dist/i18n/en.js +6 -3
  81. package/dist/i18n/en.js.map +1 -1
  82. package/dist/i18n/zh.d.ts.map +1 -1
  83. package/dist/i18n/zh.js +6 -3
  84. package/dist/i18n/zh.js.map +1 -1
  85. package/dist/im/lark/card-handler.d.ts +12 -0
  86. package/dist/im/lark/card-handler.d.ts.map +1 -1
  87. package/dist/im/lark/card-handler.js +52 -2
  88. package/dist/im/lark/card-handler.js.map +1 -1
  89. package/dist/im/lark/doc-comment.d.ts +20 -0
  90. package/dist/im/lark/doc-comment.d.ts.map +1 -1
  91. package/dist/im/lark/doc-comment.js +23 -0
  92. package/dist/im/lark/doc-comment.js.map +1 -1
  93. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  94. package/dist/im/lark/event-dispatcher.js +13 -9
  95. package/dist/im/lark/event-dispatcher.js.map +1 -1
  96. package/dist/im/lark/v3-blocked-card-handler.d.ts +28 -0
  97. package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -0
  98. package/dist/im/lark/v3-blocked-card-handler.js +134 -0
  99. package/dist/im/lark/v3-blocked-card-handler.js.map +1 -0
  100. package/dist/im/lark/v3-blocked-card.d.ts +75 -0
  101. package/dist/im/lark/v3-blocked-card.d.ts.map +1 -0
  102. package/dist/im/lark/v3-blocked-card.js +206 -0
  103. package/dist/im/lark/v3-blocked-card.js.map +1 -0
  104. package/dist/im/lark/v3-gate-card-handler.d.ts +31 -0
  105. package/dist/im/lark/v3-gate-card-handler.d.ts.map +1 -0
  106. package/dist/im/lark/v3-gate-card-handler.js +110 -0
  107. package/dist/im/lark/v3-gate-card-handler.js.map +1 -0
  108. package/dist/im/lark/v3-gate-card.d.ts +47 -0
  109. package/dist/im/lark/v3-gate-card.d.ts.map +1 -0
  110. package/dist/im/lark/v3-gate-card.js +119 -0
  111. package/dist/im/lark/v3-gate-card.js.map +1 -0
  112. package/dist/im/lark/v3-loop-grant-card-handler.d.ts +28 -0
  113. package/dist/im/lark/v3-loop-grant-card-handler.d.ts.map +1 -0
  114. package/dist/im/lark/v3-loop-grant-card-handler.js +90 -0
  115. package/dist/im/lark/v3-loop-grant-card-handler.js.map +1 -0
  116. package/dist/im/lark/v3-loop-grant-card.d.ts +46 -0
  117. package/dist/im/lark/v3-loop-grant-card.d.ts.map +1 -0
  118. package/dist/im/lark/v3-loop-grant-card.js +119 -0
  119. package/dist/im/lark/v3-loop-grant-card.js.map +1 -0
  120. package/dist/im/lark/v3-revisit-grant-card-handler.d.ts +29 -0
  121. package/dist/im/lark/v3-revisit-grant-card-handler.d.ts.map +1 -0
  122. package/dist/im/lark/v3-revisit-grant-card-handler.js +96 -0
  123. package/dist/im/lark/v3-revisit-grant-card-handler.js.map +1 -0
  124. package/dist/im/lark/v3-revisit-grant-card.d.ts +52 -0
  125. package/dist/im/lark/v3-revisit-grant-card.d.ts.map +1 -0
  126. package/dist/im/lark/v3-revisit-grant-card.js +123 -0
  127. package/dist/im/lark/v3-revisit-grant-card.js.map +1 -0
  128. package/dist/im/lark/workflow-cards.d.ts.map +1 -1
  129. package/dist/im/lark/workflow-cards.js +5 -1
  130. package/dist/im/lark/workflow-cards.js.map +1 -1
  131. package/dist/im/lark/workflow-progress-card.d.ts +1 -1
  132. package/dist/im/lark/workflow-progress-card.js +1 -1
  133. package/dist/im/lark/workflow-slash-command.d.ts +28 -0
  134. package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
  135. package/dist/im/lark/workflow-slash-command.js +61 -5
  136. package/dist/im/lark/workflow-slash-command.js.map +1 -1
  137. package/dist/platform/bind.d.ts.map +1 -1
  138. package/dist/platform/bind.js +17 -3
  139. package/dist/platform/bind.js.map +1 -1
  140. package/dist/services/card-prefs-store.d.ts +4 -0
  141. package/dist/services/card-prefs-store.d.ts.map +1 -1
  142. package/dist/services/card-prefs-store.js +19 -0
  143. package/dist/services/card-prefs-store.js.map +1 -1
  144. package/dist/services/group-creator.d.ts.map +1 -1
  145. package/dist/services/group-creator.js +18 -2
  146. package/dist/services/group-creator.js.map +1 -1
  147. package/dist/skills/definitions.d.ts.map +1 -1
  148. package/dist/skills/definitions.js +208 -4
  149. package/dist/skills/definitions.js.map +1 -1
  150. package/dist/worker.js +79 -13
  151. package/dist/worker.js.map +1 -1
  152. package/dist/workflows/definition.d.ts +80 -80
  153. package/dist/workflows/events/payloads.d.ts +4 -4
  154. package/dist/workflows/events/schema.d.ts +16 -16
  155. package/dist/workflows/v3/architect.d.ts +37 -0
  156. package/dist/workflows/v3/architect.d.ts.map +1 -0
  157. package/dist/workflows/v3/architect.js +226 -0
  158. package/dist/workflows/v3/architect.js.map +1 -0
  159. package/dist/workflows/v3/bot-resolve.d.ts +21 -0
  160. package/dist/workflows/v3/bot-resolve.d.ts.map +1 -0
  161. package/dist/workflows/v3/bot-resolve.js +47 -0
  162. package/dist/workflows/v3/bot-resolve.js.map +1 -0
  163. package/dist/workflows/v3/cli-run.d.ts +24 -0
  164. package/dist/workflows/v3/cli-run.d.ts.map +1 -0
  165. package/dist/workflows/v3/cli-run.js +265 -0
  166. package/dist/workflows/v3/cli-run.js.map +1 -0
  167. package/dist/workflows/v3/contract.d.ts +302 -0
  168. package/dist/workflows/v3/contract.d.ts.map +1 -0
  169. package/dist/workflows/v3/contract.js +91 -0
  170. package/dist/workflows/v3/contract.js.map +1 -0
  171. package/dist/workflows/v3/daemon-run.d.ts +311 -0
  172. package/dist/workflows/v3/daemon-run.d.ts.map +1 -0
  173. package/dist/workflows/v3/daemon-run.js +775 -0
  174. package/dist/workflows/v3/daemon-run.js.map +1 -0
  175. package/dist/workflows/v3/dag.d.ts +332 -0
  176. package/dist/workflows/v3/dag.d.ts.map +1 -0
  177. package/dist/workflows/v3/dag.js +1040 -0
  178. package/dist/workflows/v3/dag.js.map +1 -0
  179. package/dist/workflows/v3/ephemeral-pool.d.ts +29 -0
  180. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -0
  181. package/dist/workflows/v3/ephemeral-pool.js +331 -0
  182. package/dist/workflows/v3/ephemeral-pool.js.map +1 -0
  183. package/dist/workflows/v3/grill-state.d.ts +92 -0
  184. package/dist/workflows/v3/grill-state.d.ts.map +1 -0
  185. package/dist/workflows/v3/grill-state.js +151 -0
  186. package/dist/workflows/v3/grill-state.js.map +1 -0
  187. package/dist/workflows/v3/host.d.ts +88 -0
  188. package/dist/workflows/v3/host.d.ts.map +1 -0
  189. package/dist/workflows/v3/host.js +349 -0
  190. package/dist/workflows/v3/host.js.map +1 -0
  191. package/dist/workflows/v3/human-gate.d.ts +85 -0
  192. package/dist/workflows/v3/human-gate.d.ts.map +1 -0
  193. package/dist/workflows/v3/human-gate.js +153 -0
  194. package/dist/workflows/v3/human-gate.js.map +1 -0
  195. package/dist/workflows/v3/journal.d.ts +207 -0
  196. package/dist/workflows/v3/journal.d.ts.map +1 -0
  197. package/dist/workflows/v3/journal.js +74 -0
  198. package/dist/workflows/v3/journal.js.map +1 -0
  199. package/dist/workflows/v3/manifest.d.ts +17 -0
  200. package/dist/workflows/v3/manifest.d.ts.map +1 -0
  201. package/dist/workflows/v3/manifest.js +266 -0
  202. package/dist/workflows/v3/manifest.js.map +1 -0
  203. package/dist/workflows/v3/ops-projection.d.ts +110 -0
  204. package/dist/workflows/v3/ops-projection.d.ts.map +1 -0
  205. package/dist/workflows/v3/ops-projection.js +0 -0
  206. package/dist/workflows/v3/ops-projection.js.map +1 -0
  207. package/dist/workflows/v3/orchestrator.d.ts +168 -0
  208. package/dist/workflows/v3/orchestrator.d.ts.map +1 -0
  209. package/dist/workflows/v3/orchestrator.js +417 -0
  210. package/dist/workflows/v3/orchestrator.js.map +1 -0
  211. package/dist/workflows/v3/runtime.d.ts +193 -0
  212. package/dist/workflows/v3/runtime.d.ts.map +1 -0
  213. package/dist/workflows/v3/runtime.js +1284 -0
  214. package/dist/workflows/v3/runtime.js.map +1 -0
  215. package/dist/workflows/v3/spec.d.ts +32 -0
  216. package/dist/workflows/v3/spec.d.ts.map +1 -0
  217. package/dist/workflows/v3/spec.js +173 -0
  218. package/dist/workflows/v3/spec.js.map +1 -0
  219. package/dist/workflows/v3/state.d.ts +74 -0
  220. package/dist/workflows/v3/state.d.ts.map +1 -0
  221. package/dist/workflows/v3/state.js +353 -0
  222. package/dist/workflows/v3/state.js.map +1 -0
  223. package/package.json +1 -1
  224. package/dist/dashboard/web/workflow-catalog.d.ts +0 -2
  225. package/dist/dashboard/web/workflow-catalog.d.ts.map +0 -1
  226. package/dist/dashboard/web/workflow-catalog.js +0 -323
  227. package/dist/dashboard/web/workflow-catalog.js.map +0 -1
@@ -22,7 +22,7 @@
22
22
  <a href="#/" data-route="overview"><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="1.5" y="1.5" width="5.4" height="5.4" rx="1.5"/><rect x="9.1" y="1.5" width="5.4" height="5.4" rx="1.5"/><rect x="1.5" y="9.1" width="5.4" height="5.4" rx="1.5"/><rect x="9.1" y="9.1" width="5.4" height="5.4" rx="1.5"/></svg><span data-i18n="nav.overview">总览</span></a>
23
23
  <a href="#/sessions" data-route="sessions"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2 3.5h12v7H6l-3 3v-3H2z"/></svg><span data-i18n="nav.sessions">会话</span></a>
24
24
  <a href="#/insights" data-route="insights"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M2 2v12h12M5 11V7M8.5 11V4.5M12 11V8.5"/></svg><span data-i18n="nav.insights">洞察</span></a>
25
- <a href="#/workflows" data-route="workflows"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="3.4" cy="8" r="1.9"/><circle cx="12.6" cy="3.6" r="1.9"/><circle cx="12.6" cy="12.4" r="1.9"/><path d="M5.2 7.2l5.6-2.8M5.2 8.8l5.6 2.8"/></svg><span data-i18n="nav.workflows">工作流(beta)</span></a>
25
+ <a href="#/workflows" data-route="workflows"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="3.4" cy="3.6" r="1.9"/><circle cx="3.4" cy="12.4" r="1.9"/><circle cx="12.6" cy="8" r="1.9"/><path d="M5.2 4.4l5.6 2.8M5.2 11.6l5.6-2.8"/></svg><span data-i18n="nav.workflows">工作流</span></a>
26
26
  <a href="#/groups" data-route="groups"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="5.6" cy="5.8" r="2.4"/><circle cx="11" cy="6.8" r="1.9"/><path d="M1.8 13.2c.5-2.4 2-3.6 3.8-3.6s3.3 1.2 3.8 3.6M9.8 12.6c.4-1.7 1.5-2.6 2.8-2.6 1 0 1.9.5 2.4 1.6"/></svg><span data-i18n="nav.groups">群组</span></a>
27
27
  <a href="#/schedules" data-route="schedules"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="6.2"/><path d="M8 4.5V8l2.4 1.6"/></svg><span data-i18n="nav.schedules">定时</span></a>
28
28
  <a href="#/whiteboards" data-route="whiteboards"><svg viewBox="0 0 16 16" aria-hidden="true"><rect x="2.2" y="2.2" width="11.6" height="11.6" rx="2"/><path d="M4.8 5.2h6.4M4.8 8h6.4M4.8 10.8h4"/></svg><span>白板</span></a>
@@ -3121,6 +3121,17 @@ input.row-select,
3121
3121
  .wf-terminal-frame { display: block; width: 100%; height: 460px; border: 0; border-top: 1px solid var(--border); background: #0d1117; }
3122
3122
  .wf-error-msg { display: block; margin-top: 0.15rem; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 12px; }
3123
3123
 
3124
+ /* v3 per-node terminal panel (live iframe / replay) */
3125
+ .v3-terminal-panel { border: 1px solid var(--border); border-radius: 6px; overflow: hidden; background: #0d1117; }
3126
+ .v3-terminal-head { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.6rem; background: var(--surface); border-bottom: 1px solid var(--border); font-size: 12px; }
3127
+ .v3-terminal-head .muted { margin-left: 0; }
3128
+ .v3-terminal-head .btn-link { margin-left: auto; }
3129
+ .v3-terminal-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: var(--muted); }
3130
+ .v3-terminal-dot.live { background: #1a73e8; box-shadow: 0 0 0 3px rgba(26,115,232,0.25); }
3131
+ .v3-terminal-dot.replay { background: #f9ab00; }
3132
+ .v3-terminal-dot.closed { background: #188038; }
3133
+ .v3-terminal-empty { padding: 1.5rem 0.75rem; text-align: center; border: 1px dashed var(--border); border-radius: 6px; }
3134
+
3124
3135
  /* Workflow catalog */
3125
3136
  .catalog-head, .catalog-detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.8rem; margin-bottom: 0.8rem; }
3126
3137
  .catalog-head h2, .catalog-detail-head h2 { margin: 0 0 0.15rem; font-size: 18px; line-height: 1.25; }
@@ -6919,6 +6930,218 @@ body.cp-fx-slice main { animation: cp-fx-slice 0.32s steps(2, end); }
6919
6930
  .skin-intro { display: none; }
6920
6931
  }
6921
6932
 
6933
+ /* ════════════════════════════════════════════════════════════════════════
6934
+ v3 runs page — "flight recorder" visual language (v3.ts).
6935
+ Status hues derive from theme tokens so light/dark/skins all inherit;
6936
+ gateWaiting gets its own violet (approval ≠ blocked). All motion is
6937
+ CSS-only and disabled under prefers-reduced-motion.
6938
+ (`.v3-terminal-*` above is the codex-owned terminal slot — untouched.)
6939
+ ════════════════════════════════════════════════════════════════════════ */
6940
+ :root {
6941
+ --v3r-pending: var(--faint);
6942
+ --v3r-running: var(--accent);
6943
+ --v3r-done: var(--success);
6944
+ --v3r-blocked: var(--warning);
6945
+ --v3r-failed: var(--danger);
6946
+ --v3r-gate: #7c5cd6;
6947
+ /* edge-activation: 分支未选中的中性终态 — 比 pending 更"收起",绝不能像
6948
+ 失败(它是 by-design 的非事件) */
6949
+ --v3r-skipped: var(--faint);
6950
+ }
6951
+ :root[data-theme="dark"] { --v3r-gate: #a78bfa; }
6952
+
6953
+ .v3r-title { display: inline-block; margin-left: .5rem; font-family: var(--mono); font-size: 1.18rem; letter-spacing: -0.01em; }
6954
+ .v3r-runid { font-family: var(--mono); font-size: 12.5px; }
6955
+
6956
+ /* status pill — shared by list rows, panel header, run badge */
6957
+ .v3r-pill {
6958
+ display: inline-flex; align-items: center; gap: .38em;
6959
+ padding: .14em .62em; border-radius: 999px;
6960
+ font-size: 12px; font-weight: 600; line-height: 1.5;
6961
+ font-variant-numeric: tabular-nums;
6962
+ background: color-mix(in srgb, var(--ns, var(--muted)) 14%, transparent);
6963
+ color: var(--ns, var(--muted));
6964
+ border: 1px solid color-mix(in srgb, var(--ns, var(--muted)) 32%, transparent);
6965
+ }
6966
+ .v3r-pill .dot, .v3r-inst .dot {
6967
+ width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
6968
+ background: var(--ns, var(--muted));
6969
+ }
6970
+ .st-pending { --ns: var(--v3r-pending); }
6971
+ .st-running { --ns: var(--v3r-running); }
6972
+ .st-gateWaiting { --ns: var(--v3r-gate); }
6973
+ .st-done { --ns: var(--v3r-done); }
6974
+ .st-skipped { --ns: var(--v3r-skipped); }
6975
+ .st-cancelled { --ns: var(--v3r-skipped); }
6976
+ .st-blocked { --ns: var(--v3r-blocked); }
6977
+ .st-failed { --ns: var(--v3r-failed); }
6978
+ /* skipped 整体降透明度 + 虚线盒 — 一眼读出"这条路没走",与 pending 区分 */
6979
+ .v3r-node.st-skipped, .v3r-node.st-cancelled { opacity: .55; }
6980
+ .v3r-node.st-skipped .v3r-box, .v3r-node.st-cancelled .v3r-box { stroke-dasharray: 4 3; }
6981
+ .rs-running { --ns: var(--v3r-running); }
6982
+ .rs-succeeded { --ns: var(--v3r-done); }
6983
+ .rs-blocked { --ns: var(--v3r-blocked); }
6984
+ .rs-failed { --ns: var(--v3r-failed); }
6985
+
6986
+ .v3r-wrap { display: flex; flex-direction: column; gap: 1rem; align-items: stretch; }
6987
+ .v3r-graph-card {
6988
+ border: 1px solid var(--border); border-radius: 10px;
6989
+ background:
6990
+ radial-gradient(circle, color-mix(in srgb, var(--fg) 7%, transparent) 1px, transparent 1px) 0 0 / 22px 22px,
6991
+ var(--surface);
6992
+ }
6993
+ .v3r-graph { max-height: 48vh; overflow: auto; }
6994
+ .v3r-legend {
6995
+ display: flex; flex-wrap: wrap; gap: .9rem; align-items: center;
6996
+ padding: .45rem .9rem; border-top: 1px solid var(--border-soft);
6997
+ font-size: 11.5px; color: var(--muted);
6998
+ }
6999
+ .v3r-legend .lg { display: inline-flex; align-items: center; gap: .35em; }
7000
+ .v3r-legend .lg::before {
7001
+ content: ""; width: 8px; height: 8px; border-radius: 50%;
7002
+ background: var(--ns, var(--muted));
7003
+ }
7004
+ .v3r-legend .lg-loop::before { content: none; }
7005
+ .v3r-legend .lg-loop { font-family: var(--mono); }
7006
+
7007
+ /* ── graph nodes (SVG) ── */
7008
+ .v3r-node { cursor: pointer; }
7009
+ .v3r-node .v3r-box {
7010
+ fill: color-mix(in srgb, var(--ns) 9%, var(--surface-raised));
7011
+ stroke: color-mix(in srgb, var(--ns) 52%, var(--border));
7012
+ stroke-width: 1.2;
7013
+ transition: fill .2s ease, stroke .2s ease;
7014
+ }
7015
+ .v3r-node:hover .v3r-box { fill: color-mix(in srgb, var(--ns) 16%, var(--surface-raised)); }
7016
+ .v3r-node.sel .v3r-box { stroke: var(--accent-strong); stroke-width: 2; }
7017
+ .v3r-node .v3r-bar { fill: var(--ns); }
7018
+ .v3r-node .v3r-nid {
7019
+ fill: var(--fg); font-family: var(--mono); font-size: 12px; font-weight: 600;
7020
+ }
7021
+ .v3r-node .v3r-nstatus {
7022
+ fill: var(--ns); font-size: 10.5px; font-weight: 600;
7023
+ font-variant-numeric: tabular-nums;
7024
+ }
7025
+ .v3r-node.st-running .v3r-box { animation: v3r-breathe 2.2s ease-in-out infinite; }
7026
+
7027
+ /* loop capsule: dashed outer frame = composite-container affordance */
7028
+ .v3r-loopnode .v3r-cap {
7029
+ fill: none; stroke: color-mix(in srgb, var(--ns) 45%, var(--border));
7030
+ stroke-width: 1.2; stroke-dasharray: 5 4;
7031
+ }
7032
+ .v3r-loopnode.sel .v3r-cap { stroke: var(--accent-strong); stroke-dasharray: none; }
7033
+ .v3r-spin {
7034
+ fill: var(--ns); font-size: 13px; font-weight: 700;
7035
+ transform-box: fill-box; transform-origin: center;
7036
+ }
7037
+ .st-running .v3r-spin { animation: v3r-spin 2.4s linear infinite; }
7038
+ .v3r-dot.done { fill: var(--ns); }
7039
+ .v3r-dot.cur { fill: var(--ns); stroke: color-mix(in srgb, var(--ns) 40%, transparent); stroke-width: 3; }
7040
+ .v3r-dot.cur.live { animation: v3r-breathe 1.4s ease-in-out infinite; }
7041
+ .v3r-dot.todo { fill: none; stroke: var(--faint); stroke-width: 1.2; }
7042
+ .v3r-dot.grant { stroke: var(--accent-strong); stroke-width: 1.6; }
7043
+ .v3r-dot.grant.done, .v3r-dot.grant.cur { fill: var(--accent-strong); }
7044
+ .v3r-dots-verdict { font-size: 11px; font-weight: 700; }
7045
+ .v3r-dots-verdict.ok { fill: var(--v3r-done); }
7046
+ .v3r-dots-verdict.warn { fill: var(--v3r-blocked); }
7047
+
7048
+ /* edges: quiet by default, marching-ants into live nodes */
7049
+ .v3r-edge { fill: none; stroke: color-mix(in srgb, var(--fg) 26%, transparent); stroke-width: 1.5; }
7050
+ .v3r-edge.live {
7051
+ stroke: var(--v3r-running); stroke-width: 1.8;
7052
+ stroke-dasharray: 6 5; animation: v3r-flow 0.9s linear infinite;
7053
+ }
7054
+
7055
+ /* ── node panel ── */
7056
+ .v3r-panel {
7057
+ border: 1px solid var(--border); border-radius: 10px;
7058
+ padding: 1rem; background: var(--surface);
7059
+ }
7060
+ .v3r-panel-head { display: flex; align-items: center; gap: .6rem; margin-bottom: .55rem; }
7061
+ .v3r-loop-mark { font-size: 17px; font-weight: 700; color: var(--accent); }
7062
+ .v3r-nodeid { font-family: var(--mono); font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
7063
+ .v3r-crumb { margin: .2rem 0 .55rem; font-size: 12.5px; color: var(--muted); display: flex; align-items: center; gap: .45em; }
7064
+ .v3r-crumb .sep { color: var(--faint); }
7065
+ .v3r-goal {
7066
+ margin: .45rem 0; padding: .5rem .7rem; font-size: 12.5px; color: var(--muted);
7067
+ border-left: 3px solid var(--border); background: var(--surface-muted);
7068
+ border-radius: 0 6px 6px 0; white-space: pre-wrap;
7069
+ }
7070
+ .v3r-deps { margin: .4rem 0; font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: .4em; flex-wrap: wrap; }
7071
+ .v3r-dep {
7072
+ font-family: var(--mono); font-size: 11.5px; padding: .1em .5em;
7073
+ border: 1px solid var(--border); border-radius: 6px; background: var(--surface-muted);
7074
+ }
7075
+ .v3r-err { margin: .4rem 0; font-size: 12.5px; color: var(--v3r-blocked); }
7076
+ .v3r-term-slot { margin-top: .75rem; }
7077
+
7078
+ /* ── loop iteration timeline ── */
7079
+ .v3r-loop-sec { margin-top: .65rem; }
7080
+ .v3r-loop-meter {
7081
+ display: flex; align-items: center; gap: .7rem; margin-bottom: .55rem;
7082
+ font-size: 13px; color: var(--muted);
7083
+ }
7084
+ .v3r-loop-meter .num { font-variant-numeric: tabular-nums; }
7085
+ .v3r-loop-meter .num b { font-family: var(--mono); font-size: 15px; color: var(--fg); }
7086
+ .v3r-granted-tag {
7087
+ font-size: 11px; font-weight: 700; padding: .1em .5em; border-radius: 999px;
7088
+ color: var(--accent-strong);
7089
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
7090
+ border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
7091
+ }
7092
+ .v3r-rounds {
7093
+ display: flex; flex-direction: column; gap: .45rem;
7094
+ max-height: 380px; overflow-y: auto; padding: .15rem;
7095
+ }
7096
+ .v3r-round {
7097
+ border: 1px solid var(--border); border-radius: 9px;
7098
+ padding: .45rem .6rem; background: var(--surface-muted);
7099
+ }
7100
+ .v3r-round.cur { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 18%, transparent); }
7101
+ .v3r-round.vd-exit { border-color: color-mix(in srgb, var(--v3r-done) 50%, var(--border)); }
7102
+ .v3r-round.vd-exhausted { border-color: color-mix(in srgb, var(--v3r-blocked) 55%, var(--border)); }
7103
+ .v3r-round-head { display: flex; align-items: center; gap: .45em; margin-bottom: .15rem; }
7104
+ .v3r-round-head .rn { font-family: var(--mono); font-size: 12.5px; font-weight: 700; color: var(--fg); }
7105
+ .v3r-verdict { font-size: 11px; font-weight: 700; white-space: nowrap; }
7106
+ .v3r-verdict.vd-exit { color: var(--v3r-done); }
7107
+ .v3r-verdict.vd-continue { color: var(--muted); }
7108
+ .v3r-verdict.vd-exhausted { color: var(--v3r-blocked); }
7109
+ .v3r-verdict.vd-live { color: var(--v3r-running); animation: v3r-blink 1.6s ease-in-out infinite; }
7110
+ /* round mini-dag: body instances drawn like real graph nodes (template gives
7111
+ the shape; undispatched slots are dashed ghosts) */
7112
+ .v3r-mini-svg { display: block; }
7113
+ .v3r-mini .v3r-nid { font-size: 11px; }
7114
+ .v3r-mini .v3r-mini-dot { fill: var(--ns); }
7115
+ .v3r-mini.st-running .v3r-mini-dot { animation: v3r-breathe 1.4s ease-in-out infinite; }
7116
+ .v3r-mini.sel .v3r-box { stroke: var(--accent-strong); stroke-width: 2; }
7117
+ .v3r-mini.ghost .v3r-box { stroke-dasharray: 3 3; fill: transparent; }
7118
+ .v3r-mini.ghost .v3r-nid, .v3r-mini.ghost .v3r-mini-dot { opacity: .55; }
7119
+ /* the strip naming which instance's terminal is mounted below the timeline */
7120
+ .v3r-inst-strip {
7121
+ display: flex; align-items: center; gap: .55rem; flex-wrap: wrap;
7122
+ margin-top: .7rem; padding: .45rem .65rem;
7123
+ border: 1px solid var(--border-soft); border-radius: 8px 8px 0 0; border-bottom: none;
7124
+ background: var(--surface-muted); font-size: 12px; color: var(--muted);
7125
+ }
7126
+ .v3r-inst-strip .lbl { font-weight: 700; color: var(--faint); letter-spacing: .04em; }
7127
+ .v3r-nodeid.sm { font-size: 12.5px; }
7128
+ #v3-inst-strip:not(:empty) + .v3r-term-slot { margin-top: 0; }
7129
+ .v3r-cta {
7130
+ margin-top: .55rem; padding: .5rem .7rem; font-size: 12.5px;
7131
+ color: var(--v3r-blocked); border-radius: 8px;
7132
+ background: color-mix(in srgb, var(--v3r-blocked) 10%, transparent);
7133
+ border: 1px solid color-mix(in srgb, var(--v3r-blocked) 35%, transparent);
7134
+ }
7135
+ .v3r-cta code { font-family: var(--mono); }
7136
+
7137
+ @keyframes v3r-spin { to { transform: rotate(360deg); } }
7138
+ @keyframes v3r-flow { to { stroke-dashoffset: -11; } }
7139
+ @keyframes v3r-breathe { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
7140
+ @keyframes v3r-blink { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
7141
+ @media (prefers-reduced-motion: reduce) {
7142
+ .st-running .v3r-spin, .v3r-edge.live, .v3r-node.st-running .v3r-box,
7143
+ .v3r-dot.cur.live, .v3r-verdict.vd-live { animation: none; }
7144
+ }
6922
7145
  /* ── Insight workbench (owner-only #/insights page) ───────────────────────────
6923
7146
  Visual layer ported from the reference app (agent-session-insights, html.ts
6924
7147
  STYLE) so this page reads as that read-only "工作台", not generic dashboard
package/dist/dashboard.js CHANGED
@@ -16,12 +16,14 @@ import { Aggregator, subscribeDaemon } from './dashboard/aggregator.js';
16
16
  import { pickCreatorForGroup } from './dashboard/operator-selector.js';
17
17
  import { planGroupCreator } from './dashboard/team-group.js';
18
18
  import { handleWorkflowApi, jsonRes } from './dashboard/workflow-api.js';
19
+ import { handleV3RunsApi } from './dashboard/v3-runs-api.js';
20
+ import { defaultRunsDir as v3RunsDir } from './workflows/v3/ops-projection.js';
19
21
  import { handleDashboardTriggerApi } from './dashboard/trigger-api.js';
20
22
  import { handleConnectorApi } from './dashboard/connector-api.js';
21
23
  import { redactGroupsForPublic, redactSchedulesForPublic } from './dashboard/public-redact.js';
22
24
  import { handleWebhookRoute } from './dashboard/webhook-routes.js';
23
25
  import { handleFederationApi } from './dashboard/federation-api.js';
24
- import { handleFederationSpokeApi, syncAllMemberships } from './dashboard/federation-spoke-api.js';
26
+ import { handleFederationSpokeApi, syncAllMemberships, autoBindOwnerIfUnambiguous } from './dashboard/federation-spoke-api.js';
25
27
  import { getRunsDir } from './workflows/runs-dir.js';
26
28
  import { BotOnboardingManager } from './dashboard/bot-onboarding.js';
27
29
  import { CLI_SELECT_OPTIONS, resolveCliSelection, isTtadkWrapper, ttadkAcceptsModel, TTADK_DEFAULT_MODEL, TTADK_MODEL_SUGGESTIONS, } from './setup/cli-selection.js';
@@ -897,6 +899,22 @@ const server = createServer(async (req, res) => {
897
899
  return jsonRes(res, 404, { error: 'no_active_token' });
898
900
  return jsonRes(res, 200, { url: dashboardUrlFor(activeToken) });
899
901
  }
902
+ // CLI 通知绑定变化(HMAC + loopback)——`botmux bind` 写完绑定后捅一下,立即重连平台,
903
+ // 无需重启 daemon,也不依赖 fs.watch。
904
+ if (req.method === 'POST' && url.pathname === '/__cli/reload-binding') {
905
+ const gate = verifyCliRequest(req, url.pathname);
906
+ if (!gate.ok)
907
+ return jsonRes(res, gate.status, gate.body);
908
+ try {
909
+ platformTunnel?.stop();
910
+ }
911
+ catch {
912
+ /* ignore */
913
+ }
914
+ platformTunnel = null;
915
+ startPlatformTunnelIfBound();
916
+ return jsonRes(res, 200, { ok: true });
917
+ }
900
918
  const presentedToken = authedToken(req, url);
901
919
  const dashboardSettings = resolveDashboardSettings();
902
920
  const decision = decideDashboardAuth({
@@ -1577,6 +1595,11 @@ const server = createServer(async (req, res) => {
1577
1595
  }, authed)) {
1578
1596
  return;
1579
1597
  }
1598
+ // v3 workflow runs (read-only DAG + per-node terminal projection). Reads
1599
+ // the v3 run dirs directly; no daemon proxy (v3 runs are plain files).
1600
+ if (await handleV3RunsApi(req, res, url, { runsDir: v3RunsDir() }, authed)) {
1601
+ return;
1602
+ }
1580
1603
  // ─── Groups (Phase B) ────────────────────────────────────────────────────
1581
1604
  if (req.method === 'GET' && url.pathname === '/api/groups') {
1582
1605
  // Fan out via the shared `buildGroupsMatrix` helper so the browser
@@ -2305,7 +2328,6 @@ listenWithProbe({
2305
2328
  }
2306
2329
  logger.info(`[dashboard] listening on ${config.dashboard.host}:${port}`);
2307
2330
  startPlatformTunnelIfBound();
2308
- watchPlatformBinding(); // bind 后无需重启 daemon,自动连接平台
2309
2331
  }).catch((err) => {
2310
2332
  logger.error(`[dashboard] could not bind near ${config.dashboard.host}:${config.dashboard.port} after probing — set BOTMUX_DASHBOARD_PORT to a free port. ${err.message}`);
2311
2333
  process.exit(1);
@@ -2320,14 +2342,46 @@ const federationSync = setInterval(() => {
2320
2342
  .catch(() => { });
2321
2343
  }, 2 * 60 * 1000);
2322
2344
  federationSync.unref();
2345
+ // 单候选自动绑定:standalone(未入团队)部署不必手动点面板「绑定」——用各机器人自己的
2346
+ // 凭证从 allowedUsers 解析出唯一负责人就自动认领,左上角飞书头像 / 拉群把发起人拉进群 /
2347
+ // 机器人归属随即生效。多候选(部署里配了多个人)仍保留手动选择。幂等:绑定后即刻 no-op。
2348
+ // 启动时按 0/5/15/60s 退避重试几次以覆盖 boot 时网络/凭证尚未就绪,之后交给手动按钮,
2349
+ // 不挂进永久心跳(避免对真·多候选/无 allowedUsers 的部署每 2 分钟空打飞书)。
2350
+ async function tryAutoBindOwner() {
2351
+ try {
2352
+ const r = await autoBindOwnerIfUnambiguous(config.session.dataDir, { fetcher: fetch, live: liveBots() });
2353
+ if (r.status === 'bound') {
2354
+ logger.info(`[identity] 已自动绑定本部署负责人:${r.owner?.name || r.owner?.unionId}(头像/拉群/归属即时生效)`);
2355
+ return 'done';
2356
+ }
2357
+ if (r.status === 'already_bound')
2358
+ return 'done';
2359
+ if (r.status === 'need_choice') {
2360
+ logger.info(`[identity] 检测到 ${r.candidates?.length ?? 0} 个候选负责人,请到面板「团队」手动选择绑定`);
2361
+ return 'done';
2362
+ }
2363
+ return 'retry'; // no_candidates:可能是网络/凭证未就绪的瞬时失败,退避后重试
2364
+ }
2365
+ catch (e) {
2366
+ logger.debug(`[identity] 自动绑定尝试失败(将退避重试):${e.message}`);
2367
+ return 'retry';
2368
+ }
2369
+ }
2370
+ void (async () => {
2371
+ for (const delayMs of [0, 5_000, 15_000, 60_000]) {
2372
+ if (delayMs)
2373
+ await new Promise((r) => setTimeout(r, delayMs));
2374
+ if ((await tryAutoBindOwner()) === 'done')
2375
+ return;
2376
+ }
2377
+ })();
2323
2378
  // 中心化平台隧道(已绑定才启动;每台机器一个,跑在 dashboard 进程里)
2324
2379
  let platformTunnel = null;
2325
- // 当前隧道对应的绑定身份(platformUrl|machineId|machineToken);用于判断 bind 变化是否需要重连
2326
- let platformBindingKey = null;
2327
2380
  function readBotmuxVersion() {
2381
+ // 与本地 dashboard「版本与更新」卡同源:源码 checkout 的 package.json 是占位的 0.0.0,
2382
+ // resolveCurrentVersion() 会用 git describe 推出真实版本(如 2.91.1),npm 安装则用 package.json。
2328
2383
  try {
2329
- const pkg = JSON.parse(readFileSync(join(dirname(__dirname), 'package.json'), 'utf8'));
2330
- return pkg.version || 'unknown';
2384
+ return resolveCurrentVersion();
2331
2385
  }
2332
2386
  catch {
2333
2387
  return 'unknown';
@@ -2359,10 +2413,8 @@ function readPlatformBotsInfo() {
2359
2413
  function startPlatformTunnelIfBound() {
2360
2414
  try {
2361
2415
  const binding = readPlatformBinding();
2362
- if (!binding) {
2363
- platformBindingKey = null;
2416
+ if (!binding)
2364
2417
  return;
2365
- }
2366
2418
  const version = readBotmuxVersion();
2367
2419
  platformTunnel = startPlatformTunnelClient({
2368
2420
  binding,
@@ -2372,43 +2424,12 @@ function startPlatformTunnelIfBound() {
2372
2424
  getBots: () => readPlatformBotsInfo(),
2373
2425
  log: (msg, extra) => logger.info(`[platform-tunnel] ${msg}${extra ? ' ' + JSON.stringify(extra) : ''}`),
2374
2426
  });
2375
- platformBindingKey = `${binding.platformUrl}|${binding.machineId}|${binding.machineToken}`;
2376
2427
  logger.info(`[platform-tunnel] 绑定到 ${binding.platformUrl},启动隧道`);
2377
2428
  }
2378
2429
  catch (e) {
2379
2430
  logger.warn(`[platform-tunnel] 启动失败: ${e.message}`);
2380
2431
  }
2381
2432
  }
2382
- /**
2383
- * 监听绑定文件变化:`botmux bind` 写入后无需重启 daemon,自动连接平台。
2384
- * 只在绑定「身份」(platformUrl/machineId/machineToken) 变化时重连——团队成员变化也会改写该文件
2385
- * (tunnel-client 自己写的),那种不重连,避免反复重启。
2386
- */
2387
- function watchPlatformBinding() {
2388
- // 每 3s 轮询绑定文件——`botmux bind` 写入后自动连接,无需重启 daemon。
2389
- // 用轮询而非 fs.watch:绑定走原子写(临时文件 + rename),fs.watch 对 rename 在不同
2390
- // 文件系统上不可靠(实测某些机器收不到事件),轮询在任何环境都稳。
2391
- setInterval(() => {
2392
- try {
2393
- const b = readPlatformBinding();
2394
- const key = b ? `${b.platformUrl}|${b.machineId}|${b.machineToken}` : null;
2395
- if (key === platformBindingKey)
2396
- return; // 绑定身份没变(团队成员变化不在此 key 内)→ 不重连
2397
- logger.info('[platform-tunnel] 检测到绑定变化,重连平台');
2398
- try {
2399
- platformTunnel?.stop();
2400
- }
2401
- catch {
2402
- /* ignore */
2403
- }
2404
- platformTunnel = null;
2405
- startPlatformTunnelIfBound();
2406
- }
2407
- catch {
2408
- /* ignore */
2409
- }
2410
- }, 3000).unref();
2411
- }
2412
2433
  // Graceful shutdown
2413
2434
  function shutdown() {
2414
2435
  for (const off of subs.values())