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.
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +6 -1
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/bot-registry.d.ts +10 -1
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +2 -0
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/dashboard-endpoint.d.ts +1 -1
- package/dist/cli/dashboard-endpoint.d.ts.map +1 -1
- package/dist/cli/dashboard-endpoint.js +3 -0
- package/dist/cli/dashboard-endpoint.js.map +1 -1
- package/dist/cli/workflow.d.ts.map +1 -1
- package/dist/cli/workflow.js +11 -4
- package/dist/cli/workflow.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +133 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +3 -0
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/inherit-peer.d.ts +5 -0
- package/dist/core/inherit-peer.d.ts.map +1 -1
- package/dist/core/inherit-peer.js +3 -0
- package/dist/core/inherit-peer.js.map +1 -1
- package/dist/core/trigger-session.d.ts +10 -0
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +22 -2
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/worker-pool.d.ts +6 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +49 -6
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +297 -13
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +7 -1
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +1 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +1 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/federation-spoke-api.d.ts +31 -0
- package/dist/dashboard/federation-spoke-api.d.ts.map +1 -1
- package/dist/dashboard/federation-spoke-api.js +36 -14
- package/dist/dashboard/federation-spoke-api.js.map +1 -1
- package/dist/dashboard/v3-runs-api.d.ts +26 -0
- package/dist/dashboard/v3-runs-api.d.ts.map +1 -0
- package/dist/dashboard/v3-runs-api.js +67 -0
- package/dist/dashboard/v3-runs-api.js.map +1 -0
- package/dist/dashboard/web/app.js +21 -9
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +24 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +12 -4
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/legacy-workflow-link.d.ts +2 -0
- package/dist/dashboard/web/legacy-workflow-link.d.ts.map +1 -0
- package/dist/dashboard/web/legacy-workflow-link.js +12 -0
- package/dist/dashboard/web/legacy-workflow-link.js.map +1 -0
- package/dist/dashboard/web/v3-terminal.d.ts +11 -0
- package/dist/dashboard/web/v3-terminal.d.ts.map +1 -0
- package/dist/dashboard/web/v3-terminal.js +143 -0
- package/dist/dashboard/web/v3-terminal.js.map +1 -0
- package/dist/dashboard/web/v3.d.ts +2 -0
- package/dist/dashboard/web/v3.d.ts.map +1 -0
- package/dist/dashboard/web/v3.js +564 -0
- package/dist/dashboard/web/v3.js.map +1 -0
- package/dist/dashboard/web/workflows.d.ts.map +1 -1
- package/dist/dashboard/web/workflows.js +12 -8
- package/dist/dashboard/web/workflows.js.map +1 -1
- package/dist/dashboard-web/app.js +787 -699
- package/dist/dashboard-web/index.html +1 -1
- package/dist/dashboard-web/style.css +223 -0
- package/dist/dashboard.js +61 -40
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +6 -3
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +6 -3
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +12 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +52 -2
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/doc-comment.d.ts +20 -0
- package/dist/im/lark/doc-comment.d.ts.map +1 -1
- package/dist/im/lark/doc-comment.js +23 -0
- package/dist/im/lark/doc-comment.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +13 -9
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/v3-blocked-card-handler.d.ts +28 -0
- package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-blocked-card-handler.js +134 -0
- package/dist/im/lark/v3-blocked-card-handler.js.map +1 -0
- package/dist/im/lark/v3-blocked-card.d.ts +75 -0
- package/dist/im/lark/v3-blocked-card.d.ts.map +1 -0
- package/dist/im/lark/v3-blocked-card.js +206 -0
- package/dist/im/lark/v3-blocked-card.js.map +1 -0
- package/dist/im/lark/v3-gate-card-handler.d.ts +31 -0
- package/dist/im/lark/v3-gate-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-gate-card-handler.js +110 -0
- package/dist/im/lark/v3-gate-card-handler.js.map +1 -0
- package/dist/im/lark/v3-gate-card.d.ts +47 -0
- package/dist/im/lark/v3-gate-card.d.ts.map +1 -0
- package/dist/im/lark/v3-gate-card.js +119 -0
- package/dist/im/lark/v3-gate-card.js.map +1 -0
- package/dist/im/lark/v3-loop-grant-card-handler.d.ts +28 -0
- package/dist/im/lark/v3-loop-grant-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-loop-grant-card-handler.js +90 -0
- package/dist/im/lark/v3-loop-grant-card-handler.js.map +1 -0
- package/dist/im/lark/v3-loop-grant-card.d.ts +46 -0
- package/dist/im/lark/v3-loop-grant-card.d.ts.map +1 -0
- package/dist/im/lark/v3-loop-grant-card.js +119 -0
- package/dist/im/lark/v3-loop-grant-card.js.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.d.ts +29 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.d.ts.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.js +96 -0
- package/dist/im/lark/v3-revisit-grant-card-handler.js.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card.d.ts +52 -0
- package/dist/im/lark/v3-revisit-grant-card.d.ts.map +1 -0
- package/dist/im/lark/v3-revisit-grant-card.js +123 -0
- package/dist/im/lark/v3-revisit-grant-card.js.map +1 -0
- package/dist/im/lark/workflow-cards.d.ts.map +1 -1
- package/dist/im/lark/workflow-cards.js +5 -1
- package/dist/im/lark/workflow-cards.js.map +1 -1
- package/dist/im/lark/workflow-progress-card.d.ts +1 -1
- package/dist/im/lark/workflow-progress-card.js +1 -1
- package/dist/im/lark/workflow-slash-command.d.ts +28 -0
- package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
- package/dist/im/lark/workflow-slash-command.js +61 -5
- package/dist/im/lark/workflow-slash-command.js.map +1 -1
- package/dist/platform/bind.d.ts.map +1 -1
- package/dist/platform/bind.js +17 -3
- package/dist/platform/bind.js.map +1 -1
- package/dist/services/card-prefs-store.d.ts +4 -0
- package/dist/services/card-prefs-store.d.ts.map +1 -1
- package/dist/services/card-prefs-store.js +19 -0
- package/dist/services/card-prefs-store.js.map +1 -1
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +18 -2
- package/dist/services/group-creator.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +208 -4
- package/dist/skills/definitions.js.map +1 -1
- package/dist/worker.js +79 -13
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +80 -80
- package/dist/workflows/events/payloads.d.ts +4 -4
- package/dist/workflows/events/schema.d.ts +16 -16
- package/dist/workflows/v3/architect.d.ts +37 -0
- package/dist/workflows/v3/architect.d.ts.map +1 -0
- package/dist/workflows/v3/architect.js +226 -0
- package/dist/workflows/v3/architect.js.map +1 -0
- package/dist/workflows/v3/bot-resolve.d.ts +21 -0
- package/dist/workflows/v3/bot-resolve.d.ts.map +1 -0
- package/dist/workflows/v3/bot-resolve.js +47 -0
- package/dist/workflows/v3/bot-resolve.js.map +1 -0
- package/dist/workflows/v3/cli-run.d.ts +24 -0
- package/dist/workflows/v3/cli-run.d.ts.map +1 -0
- package/dist/workflows/v3/cli-run.js +265 -0
- package/dist/workflows/v3/cli-run.js.map +1 -0
- package/dist/workflows/v3/contract.d.ts +302 -0
- package/dist/workflows/v3/contract.d.ts.map +1 -0
- package/dist/workflows/v3/contract.js +91 -0
- package/dist/workflows/v3/contract.js.map +1 -0
- package/dist/workflows/v3/daemon-run.d.ts +311 -0
- package/dist/workflows/v3/daemon-run.d.ts.map +1 -0
- package/dist/workflows/v3/daemon-run.js +775 -0
- package/dist/workflows/v3/daemon-run.js.map +1 -0
- package/dist/workflows/v3/dag.d.ts +332 -0
- package/dist/workflows/v3/dag.d.ts.map +1 -0
- package/dist/workflows/v3/dag.js +1040 -0
- package/dist/workflows/v3/dag.js.map +1 -0
- package/dist/workflows/v3/ephemeral-pool.d.ts +29 -0
- package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -0
- package/dist/workflows/v3/ephemeral-pool.js +331 -0
- package/dist/workflows/v3/ephemeral-pool.js.map +1 -0
- package/dist/workflows/v3/grill-state.d.ts +92 -0
- package/dist/workflows/v3/grill-state.d.ts.map +1 -0
- package/dist/workflows/v3/grill-state.js +151 -0
- package/dist/workflows/v3/grill-state.js.map +1 -0
- package/dist/workflows/v3/host.d.ts +88 -0
- package/dist/workflows/v3/host.d.ts.map +1 -0
- package/dist/workflows/v3/host.js +349 -0
- package/dist/workflows/v3/host.js.map +1 -0
- package/dist/workflows/v3/human-gate.d.ts +85 -0
- package/dist/workflows/v3/human-gate.d.ts.map +1 -0
- package/dist/workflows/v3/human-gate.js +153 -0
- package/dist/workflows/v3/human-gate.js.map +1 -0
- package/dist/workflows/v3/journal.d.ts +207 -0
- package/dist/workflows/v3/journal.d.ts.map +1 -0
- package/dist/workflows/v3/journal.js +74 -0
- package/dist/workflows/v3/journal.js.map +1 -0
- package/dist/workflows/v3/manifest.d.ts +17 -0
- package/dist/workflows/v3/manifest.d.ts.map +1 -0
- package/dist/workflows/v3/manifest.js +266 -0
- package/dist/workflows/v3/manifest.js.map +1 -0
- package/dist/workflows/v3/ops-projection.d.ts +110 -0
- package/dist/workflows/v3/ops-projection.d.ts.map +1 -0
- package/dist/workflows/v3/ops-projection.js +0 -0
- package/dist/workflows/v3/ops-projection.js.map +1 -0
- package/dist/workflows/v3/orchestrator.d.ts +168 -0
- package/dist/workflows/v3/orchestrator.d.ts.map +1 -0
- package/dist/workflows/v3/orchestrator.js +417 -0
- package/dist/workflows/v3/orchestrator.js.map +1 -0
- package/dist/workflows/v3/runtime.d.ts +193 -0
- package/dist/workflows/v3/runtime.d.ts.map +1 -0
- package/dist/workflows/v3/runtime.js +1284 -0
- package/dist/workflows/v3/runtime.js.map +1 -0
- package/dist/workflows/v3/spec.d.ts +32 -0
- package/dist/workflows/v3/spec.d.ts.map +1 -0
- package/dist/workflows/v3/spec.js +173 -0
- package/dist/workflows/v3/spec.js.map +1 -0
- package/dist/workflows/v3/state.d.ts +74 -0
- package/dist/workflows/v3/state.d.ts.map +1 -0
- package/dist/workflows/v3/state.js +353 -0
- package/dist/workflows/v3/state.js.map +1 -0
- package/package.json +1 -1
- package/dist/dashboard/web/workflow-catalog.d.ts +0 -2
- package/dist/dashboard/web/workflow-catalog.d.ts.map +0 -1
- package/dist/dashboard/web/workflow-catalog.js +0 -323
- 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="
|
|
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
|
-
|
|
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())
|