botmux 2.93.1 → 2.95.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/backend/tmux-backend.d.ts +18 -2
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +45 -3
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/backend/types.d.ts +8 -0
- package/dist/adapters/backend/types.d.ts.map +1 -1
- package/dist/adapters/backend/types.js.map +1 -1
- package/dist/adapters/backend/zellij-backend.js +1 -1
- package/dist/adapters/backend/zellij-backend.js.map +1 -1
- 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 +50 -1
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +30 -0
- package/dist/bot-registry.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 +146 -1
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +28 -3
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +92 -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/session-discovery.d.ts +9 -0
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +24 -0
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +7 -6
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/terminal-url.d.ts.map +1 -1
- package/dist/core/terminal-url.js +15 -0
- package/dist/core/terminal-url.js.map +1 -1
- package/dist/core/trigger-session.js +2 -2
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +30 -0
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +296 -23
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/aggregator.d.ts +5 -0
- package/dist/dashboard/aggregator.d.ts.map +1 -1
- package/dist/dashboard/aggregator.js +7 -0
- package/dist/dashboard/aggregator.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 +2 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +2 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/connector-api.d.ts.map +1 -1
- package/dist/dashboard/connector-api.js +14 -3
- package/dist/dashboard/connector-api.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +2 -1
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +7 -0
- package/dist/dashboard/settings-write-applier.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 +128 -33
- 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 +42 -6
- 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/settings.d.ts.map +1 -1
- package/dist/dashboard/web/settings.js +11 -0
- package/dist/dashboard/web/settings.js.map +1 -1
- 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/whiteboards.d.ts.map +1 -1
- package/dist/dashboard/web/whiteboards.js +14 -5
- package/dist/dashboard/web/whiteboards.js.map +1 -1
- 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 +834 -724
- package/dist/dashboard-web/apple-touch-icon.png +0 -0
- package/dist/dashboard-web/favicon.png +0 -0
- package/dist/dashboard-web/index.html +3 -1
- package/dist/dashboard-web/style.css +223 -0
- package/dist/dashboard.js +170 -10
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +10 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +8 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +23 -3
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +23 -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 +28 -0
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +3 -12
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +2 -1
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +20 -6
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/grant-command.js +4 -4
- package/dist/im/lark/grant-command.js.map +1 -1
- package/dist/im/lark/message-parser.d.ts +29 -1
- package/dist/im/lark/message-parser.d.ts.map +1 -1
- package/dist/im/lark/message-parser.js +35 -1
- package/dist/im/lark/message-parser.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/binding.d.ts +6 -0
- package/dist/platform/binding.d.ts.map +1 -1
- package/dist/platform/binding.js +17 -0
- package/dist/platform/binding.js.map +1 -1
- package/dist/platform/tunnel-client.d.ts +2 -0
- package/dist/platform/tunnel-client.d.ts.map +1 -1
- package/dist/platform/tunnel-client.js.map +1 -1
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +1 -0
- package/dist/services/bot-config-store.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/oncall-store.d.ts +25 -0
- package/dist/services/oncall-store.d.ts.map +1 -1
- package/dist/services/oncall-store.js +56 -0
- package/dist/services/oncall-store.js.map +1 -1
- package/dist/services/transcript-resolver.d.ts.map +1 -1
- package/dist/services/transcript-resolver.js +21 -4
- package/dist/services/transcript-resolver.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts +7 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +33 -0
- package/dist/setup/bot-config-editor.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/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/terminal-favicon.d.ts +2 -0
- package/dist/utils/terminal-favicon.d.ts.map +1 -0
- package/dist/utils/terminal-favicon.js +5 -0
- package/dist/utils/terminal-favicon.js.map +1 -0
- package/dist/worker.js +152 -8
- 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 +48 -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 +2 -2
- 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
|
Binary file
|
|
Binary file
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>botmux dashboard</title>
|
|
7
|
+
<link rel="icon" type="image/png" href="/assets/favicon.png">
|
|
8
|
+
<link rel="apple-touch-icon" href="/assets/apple-touch-icon.png">
|
|
7
9
|
<link rel="stylesheet" href="/assets/style.css">
|
|
8
10
|
</head>
|
|
9
11
|
<body>
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
<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
25
|
<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
26
|
<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="
|
|
27
|
+
<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
28
|
<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
29
|
<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
30
|
<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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/dashboard.ts
|
|
2
|
-
import { createServer, get as httpGet } from 'node:http';
|
|
3
|
-
import { createServer as createTcpServer } from 'node:net';
|
|
2
|
+
import { createServer, get as httpGet, request as httpRequest } from 'node:http';
|
|
3
|
+
import { createServer as createTcpServer, connect as netConnect } from 'node:net';
|
|
4
4
|
import { readFileSync, existsSync, mkdirSync, statSync, createReadStream, } from 'node:fs';
|
|
5
5
|
import { atomicWriteFileSync } from './utils/atomic-write.js';
|
|
6
6
|
import { join, dirname, extname, resolve, relative, isAbsolute } from 'node:path';
|
|
@@ -16,6 +16,8 @@ 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';
|
|
@@ -176,6 +178,7 @@ function resolveDashboardSettings() {
|
|
|
176
178
|
maintenance: global.maintenance ?? {},
|
|
177
179
|
localDevInstall: isLocalDevInstall(),
|
|
178
180
|
whiteboard: { enabled: global.whiteboard?.enabled === true },
|
|
181
|
+
remoteAccess: global.remoteAccess === true,
|
|
179
182
|
};
|
|
180
183
|
}
|
|
181
184
|
// Single shared deps object for `applySettingsWrite` — both the browser
|
|
@@ -831,6 +834,15 @@ async function dashboardSkillReferences(skillName) {
|
|
|
831
834
|
bots: [...refs.values()].sort((a, b) => a.botName.localeCompare(b.botName)),
|
|
832
835
|
};
|
|
833
836
|
}
|
|
837
|
+
/** Extract the sessionId from a terminal path `/s/<sessionId>[/...]`. Returns
|
|
838
|
+
* the first path segment after `/s/` (stops at the next `/`; query/hash are
|
|
839
|
+
* already stripped by URL.pathname). undefined when there's no segment. */
|
|
840
|
+
function parseTerminalSessionId(pathname) {
|
|
841
|
+
if (!pathname.startsWith('/s/'))
|
|
842
|
+
return undefined;
|
|
843
|
+
const seg = pathname.slice(3).split('/')[0];
|
|
844
|
+
return seg || undefined;
|
|
845
|
+
}
|
|
834
846
|
const server = createServer(async (req, res) => {
|
|
835
847
|
try {
|
|
836
848
|
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
@@ -845,6 +857,35 @@ const server = createServer(async (req, res) => {
|
|
|
845
857
|
res.writeHead(200, { 'content-type': 'text/plain' });
|
|
846
858
|
return res.end(DASHBOARD_SELF_NONCE);
|
|
847
859
|
}
|
|
860
|
+
// Web terminal reverse-proxy: `/s/<sessionId>/*` → the owning bot daemon's
|
|
861
|
+
// terminal proxy. The central platform only tunnels the dashboard port, so
|
|
862
|
+
// terminal links served under the machine subdomain
|
|
863
|
+
// (`https://m-<id>.<host>/s/<sessionId>`) land here. The dashboard is the
|
|
864
|
+
// aggregator process (it fronts many bot daemons, each with its own terminal
|
|
865
|
+
// proxy on proxyBasePort+idx), so we resolve the session's owning daemon's
|
|
866
|
+
// proxy port from the aggregator rows and forward there, streaming the
|
|
867
|
+
// response straight back. Mounted before the dashboard auth gate because the
|
|
868
|
+
// terminal proxy / worker enforces its own write gate (read-only without
|
|
869
|
+
// token / platform role).
|
|
870
|
+
if (url.pathname === '/s' || url.pathname.startsWith('/s/')) {
|
|
871
|
+
const sessionId = parseTerminalSessionId(url.pathname);
|
|
872
|
+
const tport = sessionId ? aggregator.terminalProxyPortOf(sessionId) : undefined;
|
|
873
|
+
if (!tport) {
|
|
874
|
+
res.writeHead(404, { 'content-type': 'text/plain; charset=utf-8' });
|
|
875
|
+
return res.end('session terminal not available');
|
|
876
|
+
}
|
|
877
|
+
const upstream = httpRequest({ host: '127.0.0.1', port: tport, method: req.method, path: req.url, headers: req.headers }, (up) => {
|
|
878
|
+
res.writeHead(up.statusCode ?? 502, up.headers);
|
|
879
|
+
up.pipe(res);
|
|
880
|
+
});
|
|
881
|
+
upstream.on('error', () => {
|
|
882
|
+
if (!res.headersSent)
|
|
883
|
+
res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });
|
|
884
|
+
res.end('terminal proxy error');
|
|
885
|
+
});
|
|
886
|
+
req.pipe(upstream);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
848
889
|
if (await handleWebhookRoute(req, res, url, {
|
|
849
890
|
proxyToDaemon,
|
|
850
891
|
createLifecycleGroup: createLifecycleGroupForWebhook,
|
|
@@ -1089,7 +1130,14 @@ const server = createServer(async (req, res) => {
|
|
|
1089
1130
|
// `lang` is the global UI locale (single source of truth shared with
|
|
1090
1131
|
// `botmux lang` and the Feishu cards) — the web UI reads it as its
|
|
1091
1132
|
// authoritative initial language when set.
|
|
1092
|
-
|
|
1133
|
+
// `bound` reflects central-platform binding; the Settings UI only shows the
|
|
1134
|
+
// 远程访问 toggle when bound (the central URLs are meaningless otherwise).
|
|
1135
|
+
return jsonRes(res, 200, {
|
|
1136
|
+
settings: dashboardSettings,
|
|
1137
|
+
lang: readGlobalConfig().lang ?? null,
|
|
1138
|
+
authed,
|
|
1139
|
+
bound: readPlatformBinding() !== null,
|
|
1140
|
+
});
|
|
1093
1141
|
}
|
|
1094
1142
|
if (req.method === 'PUT' && url.pathname === '/api/settings') {
|
|
1095
1143
|
let parsed;
|
|
@@ -1593,6 +1641,11 @@ const server = createServer(async (req, res) => {
|
|
|
1593
1641
|
}, authed)) {
|
|
1594
1642
|
return;
|
|
1595
1643
|
}
|
|
1644
|
+
// v3 workflow runs (read-only DAG + per-node terminal projection). Reads
|
|
1645
|
+
// the v3 run dirs directly; no daemon proxy (v3 runs are plain files).
|
|
1646
|
+
if (await handleV3RunsApi(req, res, url, { runsDir: v3RunsDir() }, authed)) {
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1596
1649
|
// ─── Groups (Phase B) ────────────────────────────────────────────────────
|
|
1597
1650
|
if (req.method === 'GET' && url.pathname === '/api/groups') {
|
|
1598
1651
|
// Fan out via the shared `buildGroupsMatrix` helper so the browser
|
|
@@ -1874,6 +1927,25 @@ const server = createServer(async (req, res) => {
|
|
|
1874
1927
|
res.end(await upstream.text());
|
|
1875
1928
|
return;
|
|
1876
1929
|
}
|
|
1930
|
+
// PUT /api/bots/:appId/working-dir-mode — proxy to that bot's daemon. Body
|
|
1931
|
+
// `{ mode: 'off'|'default'|'oncall', workingDir }` — sets the 3-way
|
|
1932
|
+
// mutually-exclusive default-dir mode (defaultWorkingDir vs defaultOncall).
|
|
1933
|
+
let mBotWdMode;
|
|
1934
|
+
if (req.method === 'PUT' && (mBotWdMode = url.pathname.match(/^\/api\/bots\/([^/]+)\/working-dir-mode$/))) {
|
|
1935
|
+
const appId = decodeURIComponent(mBotWdMode[1]);
|
|
1936
|
+
const chunks = [];
|
|
1937
|
+
for await (const c of req)
|
|
1938
|
+
chunks.push(c);
|
|
1939
|
+
const raw = Buffer.concat(chunks).toString('utf8') || '{}';
|
|
1940
|
+
const upstream = await proxyToDaemon(appId, `/api/bot-working-dir-mode`, {
|
|
1941
|
+
method: 'PUT',
|
|
1942
|
+
headers: { 'content-type': 'application/json' },
|
|
1943
|
+
body: raw,
|
|
1944
|
+
});
|
|
1945
|
+
res.writeHead(upstream.status, { 'content-type': 'application/json' });
|
|
1946
|
+
res.end(await upstream.text());
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1877
1949
|
// PUT /api/bots/:appId/skills — proxy to that bot's daemon. Body accepts
|
|
1878
1950
|
// `{ action:'attach'|'detach', name }` or `{ action:'set', policy|null }`.
|
|
1879
1951
|
let mBotSkills;
|
|
@@ -1928,6 +2000,24 @@ const server = createServer(async (req, res) => {
|
|
|
1928
2000
|
res.end(await upstream.text());
|
|
1929
2001
|
return;
|
|
1930
2002
|
}
|
|
2003
|
+
// PUT /api/bots/:appId/launch-shell — proxy to that bot's daemon. Body
|
|
2004
|
+
// `{ launchShell: string }` (shell name or absolute path; '' = clear → $SHELL).
|
|
2005
|
+
let mBotLaunchShell;
|
|
2006
|
+
if (req.method === 'PUT' && (mBotLaunchShell = url.pathname.match(/^\/api\/bots\/([^/]+)\/launch-shell$/))) {
|
|
2007
|
+
const appId = decodeURIComponent(mBotLaunchShell[1]);
|
|
2008
|
+
const chunks = [];
|
|
2009
|
+
for await (const c of req)
|
|
2010
|
+
chunks.push(c);
|
|
2011
|
+
const raw = Buffer.concat(chunks).toString('utf8') || '{}';
|
|
2012
|
+
const upstream = await proxyToDaemon(appId, `/api/bot-launch-shell`, {
|
|
2013
|
+
method: 'PUT',
|
|
2014
|
+
headers: { 'content-type': 'application/json' },
|
|
2015
|
+
body: raw,
|
|
2016
|
+
});
|
|
2017
|
+
res.writeHead(upstream.status, { 'content-type': 'application/json' });
|
|
2018
|
+
res.end(await upstream.text());
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
1931
2021
|
// PUT /api/bots/:appId/env — proxy to that bot's daemon. Body
|
|
1932
2022
|
// `{ env: string }` (raw JSON text; '' = clear).
|
|
1933
2023
|
let mBotEnv;
|
|
@@ -2300,6 +2390,59 @@ const server = createServer(async (req, res) => {
|
|
|
2300
2390
|
jsonRes(res, 500, { error: String(err) });
|
|
2301
2391
|
}
|
|
2302
2392
|
});
|
|
2393
|
+
// Web terminal WebSocket reverse-proxy: bridge `/s/*` upgrade requests through to
|
|
2394
|
+
// the local terminal proxy (which in turn bridges to the session worker). Raw
|
|
2395
|
+
// socket-to-socket bridge: dial 127.0.0.1:<terminalProxyPort>, replay the upgrade
|
|
2396
|
+
// request line + headers verbatim, then pipe both directions. Mirrors how
|
|
2397
|
+
// terminal-proxy.ts bridges to the worker. Non-`/s/*` upgrades are dropped (the
|
|
2398
|
+
// dashboard SPA uses SSE, not WebSocket).
|
|
2399
|
+
server.on('upgrade', (req, clientSocket, head) => {
|
|
2400
|
+
try {
|
|
2401
|
+
const rawUrl = req.url ?? '/';
|
|
2402
|
+
if (!(rawUrl === '/s' || rawUrl.startsWith('/s/') || rawUrl.startsWith('/s?'))) {
|
|
2403
|
+
return clientSocket.destroy();
|
|
2404
|
+
}
|
|
2405
|
+
// Strip query/hash before extracting the sessionId path segment.
|
|
2406
|
+
const pathname = rawUrl.split(/[?#]/)[0];
|
|
2407
|
+
const sessionId = parseTerminalSessionId(pathname);
|
|
2408
|
+
const tport = sessionId ? aggregator.terminalProxyPortOf(sessionId) : undefined;
|
|
2409
|
+
if (!tport)
|
|
2410
|
+
return clientSocket.destroy();
|
|
2411
|
+
const upstream = netConnect(tport, '127.0.0.1', () => {
|
|
2412
|
+
// rawHeaders is a flat [k, v, k, v, ...] list — preserves casing/duplicates.
|
|
2413
|
+
const lines = [`${req.method} ${req.url} HTTP/1.1`];
|
|
2414
|
+
const rh = req.rawHeaders;
|
|
2415
|
+
for (let i = 0; i + 1 < rh.length; i += 2)
|
|
2416
|
+
lines.push(`${rh[i]}: ${rh[i + 1]}`);
|
|
2417
|
+
lines.push('', '');
|
|
2418
|
+
upstream.write(lines.join('\r\n'));
|
|
2419
|
+
if (head?.length)
|
|
2420
|
+
upstream.write(head);
|
|
2421
|
+
upstream.pipe(clientSocket);
|
|
2422
|
+
clientSocket.pipe(upstream);
|
|
2423
|
+
});
|
|
2424
|
+
const cleanup = () => {
|
|
2425
|
+
try {
|
|
2426
|
+
upstream.destroy();
|
|
2427
|
+
}
|
|
2428
|
+
catch { /* ignore */ }
|
|
2429
|
+
try {
|
|
2430
|
+
clientSocket.destroy();
|
|
2431
|
+
}
|
|
2432
|
+
catch { /* ignore */ }
|
|
2433
|
+
};
|
|
2434
|
+
upstream.on('error', cleanup);
|
|
2435
|
+
clientSocket.on('error', cleanup);
|
|
2436
|
+
upstream.on('close', () => clientSocket.destroy());
|
|
2437
|
+
clientSocket.on('close', () => upstream.destroy());
|
|
2438
|
+
}
|
|
2439
|
+
catch {
|
|
2440
|
+
try {
|
|
2441
|
+
clientSocket.destroy();
|
|
2442
|
+
}
|
|
2443
|
+
catch { /* ignore */ }
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2303
2446
|
// Probe upward on EADDRINUSE rather than crashing with an unhandled 'error':
|
|
2304
2447
|
// a second botmux instance on this host (or a stray process) holding the
|
|
2305
2448
|
// configured port would otherwise tear the dashboard process down on bind.
|
|
@@ -2389,14 +2532,31 @@ function readPlatformBotsInfo() {
|
|
|
2389
2532
|
const entries = JSON.parse(readFileSync(fp, 'utf8'));
|
|
2390
2533
|
if (!Array.isArray(entries))
|
|
2391
2534
|
return [];
|
|
2535
|
+
// Merge per-bot team-visibility config (showInTeam) from bots.json by
|
|
2536
|
+
// larkAppId so the platform team page can hide bots. Default: showInTeam =
|
|
2537
|
+
// true (shown). bots.json may be unreadable from the dashboard process →
|
|
2538
|
+
// fall back to the default.
|
|
2539
|
+
const cfgByAppId = new Map();
|
|
2540
|
+
try {
|
|
2541
|
+
for (const cfg of loadBotConfigs()) {
|
|
2542
|
+
cfgByAppId.set(cfg.larkAppId, { showInTeam: cfg.showInTeam });
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
catch {
|
|
2546
|
+
/* defaults below */
|
|
2547
|
+
}
|
|
2392
2548
|
return entries
|
|
2393
|
-
.map((e) =>
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2549
|
+
.map((e) => {
|
|
2550
|
+
const cfg = cfgByAppId.get(e.larkAppId || '');
|
|
2551
|
+
return {
|
|
2552
|
+
appId: e.larkAppId || '',
|
|
2553
|
+
openId: e.botOpenId ?? null,
|
|
2554
|
+
name: e.botName || e.larkAppId || 'bot',
|
|
2555
|
+
avatar: e.botAvatarUrl || undefined,
|
|
2556
|
+
cli: e.cliId,
|
|
2557
|
+
showInTeam: cfg?.showInTeam !== false, // default true
|
|
2558
|
+
};
|
|
2559
|
+
})
|
|
2400
2560
|
.filter((b) => b.appId);
|
|
2401
2561
|
}
|
|
2402
2562
|
catch {
|