botmux 3.16.0 → 3.17.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/.runtime-build-id +1 -1
- package/dist/adapters/backend/riff-backend.d.ts +84 -1
- package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
- package/dist/adapters/backend/riff-backend.js +202 -19
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/sandbox.d.ts +8 -0
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +15 -0
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/tmux-backend.d.ts +61 -7
- package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-backend.js +80 -9
- package/dist/adapters/backend/tmux-backend.js.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.d.ts +62 -4
- package/dist/adapters/backend/tmux-pipe-backend.d.ts.map +1 -1
- package/dist/adapters/backend/tmux-pipe-backend.js +240 -27
- package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +4 -2
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/adapters/cli/coco.d.ts.map +1 -1
- package/dist/adapters/cli/coco.js +27 -0
- package/dist/adapters/cli/coco.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +28 -0
- package/dist/adapters/cli/codex-app.js.map +1 -1
- package/dist/adapters/cli/codex.d.ts.map +1 -1
- package/dist/adapters/cli/codex.js +51 -23
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/dsh-tui.d.ts +24 -0
- package/dist/adapters/cli/dsh-tui.d.ts.map +1 -0
- package/dist/adapters/cli/dsh-tui.js +99 -0
- package/dist/adapters/cli/dsh-tui.js.map +1 -0
- package/dist/adapters/cli/dsh.d.ts.map +1 -1
- package/dist/adapters/cli/dsh.js +15 -9
- package/dist/adapters/cli/dsh.js.map +1 -1
- package/dist/adapters/cli/fs-policy.d.ts +98 -1
- package/dist/adapters/cli/fs-policy.d.ts.map +1 -1
- package/dist/adapters/cli/fs-policy.js +182 -7
- package/dist/adapters/cli/fs-policy.js.map +1 -1
- package/dist/adapters/cli/grok.js +16 -18
- package/dist/adapters/cli/grok.js.map +1 -1
- package/dist/adapters/cli/model-catalog-json.d.ts +17 -0
- package/dist/adapters/cli/model-catalog-json.d.ts.map +1 -0
- package/dist/adapters/cli/model-catalog-json.js +43 -0
- package/dist/adapters/cli/model-catalog-json.js.map +1 -0
- package/dist/adapters/cli/oh-my-pi.d.ts +2 -0
- package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
- package/dist/adapters/cli/oh-my-pi.js +45 -13
- package/dist/adapters/cli/oh-my-pi.js.map +1 -1
- package/dist/adapters/cli/opencode.js +1 -1
- package/dist/adapters/cli/opencode.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +2 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +6 -1
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/relay.d.ts.map +1 -1
- package/dist/adapters/cli/relay.js +7 -0
- package/dist/adapters/cli/relay.js.map +1 -1
- package/dist/adapters/cli/seed.d.ts.map +1 -1
- package/dist/adapters/cli/seed.js +6 -0
- package/dist/adapters/cli/seed.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +20 -14
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/traex.d.ts +4 -0
- package/dist/adapters/cli/traex.d.ts.map +1 -1
- package/dist/adapters/cli/traex.js +153 -0
- package/dist/adapters/cli/traex.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +42 -1
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/autostart.d.ts +6 -0
- package/dist/autostart.d.ts.map +1 -1
- package/dist/autostart.js +21 -1
- package/dist/autostart.js.map +1 -1
- package/dist/bot-registry.d.ts +27 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +62 -2
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/vc-agent.d.ts.map +1 -1
- package/dist/cli/vc-agent.js +21 -3
- package/dist/cli/vc-agent.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +92 -1
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +28 -0
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/core/bot-steer-directive.d.ts +25 -0
- package/dist/core/bot-steer-directive.d.ts.map +1 -0
- package/dist/core/bot-steer-directive.js +47 -0
- package/dist/core/bot-steer-directive.js.map +1 -0
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +102 -18
- 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 +53 -13
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +3 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +26 -5
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/dashboard-url.d.ts +10 -1
- package/dist/core/dashboard-url.d.ts.map +1 -1
- package/dist/core/dashboard-url.js +12 -2
- package/dist/core/dashboard-url.js.map +1 -1
- package/dist/core/dispatch.d.ts.map +1 -1
- package/dist/core/dispatch.js +5 -4
- package/dist/core/dispatch.js.map +1 -1
- package/dist/core/existing-app-server.d.ts +22 -0
- package/dist/core/existing-app-server.d.ts.map +1 -0
- package/dist/core/existing-app-server.js +85 -0
- package/dist/core/existing-app-server.js.map +1 -0
- package/dist/core/native-topic-id.d.ts +9 -0
- package/dist/core/native-topic-id.d.ts.map +1 -0
- package/dist/core/native-topic-id.js +14 -0
- package/dist/core/native-topic-id.js.map +1 -0
- package/dist/core/per-bot-env.d.ts.map +1 -1
- package/dist/core/per-bot-env.js +10 -0
- package/dist/core/per-bot-env.js.map +1 -1
- package/dist/core/plugins/mcp/gateway.d.ts +27 -3
- package/dist/core/plugins/mcp/gateway.d.ts.map +1 -1
- package/dist/core/plugins/mcp/gateway.js +272 -26
- package/dist/core/plugins/mcp/gateway.js.map +1 -1
- package/dist/core/plugins/mcp/host.d.ts +18 -0
- package/dist/core/plugins/mcp/host.d.ts.map +1 -1
- package/dist/core/plugins/mcp/host.js +80 -16
- package/dist/core/plugins/mcp/host.js.map +1 -1
- package/dist/core/plugins/mcp/launch-record.d.ts +14 -0
- package/dist/core/plugins/mcp/launch-record.d.ts.map +1 -0
- package/dist/core/plugins/mcp/launch-record.js +63 -0
- package/dist/core/plugins/mcp/launch-record.js.map +1 -0
- package/dist/core/session-activity.d.ts +11 -0
- package/dist/core/session-activity.d.ts.map +1 -1
- package/dist/core/session-activity.js +23 -0
- package/dist/core/session-activity.js.map +1 -1
- package/dist/core/session-group-birth.d.ts.map +1 -1
- package/dist/core/session-group-birth.js +23 -8
- package/dist/core/session-group-birth.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +16 -20
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/shared-adopt.d.ts +20 -0
- package/dist/core/shared-adopt.d.ts.map +1 -0
- package/dist/core/shared-adopt.js +26 -0
- package/dist/core/shared-adopt.js.map +1 -0
- package/dist/core/skills/customize-command.d.ts +7 -0
- package/dist/core/skills/customize-command.d.ts.map +1 -0
- package/dist/core/skills/customize-command.js +303 -0
- package/dist/core/skills/customize-command.js.map +1 -0
- package/dist/core/terminal-write-auth.d.ts +15 -0
- package/dist/core/terminal-write-auth.d.ts.map +1 -1
- package/dist/core/terminal-write-auth.js +15 -0
- package/dist/core/terminal-write-auth.js.map +1 -1
- package/dist/core/terminal-write-frame.d.ts +30 -0
- package/dist/core/terminal-write-frame.d.ts.map +1 -0
- package/dist/core/terminal-write-frame.js +44 -0
- package/dist/core/terminal-write-frame.js.map +1 -0
- package/dist/core/types.d.ts +14 -4
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +6 -8
- package/dist/core/types.js.map +1 -1
- package/dist/core/worker-pool.d.ts +31 -6
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +444 -102
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/core/worker-startup-retry.d.ts +52 -0
- package/dist/core/worker-startup-retry.d.ts.map +1 -0
- package/dist/core/worker-startup-retry.js +68 -0
- package/dist/core/worker-startup-retry.js.map +1 -0
- package/dist/daemon.d.ts +9 -8
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +467 -171
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/autostart-api.d.ts +26 -0
- package/dist/dashboard/autostart-api.d.ts.map +1 -0
- package/dist/dashboard/autostart-api.js +88 -0
- package/dist/dashboard/autostart-api.js.map +1 -0
- package/dist/dashboard/bot-payload.d.ts +5 -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/control-csrf.d.ts +29 -1
- package/dist/dashboard/control-csrf.d.ts.map +1 -1
- package/dist/dashboard/control-csrf.js +49 -10
- package/dist/dashboard/control-csrf.js.map +1 -1
- package/dist/dashboard/customization-api.d.ts +23 -0
- package/dist/dashboard/customization-api.d.ts.map +1 -0
- package/dist/dashboard/customization-api.js +198 -0
- package/dist/dashboard/customization-api.js.map +1 -0
- package/dist/dashboard/debug-terminal.d.ts +13 -1
- package/dist/dashboard/debug-terminal.d.ts.map +1 -1
- package/dist/dashboard/debug-terminal.js +18 -4
- package/dist/dashboard/debug-terminal.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +0 -23
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +7 -28
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/terminal-control-route.d.ts +32 -0
- package/dist/dashboard/terminal-control-route.d.ts.map +1 -0
- package/dist/dashboard/terminal-control-route.js +70 -0
- package/dist/dashboard/terminal-control-route.js.map +1 -0
- package/dist/dashboard/terminal-control.d.ts +64 -13
- package/dist/dashboard/terminal-control.d.ts.map +1 -1
- package/dist/dashboard/terminal-control.js +77 -14
- package/dist/dashboard/terminal-control.js.map +1 -1
- package/dist/dashboard/terminal-front-proxy.d.ts.map +1 -1
- package/dist/dashboard/terminal-front-proxy.js +41 -9
- package/dist/dashboard/terminal-front-proxy.js.map +1 -1
- package/dist/dashboard/vc-consumer-profiles-api.d.ts +69 -18
- package/dist/dashboard/vc-consumer-profiles-api.d.ts.map +1 -1
- package/dist/dashboard/vc-consumer-profiles-api.js +149 -29
- package/dist/dashboard/vc-consumer-profiles-api.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-api.d.ts +34 -2
- package/dist/dashboard/web/agent-workbench-api.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-api.js +39 -4
- package/dist/dashboard/web/agent-workbench-api.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-appearance.d.ts +6 -3
- package/dist/dashboard/web/agent-workbench-appearance.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-appearance.js +7 -4
- package/dist/dashboard/web/agent-workbench-appearance.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-model.d.ts +2 -0
- package/dist/dashboard/web/agent-workbench-model.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-model.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-page.js +2 -2
- package/dist/dashboard/web/agent-workbench-page.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-panes.d.ts +59 -4
- package/dist/dashboard/web/agent-workbench-panes.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-panes.js +493 -85
- package/dist/dashboard/web/agent-workbench-panes.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-session-list.d.ts +11 -7
- package/dist/dashboard/web/agent-workbench-session-list.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-session-list.js +24 -31
- package/dist/dashboard/web/agent-workbench-session-list.js.map +1 -1
- package/dist/dashboard/web/agent-workbench-terminal-control.d.ts +198 -0
- package/dist/dashboard/web/agent-workbench-terminal-control.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-terminal-control.js +292 -0
- package/dist/dashboard/web/agent-workbench-terminal-control.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-view.d.ts +3 -2
- package/dist/dashboard/web/agent-workbench-view.d.ts.map +1 -1
- package/dist/dashboard/web/agent-workbench-view.js +69 -50
- package/dist/dashboard/web/agent-workbench-view.js.map +1 -1
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +58 -7
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +24 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +191 -16
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +17 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js +51 -2
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/bot-onboarding.d.ts.map +1 -1
- package/dist/dashboard/web/bot-onboarding.js +32 -8
- package/dist/dashboard/web/bot-onboarding.js.map +1 -1
- package/dist/dashboard/web/confirm-modal.d.ts +35 -0
- package/dist/dashboard/web/confirm-modal.d.ts.map +1 -0
- package/dist/dashboard/web/confirm-modal.js +111 -0
- package/dist/dashboard/web/confirm-modal.js.map +1 -0
- package/dist/dashboard/web/connectors-page.d.ts.map +1 -1
- package/dist/dashboard/web/connectors-page.js +2 -1
- package/dist/dashboard/web/connectors-page.js.map +1 -1
- package/dist/dashboard/web/customization-page.d.ts +3 -0
- package/dist/dashboard/web/customization-page.d.ts.map +1 -0
- package/dist/dashboard/web/customization-page.js +315 -0
- package/dist/dashboard/web/customization-page.js.map +1 -0
- package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-routes.js +1 -0
- package/dist/dashboard/web/dashboard-routes.js.map +1 -1
- package/dist/dashboard/web/groups-page.d.ts.map +1 -1
- package/dist/dashboard/web/groups-page.js +11 -9
- package/dist/dashboard/web/groups-page.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +226 -42
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/monitor-room.d.ts.map +1 -1
- package/dist/dashboard/web/monitor-room.js +3 -2
- package/dist/dashboard/web/monitor-room.js.map +1 -1
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js +98 -63
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/roles-page.d.ts.map +1 -1
- package/dist/dashboard/web/roles-page.js +4 -3
- package/dist/dashboard/web/roles-page.js.map +1 -1
- package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
- package/dist/dashboard/web/schedules-page.js +165 -18
- package/dist/dashboard/web/schedules-page.js.map +1 -1
- package/dist/dashboard/web/sessions-kanban.d.ts +2 -0
- package/dist/dashboard/web/sessions-kanban.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-kanban.js +142 -24
- package/dist/dashboard/web/sessions-kanban.js.map +1 -1
- package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-page.js +177 -94
- package/dist/dashboard/web/sessions-page.js.map +1 -1
- package/dist/dashboard/web/sessions.d.ts.map +1 -1
- package/dist/dashboard/web/sessions.js +5 -4
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts +0 -8
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js +185 -65
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard/web/skills/skill-library-tab.d.ts +2 -0
- package/dist/dashboard/web/skills/skill-library-tab.d.ts.map +1 -1
- package/dist/dashboard/web/skills/skill-library-tab.js +15 -1
- package/dist/dashboard/web/skills/skill-library-tab.js.map +1 -1
- package/dist/dashboard/web/skills-page.d.ts.map +1 -1
- package/dist/dashboard/web/skills-page.js +5 -4
- package/dist/dashboard/web/skills-page.js.map +1 -1
- package/dist/dashboard/web/store.d.ts +5 -0
- package/dist/dashboard/web/store.d.ts.map +1 -1
- package/dist/dashboard/web/store.js +4 -0
- package/dist/dashboard/web/store.js.map +1 -1
- package/dist/dashboard/web/team-federation-page.d.ts.map +1 -1
- package/dist/dashboard/web/team-federation-page.js +3 -2
- package/dist/dashboard/web/team-federation-page.js.map +1 -1
- package/dist/dashboard/web/toast.d.ts +15 -0
- package/dist/dashboard/web/toast.d.ts.map +1 -0
- package/dist/dashboard/web/toast.js +70 -0
- package/dist/dashboard/web/toast.js.map +1 -0
- package/dist/dashboard/web/v3-components.d.ts.map +1 -1
- package/dist/dashboard/web/v3-components.js +2 -1
- package/dist/dashboard/web/v3-components.js.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts +10 -12
- package/dist/dashboard/web/vc-consumer-profiles-section.d.ts.map +1 -1
- package/dist/dashboard/web/vc-consumer-profiles-section.js +219 -200
- package/dist/dashboard/web/vc-consumer-profiles-section.js.map +1 -1
- package/dist/dashboard/web/whiteboards-page.d.ts.map +1 -1
- package/dist/dashboard/web/whiteboards-page.js +2 -1
- package/dist/dashboard/web/whiteboards-page.js.map +1 -1
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/agent-workbench-dock-page-LZSUOCEQ.js +1 -0
- package/dist/dashboard-web/chunks/agent-workbench-page-YONDRJU7.js +1 -0
- package/dist/dashboard-web/chunks/bot-defaults-page-X7LV6373.js +1 -0
- package/dist/dashboard-web/chunks/chunk-2PVRDXEL.js +1 -0
- package/dist/dashboard-web/chunks/chunk-53JUKBU2.js +10 -0
- package/dist/dashboard-web/chunks/{chunk-5CJMHTT4.js → chunk-5QX4OYOR.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-NACP7BMR.js → chunk-5VRVJFQR.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-FDZ7WOBW.js → chunk-6ROOZWYV.js} +1 -1
- package/dist/dashboard-web/chunks/{chunk-F6KNPF4R.js → chunk-CK22743G.js} +15 -19
- package/dist/dashboard-web/chunks/chunk-CVNIMUPY.js +25 -0
- package/dist/dashboard-web/chunks/chunk-GJC2TMWS.js +2 -0
- package/dist/dashboard-web/chunks/chunk-OT6L6G7R.js +1 -0
- package/dist/dashboard-web/chunks/chunk-QITAMHW6.js +1 -0
- package/dist/dashboard-web/chunks/chunk-RHVFZC5Z.js +1 -0
- package/dist/dashboard-web/chunks/chunk-SOBMN2VY.js +1 -0
- package/dist/dashboard-web/chunks/chunk-SZOB6VK2.js +1 -0
- package/dist/dashboard-web/chunks/chunk-XVIXNQGC.js +44 -0
- package/dist/dashboard-web/chunks/chunk-YUJF34ME.js +1 -0
- package/dist/dashboard-web/chunks/connectors-page-LB2HEJ7F.js +1 -0
- package/dist/dashboard-web/chunks/customization-page-4GXBYLG6.js +105 -0
- package/dist/dashboard-web/chunks/feedback-page-IZQ7VLDG.js +1 -0
- package/dist/dashboard-web/chunks/groups-page-4WCP5OEV.js +8 -0
- package/dist/dashboard-web/chunks/{insights-page-HJFDYR5N.js → insights-page-TXQHIPQL.js} +1 -1
- package/dist/dashboard-web/chunks/{monitor-room-V7PCP47V.js → monitor-room-VBRVWXCM.js} +8 -8
- package/dist/dashboard-web/chunks/monitoring-page-QDDZWERE.js +2 -0
- package/dist/dashboard-web/chunks/office-page-PENFNYPG.js +1 -0
- package/dist/dashboard-web/chunks/overview-page-BZQDP6MP.js +1 -0
- package/dist/dashboard-web/chunks/plugin-page-JX4GSWZS.js +1 -0
- package/dist/dashboard-web/chunks/roles-page-VPNINZNK.js +1 -0
- package/dist/dashboard-web/chunks/schedules-page-BITO6HEA.js +1 -0
- package/dist/dashboard-web/chunks/sessions-page-ZKCOVTD2.js +8 -0
- package/dist/dashboard-web/chunks/settings-page-UT6JDTS6.js +2 -0
- package/dist/dashboard-web/chunks/skills-page-GULXVAJY.js +4 -0
- package/dist/dashboard-web/chunks/team-federation-page-CUUJWGEG.js +1 -0
- package/dist/dashboard-web/chunks/v3-page-5WVJ5AUR.js +94 -0
- package/dist/dashboard-web/chunks/whiteboards-page-FZ2CME4H.js +1 -0
- package/dist/dashboard-web/design-tokens.css +236 -0
- package/dist/dashboard-web/index.html +1 -0
- package/dist/dashboard-web/style.css +1930 -114
- package/dist/dashboard.js +360 -279
- package/dist/dashboard.js.map +1 -1
- package/dist/desktop/renderer/app.js +6 -0
- package/dist/desktop/renderer/app.js.map +1 -1
- package/dist/dsh-runner.js +139 -17
- package/dist/dsh-runner.js.map +1 -1
- package/dist/global-config.d.ts +33 -2
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +62 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +13 -4
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/index.d.ts +27 -3
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +33 -4
- package/dist/i18n/index.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +13 -4
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +2 -0
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +7 -4
- package/dist/im/lark/card-builder.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +135 -20
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +38 -3
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +163 -13
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/v3-blocked-card-handler.d.ts.map +1 -1
- package/dist/im/lark/v3-blocked-card-handler.js +2 -1
- package/dist/im/lark/v3-blocked-card-handler.js.map +1 -1
- package/dist/im/lark/v3-blocked-card.d.ts +1 -1
- package/dist/im/lark/v3-blocked-card.d.ts.map +1 -1
- package/dist/im/lark/v3-blocked-card.js +14 -0
- package/dist/im/lark/v3-blocked-card.js.map +1 -1
- package/dist/index-core-only.js +2 -0
- package/dist/index-core-only.js.map +1 -1
- package/dist/index-daemon.js +3 -0
- package/dist/index-daemon.js.map +1 -1
- package/dist/platform/binding.d.ts +37 -0
- package/dist/platform/binding.d.ts.map +1 -1
- package/dist/platform/binding.js +15 -0
- package/dist/platform/binding.js.map +1 -1
- package/dist/services/bridge-turn-journal.d.ts +63 -0
- package/dist/services/bridge-turn-journal.d.ts.map +1 -0
- package/dist/services/bridge-turn-journal.js +149 -0
- package/dist/services/bridge-turn-journal.js.map +1 -0
- package/dist/services/bridge-turn-queue.d.ts +8 -1
- package/dist/services/bridge-turn-queue.d.ts.map +1 -1
- package/dist/services/bridge-turn-queue.js +2 -1
- package/dist/services/bridge-turn-queue.js.map +1 -1
- package/dist/services/codex-app-runner-protocol.d.ts +5 -0
- package/dist/services/codex-app-runner-protocol.d.ts.map +1 -1
- package/dist/services/codex-app-runner-protocol.js +5 -0
- package/dist/services/codex-app-runner-protocol.js.map +1 -1
- package/dist/services/customization-store.d.ts +93 -0
- package/dist/services/customization-store.d.ts.map +1 -0
- package/dist/services/customization-store.js +542 -0
- package/dist/services/customization-store.js.map +1 -0
- package/dist/services/file-bridge-path.d.ts.map +1 -1
- package/dist/services/file-bridge-path.js +3 -0
- package/dist/services/file-bridge-path.js.map +1 -1
- package/dist/services/grok-transcript.d.ts.map +1 -1
- package/dist/services/grok-transcript.js +44 -9
- package/dist/services/grok-transcript.js.map +1 -1
- package/dist/services/local-cli-opener.d.ts.map +1 -1
- package/dist/services/local-cli-opener.js +12 -3
- package/dist/services/local-cli-opener.js.map +1 -1
- package/dist/services/model-catalog.d.ts +54 -0
- package/dist/services/model-catalog.d.ts.map +1 -0
- package/dist/services/model-catalog.js +147 -0
- package/dist/services/model-catalog.js.map +1 -0
- package/dist/services/omp-transcript.d.ts +27 -0
- package/dist/services/omp-transcript.d.ts.map +1 -0
- package/dist/services/omp-transcript.js +214 -0
- package/dist/services/omp-transcript.js.map +1 -0
- package/dist/services/platform-team-store.d.ts +16 -8
- package/dist/services/platform-team-store.d.ts.map +1 -1
- package/dist/services/platform-team-store.js +17 -10
- package/dist/services/platform-team-store.js.map +1 -1
- package/dist/services/project-scanner.d.ts.map +1 -1
- package/dist/services/project-scanner.js +13 -8
- package/dist/services/project-scanner.js.map +1 -1
- package/dist/services/resumable-session-discovery.d.ts.map +1 -1
- package/dist/services/resumable-session-discovery.js +117 -35
- package/dist/services/resumable-session-discovery.js.map +1 -1
- package/dist/services/structured-bridge-clis.d.ts +5 -3
- package/dist/services/structured-bridge-clis.d.ts.map +1 -1
- package/dist/services/structured-bridge-clis.js +5 -1
- package/dist/services/structured-bridge-clis.js.map +1 -1
- package/dist/services/vc-meeting-action-gate.d.ts.map +1 -1
- package/dist/services/vc-meeting-action-gate.js +15 -4
- package/dist/services/vc-meeting-action-gate.js.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts +46 -66
- package/dist/services/vc-meeting-consumer-profile-bootstrap.d.ts.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js +33 -292
- package/dist/services/vc-meeting-consumer-profile-bootstrap.js.map +1 -1
- package/dist/services/vc-meeting-consumer-profile-templates.js +3 -3
- package/dist/services/vc-meeting-consumer-profile-templates.js.map +1 -1
- package/dist/services/vc-meeting-delivery-store.d.ts +18 -0
- package/dist/services/vc-meeting-delivery-store.d.ts.map +1 -1
- package/dist/services/vc-meeting-delivery-store.js +55 -0
- package/dist/services/vc-meeting-delivery-store.js.map +1 -1
- package/dist/services/vc-meeting-send-policy.d.ts +21 -1
- package/dist/services/vc-meeting-send-policy.d.ts.map +1 -1
- package/dist/services/vc-meeting-send-policy.js +30 -2
- package/dist/services/vc-meeting-send-policy.js.map +1 -1
- package/dist/services/vc-meeting-shared-consumer-catalog-store.d.ts +78 -0
- package/dist/services/vc-meeting-shared-consumer-catalog-store.d.ts.map +1 -0
- package/dist/services/vc-meeting-shared-consumer-catalog-store.js +227 -0
- package/dist/services/vc-meeting-shared-consumer-catalog-store.js.map +1 -0
- package/dist/services/vc-meeting-shared-consumer-catalog.d.ts +53 -0
- package/dist/services/vc-meeting-shared-consumer-catalog.d.ts.map +1 -0
- package/dist/services/vc-meeting-shared-consumer-catalog.js +161 -0
- package/dist/services/vc-meeting-shared-consumer-catalog.js.map +1 -0
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +1 -0
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/open-platform-automation.d.ts +20 -0
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +27 -0
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/skills/customization-bundle.d.ts +83 -0
- package/dist/skills/customization-bundle.d.ts.map +1 -0
- package/dist/skills/customization-bundle.js +214 -0
- package/dist/skills/customization-bundle.js.map +1 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +10 -3
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/effective-builtins.d.ts +38 -0
- package/dist/skills/effective-builtins.d.ts.map +1 -0
- package/dist/skills/effective-builtins.js +96 -0
- package/dist/skills/effective-builtins.js.map +1 -0
- package/dist/skills/injection-mode.d.ts +4 -1
- package/dist/skills/injection-mode.d.ts.map +1 -1
- package/dist/skills/injection-mode.js +11 -3
- package/dist/skills/injection-mode.js.map +1 -1
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +24 -1
- package/dist/skills/installer.js.map +1 -1
- package/dist/skills/prompt-fragments.d.ts +58 -0
- package/dist/skills/prompt-fragments.d.ts.map +1 -0
- package/dist/skills/prompt-fragments.js +88 -0
- package/dist/skills/prompt-fragments.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cli-usage-limit.d.ts +50 -0
- package/dist/utils/cli-usage-limit.d.ts.map +1 -1
- package/dist/utils/cli-usage-limit.js +43 -0
- package/dist/utils/cli-usage-limit.js.map +1 -1
- package/dist/utils/idle-detector.d.ts +12 -0
- package/dist/utils/idle-detector.d.ts.map +1 -1
- package/dist/utils/idle-detector.js +88 -2
- package/dist/utils/idle-detector.js.map +1 -1
- package/dist/utils/stuck-detector.d.ts +5 -0
- package/dist/utils/stuck-detector.d.ts.map +1 -1
- package/dist/utils/stuck-detector.js +41 -0
- package/dist/utils/stuck-detector.js.map +1 -1
- package/dist/utils/usage-limit-tracker.d.ts +46 -0
- package/dist/utils/usage-limit-tracker.d.ts.map +1 -0
- package/dist/utils/usage-limit-tracker.js +91 -0
- package/dist/utils/usage-limit-tracker.js.map +1 -0
- package/dist/utils/user-token.js +1 -1
- package/dist/utils/user-token.js.map +1 -1
- package/dist/worker.js +812 -125
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +14 -14
- package/dist/workflows/events/payloads.d.ts +12 -12
- package/dist/workflows/events/schema.d.ts +164 -164
- package/dist/workflows/migration/v2-to-v3.js +1 -1
- package/dist/workflows/migration/v2-to-v3.js.map +1 -1
- package/dist/workflows/v3/architect.d.ts.map +1 -1
- package/dist/workflows/v3/architect.js +11 -5
- package/dist/workflows/v3/architect.js.map +1 -1
- package/dist/workflows/v3/artifact-contract-declarations.d.ts +22 -0
- package/dist/workflows/v3/artifact-contract-declarations.d.ts.map +1 -0
- package/dist/workflows/v3/artifact-contract-declarations.js +95 -0
- package/dist/workflows/v3/artifact-contract-declarations.js.map +1 -0
- package/dist/workflows/v3/contract.d.ts +1 -0
- package/dist/workflows/v3/contract.d.ts.map +1 -1
- package/dist/workflows/v3/contract.js.map +1 -1
- package/dist/workflows/v3/daemon-run.d.ts +2 -2
- package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
- package/dist/workflows/v3/daemon-run.js +4 -0
- package/dist/workflows/v3/daemon-run.js.map +1 -1
- package/dist/workflows/v3/dag.d.ts +7 -0
- package/dist/workflows/v3/dag.d.ts.map +1 -1
- package/dist/workflows/v3/dag.js +69 -8
- package/dist/workflows/v3/dag.js.map +1 -1
- package/dist/workflows/v3/ephemeral-pool.js +1 -1
- package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
- package/dist/workflows/v3/event-contract.d.ts +3 -1
- package/dist/workflows/v3/event-contract.d.ts.map +1 -1
- package/dist/workflows/v3/host.d.ts.map +1 -1
- package/dist/workflows/v3/host.js +5 -1
- package/dist/workflows/v3/host.js.map +1 -1
- package/dist/workflows/v3/journal.d.ts +1 -1
- package/dist/workflows/v3/journal.d.ts.map +1 -1
- package/dist/workflows/v3/journal.js.map +1 -1
- package/dist/workflows/v3/library-materialize.d.ts.map +1 -1
- package/dist/workflows/v3/library-materialize.js +9 -1
- package/dist/workflows/v3/library-materialize.js.map +1 -1
- package/dist/workflows/v3/library-schema.d.ts +3 -1
- package/dist/workflows/v3/library-schema.d.ts.map +1 -1
- package/dist/workflows/v3/library-schema.js +20 -4
- package/dist/workflows/v3/library-schema.js.map +1 -1
- package/dist/workflows/v3/library-store.d.ts.map +1 -1
- package/dist/workflows/v3/library-store.js +15 -3
- package/dist/workflows/v3/library-store.js.map +1 -1
- package/dist/workflows/v3/run-envelope.d.ts +16 -16
- package/dist/workflows/v3/shared-node-runtime.d.ts +2 -1
- package/dist/workflows/v3/shared-node-runtime.d.ts.map +1 -1
- package/dist/workflows/v3/shared-node-runtime.js +48 -7
- package/dist/workflows/v3/shared-node-runtime.js.map +1 -1
- package/package.json +2 -1
- package/dist/dashboard-web/chunks/agent-workbench-dock-page-IKAC5CFL.js +0 -1
- package/dist/dashboard-web/chunks/agent-workbench-page-M53UN5EB.js +0 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-YKE5SDZF.js +0 -10
- package/dist/dashboard-web/chunks/chunk-22WIADUT.js +0 -2
- package/dist/dashboard-web/chunks/chunk-24ONYQMR.js +0 -1
- package/dist/dashboard-web/chunks/chunk-2W6SCN3M.js +0 -1
- package/dist/dashboard-web/chunks/chunk-4XNJX6B3.js +0 -1
- package/dist/dashboard-web/chunks/chunk-5THX4DI2.js +0 -66
- package/dist/dashboard-web/chunks/chunk-7SZRL6FY.js +0 -1
- package/dist/dashboard-web/chunks/chunk-AGCPF6MT.js +0 -1
- package/dist/dashboard-web/chunks/chunk-FXW3V4JR.js +0 -1
- package/dist/dashboard-web/chunks/chunk-SYC6D5XU.js +0 -1
- package/dist/dashboard-web/chunks/connectors-page-VOISXXII.js +0 -1
- package/dist/dashboard-web/chunks/feedback-page-RN6HRZMS.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-UQT6DCB7.js +0 -8
- package/dist/dashboard-web/chunks/monitoring-page-NKEKVQAP.js +0 -2
- package/dist/dashboard-web/chunks/office-page-GVJF73XW.js +0 -1
- package/dist/dashboard-web/chunks/overview-page-KHLV6VTI.js +0 -1
- package/dist/dashboard-web/chunks/plugin-page-J3OF5IY4.js +0 -1
- package/dist/dashboard-web/chunks/roles-page-WQIRSOLZ.js +0 -1
- package/dist/dashboard-web/chunks/schedules-page-J2DEY2X6.js +0 -1
- package/dist/dashboard-web/chunks/sessions-page-7BQFEA5P.js +0 -8
- package/dist/dashboard-web/chunks/settings-page-BJEIOFJH.js +0 -2
- package/dist/dashboard-web/chunks/skills-page-HGIFR3IU.js +0 -4
- package/dist/dashboard-web/chunks/team-federation-page-MR5ZPL4B.js +0 -1
- package/dist/dashboard-web/chunks/v3-page-GBR5JWPE.js +0 -94
- package/dist/dashboard-web/chunks/whiteboards-page-QAZM4BN3.js +0 -1
- package/dist/services/vc-meeting-consumer-profile-store.d.ts +0 -39
- package/dist/services/vc-meeting-consumer-profile-store.d.ts.map +0 -1
- package/dist/services/vc-meeting-consumer-profile-store.js +0 -191
- package/dist/services/vc-meeting-consumer-profile-store.js.map +0 -1
package/dist/daemon.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
|
4
4
|
import { installDaemonRejectionGuard } from './utils/daemon-rejection-guard.js';
|
|
5
5
|
import { atomicWriteFileSync } from './utils/atomic-write.js';
|
|
6
6
|
import { readPeerCrossRef } from './services/peer-cross-ref-store.js';
|
|
7
|
+
import { parseBotSteerDirective } from './core/bot-steer-directive.js';
|
|
7
8
|
import { readAllowedUsersResolveCache, writeAllowedUsersResolveCache } from './utils/allowed-users-cache.js';
|
|
8
9
|
import { join, dirname } from 'node:path';
|
|
9
10
|
import { homedir, loadavg, cpus, totalmem, freemem } from 'node:os';
|
|
@@ -114,6 +115,7 @@ import { runIdempotencyFailClose, runWithdrawAutoClose, } from './core/daemon-ba
|
|
|
114
115
|
import { runDetachedBotTurnMutation, tryWithBotTurnMutation, withBotTurnAdmission, withBotTurnMutation, } from './core/bot-turn-mutation-gate.js';
|
|
115
116
|
import { claimInitialUserTurn, isInitialUserTurnPending, releaseInitialUserTurn } from './core/initial-user-turn.js';
|
|
116
117
|
import { applyQueuedCodexAppLegacyFallback, mergeQueuedCodexAppTurn } from './core/session-create.js';
|
|
118
|
+
import { fillNativeTopicId } from './core/native-topic-id.js';
|
|
117
119
|
import { findOnlineDaemon, listOnlineDaemons } from './utils/daemon-discovery.js';
|
|
118
120
|
import { beginReplyTargetTurn, buildTurnParticipantsFrom, fallbackTurnId, isSubstituteTurn, resolveInboundReplyTarget, resolveSessionReplyTarget, syncReplyTargetState } from './core/reply-target.js';
|
|
119
121
|
import { readDeferredTopicBinding } from './core/deferred-topic-binding.js';
|
|
@@ -188,7 +190,7 @@ function republishResolvedAllowedUsers(larkAppId, resolved) {
|
|
|
188
190
|
catch { /* best effort */ }
|
|
189
191
|
}
|
|
190
192
|
let vcMeetingTerminalReconciler;
|
|
191
|
-
import { isBotMentioned, probeBotOpenId, startLarkEventDispatcher, markForwardFollowupsSessionsReady, writeBotInfoFile, canOperate, canRunDaemonCommand, evaluateTalk, evaluateBotTalk, evaluateAskAnswerTalk, askCustomReplyCandidate, grantCommandRestriction, isKnownPeerBot, checkRequiredScopes } from './im/lark/event-dispatcher.js';
|
|
193
|
+
import { isBotMentioned, probeBotOpenId, startLarkEventDispatcher, markForwardFollowupsSessionsReady, writeBotInfoFile, canOperate, canRunDaemonCommand, evaluateTalk, evaluateBotTalk, evaluateAskAnswerTalk, askCustomReplyCandidate, grantCommandRestriction, isKnownPeerBot, resolveSiblingBotNameByUnionId, checkRequiredScopes, ensureVcMeetingEventsSubscribed } from './im/lark/event-dispatcher.js';
|
|
192
194
|
import { getDocSubscription, listAllDocSubscriptions, putDocSubscription, removeDocSubscription, setDocCommentPollCursor } from './services/doc-subs-store.js';
|
|
193
195
|
import { BOT_REPLY_SENTINEL, subscribeDocFile, unsubscribeDocFile, addCommentReaction, removeCommentReaction, hasBotSentinel, isBotAuthoredReply, listDocComments } from './im/lark/doc-comment.js';
|
|
194
196
|
import { learnFromMentions, resolveSender, flushIdentityCacheSync } from './im/lark/identity-cache.js';
|
|
@@ -200,7 +202,7 @@ import { shutdownBackendDisposition } from './core/persistent-backend.js';
|
|
|
200
202
|
import { abortRemoteShutdownFleet, canAbortVerifiedExitedRemotePreparation, collectUniqueDaemonShutdownSessions, commitPreparedRemoteShutdown, isPreparedRemoteSessionCurrent, persistPreparedRemoteShutdownFleet, prepareRemoteFleetForShutdown, } from './core/remote-shutdown-detach.js';
|
|
201
203
|
import { BOT_TURN_MUTATION_SHUTDOWN_ACQUIRE_TIMEOUT_MS, DAEMON_SHUTDOWN_MAX_MS, DAEMON_WORKER_EXIT_GRACE_MS, } from './core/shutdown-budgets.js';
|
|
202
204
|
import { evaluateVcMeetingConsumerIsolation } from './services/vc-meeting-consumer-isolation.js';
|
|
203
|
-
import { markSessionActivity, announcePendingRepoSession, publishAttentionPatch, publishLastInputFromBotPatch, publishSessionMessagePreviewPatch, publishClosedSessionPatch, clearAgentAttention, } from './core/session-activity.js';
|
|
205
|
+
import { markSessionActivity, announcePendingRepoSession, publishAttentionPatch, publishLastInputFromBotPatch, publishNativeTopicLinkPatch, publishSessionMessagePreviewPatch, publishClosedSessionPatch, clearAgentAttention, } from './core/session-activity.js';
|
|
204
206
|
import { emitSessionLifecycleHook } from './services/session-lifecycle-hooks.js';
|
|
205
207
|
import { botAutoWorktreeEnabled } from './services/default-worktree.js';
|
|
206
208
|
import { setCardDispatcher as setAskCardDispatcher, setCanTalkChecker as setAskCanTalkChecker, setAskPersistStore as setAskPersistStoreBroker, registerAsk as registerAskBroker, restorePersistedAsks as restorePersistedAsksBroker, findPendingAskByAnchor, submitCustomReply, } from './core/ask-broker.js';
|
|
@@ -222,7 +224,7 @@ import { scheduleSessionGroupTitle } from './services/session-group-title.js';
|
|
|
222
224
|
import { setChatReplyMode } from './services/chat-reply-mode-store.js';
|
|
223
225
|
import { hasVcMeetingEndedTombstone, listVcMeetingRuntimeSessionsByListenerAndAgent, listVcMeetingRuntimeSessions, pruneExpiredVcMeetingRuntimeSessions, recordVcMeetingEndedTombstone, recordVcMeetingRuntimeSession, removeVcMeetingRuntimeSession, } from './services/vc-meeting-runtime-store.js';
|
|
224
226
|
import { computeVcMeetingConsumerProfileHash, normalizeVcMeetingProfileInstructions, } from './services/vc-meeting-profile-instructions.js';
|
|
225
|
-
import {
|
|
227
|
+
import { bindVcMeetingConsumerCatalogToBot } from './services/vc-meeting-shared-consumer-catalog.js';
|
|
226
228
|
import { getVcMeetingPreparation, normalizeVcMeetingNumber, } from './services/vc-meeting-preparations-store.js';
|
|
227
229
|
import { abandonPoisonedVcMeetingDelivery, getVcMeetingDeliveryStatus, handleVcMeetingTurnTerminal, handleVcMeetingWorkerGenerationExit, receiveVcMeetingDelivery, registerVcMeetingMember, retryPoisonedVcMeetingDelivery, } from './services/vc-meeting-delivery-receiver.js';
|
|
228
230
|
import { abandonVcMeetingDeliveryStream, applyVcMeetingMemberProjection, expireVcMeetingDeliveryLeases, findVcMeetingDeliveryByKey, getVcMeetingMemberProjection, listVcMeetingMemberProjections, reconcileVcMeetingDeliveriesOnBoot, } from './services/vc-meeting-delivery-store.js';
|
|
@@ -231,7 +233,7 @@ import { buildVcMeetingDeliveryEntries, renderVcMeetingDeliveryItem, sealVcMeeti
|
|
|
231
233
|
import { applyVcMeetingHubMemberProjection, freezeVcMeetingHubDeliveryAssignment, getVcMeetingHubCloseState, getVcMeetingHubDeliveryAssignment, getVcMeetingHubMember, listVcMeetingHubMembers, observeVcMeetingHubReceiverReceipt, updateVcMeetingHubCloseState, } from './services/vc-meeting-delivery-hub-store.js';
|
|
232
234
|
import { getVcMeetingFeedMetadataState, ingestVcMeetingFeedMetadata, } from './services/vc-meeting-feed-metadata-store.js';
|
|
233
235
|
import { VcMeetingTerminalReconciler } from './services/vc-meeting-terminal-reconciler.js';
|
|
234
|
-
import { resolveVcMeetingImTurnOrigin, verifyVcMeetingManagedOriginClaim, } from './services/vc-meeting-send-policy.js';
|
|
236
|
+
import { resolveVcMeetingImTurnOrigin, verifyVcMeetingManagedOriginClaim, evaluateVcMeetingManagedSend, } from './services/vc-meeting-send-policy.js';
|
|
235
237
|
import { ensureVcMeetingListenerTopicRoot, } from './services/vc-meeting-listener-topic-store.js';
|
|
236
238
|
import { finishVcMeetingManagedActionProvider, finishVcMeetingManagedApprovalCard, requestVcMeetingManagedImAction, requestVcMeetingManagedAction, resolveVcMeetingManagedActionApproval, } from './services/vc-meeting-action-gate.js';
|
|
237
239
|
import { claimVcMeetingApprovalCardAttempt, findVcMeetingAction, listVcMeetingActionScopes, listVcMeetingActions, reconcileVcMeetingActionsOnBoot, } from './services/vc-meeting-action-store.js';
|
|
@@ -1129,14 +1131,34 @@ function vcMeetingConsumerRecoveryResolutionGraceMs() {
|
|
|
1129
1131
|
const vcMeetingClosingConsumerSessions = new Map();
|
|
1130
1132
|
let vcMeetingAgentGlobalEnabledOverrideForTest;
|
|
1131
1133
|
let vcMeetingAgentGlobalListenerBotAppIdOverrideForTest;
|
|
1134
|
+
let vcMeetingListenerPinDeprecationWarned = false;
|
|
1132
1135
|
function vcMeetingAgentGlobalEnabled() {
|
|
1133
1136
|
return vcMeetingAgentGlobalEnabledOverrideForTest ?? isVcMeetingAgentGloballyEnabled();
|
|
1134
1137
|
}
|
|
1138
|
+
/**
|
|
1139
|
+
* RETIRED (2026-08): the global VC listener pin is gone — every bot with
|
|
1140
|
+
* `vcMeetingAgent.enabled` now handles the meeting events IT receives, so a
|
|
1141
|
+
* meeting can run multiple bots (each with its own presets) instead of routing
|
|
1142
|
+
* everything through one designated listener. Always returns undefined so the
|
|
1143
|
+
* `listenerAppId &&` guards at every call site short-circuit to the
|
|
1144
|
+
* every-bot-handles-its-own behaviour (which was already the semantics when
|
|
1145
|
+
* `listenerBotAppId` was unset). A legacy `vcMeetingAgent.listenerBotAppId`
|
|
1146
|
+
* still in config is ignored with a one-time warning.
|
|
1147
|
+
*
|
|
1148
|
+
* The test override is retained ONLY so the test harness can still call the
|
|
1149
|
+
* setter without a signature change; it no longer re-pins routing.
|
|
1150
|
+
*/
|
|
1135
1151
|
function vcMeetingAgentGlobalListenerAppId() {
|
|
1136
|
-
|
|
1137
|
-
|
|
1152
|
+
const legacyPin = vcMeetingAgentGlobalListenerBotAppIdOverrideForTest !== undefined
|
|
1153
|
+
? (vcMeetingAgentGlobalListenerBotAppIdOverrideForTest ?? undefined)
|
|
1154
|
+
: vcMeetingAgentGlobalListenerBotAppId();
|
|
1155
|
+
if (legacyPin && !vcMeetingListenerPinDeprecationWarned) {
|
|
1156
|
+
vcMeetingListenerPinDeprecationWarned = true;
|
|
1157
|
+
logger.warn(`[vc-agent] vcMeetingAgent.listenerBotAppId=${legacyPin} is deprecated and ignored: `
|
|
1158
|
+
+ 'every bot with vcMeetingAgent.enabled now handles its own meeting invites. '
|
|
1159
|
+
+ 'Remove this field from the global config.');
|
|
1138
1160
|
}
|
|
1139
|
-
return
|
|
1161
|
+
return undefined;
|
|
1140
1162
|
}
|
|
1141
1163
|
function vcMeetingPushIsTrackedLifecycleEvent(ctx) {
|
|
1142
1164
|
const key = ctx.meeting.id ? vcMeetingSessionKey(ctx.larkAppId, ctx.meeting.id) : '';
|
|
@@ -1151,7 +1173,11 @@ const DEFAULT_VC_MEETING_FLUSH_INTERVAL_MS = 30_000;
|
|
|
1151
1173
|
const DEFAULT_VC_MEETING_TIME_ZONE = 'Asia/Shanghai';
|
|
1152
1174
|
const DEFAULT_VC_MEETING_CONSUMER_SELECTION_TIMEOUT_MS = 20_000;
|
|
1153
1175
|
const DEFAULT_VC_MEETING_CONSUMER_INJECT_INTERVAL_MS = 30_000;
|
|
1154
|
-
|
|
1176
|
+
// Effectively no char-accumulation gate: with minBatchItems=1 a single
|
|
1177
|
+
// finalized transcript segment already qualifies, and the operator explicitly
|
|
1178
|
+
// asked for no "wait until enough text piles up" behavior (esp. at meeting
|
|
1179
|
+
// start). Kept as a config knob for bots that want to raise it.
|
|
1180
|
+
const DEFAULT_VC_MEETING_CONSUMER_MIN_BATCH_CHARS = 1;
|
|
1155
1181
|
const VC_MEETING_CONSUMER_DELIVERY_MAX_ITEMS = 100;
|
|
1156
1182
|
const VC_MEETING_CONSUMER_DELIVERY_MAX_RENDERED_CHARS = 20_000;
|
|
1157
1183
|
// By default, keep the selected agent as fresh as the listener group: one new
|
|
@@ -1345,11 +1371,42 @@ function vcMeetingConsumerMinBatchItems(cfg) {
|
|
|
1345
1371
|
function vcMeetingConsumerMaxInjectIntervalMs(cfg) {
|
|
1346
1372
|
return cfg.meetingConsumer?.maxInjectIntervalMs ?? DEFAULT_VC_MEETING_CONSUMER_MAX_INJECT_INTERVAL_MS;
|
|
1347
1373
|
}
|
|
1348
|
-
function defaultVcMeetingTextOutputPolicy() {
|
|
1349
|
-
|
|
1374
|
+
function defaultVcMeetingTextOutputPolicy(cfg) {
|
|
1375
|
+
// In-meeting text now sends without per-message approval by default; an
|
|
1376
|
+
// operator can restore the review gate per-bot via
|
|
1377
|
+
// meetingConsumer.textOutputPolicy = 'approval' (or 'deny').
|
|
1378
|
+
const configured = cfg?.meetingConsumer?.textOutputPolicy;
|
|
1379
|
+
if (configured === 'approval' || configured === 'deny' || configured === 'allow')
|
|
1380
|
+
return configured;
|
|
1381
|
+
return 'allow';
|
|
1350
1382
|
}
|
|
1351
1383
|
function defaultVcMeetingVoiceOutputPolicy(cfg) {
|
|
1352
|
-
|
|
1384
|
+
// Voice is denied only when realtime voice is explicitly OFF. Realtime voice is
|
|
1385
|
+
// now ON BY DEFAULT (vcMeetingRealtimeVoiceEnabled: unset ⇒ enabled), so unless
|
|
1386
|
+
// an operator set realtimeVoice.enabled:false, voice falls through to the
|
|
1387
|
+
// default below. ⚠ That default is 'allow' — matching text — meaning a bot
|
|
1388
|
+
// pulled into a meeting speaks aloud WITHOUT per-utterance approval by default.
|
|
1389
|
+
// Tighten per-bot to 'approval'/'deny' via meetingConsumer.voiceOutputPolicy
|
|
1390
|
+
// (dashboard-editable). 'allow' only drops the per-send approval step; the
|
|
1391
|
+
// managed request-output/action gate + capability check still apply.
|
|
1392
|
+
if (!vcMeetingRealtimeVoiceEnabled(cfg))
|
|
1393
|
+
return 'deny';
|
|
1394
|
+
const configured = cfg.meetingConsumer?.voiceOutputPolicy;
|
|
1395
|
+
if (configured === 'approval' || configured === 'deny' || configured === 'allow')
|
|
1396
|
+
return configured;
|
|
1397
|
+
return 'allow';
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* 实时语音能力现在**默认开启**:`realtimeVoice.enabled` 未配 = 视为开,只有显式
|
|
1401
|
+
* `false` 才关。scope 已 fleet 级预授(实测含 vc:meeting.bot.realtime:write),所以
|
|
1402
|
+
* 语音关着只是保守默认、不是权限卡。
|
|
1403
|
+
*
|
|
1404
|
+
* 注意「能力开」不等于「入会即建连」:语音 WebSocket 只在这个 bot 真要发言时
|
|
1405
|
+
* (deliverVcMeetingVoiceOutput → ensureVcMeetingRealtimeVoiceSession)按需建立,
|
|
1406
|
+
* 纯监听 / 从不发言的 bot 不会挂空闲连接。见 maybeStartVcMeetingRealtimeVoice。
|
|
1407
|
+
*/
|
|
1408
|
+
function vcMeetingRealtimeVoiceEnabled(cfg) {
|
|
1409
|
+
return cfg?.realtimeVoice?.enabled !== false;
|
|
1353
1410
|
}
|
|
1354
1411
|
function vcMeetingOutputReviewTimeoutMs(channel) {
|
|
1355
1412
|
return channel === 'voice' ? DEFAULT_VC_MEETING_VOICE_REVIEW_TIMEOUT_MS : DEFAULT_VC_MEETING_TEXT_REVIEW_TIMEOUT_MS;
|
|
@@ -1616,36 +1673,29 @@ async function ensureVcMeetingReceiverSession(request, existingSessionId, receiv
|
|
|
1616
1673
|
if (!existing) {
|
|
1617
1674
|
throw new Error(`registered receiver session is not active or lacks managed side-effect isolation: ${existingSessionId}`);
|
|
1618
1675
|
}
|
|
1676
|
+
// Plan B: the meeting agent is an ordinary chat-scope session, so a chat can
|
|
1677
|
+
// legitimately host several meeting projections in one transcript. The old
|
|
1678
|
+
// strict "one session ⇔ one exact meeting/member/epoch" identity check no
|
|
1679
|
+
// longer holds. Only require that the resolved session is the right listener
|
|
1680
|
+
// chat under the right agent app (verified via the resolver binding above)
|
|
1681
|
+
// and stamp/refresh the delivery-identity metadata for this member epoch so
|
|
1682
|
+
// later meeting-directed output (Stage 6) can find it. The marker is pure
|
|
1683
|
+
// metadata now — it does not affect routing.
|
|
1619
1684
|
const ds = [...activeSessions.values()].find(candidate => candidate.session.sessionId === existingSessionId) ?? findActiveBySessionId(existingSessionId);
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|| identity.listenerAppId !== request.meeting.listenerAppId
|
|
1623
|
-
|| identity.meetingId !== request.meeting.meetingId
|
|
1624
|
-
|| identity.memberId !== request.member.memberId
|
|
1625
|
-
|| identity.memberEpoch !== request.member.epoch) {
|
|
1626
|
-
throw new Error('registered receiver session is not dedicated to this meeting member epoch');
|
|
1685
|
+
if (ds && ds.chatId === request.outputRoute.chatId) {
|
|
1686
|
+
stampVcMeetingBinding(ds, request);
|
|
1627
1687
|
}
|
|
1628
1688
|
return existing;
|
|
1629
1689
|
}
|
|
1630
|
-
//
|
|
1631
|
-
//
|
|
1632
|
-
//
|
|
1633
|
-
//
|
|
1690
|
+
// Plan B core cut: a meeting agent is a normal chat-scope session in its
|
|
1691
|
+
// listener group, keyed by the ordinary `(chatId, appId)` slot. Plain IM and
|
|
1692
|
+
// meeting transcripts therefore fold into the SAME session (transcripts are
|
|
1693
|
+
// delivered by target.sessionId; IM is routed by the chat anchor). Reuse an
|
|
1694
|
+
// existing chat-scope session at that slot if present (whether it was opened
|
|
1695
|
+
// by IM or by an earlier meeting), else create a cold `worker:null` session
|
|
1696
|
+
// shaped exactly like an auto-created IM session so triggerSessionTurn's
|
|
1697
|
+
// cold-fork path spawns it on first delivery.
|
|
1634
1698
|
const chatId = request.outputRoute.chatId;
|
|
1635
|
-
const matching = [...activeSessions.values()].find((candidate) => {
|
|
1636
|
-
const identity = candidate.session.vcMeetingReceiver;
|
|
1637
|
-
return candidate.larkAppId === selfAppId
|
|
1638
|
-
&& identity?.listenerAppId === request.meeting.listenerAppId
|
|
1639
|
-
&& identity.meetingId === request.meeting.meetingId
|
|
1640
|
-
&& identity.memberId === request.member.memberId
|
|
1641
|
-
&& identity.memberEpoch === request.member.epoch;
|
|
1642
|
-
});
|
|
1643
|
-
if (matching) {
|
|
1644
|
-
const binding = resolveVcMeetingReceiverSession(matching.session.sessionId);
|
|
1645
|
-
if (!binding)
|
|
1646
|
-
throw new Error('existing dedicated receiver session has an unsupported CLI adapter');
|
|
1647
|
-
return binding;
|
|
1648
|
-
}
|
|
1649
1699
|
const bot = getBot(selfAppId);
|
|
1650
1700
|
const isolation = vcMeetingConsumerIsolationForBot(bot.config);
|
|
1651
1701
|
if (!isolation.decision.ok) {
|
|
@@ -1657,56 +1707,84 @@ async function ensureVcMeetingReceiverSession(request, existingSessionId, receiv
|
|
|
1657
1707
|
// whose environment/working dir was never set up for bwrap, and the CLI would
|
|
1658
1708
|
// fail to spawn or be unable to work (the "joined but never replies" bug).
|
|
1659
1709
|
const receiverSandboxed = isolation.decision.isolated;
|
|
1660
|
-
const
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1710
|
+
const key = sessionKey(chatId, selfAppId);
|
|
1711
|
+
const bound = await withActiveSessionKeyLock(activeSessions, key, () => {
|
|
1712
|
+
const current = activeSessions.get(key);
|
|
1713
|
+
if (current) {
|
|
1714
|
+
// A chat-scope session already occupies this slot. Adopt it as the meeting
|
|
1715
|
+
// agent by stamping the delivery-identity metadata; do NOT create a second
|
|
1716
|
+
// universe. The session keeps whatever launch/sandbox decision it already
|
|
1717
|
+
// froze — we never retroactively weaken or strengthen a live session here.
|
|
1718
|
+
stampVcMeetingBinding(current, request);
|
|
1719
|
+
return current;
|
|
1720
|
+
}
|
|
1721
|
+
const rawWorkingDir = findOncallChat(selfAppId, chatId)?.workingDir
|
|
1722
|
+
?? effectiveDefaultWorkingDir(bot.config)
|
|
1723
|
+
?? bot.config.workingDir
|
|
1724
|
+
?? '~';
|
|
1725
|
+
const workingDir = validateWorkingDir(rawWorkingDir, localeForBot(selfAppId));
|
|
1726
|
+
if (!workingDir.ok)
|
|
1727
|
+
throw new Error(workingDir.error);
|
|
1728
|
+
const session = sessionStore.createSession(chatId, chatId, `[Meeting] ${request.meeting.meetingId}`.slice(0, 50), 'group');
|
|
1729
|
+
const now = Date.now();
|
|
1730
|
+
session.larkAppId = selfAppId;
|
|
1731
|
+
session.scope = 'chat';
|
|
1732
|
+
session.vcMeetingReceiver = {
|
|
1733
|
+
listenerAppId: request.meeting.listenerAppId,
|
|
1734
|
+
meetingId: request.meeting.meetingId,
|
|
1735
|
+
memberId: request.member.memberId,
|
|
1736
|
+
memberEpoch: request.member.epoch,
|
|
1737
|
+
};
|
|
1738
|
+
session.lastMessageAt = new Date(now).toISOString();
|
|
1739
|
+
session.workingDir = workingDir.resolvedPath;
|
|
1740
|
+
session.cliId = bot.config.cliId;
|
|
1741
|
+
// Freeze the security-critical launch decision at creation. A later live
|
|
1742
|
+
// Bot-config edit must neither weaken this session nor make an old
|
|
1743
|
+
// unisolated session appear eligible retroactively. Under plan B the frozen
|
|
1744
|
+
// value follows the bot's opt-in, not a hardcoded true.
|
|
1745
|
+
session.sandbox = receiverSandboxed;
|
|
1746
|
+
session.sandboxHidePaths = receiverSandboxed ? (bot.config.sandboxHidePaths ?? []) : [];
|
|
1747
|
+
session.sandboxReadonlyPaths = receiverSandboxed ? (bot.config.sandboxReadonlyPaths ?? []) : [];
|
|
1748
|
+
session.sandboxNetwork = receiverSandboxed ? (bot.config.sandboxNetwork !== false) : true;
|
|
1749
|
+
session.backendType = isolation.backendType;
|
|
1750
|
+
sessionStore.updateSession(session);
|
|
1751
|
+
const ds = {
|
|
1752
|
+
session,
|
|
1753
|
+
worker: null,
|
|
1754
|
+
workerPort: null,
|
|
1755
|
+
workerToken: null,
|
|
1756
|
+
larkAppId: selfAppId,
|
|
1757
|
+
chatId,
|
|
1758
|
+
chatType: 'group',
|
|
1759
|
+
scope: 'chat',
|
|
1760
|
+
spawnedAt: Date.parse(session.createdAt) || now,
|
|
1761
|
+
cliVersion: getCurrentCliVersion(),
|
|
1762
|
+
lastMessageAt: now,
|
|
1763
|
+
hasHistory: false,
|
|
1764
|
+
workingDir: workingDir.resolvedPath,
|
|
1765
|
+
};
|
|
1766
|
+
activeSessions.set(key, ds);
|
|
1767
|
+
return ds;
|
|
1768
|
+
});
|
|
1769
|
+
const binding = resolveVcMeetingReceiverSession(bound.session.sessionId);
|
|
1770
|
+
if (!binding)
|
|
1771
|
+
throw new Error('meeting agent session has an unsupported CLI adapter');
|
|
1772
|
+
return binding;
|
|
1773
|
+
}
|
|
1774
|
+
/** Stamp/refresh the VC meeting delivery-identity metadata onto an ordinary
|
|
1775
|
+
* chat-scope session (Plan B). This binds the session as the delivery + future
|
|
1776
|
+
* meeting-output target for this member epoch WITHOUT changing routing: the
|
|
1777
|
+
* session is still keyed by its normal chat slot. The most-recent meeting/member
|
|
1778
|
+
* epoch wins when one chat hosts several meetings, matching the transcript
|
|
1779
|
+
* delivery model (targets pick the session by id, not by this marker). */
|
|
1780
|
+
function stampVcMeetingBinding(ds, request) {
|
|
1781
|
+
ds.session.vcMeetingReceiver = {
|
|
1672
1782
|
listenerAppId: request.meeting.listenerAppId,
|
|
1673
1783
|
meetingId: request.meeting.meetingId,
|
|
1674
1784
|
memberId: request.member.memberId,
|
|
1675
1785
|
memberEpoch: request.member.epoch,
|
|
1676
1786
|
};
|
|
1677
|
-
|
|
1678
|
-
session.workingDir = workingDir.resolvedPath;
|
|
1679
|
-
session.cliId = bot.config.cliId;
|
|
1680
|
-
// Freeze the security-critical launch decision at receiver creation. A
|
|
1681
|
-
// later live Bot-config edit must neither weaken this session nor make an
|
|
1682
|
-
// old unisolated receiver appear eligible retroactively. Under plan B the
|
|
1683
|
-
// frozen value follows the bot's opt-in, not a hardcoded true.
|
|
1684
|
-
session.sandbox = receiverSandboxed;
|
|
1685
|
-
session.sandboxHidePaths = receiverSandboxed ? (bot.config.sandboxHidePaths ?? []) : [];
|
|
1686
|
-
session.sandboxReadonlyPaths = receiverSandboxed ? (bot.config.sandboxReadonlyPaths ?? []) : [];
|
|
1687
|
-
session.sandboxNetwork = receiverSandboxed ? (bot.config.sandboxNetwork !== false) : true;
|
|
1688
|
-
session.backendType = isolation.backendType;
|
|
1689
|
-
sessionStore.updateSession(session);
|
|
1690
|
-
const ds = {
|
|
1691
|
-
session,
|
|
1692
|
-
worker: null,
|
|
1693
|
-
workerPort: null,
|
|
1694
|
-
workerToken: null,
|
|
1695
|
-
larkAppId: selfAppId,
|
|
1696
|
-
chatId,
|
|
1697
|
-
chatType: 'group',
|
|
1698
|
-
scope: 'chat',
|
|
1699
|
-
spawnedAt: Date.parse(session.createdAt) || now,
|
|
1700
|
-
cliVersion: getCurrentCliVersion(),
|
|
1701
|
-
lastMessageAt: now,
|
|
1702
|
-
hasHistory: false,
|
|
1703
|
-
workingDir: workingDir.resolvedPath,
|
|
1704
|
-
};
|
|
1705
|
-
activeSessions.set(activeSessionKey(ds), ds);
|
|
1706
|
-
const binding = resolveVcMeetingReceiverSession(session.sessionId);
|
|
1707
|
-
if (!binding)
|
|
1708
|
-
throw new Error('created receiver session has an unsupported CLI adapter');
|
|
1709
|
-
return binding;
|
|
1787
|
+
sessionStore.updateSession(ds.session);
|
|
1710
1788
|
}
|
|
1711
1789
|
function vcMeetingDeliveryReceiverDeps(receiverAppId) {
|
|
1712
1790
|
const selfAppId = receiverAppId ?? selfDaemonLarkAppId;
|
|
@@ -1722,6 +1800,18 @@ function vcMeetingDeliveryReceiverDeps(receiverAppId) {
|
|
|
1722
1800
|
const target = findActiveBySessionId(request.target.sessionId ?? '');
|
|
1723
1801
|
if (target)
|
|
1724
1802
|
target.vcMeetingImTurnOrigin = undefined;
|
|
1803
|
+
// VC transcript delivery turns dispatch straight through triggerSessionTurn,
|
|
1804
|
+
// which (unlike the ordinary IM path) never calls beginNewTurn — so without
|
|
1805
|
+
// this the meeting agent's streaming-card lifecycle would never arm and no
|
|
1806
|
+
// live card would post for a transcript-driven turn. Under Plan B the
|
|
1807
|
+
// meeting agent is an ordinary chat-scope session whose card should surface
|
|
1808
|
+
// like any group session (the "看不到流式卡片" report), so arm it for every
|
|
1809
|
+
// delivery turn. A silent-responseMode turn still suppresses only its final
|
|
1810
|
+
// output (managedFinalOutputSuppressed), not the live card.
|
|
1811
|
+
if (target?.session.vcMeetingReceiver && context.stableTurnId) {
|
|
1812
|
+
const title = target.currentTurnTitle || target.session.title || '会议监听';
|
|
1813
|
+
beginNewTurn(target, title, context.stableTurnId);
|
|
1814
|
+
}
|
|
1725
1815
|
return triggerSessionTurn(request, { larkAppId: selfAppId, activeSessions }, {
|
|
1726
1816
|
stableTurnId: context.stableTurnId,
|
|
1727
1817
|
beforeDispatch: context.beforeDispatch,
|
|
@@ -1926,7 +2016,13 @@ async function maybeCatchUpVcMeetingConsumerBeforeTurn(data, ctx) {
|
|
|
1926
2016
|
logger.warn(`[vc-agent] IM follow-up routed with possibly stale context meeting=${caughtUp.candidate.meetingId} `
|
|
1927
2017
|
+ `agent=${ctx.larkAppId} status=${caughtUp.catchUpStatus} error=${caughtUp.catchUpError ?? '-'}`);
|
|
1928
2018
|
}
|
|
1929
|
-
|
|
2019
|
+
// Plan B: the meeting agent is an ordinary chat-scope session keyed by the
|
|
2020
|
+
// normal `(chatId, appId)` slot, so the natural chat anchor already resolves
|
|
2021
|
+
// it — no `vc-receiver:` anchor override is needed (or correct) anymore. This
|
|
2022
|
+
// hook now only (a) blocks on ambiguous/undeliverable meeting context and
|
|
2023
|
+
// (b) stamps vcMeetingImTurnOrigin so an @mention follow-up carries the
|
|
2024
|
+
// meeting delivery identity for catch-up/echo purposes.
|
|
2025
|
+
return;
|
|
1930
2026
|
}
|
|
1931
2027
|
async function pinVcMeetingConsumerChatReplyMode(larkAppId, chatId) {
|
|
1932
2028
|
if (vcMeetingConsumerUsesLocalReceiver(larkAppId)) {
|
|
@@ -2282,7 +2378,14 @@ export async function noteTurnReceived(ds, triggerMessageId, _prompt, _sender, _
|
|
|
2282
2378
|
// message — not a worker status edge — means type-ahead / busy-batched messages
|
|
2283
2379
|
// each get their own ✋. `finishTurnReactions` flips every pending ✋ to ✅ when
|
|
2284
2380
|
// the worker next goes idle.
|
|
2285
|
-
|
|
2381
|
+
// Plan B: a meeting agent is an ordinary chat-scope session that hosts plain
|
|
2382
|
+
// user turns. A plain user message should get the ✋→✅ progress reaction like
|
|
2383
|
+
// any card-off session. Only a stamped meeting @mention follow-up stays
|
|
2384
|
+
// reaction-free (it is meeting-driven and routes through the audited listener
|
|
2385
|
+
// action, not the ordinary progress-reaction channel). Transcript deliveries
|
|
2386
|
+
// never reach this inbound-message acceptance point at all.
|
|
2387
|
+
if (ds.session.vcMeetingReceiver
|
|
2388
|
+
&& resolveVcMeetingImTurnOrigin(ds.session, triggerMessageId) !== undefined)
|
|
2286
2389
|
return;
|
|
2287
2390
|
// Turn-exact card-off check: the reaction ack belongs to THIS message's turn,
|
|
2288
2391
|
// not to whichever turn most recently overwrote currentReplyTarget.
|
|
@@ -4194,7 +4297,8 @@ workflowDaemonMutationRoute('retry', async (reply, params, body, identity) => {
|
|
|
4194
4297
|
error: outcome.reason === 'missing' ? 'unknown_run'
|
|
4195
4298
|
: outcome.reason === 'loop-node' ? 'loop_node_use_grant'
|
|
4196
4299
|
: outcome.reason === 'host-effect-uncertain' ? 'host_effect_reconcile_required'
|
|
4197
|
-
: '
|
|
4300
|
+
: outcome.reason === 'revise-workflow-required' ? 'workflow_revision_required'
|
|
4301
|
+
: 'not_blocked',
|
|
4198
4302
|
});
|
|
4199
4303
|
}
|
|
4200
4304
|
// requested / already-requested → make sure the run is moving.
|
|
@@ -5185,8 +5289,66 @@ ipcRoute('POST', '/api/vc-meetings/action-request', async (req, res) => {
|
|
|
5185
5289
|
claimedTurnId: typeof body.originTurnId === 'string' ? body.originTurnId : undefined,
|
|
5186
5290
|
claimedDispatchAttempt: claimedAttempt,
|
|
5187
5291
|
});
|
|
5188
|
-
|
|
5189
|
-
|
|
5292
|
+
// Plan B: the meeting agent is an ordinary chat-scope session that interleaves
|
|
5293
|
+
// plain user IM turns with meeting deliveries and reaches idle between them.
|
|
5294
|
+
// The in-memory managedTurnOrigin is cleared at each delivery turn's terminal
|
|
5295
|
+
// edge, so a request-output the model runs AFTER the delivery turn goes idle
|
|
5296
|
+
// (or after an intervening IM turn) finds no live origin and would fail
|
|
5297
|
+
// `origin_unproven` — even though the durable delivery receipt still fully
|
|
5298
|
+
// authorizes it. Fall back to the DURABLE receipt for a claimed delivery origin
|
|
5299
|
+
// (turnId + dispatchAttempt): evaluateVcMeetingManagedSend re-derives authority
|
|
5300
|
+
// from the on-disk receipt exactly as the final-output path does — receipt must
|
|
5301
|
+
// exist for THIS receiver session, the attempt must match, its status must be
|
|
5302
|
+
// dispatched/completed, the projection must still be active, and a silent
|
|
5303
|
+
// delivery is refused. This never authorizes anything the receipt itself
|
|
5304
|
+
// wouldn't, so it does not weaken the boundary; it only survives the idle gap.
|
|
5305
|
+
//
|
|
5306
|
+
// The fallback intentionally does NOT require the live origin to be absent:
|
|
5307
|
+
// live verification proves origin via the rotating worker capability only,
|
|
5308
|
+
// and non-sandboxed sessions have no origin-channel transport for that
|
|
5309
|
+
// capability (managedOriginChannelRequired is darwin-isolate/credential-only
|
|
5310
|
+
// bwrap), so their live check ALWAYS fails — including while the delivery
|
|
5311
|
+
// turn is still executing. Gating the fallback on "live origin cleared"
|
|
5312
|
+
// hard-bricked exactly that case (in-turn speech from a non-sandboxed
|
|
5313
|
+
// meeting agent). The durable receipt check is the same strength either way,
|
|
5314
|
+
// so the fallback runs whenever live verification failed.
|
|
5315
|
+
let effectiveVerified = verified;
|
|
5316
|
+
if (!verified.ok
|
|
5317
|
+
&& typeof body.originTurnId === 'string'
|
|
5318
|
+
&& body.originTurnId.trim()
|
|
5319
|
+
&& claimedAttempt !== undefined) {
|
|
5320
|
+
const claimedDeliveryTurnId = body.originTurnId.trim();
|
|
5321
|
+
const durable = evaluateVcMeetingManagedSend(config.session.dataDir, {
|
|
5322
|
+
receiverSessionId,
|
|
5323
|
+
receiverSession: true,
|
|
5324
|
+
turnId: claimedDeliveryTurnId,
|
|
5325
|
+
dispatchAttempt: claimedAttempt,
|
|
5326
|
+
allowTerminalReceipt: true,
|
|
5327
|
+
// In-meeting output channel: silent responseMode gates only listener-group
|
|
5328
|
+
// auto-post, not in-meeting speech (the hub applies capability +
|
|
5329
|
+
// textOutputPolicy/voiceOutputPolicy). Prove receipt identity/liveness here
|
|
5330
|
+
// but do not apply the silent veto.
|
|
5331
|
+
forInMeetingOutput: true,
|
|
5332
|
+
});
|
|
5333
|
+
if (durable.ok && durable.kind === 'listener_thread') {
|
|
5334
|
+
logger.info(`[vc-agent] request-output authorized via durable receipt fallback `
|
|
5335
|
+
+ `(live origin ${ds.managedTurnOrigin ? 'present but unverifiable — no capability transport' : 'cleared at turn terminal'}) `
|
|
5336
|
+
+ `session=${receiverSessionId.slice(0, 8)} `
|
|
5337
|
+
+ `turn=${claimedDeliveryTurnId.slice(0, 12)} attempt=${claimedAttempt}`);
|
|
5338
|
+
effectiveVerified = {
|
|
5339
|
+
ok: true,
|
|
5340
|
+
origin: {
|
|
5341
|
+
receiverSessionId,
|
|
5342
|
+
turnId: claimedDeliveryTurnId,
|
|
5343
|
+
dispatchAttempt: claimedAttempt,
|
|
5344
|
+
currentImTurnId: undefined,
|
|
5345
|
+
currentImTurnOrigin: undefined,
|
|
5346
|
+
},
|
|
5347
|
+
};
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
if (!effectiveVerified.ok)
|
|
5351
|
+
return jsonRes(res, 403, effectiveVerified);
|
|
5190
5352
|
const channel = body.channel === 'text' || body.channel === 'voice' ? body.channel : undefined;
|
|
5191
5353
|
const content = sanitizeVcMeetingOutputContent(body.content, 'content');
|
|
5192
5354
|
const reason = sanitizeVcMeetingOutputContent(body.reason, 'reason');
|
|
@@ -5198,13 +5360,13 @@ ipcRoute('POST', '/api/vc-meetings/action-request', async (req, res) => {
|
|
|
5198
5360
|
? body.expectedListenerAppId.trim()
|
|
5199
5361
|
: '';
|
|
5200
5362
|
const expectedMeetingId = typeof body.expectedMeetingId === 'string' ? body.expectedMeetingId.trim() : '';
|
|
5201
|
-
if (
|
|
5202
|
-
const imOrigin = resolveVcMeetingImTurnOrigin(ds.session,
|
|
5203
|
-
if (!
|
|
5204
|
-
||
|
|
5363
|
+
if (effectiveVerified.origin.dispatchAttempt === undefined) {
|
|
5364
|
+
const imOrigin = resolveVcMeetingImTurnOrigin(ds.session, effectiveVerified.origin.turnId);
|
|
5365
|
+
if (!effectiveVerified.origin.turnId
|
|
5366
|
+
|| effectiveVerified.origin.currentImTurnId !== effectiveVerified.origin.turnId
|
|
5205
5367
|
|| !imOrigin
|
|
5206
5368
|
|| imOrigin.receiverSessionId !== receiverSessionId
|
|
5207
|
-
|| imOrigin.larkMessageId !==
|
|
5369
|
+
|| imOrigin.larkMessageId !== effectiveVerified.origin.turnId) {
|
|
5208
5370
|
return jsonRes(res, 409, {
|
|
5209
5371
|
ok: false,
|
|
5210
5372
|
errorCode: 'im_turn_origin_mismatch',
|
|
@@ -5233,14 +5395,14 @@ ipcRoute('POST', '/api/vc-meetings/action-request', async (req, res) => {
|
|
|
5233
5395
|
});
|
|
5234
5396
|
return jsonRes(res, upstream.status, upstream.body);
|
|
5235
5397
|
}
|
|
5236
|
-
if (!
|
|
5398
|
+
if (!effectiveVerified.origin.turnId) {
|
|
5237
5399
|
return jsonRes(res, 409, {
|
|
5238
5400
|
ok: false,
|
|
5239
5401
|
errorCode: 'delivery_origin_mismatch',
|
|
5240
5402
|
error: 'durable delivery action has no stable turn id',
|
|
5241
5403
|
});
|
|
5242
5404
|
}
|
|
5243
|
-
const lookup = findVcMeetingDeliveryByKey(config.session.dataDir,
|
|
5405
|
+
const lookup = findVcMeetingDeliveryByKey(config.session.dataDir, effectiveVerified.origin.turnId, {
|
|
5244
5406
|
receiverSessionId,
|
|
5245
5407
|
});
|
|
5246
5408
|
if (!lookup) {
|
|
@@ -5271,8 +5433,8 @@ ipcRoute('POST', '/api/vc-meetings/action-request', async (req, res) => {
|
|
|
5271
5433
|
body: JSON.stringify({
|
|
5272
5434
|
agentAppId: ds.larkAppId,
|
|
5273
5435
|
receiverSessionId,
|
|
5274
|
-
stableTurnId:
|
|
5275
|
-
dispatchAttempt:
|
|
5436
|
+
stableTurnId: effectiveVerified.origin.turnId,
|
|
5437
|
+
dispatchAttempt: effectiveVerified.origin.dispatchAttempt,
|
|
5276
5438
|
channel,
|
|
5277
5439
|
content,
|
|
5278
5440
|
...(reason ? { reason } : {}),
|
|
@@ -5428,7 +5590,48 @@ function effectiveVcMeetingAgentConfig(larkAppId) {
|
|
|
5428
5590
|
// `restoreVcMeetingRuntimeSessionsForBot`, whose call site sits OUTSIDE the
|
|
5429
5591
|
// `!cfg.apiOnly` boot block — so a migrated bots.json (normal VC bot flipped to
|
|
5430
5592
|
// apiOnly, stale runtime record on disk) can no longer re-spawn lark-cli at boot.
|
|
5431
|
-
|
|
5593
|
+
//
|
|
5594
|
+
// 这是 daemon 侧唯一一处产出 VcMeetingAgentConfig 的地方,所以角色预设的绑定也在
|
|
5595
|
+
// 这里做:没有自己 consumerProfiles 的 bot 继承 fleet 共享目录,且**所有**预设的
|
|
5596
|
+
// 执行方一律重绑为 larkAppId 本人——「拉 A 进会却拉 B 进群」在这一层被彻底切断,
|
|
5597
|
+
// 历史配置里写歪的 agentAppId 也在读路径上被纠正,不需要迁移写盘。
|
|
5598
|
+
const cfg = vcMeetingAgentConfigActive(getBot(larkAppId)?.config);
|
|
5599
|
+
if (!cfg)
|
|
5600
|
+
return cfg;
|
|
5601
|
+
return withDefaultVcMeetingJoinProfile(larkAppId, bindVcMeetingConsumerCatalogToBot(larkAppId, cfg));
|
|
5602
|
+
}
|
|
5603
|
+
/**
|
|
5604
|
+
* 没配 `larkCliProfile` 的 bot,入会身份默认用它**自己的 appId** 作为 lark-cli
|
|
5605
|
+
* profile 名。
|
|
5606
|
+
*
|
|
5607
|
+
* 背景:入会门禁 {@link ensureVcMeetingJoinProfile} 要求 `larkCliProfile` 非空,
|
|
5608
|
+
* 否则以 `no_profile` 拒绝入会。而这个字段过去只有 Dashboard 的「配置权限」按钮
|
|
5609
|
+
* 会落盘(见 preflightVcMeetingBot),于是 fleet 里绝大多数从没点过那颗按钮的 bot
|
|
5610
|
+
* 被拉进会一律被拒——正是「拉别的 bot 进会还是不行」。
|
|
5611
|
+
*
|
|
5612
|
+
* 把默认值放在**读路径**而不是要求人工点按钮,是因为这个默认值是纯确定性的:
|
|
5613
|
+
* - 就是 bot **自己的 appId**,既不是跨 app 身份、也不含任何 secret,app-scoped,
|
|
5614
|
+
* 不触碰 owner 身份边界;
|
|
5615
|
+
* - profile 一旦有名字,{@link ensureLarkCliBotProfile} 会用该 bot **自己**保存的
|
|
5616
|
+
* appSecret 走 `--app-secret-stdin`(不进 argv、只落 lark-cli 加密库、只在受信
|
|
5617
|
+
* daemon 里)自动注册它——PR #392 当年之所以 fail-closed(“no faked profile”),
|
|
5618
|
+
* 是因为那时没有自动注册、写个名字会 ringing;PR #782 补上自动注册后这个顾虑
|
|
5619
|
+
* 已消除。
|
|
5620
|
+
*
|
|
5621
|
+
* 真正需要人在场的是**开放平台权限开通 / 事件订阅**(可能要扫码登录),那部分仍留在
|
|
5622
|
+
* 「配置权限」按钮里;权限/secret 真缺时,入会会在后面以 `missing_secret` /
|
|
5623
|
+
* `add_failed` / scope 校验等**可操作**错误失败,而不是这里这条造出来的 `no_profile`。
|
|
5624
|
+
*
|
|
5625
|
+
* apiOnly bot 在 {@link vcMeetingAgentConfigActive} 已返回 undefined,走不到这里,
|
|
5626
|
+
* 所以默认只加给结构上真能入会的 bot。纯函数,不改入参、不写盘。
|
|
5627
|
+
*/
|
|
5628
|
+
function withDefaultVcMeetingJoinProfile(larkAppId, cfg) {
|
|
5629
|
+
if (cfg.larkCliProfile?.trim())
|
|
5630
|
+
return cfg;
|
|
5631
|
+
const appId = larkAppId.trim();
|
|
5632
|
+
if (!appId)
|
|
5633
|
+
return cfg;
|
|
5634
|
+
return { ...cfg, larkCliProfile: appId };
|
|
5432
5635
|
}
|
|
5433
5636
|
function configuredVcMeetingListenerChatId(cfg) {
|
|
5434
5637
|
return cfg.listenerChatId ?? cfg.notificationChatId;
|
|
@@ -5557,7 +5760,7 @@ function restoreVcMeetingRuntimeSessionsForBot(larkAppId, cfg) {
|
|
|
5557
5760
|
session.consumerPaused = migratePreparedConsumer ? false : record.consumerPaused;
|
|
5558
5761
|
if (session.consumerMode === 'agent')
|
|
5559
5762
|
session.consumerLastInjectedAtMs = undefined;
|
|
5560
|
-
session.textOutputPolicy = record.textOutputPolicy ?? defaultVcMeetingTextOutputPolicy();
|
|
5763
|
+
session.textOutputPolicy = record.textOutputPolicy ?? defaultVcMeetingTextOutputPolicy(cfg);
|
|
5561
5764
|
session.voiceOutputPolicy = record.voiceOutputPolicy ?? defaultVcMeetingVoiceOutputPolicy(cfg);
|
|
5562
5765
|
session.syncIntervalMs = record.syncIntervalMs;
|
|
5563
5766
|
session.consumerSelectionExpiresAt = record.consumerSelectionExpiresAt;
|
|
@@ -5727,32 +5930,36 @@ function restoreVcMeetingRuntimeSessionsForBot(larkAppId, cfg) {
|
|
|
5727
5930
|
}
|
|
5728
5931
|
async function maybeStartVcMeetingRealtimeVoice(larkAppId, session, cfg) {
|
|
5729
5932
|
const voiceCfg = cfg.realtimeVoice;
|
|
5730
|
-
if (
|
|
5933
|
+
if (!vcMeetingRealtimeVoiceEnabled(cfg))
|
|
5934
|
+
return;
|
|
5935
|
+
// 按需建连:实时语音能力默认开,但入会时**不**急着开语音 WS——真正要发言时
|
|
5936
|
+
// deliverVcMeetingVoiceOutput 会按需 ensureVcMeetingRealtimeVoiceSession 建连,
|
|
5937
|
+
// 纯监听 / 从不发言的 bot 不挂空闲连接。唯一在入会时就预热的情况是显式配了
|
|
5938
|
+
// testSpeakOnStartText 的 dogfood 场景(要在入会瞬间说一句自检话)。
|
|
5939
|
+
if (!voiceCfg?.testSpeakOnStartText || session.realtimeVoiceTestUtteranceSent)
|
|
5731
5940
|
return;
|
|
5732
5941
|
try {
|
|
5733
5942
|
const voice = await ensureVcMeetingRealtimeVoiceSession(larkAppId, session, cfg);
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
})();
|
|
5755
|
-
}
|
|
5943
|
+
session.realtimeVoiceTestUtteranceSent = true;
|
|
5944
|
+
void (async () => {
|
|
5945
|
+
let sent = false;
|
|
5946
|
+
try {
|
|
5947
|
+
const r = await voice.speak(voiceCfg.testSpeakOnStartText);
|
|
5948
|
+
sent = true;
|
|
5949
|
+
logger.info(`[vc-agent] realtime voice test utterance sent meeting=${session.state.meeting.id} frames=${r.frames} durationMs=${r.durationMs}`);
|
|
5950
|
+
await delay(DEFAULT_VC_REALTIME_TEST_SPEAK_CLOSE_GRACE_MS);
|
|
5951
|
+
}
|
|
5952
|
+
catch (err) {
|
|
5953
|
+
logger.warn(`[vc-agent] realtime voice test utterance failed meeting=${session.state.meeting.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5954
|
+
}
|
|
5955
|
+
finally {
|
|
5956
|
+
await voice.stop(sent ? 'test-speak-finished' : 'test-speak-failed').catch((err) => {
|
|
5957
|
+
logger.warn(`[vc-agent] realtime voice test utterance stop failed meeting=${session.state.meeting.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5958
|
+
});
|
|
5959
|
+
if (session.realtimeVoice === voice)
|
|
5960
|
+
session.realtimeVoice = undefined;
|
|
5961
|
+
}
|
|
5962
|
+
})();
|
|
5756
5963
|
}
|
|
5757
5964
|
catch (err) {
|
|
5758
5965
|
await session.realtimeVoice?.stop('start-failed').catch(() => { });
|
|
@@ -5761,9 +5968,9 @@ async function maybeStartVcMeetingRealtimeVoice(larkAppId, session, cfg) {
|
|
|
5761
5968
|
}
|
|
5762
5969
|
}
|
|
5763
5970
|
async function ensureVcMeetingRealtimeVoiceSession(larkAppId, session, cfg) {
|
|
5764
|
-
|
|
5765
|
-
if (voiceCfg?.enabled !== true)
|
|
5971
|
+
if (!vcMeetingRealtimeVoiceEnabled(cfg))
|
|
5766
5972
|
throw new Error('realtime voice is disabled');
|
|
5973
|
+
const voiceCfg = cfg.realtimeVoice;
|
|
5767
5974
|
if (session.realtimeVoice && (session.realtimeVoice.status === 'failed' || session.realtimeVoice.status === 'stopped')) {
|
|
5768
5975
|
await session.realtimeVoice.stop('rebuild-stale-session').catch((err) => {
|
|
5769
5976
|
logger.warn(`[vc-agent] stale realtime voice cleanup failed meeting=${session.state.meeting.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -5780,9 +5987,9 @@ async function ensureVcMeetingRealtimeVoiceSession(larkAppId, session, cfg) {
|
|
|
5780
5987
|
protocol: createProtoRealtimeVoiceProtocol(),
|
|
5781
5988
|
transport,
|
|
5782
5989
|
audioFormat: {
|
|
5783
|
-
...(voiceCfg
|
|
5784
|
-
...(voiceCfg
|
|
5785
|
-
...(voiceCfg
|
|
5990
|
+
...(voiceCfg?.sampleRate !== undefined ? { sampleRate: voiceCfg.sampleRate } : {}),
|
|
5991
|
+
...(voiceCfg?.channels !== undefined ? { channels: voiceCfg.channels } : {}),
|
|
5992
|
+
...(voiceCfg?.frameMs !== undefined ? { frameMs: voiceCfg.frameMs } : {}),
|
|
5786
5993
|
},
|
|
5787
5994
|
});
|
|
5788
5995
|
}
|
|
@@ -5907,7 +6114,7 @@ function getOrCreateVcMeetingDaemonSession(larkAppId, meeting, cfg, opts = {}) {
|
|
|
5907
6114
|
monitoringStarted: false,
|
|
5908
6115
|
...(listenerChatId ? { listenerChatId } : {}),
|
|
5909
6116
|
pendingItems: [],
|
|
5910
|
-
textOutputPolicy: defaultVcMeetingTextOutputPolicy(),
|
|
6117
|
+
textOutputPolicy: defaultVcMeetingTextOutputPolicy(cfg),
|
|
5911
6118
|
voiceOutputPolicy: defaultVcMeetingVoiceOutputPolicy(cfg),
|
|
5912
6119
|
pendingOutputRequests: {},
|
|
5913
6120
|
consumerPendingItems: [],
|
|
@@ -5937,7 +6144,7 @@ function getOrCreateVcMeetingDaemonSession(larkAppId, meeting, cfg, opts = {}) {
|
|
|
5937
6144
|
session.listenerChatId = listenerChatId;
|
|
5938
6145
|
session.state.notificationChatId = listenerChatId;
|
|
5939
6146
|
}
|
|
5940
|
-
session.textOutputPolicy ??= defaultVcMeetingTextOutputPolicy();
|
|
6147
|
+
session.textOutputPolicy ??= defaultVcMeetingTextOutputPolicy(cfg);
|
|
5941
6148
|
session.voiceOutputPolicy ??= defaultVcMeetingVoiceOutputPolicy(cfg);
|
|
5942
6149
|
session.pendingOutputRequests ??= {};
|
|
5943
6150
|
session.consumerPendingItems ??= [];
|
|
@@ -8322,7 +8529,11 @@ function vcMeetingConsumerHasFastSignal(session, cfg, items) {
|
|
|
8322
8529
|
: item.type === 'transcript_received'
|
|
8323
8530
|
? item.speaker
|
|
8324
8531
|
: undefined;
|
|
8325
|
-
|
|
8532
|
+
// Any speech/chat from an instruction source (the authorizing user) is a
|
|
8533
|
+
// fast signal — not only questions. Waiting out the regular flush tick on
|
|
8534
|
+
// the operator's own words made the agent feel unresponsive in-meeting;
|
|
8535
|
+
// other participants still batch on the normal cadence.
|
|
8536
|
+
if (isInstructionSource(actor))
|
|
8326
8537
|
return true;
|
|
8327
8538
|
}
|
|
8328
8539
|
return false;
|
|
@@ -11699,6 +11910,42 @@ async function restoreVcMeetingMonitoringAfterObservedJoin(key, session, cfg, oc
|
|
|
11699
11910
|
await resolveVcMeetingListenerRejoinCard(session, cfg, 'rejoined');
|
|
11700
11911
|
logger.info(`[vc-agent] listener monitoring restored from own join event meeting=${session.state.meeting.id}`);
|
|
11701
11912
|
}
|
|
11913
|
+
/**
|
|
11914
|
+
* 入会即预热会议 agent 的 CLI 会话——复用「进群自动开工」(handleBotAdded)而不是走
|
|
11915
|
+
* VC delivery 冷 fork,把 bot 刚进监听群时就把会话冷起来待命,首条字幕/弹幕来了秒回
|
|
11916
|
+
* (否则要等选择卡默认生效 + 首次投递,实测 ~28s)。
|
|
11917
|
+
*
|
|
11918
|
+
* 为什么安全复用 handleBotAdded:
|
|
11919
|
+
* - Plan B 下会议 agent 本就是这个监听群的普通 chat-scope 会话,key = sessionKey(
|
|
11920
|
+
* chatId, appId);handleBotAdded 普通群 chat-scope 会话同 key。预热出来的正是后面
|
|
11921
|
+
* VC 投递 `ensureVcMeetingReceiverSession` 会 adopt 的那个(它见已有会话只 stamp
|
|
11922
|
+
* binding、不另建),零重复会话、零 delivery 机制改动。
|
|
11923
|
+
* - forcePrompt='' 绕过 autoStartOnGroupJoin 开关(入会预热是我们主动的),D7(群里
|
|
11924
|
+
* 要有 allowedUser)照跑——监听群有 owner,天然过。空 prompt = 模型自己读群上下文
|
|
11925
|
+
* (与场景① D8 一致),不塞合成指令。
|
|
11926
|
+
*
|
|
11927
|
+
* **只在会落到 chat-scope 时预热**:若这个 bot 的普通群回复模式是 new-topic,
|
|
11928
|
+
* handleBotAdded 会给监听群开一个话题(thread-scope,锚点漂移),就和 VC 固定的
|
|
11929
|
+
* chat key 岔开、可能双开会话。这种情况跳过预热,退回老的懒启动(无回归)。
|
|
11930
|
+
* best-effort:任何失败只 warn,会话仍会在首次投递时冷 fork。
|
|
11931
|
+
*/
|
|
11932
|
+
async function warmSpawnVcMeetingAgentSession(larkAppId, listenerChatId, meeting) {
|
|
11933
|
+
try {
|
|
11934
|
+
// 监听群是新建的普通群(createGroupWithBots),mode='group';只有当这个 bot 的普通群
|
|
11935
|
+
// 回复模式是 new-topic 时 handleBotAdded 才会开话题,那时跳过以免与 VC chat key 岔开。
|
|
11936
|
+
const regularGroupMode = resolveRegularGroupMode(larkAppId, listenerChatId);
|
|
11937
|
+
if (externalEventOpensOwnTopic('group', regularGroupMode)) {
|
|
11938
|
+
logger.info(`[vc-agent] skip warm-spawn for meeting=${meeting.id} chat=${listenerChatId}: `
|
|
11939
|
+
+ `bot reply mode opens a topic (would diverge from the chat-scope meeting key)`);
|
|
11940
|
+
return;
|
|
11941
|
+
}
|
|
11942
|
+
await handleBotAdded(listenerChatId, undefined, larkAppId, { forcePrompt: '' });
|
|
11943
|
+
}
|
|
11944
|
+
catch (err) {
|
|
11945
|
+
logger.warn(`[vc-agent] warm-spawn on join failed meeting=${meeting.id} chat=${listenerChatId}: `
|
|
11946
|
+
+ `${err instanceof Error ? err.message : String(err)} (falling back to lazy spawn on first delivery)`);
|
|
11947
|
+
}
|
|
11948
|
+
}
|
|
11702
11949
|
async function startVcMeetingMonitoring(input) {
|
|
11703
11950
|
if (!input.forceJoin
|
|
11704
11951
|
&& input.session.monitoringStarted
|
|
@@ -11786,6 +12033,13 @@ async function startVcMeetingMonitoring(input) {
|
|
|
11786
12033
|
persistVcMeetingRuntimeSession(session, input.cfg);
|
|
11787
12034
|
scheduleVcMeetingListenerFlush(currentKey, input.cfg);
|
|
11788
12035
|
void maybeStartVcMeetingRealtimeVoice(input.larkAppId, session, input.cfg);
|
|
12036
|
+
// 入会即预热 CLI:监听群一建好就把这个 bot 的会话冷起来待命,而不是等第一条
|
|
12037
|
+
// 字幕/弹幕投递才冷 fork(实测那要 ~28s)。复用「进群自动开工」的 handleBotAdded
|
|
12038
|
+
// ——不碰 VC delivery/attribution 机制,且 Plan B 下会议 agent 本就是这个监听群的
|
|
12039
|
+
// 普通 chat-scope 会话(sessionKey(chatId,appId)),与 handleBotAdded 普通群 chat
|
|
12040
|
+
// 会话同 key:预热出来的正是后面 VC 投递会 adopt 的那个,零重复会话。best-effort,
|
|
12041
|
+
// 失败只 warn(会话仍会在首次投递时按老路径冷 fork)。
|
|
12042
|
+
void warmSpawnVcMeetingAgentSession(input.larkAppId, listenerChatId, meeting);
|
|
11789
12043
|
await sendMessage(input.larkAppId, listenerChatId, formatVcMeetingStartMessage(meeting, input.cfg), 'text', `vc_${meeting.id.slice(-12)}_start`).catch((err) => {
|
|
11790
12044
|
logger.warn(`[vc-agent] listener start message failed meeting=${meeting.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
11791
12045
|
});
|
|
@@ -13363,6 +13617,8 @@ export const __vcMeetingAgentTest = {
|
|
|
13363
13617
|
if (cfg)
|
|
13364
13618
|
restoreVcMeetingRuntimeSessionsForBot(larkAppId, cfg);
|
|
13365
13619
|
},
|
|
13620
|
+
/** 测试用:读某个 bot 的有效 VC 配置(含共享目录绑定 + larkCliProfile 默认值)。 */
|
|
13621
|
+
effectiveConfig: (larkAppId) => effectiveVcMeetingAgentConfig(larkAppId),
|
|
13366
13622
|
reset: () => {
|
|
13367
13623
|
for (const session of vcMeetingSessions.values()) {
|
|
13368
13624
|
if (session.flushTimer)
|
|
@@ -14102,6 +14358,7 @@ async function startInitialPassthroughSession(args) {
|
|
|
14102
14358
|
session.quoteTargetSenderIsBot = resolvedSenderIsBot;
|
|
14103
14359
|
session.lastMessageAt = new Date(now).toISOString();
|
|
14104
14360
|
session.scope = scope;
|
|
14361
|
+
fillNativeTopicId(session, scope, parsed.threadId);
|
|
14105
14362
|
sessionStore.updateSession(session);
|
|
14106
14363
|
const { pinnedWorkingDir, oncallEntry, inheritedFrom, pinnedFromBotDefault } = await resolvePinnedWorkingDir({ scope, anchor, chatId, chatType, larkAppId });
|
|
14107
14364
|
// Auto-worktree: register PENDING (router buffers, no force-fork) and build the
|
|
@@ -14286,19 +14543,20 @@ async function handleNewTopic(data, ctx) {
|
|
|
14286
14543
|
* (handleNewTopicAdmitted + handleThreadReplyAdmitted), so a plain-human turn is
|
|
14287
14544
|
* authorized identically whether it opens a new topic or continues one (R6/R7-B1).
|
|
14288
14545
|
*
|
|
14289
|
-
* FAIL-CLOSED by construction (R7-B1): authorization requires a POSITIVE
|
|
14290
|
-
* `humanSender` (senderType === 'user' AND not a known peer bot)
|
|
14291
|
-
*
|
|
14292
|
-
*
|
|
14293
|
-
*
|
|
14294
|
-
* gate makes the default deny: anything that is not provably a real human turn
|
|
14295
|
-
* with no special semantics stays forced-serial.
|
|
14546
|
+
* FAIL-CLOSED by construction (R7-B1): authorization requires either a POSITIVE
|
|
14547
|
+
* `humanSender` (senderType === 'user' AND not a known peer bot), or a known peer
|
|
14548
|
+
* bot carrying the explicit `@steer` directive. Both lanes must also have no
|
|
14549
|
+
* control-rewrite / dedicated-receiver signal. Anything not positively matched
|
|
14550
|
+
* by one of those lanes stays forced-serial.
|
|
14296
14551
|
*/
|
|
14297
14552
|
function computeCodexAppSteerable(facts) {
|
|
14298
|
-
|
|
14299
|
-
&& !facts.adopted
|
|
14553
|
+
const plainHuman = facts.humanSender
|
|
14300
14554
|
&& !facts.isForeignBot
|
|
14301
|
-
&& !facts.isBotSenderType
|
|
14555
|
+
&& !facts.isBotSenderType;
|
|
14556
|
+
const explicitBotSteer = facts.explicitBotSteer
|
|
14557
|
+
&& facts.isForeignBot;
|
|
14558
|
+
return (plainHuman || explicitBotSteer)
|
|
14559
|
+
&& !facts.adopted
|
|
14302
14560
|
&& !facts.substituteTrigger
|
|
14303
14561
|
&& !facts.controlRewrite
|
|
14304
14562
|
&& !facts.messageListener
|
|
@@ -14409,6 +14667,19 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14409
14667
|
// every event that flows through us teaches the cache without touching
|
|
14410
14668
|
// the contact API. Must run before any await on the sender resolver.
|
|
14411
14669
|
learnFromMentions(larkAppId, parsed.mentions);
|
|
14670
|
+
const senderOpenId = data.sender?.sender_id?.open_id;
|
|
14671
|
+
const isBotSenderType = data.sender?.sender_type === 'app' || data.sender?.sender_type === 'bot';
|
|
14672
|
+
const isForeignBotSender = isBotSenderType
|
|
14673
|
+
|| (!!senderOpenId && senderOpenId !== getBot(larkAppId).botOpenId
|
|
14674
|
+
&& isKnownPeerBot(config.session.dataDir, larkAppId, senderOpenId));
|
|
14675
|
+
// `@steer` is a generic bot-to-bot transport directive, not model content.
|
|
14676
|
+
// Consume it only from a positively classified bot sender; a human writing
|
|
14677
|
+
// the same text keeps the literal body (human turns are already steerable).
|
|
14678
|
+
const botSteerDirective = isForeignBotSender
|
|
14679
|
+
? parseBotSteerDirective(parsed.content)
|
|
14680
|
+
: { requested: false, content: parsed.content };
|
|
14681
|
+
if (botSteerDirective.requested)
|
|
14682
|
+
parsed.content = botSteerDirective.content;
|
|
14412
14683
|
const followupContent = parsed.content.trim();
|
|
14413
14684
|
let content = composeForwardFollowupContent(forwardSeedContent, followupContent);
|
|
14414
14685
|
// Strip leading @<bot> mentions so "@bot /oncall bind" is recognized as a command.
|
|
@@ -14420,7 +14691,6 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14420
14691
|
// (already thread-scope) it's just a prefix strip — no routing change.
|
|
14421
14692
|
// Empty prompt is allowed: later setup chooses either a repo picker or a
|
|
14422
14693
|
// visible thread that waits for the first real task, without an empty worker.
|
|
14423
|
-
const senderOpenId = data.sender?.sender_id?.open_id;
|
|
14424
14694
|
const forceTopic = parseForceTopicInvocation(cmdContent);
|
|
14425
14695
|
if (forceTopic) {
|
|
14426
14696
|
if (await replyGrantRestrictionIfNeeded(larkAppId, chatId, senderOpenId, anchor, forceTopicCommandLabel(cmdContent))) {
|
|
@@ -14449,7 +14719,6 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14449
14719
|
// 飞书盖章的 bot 发送方。既锁 union 信任腿(下面的 teamTrustUnionId),也决定
|
|
14450
14720
|
// talk 复查走哪个谓词(evaluateBotTalk vs evaluateTalk)——两者必须同源,见
|
|
14451
14721
|
// enforceMessageQuotaForCliInput 的 botSender 说明。
|
|
14452
|
-
const isBotSenderType = data.sender?.sender_type === 'app' || data.sender?.sender_type === 'bot';
|
|
14453
14722
|
const teamTrustUnionId = isBotSenderType ? senderUnionId : undefined;
|
|
14454
14723
|
// A bot-sent new topic (e.g. a message-listener match on a third-party alert
|
|
14455
14724
|
// bot's card) must NOT make that bot the session owner: daemon-generated
|
|
@@ -14458,9 +14727,6 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14458
14727
|
// surfaces (restart/report/cards) to it. Mirror the handleThreadReply +
|
|
14459
14728
|
// auto-create paths (isForeignBot → ownerOpenId/ownerUnionId undefined); keep
|
|
14460
14729
|
// creatorOpenId + quoteTarget* so botmux report / first-turn quote still work.
|
|
14461
|
-
const isForeignBotSender = isBotSenderType
|
|
14462
|
-
|| (!!senderOpenId && senderOpenId !== getBot(larkAppId).botOpenId
|
|
14463
|
-
&& isKnownPeerBot(config.session.dataDir, larkAppId, senderOpenId));
|
|
14464
14730
|
const ownerOpenIdForSession = isForeignBotSender ? undefined : senderOpenId;
|
|
14465
14731
|
const ownerUnionIdForSession = isForeignBotSender ? undefined : senderUnionId;
|
|
14466
14732
|
const botCfg = getBot(larkAppId).config;
|
|
@@ -14682,6 +14948,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14682
14948
|
session.lastCallerOpenId = senderOpenId;
|
|
14683
14949
|
session.lastMessageAt = new Date(now).toISOString();
|
|
14684
14950
|
session.scope = scope;
|
|
14951
|
+
fillNativeTopicId(session, scope, parsed.threadId);
|
|
14685
14952
|
// First-message `/repo`: seed the same pending-repo state the card flow
|
|
14686
14953
|
// uses, so the `/repo` handler launches the CLI straight away —
|
|
14687
14954
|
// `/repo <arg>` in that repo, bare `/repo` in the default workingDir —
|
|
@@ -14890,6 +15157,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14890
15157
|
session.quoteTargetSenderIsBot = isForeignBotSender || parsed.senderType === 'app' || parsed.senderType === 'bot';
|
|
14891
15158
|
session.lastMessageAt = new Date(now).toISOString();
|
|
14892
15159
|
session.scope = scope;
|
|
15160
|
+
fillNativeTopicId(session, scope, parsed.threadId);
|
|
14893
15161
|
session.nativeSessionTitle = buildBotmuxLarkNativeSessionTitle(parsed.content, parsed.mentions, groupChatName);
|
|
14894
15162
|
sessionStore.updateSession(session);
|
|
14895
15163
|
// Control card compensates for the card-less (avatar-style) chat-scope
|
|
@@ -14927,8 +15195,10 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14927
15195
|
pendingSubstituteTrigger: substituteTrigger,
|
|
14928
15196
|
pendingSubstituteControlCard: shouldSendSubstituteControlCard,
|
|
14929
15197
|
pendingSender: newTopicSender,
|
|
14930
|
-
//
|
|
14931
|
-
//
|
|
15198
|
+
// Freeze steer authorization into the NEW-TOPIC opening metadata from
|
|
15199
|
+
// inbound source facts (the same helper the follow-up twin uses). The two
|
|
15200
|
+
// allowed lanes are a plain human turn and a foreign bot carrying the
|
|
15201
|
+
// explicit, language-neutral `@steer` directive; ordinary bot traffic is serial.
|
|
14932
15202
|
// A brand-new session has no VC receiver yet; foreign-bot maps to the bot-sender
|
|
14933
15203
|
// fact here. buildReservedInitialInput COPIES this onto the opening payload;
|
|
14934
15204
|
// forkReservedInitialSession never infers it.
|
|
@@ -14944,6 +15214,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14944
15214
|
isForeignBot: isBotSenderType
|
|
14945
15215
|
|| isKnownPeerBot(config.session.dataDir, larkAppId, senderOpenId),
|
|
14946
15216
|
isBotSenderType,
|
|
15217
|
+
explicitBotSteer: botSteerDirective.requested,
|
|
14947
15218
|
substituteTrigger: !!substituteTrigger,
|
|
14948
15219
|
controlRewrite: !!newTopicGrill,
|
|
14949
15220
|
messageListener: !!messageListener,
|
|
@@ -15579,18 +15850,29 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15579
15850
|
}
|
|
15580
15851
|
}
|
|
15581
15852
|
export const __testOnly_handleBotAdded = handleBotAdded;
|
|
15582
|
-
/** Reverse-lookup a foreign bot's display name for a sender
|
|
15583
|
-
*
|
|
15853
|
+
/** Reverse-lookup a foreign bot's display name for a sender observed on this
|
|
15854
|
+
* app's WS events. Priority:
|
|
15855
|
+
* 0) union_id → current sibling name — rename-proof. The sender's tenant-
|
|
15856
|
+
* stable union_id (stamped on the event) maps to the one locally-configured
|
|
15857
|
+
* sibling that learned it, whose bots-info.json botName is rewritten by its
|
|
15858
|
+
* OWN daemon on every rename. This is the only source that reflects a rename
|
|
15859
|
+
* when the renamed bot merely SENDS to us (no @ of it flows through us, so
|
|
15860
|
+
* the by-name cross-ref below never refreshes on that event).
|
|
15584
15861
|
* 1) bot-openids-${larkAppId}.json — per-app cross-ref populated by
|
|
15585
15862
|
* updateBotOpenIdCrossRef when @mentions go through us. Open_id is
|
|
15586
15863
|
* per-app scoped, so this is the authoritative map for this larkAppId.
|
|
15864
|
+
* (The writer now evicts pre-rename aliases, so a stale name here self-heals
|
|
15865
|
+
* the next time that bot is @-mentioned by its new name.)
|
|
15587
15866
|
* 2) bots-info.json — fallback for bots not yet in our cross-ref but
|
|
15588
15867
|
* registered as botmux peers (matches by their self-reported open_id;
|
|
15589
15868
|
* only works when the peer's app id space coincides with ours).
|
|
15590
|
-
* Returns "Bot" if
|
|
15591
|
-
*
|
|
15869
|
+
* Returns "Bot" if nothing hits — keeps the prefix readable rather than
|
|
15870
|
+
* blocking the message.
|
|
15592
15871
|
*/
|
|
15593
|
-
function lookupForeignBotName(senderOpenId, larkAppId) {
|
|
15872
|
+
function lookupForeignBotName(senderOpenId, larkAppId, senderUnionId) {
|
|
15873
|
+
const currentName = resolveSiblingBotNameByUnionId(config.session.dataDir, larkAppId, senderUnionId);
|
|
15874
|
+
if (currentName)
|
|
15875
|
+
return currentName;
|
|
15594
15876
|
for (const [name, openId] of Object.entries(readPeerCrossRef(config.session.dataDir, larkAppId))) {
|
|
15595
15877
|
if (openId === senderOpenId)
|
|
15596
15878
|
return name;
|
|
@@ -15660,7 +15942,13 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
15660
15942
|
senderOpenIdForPrefix !== selfBotOpenId &&
|
|
15661
15943
|
(isBotSenderType ||
|
|
15662
15944
|
isKnownPeerBot(config.session.dataDir, larkAppId, senderOpenIdForPrefix));
|
|
15663
|
-
const
|
|
15945
|
+
const botSteerDirective = isForeignBot
|
|
15946
|
+
? parseBotSteerDirective(parsed.content)
|
|
15947
|
+
: { requested: false, content: parsed.content };
|
|
15948
|
+
if (botSteerDirective.requested)
|
|
15949
|
+
parsed.content = botSteerDirective.content;
|
|
15950
|
+
const senderUnionIdForPrefix = parsed.senderUnionId || data?.sender?.sender_id?.union_id;
|
|
15951
|
+
const foreignBotName = isForeignBot ? lookupForeignBotName(senderOpenIdForPrefix, larkAppId, senderUnionIdForPrefix) : undefined;
|
|
15664
15952
|
const botSenderPrefix = isForeignBot
|
|
15665
15953
|
? `${tr('daemon.foreign_bot_mention_prefix', { botName: foreignBotName }, localeForBot(larkAppId))}\n`
|
|
15666
15954
|
: '';
|
|
@@ -15971,6 +16259,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
15971
16259
|
session.lastCallerOpenId = threadSenderOpenId;
|
|
15972
16260
|
session.lastMessageAt = new Date(now).toISOString();
|
|
15973
16261
|
session.scope = scope;
|
|
16262
|
+
fillNativeTopicId(session, scope, parsed.threadId);
|
|
15974
16263
|
let cmdPending;
|
|
15975
16264
|
if (cmd === '/repo') {
|
|
15976
16265
|
const { pinnedWorkingDir } = await resolvePinnedWorkingDir({ scope, anchor, chatId: threadChatId, chatType: ctxChatType, larkAppId });
|
|
@@ -16063,6 +16352,10 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16063
16352
|
}
|
|
16064
16353
|
logger.info(`Reply in ${scope}-scope session ${anchor.substring(0, 12)}: ${content.substring(0, 100)} (resources: ${resources.length})`);
|
|
16065
16354
|
let ds = activeSessions.get(sessionKey(anchor, larkAppId));
|
|
16355
|
+
if (ds && fillNativeTopicId(ds.session, scope, parsed.threadId)) {
|
|
16356
|
+
sessionStore.updateSession(ds.session);
|
|
16357
|
+
publishNativeTopicLinkPatch(ds);
|
|
16358
|
+
}
|
|
16066
16359
|
// If another bot already owns this anchor, ignore unmentioned replies here as a
|
|
16067
16360
|
// second line of defense. Explicit @mentions are still allowed to spin up/take over.
|
|
16068
16361
|
// For chat-scope: another bot's session in the same chat is keyed by its own chatId.
|
|
@@ -16193,14 +16486,15 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16193
16486
|
// opening path — would silently drop it. When a claim token IS held (a
|
|
16194
16487
|
// concurrent first turn owns the opening) or a queued-activation ACK is
|
|
16195
16488
|
// pending, a live worker MUST keep buffering to preserve FIFO submission order.
|
|
16196
|
-
// Codex App steer authorization
|
|
16489
|
+
// Codex App steer authorization — computed ONCE here,
|
|
16197
16490
|
// BEFORE every admission/fork branch below (R5-B1-1): the earliest tail-admit
|
|
16198
16491
|
// (initialStartPending follower), pending-repo follower, worker-null refork,
|
|
16199
16492
|
// and new-topic auto-create paths all need the same frozen value, and several
|
|
16200
16493
|
// of them return before the later existing-owner branch. Explicit positive
|
|
16201
|
-
//
|
|
16202
|
-
//
|
|
16203
|
-
//
|
|
16494
|
+
// only for a plain-human-interactive turn or a foreign bot carrying an
|
|
16495
|
+
// explicit `@steer` directive. Plain @mentions, reports, other bot traffic,
|
|
16496
|
+
// substitute-rewrite, v3-grill, message-listener, VC and adopt stay serial.
|
|
16497
|
+
// Never inferred from the delivery sink;
|
|
16204
16498
|
// ignored by acceptCodexAppDispatch for non-codex-app CLIs. A new-topic root
|
|
16205
16499
|
// must FREEZE this into its opening payload — forkReservedInitialSession is
|
|
16206
16500
|
// shared by bot-added / scheduler / system bootstrap and only COPIES an
|
|
@@ -16212,6 +16506,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16212
16506
|
adopted: !!ds?.adoptedFrom,
|
|
16213
16507
|
isForeignBot,
|
|
16214
16508
|
isBotSenderType,
|
|
16509
|
+
explicitBotSteer: botSteerDirective.requested,
|
|
16215
16510
|
substituteTrigger: !!substituteTrigger,
|
|
16216
16511
|
controlRewrite: !!threadGrill,
|
|
16217
16512
|
messageListener: !!ctx.messageListener,
|
|
@@ -16521,6 +16816,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16521
16816
|
session.quoteTargetSenderIsBot = isForeignBot;
|
|
16522
16817
|
session.lastMessageAt = new Date(now).toISOString();
|
|
16523
16818
|
session.scope = scope;
|
|
16819
|
+
fillNativeTopicId(session, scope, parsed.threadId);
|
|
16524
16820
|
const groupChatName = await groupChatNamePromise;
|
|
16525
16821
|
if (groupChatName)
|
|
16526
16822
|
session.chatDisplayName = groupChatName;
|
|
@@ -17813,23 +18109,15 @@ export async function startDaemon(botIndex) {
|
|
|
17813
18109
|
botConfigs = loadBotConfigs();
|
|
17814
18110
|
cfg = loadBotConfigAtIndex(idx);
|
|
17815
18111
|
}
|
|
17816
|
-
//
|
|
17817
|
-
//
|
|
17818
|
-
//
|
|
17819
|
-
//
|
|
17820
|
-
//
|
|
18112
|
+
// 这里曾经有一次「给本 bot 播种默认会议角色预设」的启动写盘。已退役:角色预设
|
|
18113
|
+
// 改成全 fleet 共享目录 + 读路径内置默认(services/vc-meeting-shared-consumer-
|
|
18114
|
+
// catalog.ts),没有任何 bot 还需要自己那份 per-bot 拷贝。退役的两个理由:
|
|
18115
|
+
// 1. 播种出来的 per-bot `consumerProfiles` 会永久遮蔽共享目录——操作者在
|
|
18116
|
+
// Dashboard 改共享预设,被播种过的 bot 完全不跟随;
|
|
18117
|
+
// 2. 那次写盘还会把「另一个 bot」的 appId 焊进预设(旧的换人兜底),正是
|
|
18118
|
+
// 「拉 A 进会却把 B 拉进监听群」的源头。
|
|
18119
|
+
// 现在启动路径对 VC 预设零写盘,fleet 里几十个 daemon 同时启动也不再有写竞争。
|
|
17821
18120
|
const selectedAppId = cfg.larkAppId;
|
|
17822
|
-
const profileBootstrap = await bootstrapVcMeetingDefaultConsumerProfile(selectedAppId);
|
|
17823
|
-
if (profileBootstrap.ok) {
|
|
17824
|
-
if (profileBootstrap.seeded) {
|
|
17825
|
-
logger.info(`[vc-agent] seeded default meeting minutes profile listener=${selectedAppId} `
|
|
17826
|
-
+ `agent=${profileBootstrap.agentAppId}`);
|
|
17827
|
-
}
|
|
17828
|
-
}
|
|
17829
|
-
else if (!profileBootstrap.ok) {
|
|
17830
|
-
logger.warn(`[vc-agent] default consumer profile bootstrap skipped: ${profileBootstrap.reason}`
|
|
17831
|
-
+ `${profileBootstrap.error ? ` (${profileBootstrap.error})` : ''}`);
|
|
17832
|
-
}
|
|
17833
18121
|
// A bootstrap failure is not authority to keep an earlier in-memory config.
|
|
17834
18122
|
// Every explicit PM2 daemon must prove its same raw slot and App identity
|
|
17835
18123
|
// immediately before registerBot, regardless of the bootstrap result.
|
|
@@ -18622,6 +18910,14 @@ export async function startDaemon(botIndex) {
|
|
|
18622
18910
|
checkRequiredScopes(cfg.larkAppId).catch(err => {
|
|
18623
18911
|
logger.debug(`[${cfg.larkAppId}] required-scope check failed: ${err?.message ?? err}`);
|
|
18624
18912
|
});
|
|
18913
|
+
// Ensure VC meeting events are subscribed so ANY invited bot can receive
|
|
18914
|
+
// meeting invites (bot-agnostic auto-join). Check-first + best-effort: a
|
|
18915
|
+
// read-only probe over the cached web session, auto-subscribing only when
|
|
18916
|
+
// events are missing. Never blocks boot; the fn itself skips VC-inactive
|
|
18917
|
+
// bots via vcMeetingAgentConfigActive.
|
|
18918
|
+
ensureVcMeetingEventsSubscribed(cfg.larkAppId).catch(err => {
|
|
18919
|
+
logger.debug(`[${cfg.larkAppId}] VC event subscription check failed: ${err?.message ?? err}`);
|
|
18920
|
+
});
|
|
18625
18921
|
}
|
|
18626
18922
|
// 主动开工 — 场景①: the bot.added event can't be self-verified via API, and
|
|
18627
18923
|
// if it isn't subscribed the handler simply never fires (no runtime signal).
|