botmux 3.15.0 → 3.16.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/README.en.md +2 -2
- package/README.md +2 -2
- package/dist/.runtime-build-id +1 -1
- package/dist/adapters/backend/destroy-result.d.ts +159 -0
- package/dist/adapters/backend/destroy-result.d.ts.map +1 -0
- package/dist/adapters/backend/destroy-result.js +223 -0
- package/dist/adapters/backend/destroy-result.js.map +1 -0
- package/dist/adapters/backend/herdr-backend.d.ts +4 -0
- package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
- package/dist/adapters/backend/herdr-backend.js +23 -1
- package/dist/adapters/backend/herdr-backend.js.map +1 -1
- package/dist/adapters/backend/mojo-backend.d.ts +577 -0
- package/dist/adapters/backend/mojo-backend.d.ts.map +1 -0
- package/dist/adapters/backend/mojo-backend.js +2471 -0
- package/dist/adapters/backend/mojo-backend.js.map +1 -0
- package/dist/adapters/backend/mojo-budgets.d.ts +21 -0
- package/dist/adapters/backend/mojo-budgets.d.ts.map +1 -0
- package/dist/adapters/backend/mojo-budgets.js +22 -0
- package/dist/adapters/backend/mojo-budgets.js.map +1 -0
- package/dist/adapters/backend/mojo-isolated-workspace.d.ts +69 -0
- package/dist/adapters/backend/mojo-isolated-workspace.d.ts.map +1 -0
- package/dist/adapters/backend/mojo-isolated-workspace.js +213 -0
- package/dist/adapters/backend/mojo-isolated-workspace.js.map +1 -0
- package/dist/adapters/backend/mojo-process-tree.d.ts +292 -0
- package/dist/adapters/backend/mojo-process-tree.d.ts.map +1 -0
- package/dist/adapters/backend/mojo-process-tree.js +486 -0
- package/dist/adapters/backend/mojo-process-tree.js.map +1 -0
- package/dist/adapters/backend/mojo-types.d.ts +542 -0
- package/dist/adapters/backend/mojo-types.d.ts.map +1 -0
- package/dist/adapters/backend/mojo-types.js +682 -0
- package/dist/adapters/backend/mojo-types.js.map +1 -0
- package/dist/adapters/backend/reproduce-command.js +3 -3
- package/dist/adapters/backend/reproduce-command.js.map +1 -1
- package/dist/adapters/backend/riff-backend.js +1 -1
- package/dist/adapters/backend/riff-backend.js.map +1 -1
- package/dist/adapters/backend/sandbox.d.ts +44 -7
- package/dist/adapters/backend/sandbox.d.ts.map +1 -1
- package/dist/adapters/backend/sandbox.js +30 -7
- package/dist/adapters/backend/sandbox.js.map +1 -1
- package/dist/adapters/backend/session-backend-selector.d.ts +14 -1
- package/dist/adapters/backend/session-backend-selector.d.ts.map +1 -1
- package/dist/adapters/backend/session-backend-selector.js +82 -10
- package/dist/adapters/backend/session-backend-selector.js.map +1 -1
- package/dist/adapters/backend/types.d.ts +101 -6
- package/dist/adapters/backend/types.d.ts.map +1 -1
- package/dist/adapters/backend/types.js.map +1 -1
- package/dist/adapters/backend/zmx-backend.d.ts +11 -0
- package/dist/adapters/backend/zmx-backend.d.ts.map +1 -1
- package/dist/adapters/backend/zmx-backend.js +16 -1
- package/dist/adapters/backend/zmx-backend.js.map +1 -1
- package/dist/adapters/cli/codex-app.d.ts.map +1 -1
- package/dist/adapters/cli/codex-app.js +2 -2
- 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 +7 -0
- package/dist/adapters/cli/codex.js.map +1 -1
- package/dist/adapters/cli/copilot.d.ts +3 -1
- package/dist/adapters/cli/copilot.d.ts.map +1 -1
- package/dist/adapters/cli/copilot.js +23 -5
- package/dist/adapters/cli/copilot.js.map +1 -1
- package/dist/adapters/cli/cursor.d.ts.map +1 -1
- package/dist/adapters/cli/cursor.js +13 -3
- package/dist/adapters/cli/cursor.js.map +1 -1
- package/dist/adapters/cli/grok.d.ts.map +1 -1
- package/dist/adapters/cli/grok.js +24 -5
- package/dist/adapters/cli/grok.js.map +1 -1
- package/dist/adapters/cli/kimi.d.ts.map +1 -1
- package/dist/adapters/cli/kimi.js +19 -1
- package/dist/adapters/cli/kimi.js.map +1 -1
- package/dist/adapters/cli/mojo.d.ts +28 -0
- package/dist/adapters/cli/mojo.d.ts.map +1 -0
- package/dist/adapters/cli/mojo.js +58 -0
- package/dist/adapters/cli/mojo.js.map +1 -0
- package/dist/adapters/cli/pi.d.ts +6 -4
- package/dist/adapters/cli/pi.d.ts.map +1 -1
- package/dist/adapters/cli/pi.js +6 -4
- package/dist/adapters/cli/pi.js.map +1 -1
- package/dist/adapters/cli/read-isolation.d.ts +251 -1
- package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
- package/dist/adapters/cli/read-isolation.js +254 -1
- package/dist/adapters/cli/read-isolation.js.map +1 -1
- package/dist/adapters/cli/registry.d.ts +13 -1
- package/dist/adapters/cli/registry.d.ts.map +1 -1
- package/dist/adapters/cli/registry.js +19 -1
- package/dist/adapters/cli/registry.js.map +1 -1
- package/dist/adapters/cli/runner-input.d.ts +3 -3
- package/dist/adapters/cli/runner-input.d.ts.map +1 -1
- package/dist/adapters/cli/runner-input.js +4 -3
- package/dist/adapters/cli/runner-input.js.map +1 -1
- package/dist/adapters/cli/shared-hints.d.ts +3 -1
- package/dist/adapters/cli/shared-hints.d.ts.map +1 -1
- package/dist/adapters/cli/shared-hints.js +22 -6
- package/dist/adapters/cli/shared-hints.js.map +1 -1
- package/dist/adapters/cli/types.d.ts +29 -4
- package/dist/adapters/cli/types.d.ts.map +1 -1
- package/dist/bot-registry.d.ts +20 -0
- package/dist/bot-registry.d.ts.map +1 -1
- package/dist/bot-registry.js +30 -4
- package/dist/bot-registry.js.map +1 -1
- package/dist/cli/arg-utils.d.ts +5 -0
- package/dist/cli/arg-utils.d.ts.map +1 -1
- package/dist/cli/arg-utils.js +7 -0
- package/dist/cli/arg-utils.js.map +1 -1
- package/dist/cli/bots-list-output.d.ts +130 -2
- package/dist/cli/bots-list-output.d.ts.map +1 -1
- package/dist/cli/bots-list-output.js +173 -27
- package/dist/cli/bots-list-output.js.map +1 -1
- package/dist/cli/daemon-lifecycle-env.d.ts +10 -3
- package/dist/cli/daemon-lifecycle-env.d.ts.map +1 -1
- package/dist/cli/daemon-lifecycle-env.js +38 -11
- package/dist/cli/daemon-lifecycle-env.js.map +1 -1
- package/dist/cli/dashboard-command.d.ts +15 -0
- package/dist/cli/dashboard-command.d.ts.map +1 -1
- package/dist/cli/dashboard-command.js +22 -0
- package/dist/cli/dashboard-command.js.map +1 -1
- package/dist/cli/log-tail.d.ts +54 -0
- package/dist/cli/log-tail.d.ts.map +1 -0
- package/dist/cli/log-tail.js +167 -0
- package/dist/cli/log-tail.js.map +1 -0
- package/dist/cli/pm2-env.d.ts +16 -0
- package/dist/cli/pm2-env.d.ts.map +1 -0
- package/dist/cli/pm2-env.js +63 -0
- package/dist/cli/pm2-env.js.map +1 -0
- package/dist/cli/pm2-fleet-lock.d.ts +26 -0
- package/dist/cli/pm2-fleet-lock.d.ts.map +1 -0
- package/dist/cli/pm2-fleet-lock.js +50 -0
- package/dist/cli/pm2-fleet-lock.js.map +1 -0
- package/dist/cli/pm2-god-retirement.d.ts +59 -0
- package/dist/cli/pm2-god-retirement.d.ts.map +1 -0
- package/dist/cli/pm2-god-retirement.js +95 -0
- package/dist/cli/pm2-god-retirement.js.map +1 -0
- package/dist/cli/session-list-wake.d.ts +41 -0
- package/dist/cli/session-list-wake.d.ts.map +1 -0
- package/dist/cli/session-list-wake.js +102 -0
- package/dist/cli/session-list-wake.js.map +1 -0
- package/dist/cli/workflow.d.ts.map +1 -1
- package/dist/cli/workflow.js +26 -0
- package/dist/cli/workflow.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +933 -115
- package/dist/cli.js.map +1 -1
- package/dist/codex-app-runner.js +261 -49
- package/dist/codex-app-runner.js.map +1 -1
- package/dist/core/cli-runtime-update.d.ts +8 -0
- package/dist/core/cli-runtime-update.d.ts.map +1 -1
- package/dist/core/cli-runtime-update.js +127 -8
- package/dist/core/cli-runtime-update.js.map +1 -1
- package/dist/core/close-residual.d.ts +64 -0
- package/dist/core/close-residual.d.ts.map +1 -0
- package/dist/core/close-residual.js +93 -0
- package/dist/core/close-residual.js.map +1 -0
- package/dist/core/closed-session-card.d.ts.map +1 -1
- package/dist/core/closed-session-card.js +11 -3
- package/dist/core/closed-session-card.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +129 -27
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/cost-calculator.d.ts +3 -1
- package/dist/core/cost-calculator.d.ts.map +1 -1
- package/dist/core/cost-calculator.js +230 -1
- package/dist/core/cost-calculator.js.map +1 -1
- package/dist/core/daemon-background-close.d.ts +19 -0
- package/dist/core/daemon-background-close.d.ts.map +1 -0
- package/dist/core/daemon-background-close.js +39 -0
- package/dist/core/daemon-background-close.js.map +1 -0
- package/dist/core/dashboard-command/overview.d.ts +4 -0
- package/dist/core/dashboard-command/overview.d.ts.map +1 -1
- package/dist/core/dashboard-command/overview.js +8 -1
- package/dist/core/dashboard-command/overview.js.map +1 -1
- package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
- package/dist/core/dashboard-ipc-server.js +373 -41
- package/dist/core/dashboard-ipc-server.js.map +1 -1
- package/dist/core/dashboard-rows.d.ts +4 -0
- package/dist/core/dashboard-rows.d.ts.map +1 -1
- package/dist/core/dashboard-rows.js +3 -0
- package/dist/core/dashboard-rows.js.map +1 -1
- package/dist/core/dashboard-url.d.ts +37 -0
- package/dist/core/dashboard-url.d.ts.map +1 -1
- package/dist/core/dashboard-url.js +71 -0
- package/dist/core/dashboard-url.js.map +1 -1
- package/dist/core/deferred-schedule-settlement.d.ts +15 -1
- package/dist/core/deferred-schedule-settlement.d.ts.map +1 -1
- package/dist/core/deferred-schedule-settlement.js +4 -1
- package/dist/core/deferred-schedule-settlement.js.map +1 -1
- package/dist/core/device-isolation-daemon.d.ts +91 -1
- package/dist/core/device-isolation-daemon.d.ts.map +1 -1
- package/dist/core/device-isolation-daemon.js +346 -2
- package/dist/core/device-isolation-daemon.js.map +1 -1
- package/dist/core/local-terminal-opener.d.ts.map +1 -1
- package/dist/core/local-terminal-opener.js +5 -1
- package/dist/core/local-terminal-opener.js.map +1 -1
- package/dist/core/loopback-target.d.ts +14 -0
- package/dist/core/loopback-target.d.ts.map +1 -0
- package/dist/core/loopback-target.js +20 -0
- package/dist/core/loopback-target.js.map +1 -0
- package/dist/core/maintenance.d.ts.map +1 -1
- package/dist/core/maintenance.js +16 -2
- package/dist/core/maintenance.js.map +1 -1
- package/dist/core/mojo-containment-command.d.ts +20 -0
- package/dist/core/mojo-containment-command.d.ts.map +1 -0
- package/dist/core/mojo-containment-command.js +266 -0
- package/dist/core/mojo-containment-command.js.map +1 -0
- package/dist/core/mojo-containment.d.ts +575 -0
- package/dist/core/mojo-containment.d.ts.map +1 -0
- package/dist/core/mojo-containment.js +1158 -0
- package/dist/core/mojo-containment.js.map +1 -0
- package/dist/core/mojo-launcher-env-quarantine.d.ts +30 -0
- package/dist/core/mojo-launcher-env-quarantine.d.ts.map +1 -0
- package/dist/core/mojo-launcher-env-quarantine.js +175 -0
- package/dist/core/mojo-launcher-env-quarantine.js.map +1 -0
- package/dist/core/mojo-session-identity.d.ts +3 -0
- package/dist/core/mojo-session-identity.d.ts.map +1 -0
- package/dist/core/mojo-session-identity.js +126 -0
- package/dist/core/mojo-session-identity.js.map +1 -0
- package/dist/core/persistent-backend.d.ts +32 -8
- package/dist/core/persistent-backend.d.ts.map +1 -1
- package/dist/core/persistent-backend.js +55 -17
- package/dist/core/persistent-backend.js.map +1 -1
- package/dist/core/plugins/mcp/gateway.d.ts +14 -1
- package/dist/core/plugins/mcp/gateway.d.ts.map +1 -1
- package/dist/core/plugins/mcp/gateway.js +70 -3
- package/dist/core/plugins/mcp/gateway.js.map +1 -1
- package/dist/core/plugins/mcp/host.d.ts +2 -0
- package/dist/core/plugins/mcp/host.d.ts.map +1 -1
- package/dist/core/plugins/mcp/host.js +2 -0
- package/dist/core/plugins/mcp/host.js.map +1 -1
- package/dist/core/plugins/pm2.d.ts.map +1 -1
- package/dist/core/plugins/pm2.js +16 -3
- package/dist/core/plugins/pm2.js.map +1 -1
- package/dist/core/plugins/service-manager.d.ts +9 -0
- package/dist/core/plugins/service-manager.d.ts.map +1 -1
- package/dist/core/plugins/service-manager.js +33 -16
- package/dist/core/plugins/service-manager.js.map +1 -1
- package/dist/core/preview-port-owner.d.ts +109 -0
- package/dist/core/preview-port-owner.d.ts.map +1 -0
- package/dist/core/preview-port-owner.js +320 -0
- package/dist/core/preview-port-owner.js.map +1 -0
- package/dist/core/remote-cli-ids.d.ts +5 -0
- package/dist/core/remote-cli-ids.d.ts.map +1 -0
- package/dist/core/remote-cli-ids.js +24 -0
- package/dist/core/remote-cli-ids.js.map +1 -0
- package/dist/core/{riff-shutdown-detach.d.ts → remote-shutdown-detach.d.ts} +40 -39
- package/dist/core/remote-shutdown-detach.d.ts.map +1 -0
- package/dist/core/{riff-shutdown-detach.js → remote-shutdown-detach.js} +85 -83
- package/dist/core/remote-shutdown-detach.js.map +1 -0
- package/dist/core/{riff-worker-shutdown-readiness.d.ts → remote-worker-shutdown-readiness.d.ts} +5 -4
- package/dist/core/remote-worker-shutdown-readiness.d.ts.map +1 -0
- package/dist/core/{riff-worker-shutdown-readiness.js → remote-worker-shutdown-readiness.js} +4 -3
- package/dist/core/remote-worker-shutdown-readiness.js.map +1 -0
- package/dist/core/reply-target.d.ts +16 -1
- package/dist/core/reply-target.d.ts.map +1 -1
- package/dist/core/reply-target.js +61 -0
- package/dist/core/reply-target.js.map +1 -1
- package/dist/core/session-group-birth.d.ts +26 -0
- package/dist/core/session-group-birth.d.ts.map +1 -1
- package/dist/core/session-group-birth.js +81 -4
- package/dist/core/session-group-birth.js.map +1 -1
- package/dist/core/session-manager.d.ts +15 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +259 -5
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-model.d.ts +46 -0
- package/dist/core/session-model.d.ts.map +1 -0
- package/dist/core/session-model.js +42 -0
- package/dist/core/session-model.js.map +1 -0
- package/dist/core/session-owner-reminder.d.ts +63 -0
- package/dist/core/session-owner-reminder.d.ts.map +1 -0
- package/dist/core/session-owner-reminder.js +196 -0
- package/dist/core/session-owner-reminder.js.map +1 -0
- package/dist/core/session-preview-registry.d.ts +53 -0
- package/dist/core/session-preview-registry.d.ts.map +1 -0
- package/dist/core/session-preview-registry.js +82 -0
- package/dist/core/session-preview-registry.js.map +1 -0
- package/dist/core/session-preview.d.ts +114 -0
- package/dist/core/session-preview.d.ts.map +1 -0
- package/dist/core/session-preview.js +184 -0
- package/dist/core/session-preview.js.map +1 -0
- package/dist/core/session-rename.d.ts.map +1 -1
- package/dist/core/session-rename.js +5 -3
- package/dist/core/session-rename.js.map +1 -1
- package/dist/core/session-wake-deadline.d.ts +5 -0
- package/dist/core/session-wake-deadline.d.ts.map +1 -0
- package/dist/core/session-wake-deadline.js +13 -0
- package/dist/core/session-wake-deadline.js.map +1 -0
- package/dist/core/shutdown-budgets.d.ts +7 -6
- package/dist/core/shutdown-budgets.d.ts.map +1 -1
- package/dist/core/shutdown-budgets.js +11 -10
- package/dist/core/shutdown-budgets.js.map +1 -1
- package/dist/core/terminal-control-grant.d.ts +74 -0
- package/dist/core/terminal-control-grant.d.ts.map +1 -0
- package/dist/core/terminal-control-grant.js +183 -0
- package/dist/core/terminal-control-grant.js.map +1 -0
- package/dist/core/terminal-proxy.d.ts.map +1 -1
- package/dist/core/terminal-proxy.js +4 -5
- package/dist/core/terminal-proxy.js.map +1 -1
- package/dist/core/terminal-write-auth.d.ts +4 -11
- package/dist/core/terminal-write-auth.d.ts.map +1 -1
- package/dist/core/terminal-write-auth.js +19 -16
- package/dist/core/terminal-write-auth.js.map +1 -1
- package/dist/core/trigger-session.d.ts.map +1 -1
- package/dist/core/trigger-session.js +36 -29
- package/dist/core/trigger-session.js.map +1 -1
- package/dist/core/types.d.ts +88 -10
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +9 -7
- package/dist/core/types.js.map +1 -1
- package/dist/core/workbench-link.d.ts +81 -0
- package/dist/core/workbench-link.d.ts.map +1 -0
- package/dist/core/workbench-link.js +109 -0
- package/dist/core/workbench-link.js.map +1 -0
- package/dist/core/worker-pool.d.ts +312 -11
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +2494 -209
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +6 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +443 -106
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/aggregator.d.ts +33 -3
- package/dist/dashboard/aggregator.d.ts.map +1 -1
- package/dist/dashboard/aggregator.js +93 -17
- package/dist/dashboard/aggregator.js.map +1 -1
- package/dist/dashboard/auth-session-connections.d.ts +59 -0
- package/dist/dashboard/auth-session-connections.d.ts.map +1 -0
- package/dist/dashboard/auth-session-connections.js +109 -0
- package/dist/dashboard/auth-session-connections.js.map +1 -0
- package/dist/dashboard/auth.d.ts +99 -1
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +176 -64
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/bot-payload.d.ts +1 -0
- package/dist/dashboard/bot-payload.d.ts.map +1 -1
- package/dist/dashboard/bot-payload.js +3 -0
- package/dist/dashboard/bot-payload.js.map +1 -1
- package/dist/dashboard/control-audit.d.ts +112 -0
- package/dist/dashboard/control-audit.d.ts.map +1 -0
- package/dist/dashboard/control-audit.js +195 -0
- package/dist/dashboard/control-audit.js.map +1 -0
- package/dist/dashboard/control-csrf.d.ts +123 -0
- package/dist/dashboard/control-csrf.d.ts.map +1 -0
- package/dist/dashboard/control-csrf.js +392 -0
- package/dist/dashboard/control-csrf.js.map +1 -0
- package/dist/dashboard/daemon-reconcile.d.ts +26 -0
- package/dist/dashboard/daemon-reconcile.d.ts.map +1 -0
- package/dist/dashboard/daemon-reconcile.js +46 -0
- package/dist/dashboard/daemon-reconcile.js.map +1 -0
- 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/events-sse.d.ts +60 -0
- package/dist/dashboard/events-sse.d.ts.map +1 -0
- package/dist/dashboard/events-sse.js +63 -0
- package/dist/dashboard/events-sse.js.map +1 -0
- package/dist/dashboard/h5-auth.d.ts +256 -0
- package/dist/dashboard/h5-auth.d.ts.map +1 -0
- package/dist/dashboard/h5-auth.js +825 -0
- package/dist/dashboard/h5-auth.js.map +1 -0
- package/dist/dashboard/managed-spawn.d.ts +36 -0
- package/dist/dashboard/managed-spawn.d.ts.map +1 -0
- package/dist/dashboard/managed-spawn.js +169 -0
- package/dist/dashboard/managed-spawn.js.map +1 -0
- package/dist/dashboard/preview-content-capability.d.ts +41 -0
- package/dist/dashboard/preview-content-capability.d.ts.map +1 -0
- package/dist/dashboard/preview-content-capability.js +127 -0
- package/dist/dashboard/preview-content-capability.js.map +1 -0
- package/dist/dashboard/preview-contract.d.ts +85 -0
- package/dist/dashboard/preview-contract.d.ts.map +1 -0
- package/dist/dashboard/preview-contract.js +198 -0
- package/dist/dashboard/preview-contract.js.map +1 -0
- package/dist/dashboard/preview-guard-page.d.ts +52 -0
- package/dist/dashboard/preview-guard-page.d.ts.map +1 -0
- package/dist/dashboard/preview-guard-page.js +162 -0
- package/dist/dashboard/preview-guard-page.js.map +1 -0
- package/dist/dashboard/preview-interaction.d.ts +57 -0
- package/dist/dashboard/preview-interaction.d.ts.map +1 -0
- package/dist/dashboard/preview-interaction.js +198 -0
- package/dist/dashboard/preview-interaction.js.map +1 -0
- package/dist/dashboard/preview-proxy.d.ts +113 -0
- package/dist/dashboard/preview-proxy.d.ts.map +1 -0
- package/dist/dashboard/preview-proxy.js +543 -0
- package/dist/dashboard/preview-proxy.js.map +1 -0
- package/dist/dashboard/public-redact.d.ts +23 -0
- package/dist/dashboard/public-redact.d.ts.map +1 -1
- package/dist/dashboard/public-redact.js +90 -21
- package/dist/dashboard/public-redact.js.map +1 -1
- package/dist/dashboard/request-identity.d.ts +77 -0
- package/dist/dashboard/request-identity.d.ts.map +1 -0
- package/dist/dashboard/request-identity.js +72 -0
- package/dist/dashboard/request-identity.js.map +1 -0
- package/dist/dashboard/session-cleanup.d.ts +5 -0
- package/dist/dashboard/session-cleanup.d.ts.map +1 -1
- package/dist/dashboard/session-cleanup.js +4 -0
- package/dist/dashboard/session-cleanup.js.map +1 -1
- package/dist/dashboard/settings-write-applier.d.ts +5 -1
- package/dist/dashboard/settings-write-applier.d.ts.map +1 -1
- package/dist/dashboard/settings-write-applier.js +14 -0
- package/dist/dashboard/settings-write-applier.js.map +1 -1
- package/dist/dashboard/standing-link.d.ts +76 -0
- package/dist/dashboard/standing-link.d.ts.map +1 -0
- package/dist/dashboard/standing-link.js +111 -0
- package/dist/dashboard/standing-link.js.map +1 -0
- package/dist/dashboard/terminal-control.d.ts +105 -0
- package/dist/dashboard/terminal-control.d.ts.map +1 -0
- package/dist/dashboard/terminal-control.js +296 -0
- package/dist/dashboard/terminal-control.js.map +1 -0
- package/dist/dashboard/terminal-front-proxy.d.ts +55 -0
- package/dist/dashboard/terminal-front-proxy.d.ts.map +1 -0
- package/dist/dashboard/terminal-front-proxy.js +397 -0
- package/dist/dashboard/terminal-front-proxy.js.map +1 -0
- package/dist/dashboard/terminal-view-capability.d.ts +97 -0
- package/dist/dashboard/terminal-view-capability.d.ts.map +1 -0
- package/dist/dashboard/terminal-view-capability.js +145 -0
- package/dist/dashboard/terminal-view-capability.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-api.d.ts +59 -0
- package/dist/dashboard/web/agent-workbench-api.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-api.js +227 -0
- package/dist/dashboard/web/agent-workbench-api.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-appearance-menu.d.ts +59 -0
- package/dist/dashboard/web/agent-workbench-appearance-menu.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-appearance-menu.js +195 -0
- package/dist/dashboard/web/agent-workbench-appearance-menu.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-appearance.d.ts +222 -0
- package/dist/dashboard/web/agent-workbench-appearance.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-appearance.js +499 -0
- package/dist/dashboard/web/agent-workbench-appearance.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-capabilities.d.ts +13 -0
- package/dist/dashboard/web/agent-workbench-capabilities.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-capabilities.js +24 -0
- package/dist/dashboard/web/agent-workbench-capabilities.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-chat.d.ts +90 -0
- package/dist/dashboard/web/agent-workbench-chat.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-chat.js +168 -0
- package/dist/dashboard/web/agent-workbench-chat.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-dock-page.d.ts +3 -0
- package/dist/dashboard/web/agent-workbench-dock-page.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-dock-page.js +23 -0
- package/dist/dashboard/web/agent-workbench-dock-page.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-dock-view.d.ts +22 -0
- package/dist/dashboard/web/agent-workbench-dock-view.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-dock-view.js +76 -0
- package/dist/dashboard/web/agent-workbench-dock-view.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-model.d.ts +196 -0
- package/dist/dashboard/web/agent-workbench-model.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-model.js +529 -0
- package/dist/dashboard/web/agent-workbench-model.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-page.d.ts +3 -0
- package/dist/dashboard/web/agent-workbench-page.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-page.js +27 -0
- package/dist/dashboard/web/agent-workbench-page.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-panes.d.ts +49 -0
- package/dist/dashboard/web/agent-workbench-panes.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-panes.js +468 -0
- package/dist/dashboard/web/agent-workbench-panes.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-session-list.d.ts +42 -0
- package/dist/dashboard/web/agent-workbench-session-list.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-session-list.js +353 -0
- package/dist/dashboard/web/agent-workbench-session-list.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-storage.d.ts +49 -0
- package/dist/dashboard/web/agent-workbench-storage.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-storage.js +197 -0
- package/dist/dashboard/web/agent-workbench-storage.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-touch.d.ts +46 -0
- package/dist/dashboard/web/agent-workbench-touch.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-touch.js +96 -0
- package/dist/dashboard/web/agent-workbench-touch.js.map +1 -0
- package/dist/dashboard/web/agent-workbench-view.d.ts +34 -0
- package/dist/dashboard/web/agent-workbench-view.d.ts.map +1 -0
- package/dist/dashboard/web/agent-workbench-view.js +439 -0
- package/dist/dashboard/web/agent-workbench-view.js.map +1 -0
- package/dist/dashboard/web/app.d.ts.map +1 -1
- package/dist/dashboard/web/app.js +63 -2
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.d.ts +11 -0
- package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults-page.js +267 -36
- package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
- package/dist/dashboard/web/bot-defaults.d.ts +6 -0
- package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
- package/dist/dashboard/web/bot-defaults.js.map +1 -1
- package/dist/dashboard/web/control-csrf.d.ts +4 -0
- package/dist/dashboard/web/control-csrf.d.ts.map +1 -0
- package/dist/dashboard/web/control-csrf.js +26 -0
- package/dist/dashboard/web/control-csrf.js.map +1 -0
- package/dist/dashboard/web/dashboard-routes.d.ts.map +1 -1
- package/dist/dashboard/web/dashboard-routes.js +2 -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 -2
- 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 +132 -6
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/overview-page.d.ts.map +1 -1
- package/dist/dashboard/web/overview-page.js +3 -2
- package/dist/dashboard/web/overview-page.js.map +1 -1
- package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
- package/dist/dashboard/web/sessions-page.js +41 -1
- 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 -1
- package/dist/dashboard/web/sessions.js.map +1 -1
- package/dist/dashboard/web/settings-page.d.ts +3 -0
- package/dist/dashboard/web/settings-page.d.ts.map +1 -1
- package/dist/dashboard/web/settings-page.js +56 -10
- package/dist/dashboard/web/settings-page.js.map +1 -1
- package/dist/dashboard/web/store.d.ts +27 -2
- package/dist/dashboard/web/store.d.ts.map +1 -1
- package/dist/dashboard/web/store.js +43 -4
- package/dist/dashboard/web/store.js.map +1 -1
- package/dist/dashboard/web/ui.d.ts +3 -0
- package/dist/dashboard/web/ui.d.ts.map +1 -1
- package/dist/dashboard/web/ui.js +11 -0
- package/dist/dashboard/web/ui.js.map +1 -1
- package/dist/dashboard/web/update-action.d.ts +12 -0
- package/dist/dashboard/web/update-action.d.ts.map +1 -1
- package/dist/dashboard/web/update-action.js +11 -0
- package/dist/dashboard/web/update-action.js.map +1 -1
- package/dist/dashboard/workbench-doctor.d.ts +114 -0
- package/dist/dashboard/workbench-doctor.d.ts.map +1 -0
- package/dist/dashboard/workbench-doctor.js +620 -0
- package/dist/dashboard/workbench-doctor.js.map +1 -0
- package/dist/dashboard/workbench-ticket.d.ts +165 -0
- package/dist/dashboard/workbench-ticket.d.ts.map +1 -0
- package/dist/dashboard/workbench-ticket.js +495 -0
- package/dist/dashboard/workbench-ticket.js.map +1 -0
- package/dist/dashboard-web/app.js +1 -1
- package/dist/dashboard-web/chunks/agent-workbench-dock-page-IKAC5CFL.js +1 -0
- package/dist/dashboard-web/chunks/agent-workbench-page-M53UN5EB.js +1 -0
- package/dist/dashboard-web/chunks/bot-defaults-page-YKE5SDZF.js +10 -0
- package/dist/dashboard-web/chunks/chunk-22WIADUT.js +2 -0
- package/dist/dashboard-web/chunks/chunk-24ONYQMR.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-Z7B3E3US.js → chunk-2W6SCN3M.js} +1 -1
- package/dist/dashboard-web/chunks/chunk-4XNJX6B3.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-VMWNR3SV.js → chunk-F6KNPF4R.js} +11 -9
- package/dist/dashboard-web/chunks/chunk-FXW3V4JR.js +1 -0
- package/dist/dashboard-web/chunks/chunk-G5ZS2YUS.js +1 -0
- package/dist/dashboard-web/chunks/chunk-KTQ7B6ZR.js +1 -0
- package/dist/dashboard-web/chunks/{chunk-Z7DO42GJ.js → chunk-NACP7BMR.js} +1 -1
- package/dist/dashboard-web/chunks/{connectors-page-CPH6VVFY.js → connectors-page-VOISXXII.js} +1 -1
- package/dist/dashboard-web/chunks/{feedback-page-J2FKQ3LK.js → feedback-page-RN6HRZMS.js} +1 -1
- package/dist/dashboard-web/chunks/groups-page-UQT6DCB7.js +8 -0
- package/dist/dashboard-web/chunks/{insights-page-A2LWTKJD.js → insights-page-HJFDYR5N.js} +3 -3
- package/dist/dashboard-web/chunks/{monitor-room-2YR752E3.js → monitor-room-V7PCP47V.js} +1 -1
- package/dist/dashboard-web/chunks/{monitoring-page-BGYSKZGM.js → monitoring-page-NKEKVQAP.js} +1 -1
- package/dist/dashboard-web/chunks/{office-page-ZZHTEAE4.js → office-page-GVJF73XW.js} +1 -1
- package/dist/dashboard-web/chunks/overview-page-KHLV6VTI.js +1 -0
- package/dist/dashboard-web/chunks/{plugin-page-VEGTCEAS.js → plugin-page-J3OF5IY4.js} +1 -1
- package/dist/dashboard-web/chunks/{roles-page-YUC4YLJG.js → roles-page-WQIRSOLZ.js} +1 -1
- package/dist/dashboard-web/chunks/{schedules-page-2L2NKTDJ.js → schedules-page-J2DEY2X6.js} +1 -1
- package/dist/dashboard-web/chunks/sessions-page-7BQFEA5P.js +8 -0
- package/dist/dashboard-web/chunks/settings-page-BJEIOFJH.js +2 -0
- package/dist/dashboard-web/chunks/{skills-page-DQPBBI3T.js → skills-page-HGIFR3IU.js} +1 -1
- package/dist/dashboard-web/chunks/{team-federation-page-LQKLDV4K.js → team-federation-page-MR5ZPL4B.js} +1 -1
- package/dist/dashboard-web/chunks/{v3-page-RVKQIMAP.js → v3-page-GBR5JWPE.js} +2 -2
- package/dist/dashboard-web/chunks/{whiteboards-page-S5K55HRZ.js → whiteboards-page-QAZM4BN3.js} +1 -1
- package/dist/dashboard-web/index.html +8 -1
- package/dist/dashboard-web/style.css +2006 -10
- package/dist/dashboard.js +1006 -263
- package/dist/dashboard.js.map +1 -1
- package/dist/global-config.d.ts +30 -0
- package/dist/global-config.d.ts.map +1 -1
- package/dist/global-config.js +33 -0
- package/dist/global-config.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +31 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +28 -1
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-builder.d.ts +1 -1
- package/dist/im/lark/card-builder.d.ts.map +1 -1
- package/dist/im/lark/card-builder.js +22 -6
- 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 +118 -24
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +15 -0
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +30 -0
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/event-dispatcher.d.ts +48 -0
- package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
- package/dist/im/lark/event-dispatcher.js +133 -22
- package/dist/im/lark/event-dispatcher.js.map +1 -1
- package/dist/im/lark/identity-cache.d.ts +14 -6
- package/dist/im/lark/identity-cache.d.ts.map +1 -1
- package/dist/im/lark/identity-cache.js +69 -26
- package/dist/im/lark/identity-cache.js.map +1 -1
- package/dist/im/lark/lark-hosts.d.ts +13 -0
- package/dist/im/lark/lark-hosts.d.ts.map +1 -1
- package/dist/im/lark/lark-hosts.js +16 -0
- package/dist/im/lark/lark-hosts.js.map +1 -1
- package/dist/im/lark/overview-card.d.ts +22 -0
- package/dist/im/lark/overview-card.d.ts.map +1 -1
- package/dist/im/lark/overview-card.js +53 -3
- package/dist/im/lark/overview-card.js.map +1 -1
- package/dist/im/lark/sessions-card.d.ts.map +1 -1
- package/dist/im/lark/sessions-card.js +26 -3
- package/dist/im/lark/sessions-card.js.map +1 -1
- package/dist/im/lark/workflow-slash-command.d.ts +6 -0
- package/dist/im/lark/workflow-slash-command.d.ts.map +1 -1
- package/dist/im/lark/workflow-slash-command.js +7 -0
- package/dist/im/lark/workflow-slash-command.js.map +1 -1
- package/dist/index-daemon.js +27 -4
- package/dist/index-daemon.js.map +1 -1
- package/dist/index-dashboard.d.ts +3 -0
- package/dist/index-dashboard.d.ts.map +1 -0
- package/dist/index-dashboard.js +94 -0
- package/dist/index-dashboard.js.map +1 -0
- package/dist/platform/team-agents-client.d.ts +199 -0
- package/dist/platform/team-agents-client.d.ts.map +1 -0
- package/dist/platform/team-agents-client.js +263 -0
- package/dist/platform/team-agents-client.js.map +1 -0
- package/dist/platform/tunnel-client.d.ts +6 -0
- package/dist/platform/tunnel-client.d.ts.map +1 -1
- package/dist/platform/tunnel-client.js.map +1 -1
- package/dist/services/async-trigger-state.d.ts +7 -3
- package/dist/services/async-trigger-state.d.ts.map +1 -1
- package/dist/services/async-trigger-state.js +28 -0
- package/dist/services/async-trigger-state.js.map +1 -1
- package/dist/services/async-trigger-store.d.ts +13 -4
- package/dist/services/async-trigger-store.d.ts.map +1 -1
- package/dist/services/async-trigger-store.js +55 -8
- package/dist/services/async-trigger-store.js.map +1 -1
- package/dist/services/bot-config-store.d.ts +1 -11
- package/dist/services/bot-config-store.d.ts.map +1 -1
- package/dist/services/bot-config-store.js +27 -3
- package/dist/services/bot-config-store.js.map +1 -1
- package/dist/services/bot-profile-store.d.ts +17 -2
- package/dist/services/bot-profile-store.d.ts.map +1 -1
- package/dist/services/bot-profile-store.js +93 -12
- package/dist/services/bot-profile-store.js.map +1 -1
- package/dist/services/bridge-turn-queue.d.ts +10 -1
- package/dist/services/bridge-turn-queue.d.ts.map +1 -1
- package/dist/services/bridge-turn-queue.js +29 -9
- package/dist/services/bridge-turn-queue.js.map +1 -1
- package/dist/services/claude-transcript.d.ts +19 -0
- package/dist/services/claude-transcript.d.ts.map +1 -1
- package/dist/services/claude-transcript.js +57 -5
- package/dist/services/claude-transcript.js.map +1 -1
- package/dist/services/codex-app-threads.d.ts +2 -0
- package/dist/services/codex-app-threads.d.ts.map +1 -1
- package/dist/services/codex-app-threads.js +1 -1
- package/dist/services/codex-app-threads.js.map +1 -1
- package/dist/services/codex-reasoning-effort.d.ts +8 -0
- package/dist/services/codex-reasoning-effort.d.ts.map +1 -1
- package/dist/services/codex-reasoning-effort.js +24 -0
- package/dist/services/codex-reasoning-effort.js.map +1 -1
- package/dist/services/cursor-resume-policy.d.ts.map +1 -1
- package/dist/services/cursor-resume-policy.js +15 -3
- package/dist/services/cursor-resume-policy.js.map +1 -1
- package/dist/services/open-platform-rename.d.ts.map +1 -1
- package/dist/services/open-platform-rename.js +3 -2
- package/dist/services/open-platform-rename.js.map +1 -1
- package/dist/services/ordinary-turn-recovery.d.ts +76 -0
- package/dist/services/ordinary-turn-recovery.d.ts.map +1 -0
- package/dist/services/ordinary-turn-recovery.js +349 -0
- package/dist/services/ordinary-turn-recovery.js.map +1 -0
- package/dist/services/resume-fresh-policy.d.ts +17 -0
- package/dist/services/resume-fresh-policy.d.ts.map +1 -0
- package/dist/services/resume-fresh-policy.js +24 -0
- package/dist/services/resume-fresh-policy.js.map +1 -0
- package/dist/services/session-group-title.d.ts +1 -0
- package/dist/services/session-group-title.d.ts.map +1 -1
- package/dist/services/session-group-title.js +16 -1
- package/dist/services/session-group-title.js.map +1 -1
- package/dist/services/session-groups-store.d.ts +30 -0
- package/dist/services/session-groups-store.d.ts.map +1 -1
- package/dist/services/session-groups-store.js +26 -4
- package/dist/services/session-groups-store.js.map +1 -1
- package/dist/services/session-owner-notification.d.ts +9 -0
- package/dist/services/session-owner-notification.d.ts.map +1 -0
- package/dist/services/session-owner-notification.js +10 -0
- package/dist/services/session-owner-notification.js.map +1 -0
- package/dist/services/session-owner-reminder-config-store.d.ts +9 -0
- package/dist/services/session-owner-reminder-config-store.d.ts.map +1 -0
- package/dist/services/session-owner-reminder-config-store.js +24 -0
- package/dist/services/session-owner-reminder-config-store.js.map +1 -0
- package/dist/services/session-owner-reminder-store.d.ts +5 -0
- package/dist/services/session-owner-reminder-store.d.ts.map +1 -0
- package/dist/services/session-owner-reminder-store.js +54 -0
- package/dist/services/session-owner-reminder-store.js.map +1 -0
- package/dist/services/session-store.d.ts +98 -21
- package/dist/services/session-store.d.ts.map +1 -1
- package/dist/services/session-store.js +406 -48
- package/dist/services/session-store.js.map +1 -1
- package/dist/services/structured-bridge-clis.d.ts +9 -5
- package/dist/services/structured-bridge-clis.d.ts.map +1 -1
- package/dist/services/structured-bridge-clis.js +9 -4
- package/dist/services/structured-bridge-clis.js.map +1 -1
- package/dist/services/transcript-resolver.d.ts +1 -1
- package/dist/services/transcript-resolver.d.ts.map +1 -1
- package/dist/services/transcript-resolver.js +6 -1
- package/dist/services/transcript-resolver.js.map +1 -1
- package/dist/setup/bot-config-editor.d.ts.map +1 -1
- package/dist/setup/bot-config-editor.js +7 -2
- package/dist/setup/bot-config-editor.js.map +1 -1
- package/dist/setup/ensure-herdr-integrations.d.ts +13 -0
- package/dist/setup/ensure-herdr-integrations.d.ts.map +1 -1
- package/dist/setup/ensure-herdr-integrations.js +21 -3
- package/dist/setup/ensure-herdr-integrations.js.map +1 -1
- package/dist/setup/open-platform-automation.d.ts +1 -0
- package/dist/setup/open-platform-automation.d.ts.map +1 -1
- package/dist/setup/open-platform-automation.js +107 -7
- package/dist/setup/open-platform-automation.js.map +1 -1
- package/dist/skills/definitions.d.ts +17 -0
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +78 -8
- package/dist/skills/definitions.js.map +1 -1
- package/dist/skills/injection-mode.d.ts +24 -3
- package/dist/skills/injection-mode.d.ts.map +1 -1
- package/dist/skills/injection-mode.js +64 -15
- package/dist/skills/injection-mode.js.map +1 -1
- package/dist/skills/installer.d.ts +18 -0
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +45 -1
- package/dist/skills/installer.js.map +1 -1
- package/dist/types.d.ts +221 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/child-env.d.ts +92 -2
- package/dist/utils/child-env.d.ts.map +1 -1
- package/dist/utils/child-env.js +195 -1
- package/dist/utils/child-env.js.map +1 -1
- package/dist/utils/cli-usage-limit.d.ts +25 -14
- package/dist/utils/cli-usage-limit.d.ts.map +1 -1
- package/dist/utils/cli-usage-limit.js +25 -15
- package/dist/utils/cli-usage-limit.js.map +1 -1
- package/dist/utils/daemon-rejection-guard.d.ts +35 -0
- package/dist/utils/daemon-rejection-guard.d.ts.map +1 -0
- package/dist/utils/daemon-rejection-guard.js +101 -0
- package/dist/utils/daemon-rejection-guard.js.map +1 -0
- package/dist/utils/dashboard-env.d.ts +53 -0
- package/dist/utils/dashboard-env.d.ts.map +1 -0
- package/dist/utils/dashboard-env.js +116 -0
- package/dist/utils/dashboard-env.js.map +1 -0
- package/dist/utils/global-install.d.ts.map +1 -1
- package/dist/utils/global-install.js +61 -5
- package/dist/utils/global-install.js.map +1 -1
- package/dist/utils/install-diagnostics.d.ts +14 -7
- package/dist/utils/install-diagnostics.d.ts.map +1 -1
- package/dist/utils/install-diagnostics.js +20 -11
- package/dist/utils/install-diagnostics.js.map +1 -1
- package/dist/utils/local-dev-update.d.ts +132 -0
- package/dist/utils/local-dev-update.d.ts.map +1 -0
- package/dist/utils/local-dev-update.js +176 -0
- package/dist/utils/local-dev-update.js.map +1 -0
- package/dist/utils/pending-input-queue.d.ts +12 -1
- package/dist/utils/pending-input-queue.d.ts.map +1 -1
- package/dist/utils/pending-input-queue.js.map +1 -1
- package/dist/worker.js +1284 -225
- package/dist/worker.js.map +1 -1
- package/dist/workflows/definition.d.ts +68 -68
- package/dist/workflows/events/payloads.d.ts +14 -14
- package/dist/workflows/events/schema.d.ts +312 -312
- package/dist/workflows/migration/v2-run-archive-schema.d.ts +40 -40
- package/dist/workflows/v3/cli-run.d.ts.map +1 -1
- package/dist/workflows/v3/cli-run.js +7 -0
- package/dist/workflows/v3/cli-run.js.map +1 -1
- package/dist/workflows/v3/goal-cli.d.ts +3 -0
- package/dist/workflows/v3/goal-cli.d.ts.map +1 -1
- package/dist/workflows/v3/goal-cli.js +11 -0
- package/dist/workflows/v3/goal-cli.js.map +1 -1
- package/dist/workflows/v3/run-envelope.d.ts +144 -144
- package/package.json +3 -2
- package/dist/cli/pm2-god-admission.d.ts +0 -8
- package/dist/cli/pm2-god-admission.d.ts.map +0 -1
- package/dist/cli/pm2-god-admission.js +0 -25
- package/dist/cli/pm2-god-admission.js.map +0 -1
- package/dist/core/riff-shutdown-detach.d.ts.map +0 -1
- package/dist/core/riff-shutdown-detach.js.map +0 -1
- package/dist/core/riff-worker-shutdown-readiness.d.ts.map +0 -1
- package/dist/core/riff-worker-shutdown-readiness.js.map +0 -1
- package/dist/dashboard-web/chunks/bot-defaults-page-65SMZ4QY.js +0 -10
- package/dist/dashboard-web/chunks/chunk-G5XGBCM6.js +0 -1
- package/dist/dashboard-web/chunks/chunk-IKN6WURK.js +0 -1
- package/dist/dashboard-web/chunks/chunk-WLIVBPJC.js +0 -1
- package/dist/dashboard-web/chunks/groups-page-VDOOLS4M.js +0 -8
- package/dist/dashboard-web/chunks/overview-page-7NYPKQSB.js +0 -1
- package/dist/dashboard-web/chunks/sessions-page-DYZZMKFL.js +0 -8
- package/dist/dashboard-web/chunks/settings-page-LIULUSMH.js +0 -2
package/dist/daemon.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
3
|
import { readFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
4
|
+
import { installDaemonRejectionGuard } from './utils/daemon-rejection-guard.js';
|
|
4
5
|
import { atomicWriteFileSync } from './utils/atomic-write.js';
|
|
5
6
|
import { readPeerCrossRef } from './services/peer-cross-ref-store.js';
|
|
6
7
|
import { readAllowedUsersResolveCache, writeAllowedUsersResolveCache } from './utils/allowed-users-cache.js';
|
|
@@ -10,7 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = dirname(__filename);
|
|
12
13
|
import { config, getDashboardExternalHost, isVcMeetingAgentGloballyEnabled, vcMeetingAgentGlobalListenerBotAppId, } from './config.js';
|
|
13
|
-
import { readGlobalConfig, repoPickerScanOptions } from './global-config.js';
|
|
14
|
+
import { readGlobalConfig, repoPickerScanOptions, isWorkflowFeatureEnabled } from './global-config.js';
|
|
14
15
|
import { buildDashboardUrls } from './core/dashboard-url.js';
|
|
15
16
|
import { resolveBotmuxDataDir } from './core/data-dir.js';
|
|
16
17
|
import { reloadExactDaemonBotConfig } from './core/daemon-config-fence.js';
|
|
@@ -64,6 +65,15 @@ import { scrubTmuxServerGlobalEnv } from './setup/ensure-tmux.js';
|
|
|
64
65
|
import { entryNeedsContactResolve } from './setup/bot-config-editor.js';
|
|
65
66
|
import { invalidWorkingDirs } from './utils/working-dir.js';
|
|
66
67
|
import { validateWorkingDir } from './core/working-dir.js';
|
|
68
|
+
function trustedCallerForTurn(larkAppId, senderOpenId, senderUnionId) {
|
|
69
|
+
if (!senderOpenId && !senderUnionId)
|
|
70
|
+
return undefined;
|
|
71
|
+
return {
|
|
72
|
+
...(senderOpenId ? { requestUserOpenId: senderOpenId } : {}),
|
|
73
|
+
...(senderUnionId ? { requestUserUnionId: senderUnionId } : {}),
|
|
74
|
+
requestLarkAppId: larkAppId,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
67
77
|
import { activeSessionKey, sessionKey, sessionAnchorId, storedSessionAnchorId, larkTransportEnabled, } from './core/types.js';
|
|
68
78
|
import { stagePendingRepoSetup, persistPendingRepoCardMessageId } from './core/pending-repo-journal.js';
|
|
69
79
|
import { setTerminalProxyPort, setTerminalExternalPort } from './core/terminal-url.js';
|
|
@@ -78,10 +88,11 @@ import { isLocalCliOpenReady } from './services/local-cli-opener.js';
|
|
|
78
88
|
import { RECEIVED_REACTION_EMOJI_TYPE, SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE } from './core/pending-response.js';
|
|
79
89
|
import { t as tr, localeForBot } from './i18n/index.js';
|
|
80
90
|
import { createCliAdapterSync } from './adapters/cli/registry.js';
|
|
81
|
-
import { initWorkerPool, setActiveSessionsRegistry, forkWorker, forkAdoptWorker, sendWorkerInput, promoteQueuedActivationTail, admitQueuedActivationTail, reserveQueuedActivationTailAdmission, codexAppCleanInputAcceptedForSession, hasQueuedActivationAdmissionGate, sendWorkerSessionInput, killWorker, reapOrphanWorkers, scheduleCardPatch, setCurrentCliVersion, getCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, setActiveSessionIfActive, rollbackRejectedSessionAndGetWinner, ensureCliEnv, sweepGlobalBotmuxSkills, writableTerminalLinkFor, workerHasInitialized, sessionSupportsWebTerminal, readableTerminalUrlFor, findActiveBySessionId, withActiveSessionKeyLock, getDaemonBootId, getDaemonStreamingCardUsageSnapshot, postTurnStartingCard, isSessionTransferring, snapshotCodexAppFinalSettlements, codexAppFinalSettlementCount, } from './core/worker-pool.js';
|
|
91
|
+
import { initWorkerPool, setActiveSessionsRegistry, forkWorker, forkAdoptWorker, sendWorkerInput, promoteQueuedActivationTail, admitQueuedActivationTail, reserveQueuedActivationTailAdmission, codexAppCleanInputAcceptedForSession, hasQueuedActivationAdmissionGate, sendWorkerSessionInput, killWorker, retireWorkerProcessOnly, retiringWorkersForSession, reapOrphanWorkers, scheduleCardPatch, setCurrentCliVersion, getCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, closeSessionForBackgroundCleanup, setActiveSessionIfActive, rollbackRejectedSessionAndGetWinner, ensureCliEnv, sweepGlobalBotmuxSkills, writableTerminalLinkFor, workerHasInitialized, sessionSupportsWebTerminal, readableTerminalUrlFor, findActiveBySessionId, withActiveSessionKeyLock, getDaemonBootId, getDaemonStreamingCardUsageSnapshot, postTurnStartingCard, isSessionTransferring, snapshotCodexAppFinalSettlements, codexAppFinalSettlementCount, migrateMojoSessionIdentities, mojoLivePatchForSession, } from './core/worker-pool.js';
|
|
82
92
|
import { waitAllWithin, trackProducerQuiet, trackProcessExited } from './core/producer-quiescence.js';
|
|
83
93
|
import { AbortDeadlineError, hasExactSafeJsonKeys, ipcRoute, isTrustedHostIpcRequest, JsonBodyTooLargeError, jsonRes, readJsonBody, runWithAbortDeadline, setBotName, setLarkAppId, startIpcServer, setBotRenamer, setBotAvatarChanger, armCoreOnlyReadinessGate, setCoreOnlyReady, setSupervisorShutdownHandler } from './core/dashboard-ipc-server.js';
|
|
84
94
|
import { setDeviceIsolationDaemonIdentity } from './core/device-isolation-daemon.js';
|
|
95
|
+
import { reconcileContainmentHandlesOnBoot } from './core/mojo-containment.js';
|
|
85
96
|
import { cancelSessionReadyAck, waitForSessionReadyAck, } from './core/session-ready-handshake.js';
|
|
86
97
|
import { loadOrCreateDashboardSecret, loadPersistedToken } from './dashboard/auth.js';
|
|
87
98
|
import { daemonIpcAuthHeaders, fetchDaemonIpc, loadDaemonIpcSecret } from './core/daemon-ipc-auth.js';
|
|
@@ -99,6 +110,7 @@ import { consumeQuota, removeChatGrant, removeGlobalGrant } from './services/gra
|
|
|
99
110
|
import { abortCharge, commitCharge, beginCharge } from './services/quota-dedup.js';
|
|
100
111
|
import { getSessionWorkingDir, getProjectScanDirs, getProjectScanDirsForBot, expandHome, downloadResources, formatAttachmentsHint, buildNewTopicCliInput, buildFollowUpCliInput, buildBridgeInputContent, buildReforkCliInput, getAvailableBots, restoreActiveSessions, executeScheduledTask, persistStreamCardState, rememberLastCliInput, ensureTerminalWorkerPort, ensureSessionWhiteboard, resumeSession, closeCliMismatchedSessionsForBot, } from './core/session-manager.js';
|
|
101
112
|
import { triggerSessionTurn, reconcileIdempotencyLeasesOnBoot, convergeIdempotentAsyncTurnOnWorkerExit, externalEventOpensOwnTopic } from './core/trigger-session.js';
|
|
113
|
+
import { runIdempotencyFailClose, runWithdrawAutoClose, } from './core/daemon-background-close.js';
|
|
102
114
|
import { runDetachedBotTurnMutation, tryWithBotTurnMutation, withBotTurnAdmission, withBotTurnMutation, } from './core/bot-turn-mutation-gate.js';
|
|
103
115
|
import { claimInitialUserTurn, isInitialUserTurnPending, releaseInitialUserTurn } from './core/initial-user-turn.js';
|
|
104
116
|
import { applyQueuedCodexAppLegacyFallback, mergeQueuedCodexAppTurn } from './core/session-create.js';
|
|
@@ -114,11 +126,14 @@ import { HerdrBackend } from './adapters/backend/herdr-backend.js';
|
|
|
114
126
|
import { ZellijBackend } from './adapters/backend/zellij-backend.js';
|
|
115
127
|
import { ZmxBackend } from './adapters/backend/zmx-backend.js';
|
|
116
128
|
import { sweepIdleWorkersAfterTurnDrain, DEFAULT_MAX_LIVE_WORKERS } from './core/idle-worker-sweeper.js';
|
|
117
|
-
import {
|
|
129
|
+
import { DEFAULT_SESSION_OWNER_REMINDER, SessionOwnerReminderController, } from './core/session-owner-reminder.js';
|
|
130
|
+
import { loadSessionOwnerReminderRecords, saveSessionOwnerReminderRecords, } from './services/session-owner-reminder-store.js';
|
|
131
|
+
import { sendSessionOwnerThreadNotification } from './services/session-owner-notification.js';
|
|
132
|
+
import { getSessionPersistentBackendType, isRemoteBackendSession, killPersistentBackendTarget, killPersistentSession, probePersistentBackendTarget, probePersistentSession, resolvePersistentBackendTarget, resolvePairedSpawnBackendType, } from './core/persistent-backend.js';
|
|
118
133
|
import { handleCardAction, runAutoWorktreeCommit } from './im/lark/card-handler.js';
|
|
119
134
|
import { setIssueActivate } from './im/lark/issue-command-deps.js';
|
|
120
135
|
import { startIssueOutboxPump } from './services/issue-outbox-pump.js';
|
|
121
|
-
import { parseWorkflowGrillTrigger, buildWorkflowGrillPrompt, isLegacyTemplateCommand, LEGACY_TEMPLATE_RETIRED_MESSAGE, WORKFLOW_USAGE, } from './im/lark/workflow-slash-command.js';
|
|
136
|
+
import { parseWorkflowGrillTrigger, buildWorkflowGrillPrompt, isLegacyTemplateCommand, LEGACY_TEMPLATE_RETIRED_MESSAGE, WORKFLOW_USAGE, WORKFLOW_DISABLED_MESSAGE, } from './im/lark/workflow-slash-command.js';
|
|
122
137
|
import { parseV3SavedWorkflowCommand, v3SavedWorkflowUsage, } from './im/lark/v3-saved-workflow-command.js';
|
|
123
138
|
import { authorizeV3SavedWorkflowInvocation, defaultV3SavedWorkflowExecutionServices, deliverV3SavedWorkflowNotification, executeV3SavedWorkflowCommand, resolveV3SavedWorkflowMessageTargets, } from './im/lark/v3-saved-workflow-handler.js';
|
|
124
139
|
import { createV3GateRunner, preflightV3RunStart, readV3RunChatBinding, requestV3RunCancel, requestV3Retry, requestV3LoopGrant, } from './workflows/v3/daemon-run.js';
|
|
@@ -173,7 +188,7 @@ function republishResolvedAllowedUsers(larkAppId, resolved) {
|
|
|
173
188
|
catch { /* best effort */ }
|
|
174
189
|
}
|
|
175
190
|
let vcMeetingTerminalReconciler;
|
|
176
|
-
import { isBotMentioned, probeBotOpenId, startLarkEventDispatcher, markForwardFollowupsSessionsReady, writeBotInfoFile, canOperate, canRunDaemonCommand, evaluateTalk, evaluateBotTalk, evaluateAskAnswerTalk, grantCommandRestriction, isKnownPeerBot, checkRequiredScopes } from './im/lark/event-dispatcher.js';
|
|
191
|
+
import { isBotMentioned, probeBotOpenId, startLarkEventDispatcher, markForwardFollowupsSessionsReady, writeBotInfoFile, canOperate, canRunDaemonCommand, evaluateTalk, evaluateBotTalk, evaluateAskAnswerTalk, askCustomReplyCandidate, grantCommandRestriction, isKnownPeerBot, checkRequiredScopes } from './im/lark/event-dispatcher.js';
|
|
177
192
|
import { getDocSubscription, listAllDocSubscriptions, putDocSubscription, removeDocSubscription, setDocCommentPollCursor } from './services/doc-subs-store.js';
|
|
178
193
|
import { BOT_REPLY_SENTINEL, subscribeDocFile, unsubscribeDocFile, addCommentReaction, removeCommentReaction, hasBotSentinel, isBotAuthoredReply, listDocComments } from './im/lark/doc-comment.js';
|
|
179
194
|
import { learnFromMentions, resolveSender, flushIdentityCacheSync } from './im/lark/identity-cache.js';
|
|
@@ -182,7 +197,7 @@ import { buildDocCommentTurnInput, buildDocWatchWarmupTurnInput } from './core/d
|
|
|
182
197
|
import { advanceDocCommentCursor, docCommentRepliesAfterCursor, latestDocCommentPollCursor } from './core/doc-comment-poller.js';
|
|
183
198
|
import { renderBufferedSenderBlock } from './core/session-manager.js';
|
|
184
199
|
import { shutdownBackendDisposition } from './core/persistent-backend.js';
|
|
185
|
-
import {
|
|
200
|
+
import { abortRemoteShutdownFleet, canAbortVerifiedExitedRemotePreparation, collectUniqueDaemonShutdownSessions, commitPreparedRemoteShutdown, isPreparedRemoteSessionCurrent, persistPreparedRemoteShutdownFleet, prepareRemoteFleetForShutdown, } from './core/remote-shutdown-detach.js';
|
|
186
201
|
import { BOT_TURN_MUTATION_SHUTDOWN_ACQUIRE_TIMEOUT_MS, DAEMON_SHUTDOWN_MAX_MS, DAEMON_WORKER_EXIT_GRACE_MS, } from './core/shutdown-budgets.js';
|
|
187
202
|
import { evaluateVcMeetingConsumerIsolation } from './services/vc-meeting-consumer-isolation.js';
|
|
188
203
|
import { markSessionActivity, announcePendingRepoSession, publishAttentionPatch, publishLastInputFromBotPatch, publishSessionMessagePreviewPatch, publishClosedSessionPatch, clearAgentAttention, } from './core/session-activity.js';
|
|
@@ -202,7 +217,7 @@ import { connectRealtimeVoiceTransport, createProtoRealtimeVoiceProtocol, fetchR
|
|
|
202
217
|
import { createGroupWithBots } from './services/group-creator.js';
|
|
203
218
|
import { addBotToChat, isInChat } from './services/groups-store.js';
|
|
204
219
|
import { initSessionGroups, isSessionGroup, getSessionGroup, touchSessionGroup } from './services/session-groups-store.js';
|
|
205
|
-
import { maybeBirthSessionGroup } from './core/session-group-birth.js';
|
|
220
|
+
import { maybeBirthSessionGroup, declinesSessionGroupBirthAsSlashCommand } from './core/session-group-birth.js';
|
|
206
221
|
import { scheduleSessionGroupTitle } from './services/session-group-title.js';
|
|
207
222
|
import { setChatReplyMode } from './services/chat-reply-mode-store.js';
|
|
208
223
|
import { hasVcMeetingEndedTombstone, listVcMeetingRuntimeSessionsByListenerAndAgent, listVcMeetingRuntimeSessions, pruneExpiredVcMeetingRuntimeSessions, recordVcMeetingEndedTombstone, recordVcMeetingRuntimeSession, removeVcMeetingRuntimeSession, } from './services/vc-meeting-runtime-store.js';
|
|
@@ -231,6 +246,9 @@ const activeSessions = new Map();
|
|
|
231
246
|
* (codex P1-2). While false, /api/asks returns a retryable 503 for unknown
|
|
232
247
|
* sessions instead, so the reconnecting hook keeps waiting through the restore. */
|
|
233
248
|
let sessionsRestored = false;
|
|
249
|
+
/** Once-per-daemon guard for the mojo containment boot reconciliation. The store
|
|
250
|
+
* is bot-agnostic, so it must run once regardless of how many bots start. */
|
|
251
|
+
let mojoContainmentReconciledThisBoot = false;
|
|
234
252
|
const VC_MEETING_DELIVERY_LEASE_MS = 15 * 60_000;
|
|
235
253
|
const VC_MEETING_DELIVERY_LEASE_SCAN_MS = 60_000;
|
|
236
254
|
const VC_MEETING_RUNTIME_EXPIRY_ACK_TIMEOUT_MS = 3_000;
|
|
@@ -367,15 +385,37 @@ function vcMeetingPersistentBackendAvailable(backendType) {
|
|
|
367
385
|
return ZellijBackend.isAvailable();
|
|
368
386
|
return ZmxBackend.isAvailable();
|
|
369
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* VC receiver teardown: this fence's job is to guarantee the local PRODUCER
|
|
390
|
+
* process is dead before hub replay is admitted. killWorker refuses an
|
|
391
|
+
* unprepared live remote worker (P0-2) — the fail-safe direction for lineage,
|
|
392
|
+
* but for THIS caller a silent refusal is fail-OPEN: the pane probes then read
|
|
393
|
+
* `missing` (mojo has no persistent pane) and the fence cleared while the
|
|
394
|
+
* producer kept running. Remote-frozen receivers are therefore retired
|
|
395
|
+
* process-only — no close IPC, no remote cancel, lineage and containment
|
|
396
|
+
* handles intact — with retireWorkerProcessOnly's SIGTERM→SIGKILL backstop
|
|
397
|
+
* guaranteeing death; local receivers keep killWorker so their backing
|
|
398
|
+
* session is torn down as before.
|
|
399
|
+
*/
|
|
400
|
+
function teardownVcReceiverWorker(ds) {
|
|
401
|
+
if (isRemoteBackendSession(ds))
|
|
402
|
+
retireWorkerProcessOnly(ds, 'vc_runtime_lease');
|
|
403
|
+
else
|
|
404
|
+
killWorker(ds);
|
|
405
|
+
}
|
|
370
406
|
let testOnlyVcMeetingBootBackingMissing;
|
|
371
407
|
function vcMeetingBootBackingMissing(sessionId, destroy) {
|
|
372
408
|
if (testOnlyVcMeetingBootBackingMissing) {
|
|
373
409
|
return testOnlyVcMeetingBootBackingMissing(sessionId, destroy);
|
|
374
410
|
}
|
|
375
411
|
const ds = findActiveBySessionId(sessionId);
|
|
412
|
+
// Captured BEFORE teardown: retirement nulls ds.worker while the process
|
|
413
|
+
// dies asynchronously, and the producer-liveness check below needs the real
|
|
414
|
+
// ChildProcess to prove the exit.
|
|
415
|
+
const workerBefore = ds?.worker && !ds.worker.killed ? ds.worker : null;
|
|
376
416
|
if (destroy && ds) {
|
|
377
417
|
try {
|
|
378
|
-
|
|
418
|
+
teardownVcReceiverWorker(ds);
|
|
379
419
|
}
|
|
380
420
|
catch (err) {
|
|
381
421
|
logger.warn(`[vc-delivery] boot recovery worker teardown failed session=${sessionId}: ${err}`);
|
|
@@ -416,6 +456,16 @@ function vcMeetingBootBackingMissing(sessionId, destroy) {
|
|
|
416
456
|
+ `backend=${backendType} session=${sessionId}`);
|
|
417
457
|
}
|
|
418
458
|
}
|
|
459
|
+
// The worker PROCESS is itself the producer this recovery gates on; pane
|
|
460
|
+
// probes say nothing about it (mojo has no pane at all, so they always read
|
|
461
|
+
// `missing`). Clear only once the previously-live worker has actually
|
|
462
|
+
// exited — the retirement's SIGTERM→SIGKILL backstop makes a later reprobe
|
|
463
|
+
// see it gone.
|
|
464
|
+
if (workerBefore && workerBefore.exitCode === null && workerBefore.signalCode === null) {
|
|
465
|
+
allMissing = false;
|
|
466
|
+
logger.error(`[vc-delivery] boot recovery worker process still live; receiver remains gated `
|
|
467
|
+
+ `session=${sessionId}`);
|
|
468
|
+
}
|
|
419
469
|
return allMissing;
|
|
420
470
|
}
|
|
421
471
|
function scheduleVcMeetingBootRecoveryProbe(key, sessionId, delayMs) {
|
|
@@ -449,9 +499,11 @@ function escalateVcMeetingBootRecovery(key, sessionId) {
|
|
|
449
499
|
vcMeetingReceiverRecoveryEscalating.add(key);
|
|
450
500
|
const ds = findActiveBySessionId(sessionId);
|
|
451
501
|
if (ds)
|
|
452
|
-
|
|
453
|
-
// Wait past
|
|
454
|
-
//
|
|
502
|
+
teardownVcReceiverWorker(ds);
|
|
503
|
+
// Wait past the retirement's SIGTERM→SIGKILL backstop window (killWorker for
|
|
504
|
+
// local receivers, retireWorkerProcessOnly for remote-frozen ones — a plain
|
|
505
|
+
// killWorker would REFUSE a live remote worker and arm nothing), then
|
|
506
|
+
// direct-kill and probe. exists/unknown stays scoped-gated and reprobes.
|
|
455
507
|
scheduleVcMeetingBootRecoveryProbe(key, sessionId, VC_MEETING_RUNTIME_EXPIRY_TEARDOWN_MS);
|
|
456
508
|
}
|
|
457
509
|
function acknowledgeVcMeetingReceiverRecovery(key) {
|
|
@@ -580,6 +632,34 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
|
|
|
580
632
|
scheduleReprobe(fence, 'identity conflict');
|
|
581
633
|
return false;
|
|
582
634
|
}
|
|
635
|
+
// Captured BEFORE teardown: retirement nulls ds.worker while the process
|
|
636
|
+
// dies asynchronously; the producer-liveness gate below needs the real
|
|
637
|
+
// ChildProcess to prove the exit. Falls back to the process observed at
|
|
638
|
+
// arm time when the registry no longer resolves the ds — a deleted
|
|
639
|
+
// registry entry is not proof the producer died (fourth-round review).
|
|
640
|
+
const armedAlive = fence.armedWorker
|
|
641
|
+
&& !fence.armedWorker.killed
|
|
642
|
+
&& fence.armedWorker.exitCode === null
|
|
643
|
+
&& fence.armedWorker.signalCode === null
|
|
644
|
+
? fence.armedWorker : null;
|
|
645
|
+
// Third source, for a fence armed AFTER the registry delete (the other
|
|
646
|
+
// half of the collision-loser timing): a process-only retirement is still
|
|
647
|
+
// dying for this session id, and neither ds nor arm-time capture ever saw
|
|
648
|
+
// it. Pin it onto the fence so later reprobes keep tracking the same
|
|
649
|
+
// process.
|
|
650
|
+
let retiringAlive = null;
|
|
651
|
+
if (!armedAlive && !(ds?.worker && !ds.worker.killed)) {
|
|
652
|
+
for (const w of deps.resolveRetiringWorkers?.(fence.receiverSessionId) ?? []) {
|
|
653
|
+
if (w && !w.killed && w.exitCode === null && w.signalCode === null) {
|
|
654
|
+
retiringAlive = w;
|
|
655
|
+
fence.armedWorker = w;
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
const workerBefore = (ds?.worker && !ds.worker.killed ? ds.worker : null)
|
|
661
|
+
?? armedAlive
|
|
662
|
+
?? retiringAlive;
|
|
583
663
|
if (ds) {
|
|
584
664
|
try {
|
|
585
665
|
deps.killWorker(ds);
|
|
@@ -626,6 +706,17 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
|
|
|
626
706
|
+ `attempt=${fence.dispatchAttempt}`);
|
|
627
707
|
}
|
|
628
708
|
}
|
|
709
|
+
// The worker PROCESS is itself the producer this fence gates on; pane
|
|
710
|
+
// probes say nothing about it — mojo owns no pane, so they always read
|
|
711
|
+
// `missing`, which is exactly how a refused/incomplete teardown became
|
|
712
|
+
// fail-OPEN (third-round review, gate 3). Clear only once the previously
|
|
713
|
+
// live worker has actually EXITED; the retirement's SIGTERM→SIGKILL
|
|
714
|
+
// backstop guarantees a later reprobe sees it gone.
|
|
715
|
+
if (workerBefore && workerBefore.exitCode === null && workerBefore.signalCode === null) {
|
|
716
|
+
allMissing = false;
|
|
717
|
+
deps.error(`[vc-delivery] runtime lease worker process still live; delivery remains gated `
|
|
718
|
+
+ `session=${fence.receiverSessionId} attempt=${fence.dispatchAttempt}`);
|
|
719
|
+
}
|
|
629
720
|
// PTY has no surviving backing process once its worker has crossed the
|
|
630
721
|
// SIGKILL backstop. Persistent backends unlock only after every applicable
|
|
631
722
|
// deterministic name probes authoritatively missing. The backing proof is
|
|
@@ -680,8 +771,11 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
|
|
|
680
771
|
deps.error(`[vc-delivery] runtime lease escalation failed to kill worker `
|
|
681
772
|
+ `session=${fence.receiverSessionId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
682
773
|
}
|
|
683
|
-
//
|
|
684
|
-
//
|
|
774
|
+
// The teardown above arms a SIGTERM→SIGKILL backstop (killWorker's close
|
|
775
|
+
// path for local receivers; retireWorkerProcessOnly for remote-frozen
|
|
776
|
+
// ones — a plain killWorker would REFUSE a live remote worker and arm
|
|
777
|
+
// nothing, which is why the fence used to fail open for mojo). Only after
|
|
778
|
+
// that window do we directly kill + probe the deterministic owned pane.
|
|
685
779
|
fence.timer = setTimeout(() => {
|
|
686
780
|
if (!isCurrent(fence) || fence.phase !== 'escalating')
|
|
687
781
|
return;
|
|
@@ -718,6 +812,10 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
|
|
|
718
812
|
teardownAndProbe(fence, !ds ? 'missing-session teardown' : 'workerless teardown');
|
|
719
813
|
return;
|
|
720
814
|
}
|
|
815
|
+
// Remember the live producer process itself: registry state can stop
|
|
816
|
+
// resolving this ds before the process has died, and the liveness gate in
|
|
817
|
+
// teardownAndProbe must keep seeing it.
|
|
818
|
+
fence.armedWorker = ds.worker;
|
|
721
819
|
if ((ds.workerGeneration ?? 0) !== ref.workerGeneration) {
|
|
722
820
|
deps.error(`[vc-delivery] runtime lease worker generation mismatch; escalating `
|
|
723
821
|
+ `session=${ref.receiverSessionId} receipt=${ref.workerGeneration} `
|
|
@@ -766,6 +864,12 @@ function createVcMeetingRuntimeLeaseRecovery(deps) {
|
|
|
766
864
|
return false;
|
|
767
865
|
}
|
|
768
866
|
if (context.disposition === 'queued_removed') {
|
|
867
|
+
// No producer-exit proof required here, deliberately: `queued_removed`
|
|
868
|
+
// is an ACK from the EXACT expected worker generation saying it removed
|
|
869
|
+
// the queued delivery itself. The producer is alive, current and
|
|
870
|
+
// cooperating — the double-delivery risk this fence gates on is gone
|
|
871
|
+
// without anyone dying. Exit proof is demanded only on the teardown
|
|
872
|
+
// paths, where the producer's state is unknown or adversarial.
|
|
769
873
|
clearFence(fence);
|
|
770
874
|
return true;
|
|
771
875
|
}
|
|
@@ -837,7 +941,8 @@ const vcMeetingRuntimeLeaseRecovery = createVcMeetingRuntimeLeaseRecovery({
|
|
|
837
941
|
throw new Error('receiver worker is not live');
|
|
838
942
|
ds.worker.send(message);
|
|
839
943
|
},
|
|
840
|
-
killWorker,
|
|
944
|
+
killWorker: teardownVcReceiverWorker,
|
|
945
|
+
resolveRetiringWorkers: retiringWorkersForSession,
|
|
841
946
|
resolvePersistentScope(ds) {
|
|
842
947
|
const backendType = getSessionPersistentBackendType(ds);
|
|
843
948
|
if (backendType)
|
|
@@ -1943,19 +2048,34 @@ function scheduleDeferredScheduleSettlement(ds, context) {
|
|
|
1943
2048
|
// Exact transcript terminal needs only a short filesystem visibility grace.
|
|
1944
2049
|
// Screen-only adapters use a longer confirmation and re-check that the same
|
|
1945
2050
|
// turn is still idle before reclaiming the hidden session.
|
|
2051
|
+
// Remote backends (riff / mojo) report their turn boundary over the network,
|
|
2052
|
+
// so allow the same longer grace as the screen-only path instead of the 300ms
|
|
2053
|
+
// local-filesystem one.
|
|
2054
|
+
const remoteTerminal = ds.session.backendType === 'riff'
|
|
2055
|
+
|| ds.session.backendType === 'mojo';
|
|
1946
2056
|
const delayMs = context.source === 'terminal'
|
|
1947
|
-
? (
|
|
2057
|
+
? (remoteTerminal ? 1_500 : 300)
|
|
1948
2058
|
: 1_500;
|
|
1949
2059
|
const timer = setTimeout(() => {
|
|
1950
2060
|
deferredScheduleSettleTimers.delete(sessionId);
|
|
1951
2061
|
void settleDeferredScheduleRun(ds, context, {
|
|
1952
2062
|
reconcile: reconcileDeferredTopicBinding,
|
|
1953
|
-
|
|
2063
|
+
// Background path: no user surface, so a residual/refusal must at least be
|
|
2064
|
+
// logged with its remote id instead of being discarded.
|
|
2065
|
+
closeSession: (id) => closeSessionForBackgroundCleanup(id, 'deferred-schedule settlement'),
|
|
1954
2066
|
}).then((result) => {
|
|
1955
2067
|
if (result.action === 'materialized') {
|
|
1956
2068
|
logger.info(`[scheduler] Deferred topic materialized session=${sessionId.slice(0, 8)} root=${result.rootMessageId.slice(0, 12)}`);
|
|
1957
2069
|
return;
|
|
1958
2070
|
}
|
|
2071
|
+
if (result.action === 'close_refused') {
|
|
2072
|
+
// Must NOT print "Auto-closed": the row is still active and its remote
|
|
2073
|
+
// session may still be running. Two contradictory log lines about the same
|
|
2074
|
+
// session is exactly how a false success hides.
|
|
2075
|
+
logger.error(`[scheduler] Deferred run close REFUSED (${result.error ?? 'unknown'}); session stays `
|
|
2076
|
+
+ `ACTIVE session=${sessionId.slice(0, 8)} turn=${context.turnId.slice(0, 12)} source=${context.source}`);
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
1959
2079
|
if (result.action === 'closed') {
|
|
1960
2080
|
logger.info(`[scheduler] Auto-closed silent deferred run with no botmux send `
|
|
1961
2081
|
+ `session=${sessionId.slice(0, 8)} turn=${context.turnId.slice(0, 12)} source=${context.source}`);
|
|
@@ -2375,8 +2495,11 @@ async function maybeSeedCardlessForceTopicTurn(args) {
|
|
|
2375
2495
|
}
|
|
2376
2496
|
}
|
|
2377
2497
|
async function revokeQuotaGrant(larkAppId, chatId, senderOpenId, ev) {
|
|
2498
|
+
// 会话群里的 chatGrant 是**继承**来的:授权记录挂在出生前那个私聊上(ev.grantChatId),
|
|
2499
|
+
// 不在会话群自己身上。撤销必须落到来源 chat,否则删了个不存在的记录,硬上限失效。
|
|
2500
|
+
const grantChatId = ev.grantChatId ?? chatId;
|
|
2378
2501
|
const result = ev.reason === 'chatGrant'
|
|
2379
|
-
? await removeChatGrant(larkAppId,
|
|
2502
|
+
? await removeChatGrant(larkAppId, grantChatId, senderOpenId)
|
|
2380
2503
|
: ev.reason === 'globalGrant'
|
|
2381
2504
|
? await removeGlobalGrant(larkAppId, senderOpenId)
|
|
2382
2505
|
: { ok: true, removed: false };
|
|
@@ -2397,6 +2520,20 @@ async function notifyQuotaExhausted(larkAppId, anchor, senderOpenId, limit) {
|
|
|
2397
2520
|
export async function enforceMessageQuotaForCliInput(larkAppId, chatId, senderOpenId, messageId, anchor, senderUnionId, memberUnionId, chatType, botSender, opts) {
|
|
2398
2521
|
if (opts?.listenerAuthorized)
|
|
2399
2522
|
return true;
|
|
2523
|
+
// 会话群出生轮:**同一条消息**的授权判定与扣费,刚刚由本函数在原 DM 上下文里
|
|
2524
|
+
// 一起做完(handleNewTopicAdmitted 的建群前扣费点:扣费被拒必须零外部副作用,
|
|
2525
|
+
// 所以它必须排在 createGroupWithBots 之前)。这一轮绝不能再复查一次:
|
|
2526
|
+
// • 新群是 bot 刚为这个发送者建的,chat 维度的 talk 来源(chatGrant /
|
|
2527
|
+
// allowedChatGroup / oncall / p2p 专属的 p2pOpen)按定义不可能已经落在它
|
|
2528
|
+
// 上面,复查只会产出假阴性;
|
|
2529
|
+
// • 而这条消息**已经扣过一次费**——被假阴性丢掉就成了「扣了费还把任务丢了」:
|
|
2530
|
+
// 用户额度少一格,任务无声消失,连一句拒绝提示都没有(丢弃分支只打 debug 日志)。
|
|
2531
|
+
// 「扣了费就不能丢任务,丢任务就不能扣费」是这道闸的硬不变量,两侧只能同进同退。
|
|
2532
|
+
// 授权本身并没有被放宽:真正的判定就是 DM 那次(真实 chatId + chatType='p2p'),
|
|
2533
|
+
// 这里只是不拿一个必然更严的新上下文去推翻它。跨 chat 的授权继承缺口是另一件事
|
|
2534
|
+
//(新群里的**后续**消息仍按新 chat 判定),不由这条已扣费的出生轮来承担。
|
|
2535
|
+
if (opts?.alreadyAuthorizedAndCharged)
|
|
2536
|
+
return true;
|
|
2400
2537
|
// senderUnionId(bot-locked)让 evaluateTalk 认出跨部署团队 peer bot(teamBot 腿);
|
|
2401
2538
|
// memberUnionId(可为真人 union)走 teamMember 腿——否则外部闸门/群闸门放进来的
|
|
2402
2539
|
// 团队 bot 或团队成员消息会在这里复查处被静默丢弃(#332 端到端断点,人腿同理)。
|
|
@@ -2994,6 +3131,13 @@ async function handleV3SavedWorkflowCommandIfAny(invocation) {
|
|
|
2994
3131
|
await notify('❌ Saved Workflow 需要可验证的飞书用户身份。', 'authorization');
|
|
2995
3132
|
return true;
|
|
2996
3133
|
}
|
|
3134
|
+
// Machine-wide workflow kill-switch: refuse starting/authoring a workflow when
|
|
3135
|
+
// the feature is off. `cancel` (and other decrease-only management) stays
|
|
3136
|
+
// available so an in-flight run started before the flip can be wound down.
|
|
3137
|
+
if ((command.kind === 'save' || command.kind === 'run') && !isWorkflowFeatureEnabled()) {
|
|
3138
|
+
await notify(WORKFLOW_DISABLED_MESSAGE, 'validation');
|
|
3139
|
+
return true;
|
|
3140
|
+
}
|
|
2997
3141
|
if (
|
|
2998
3142
|
// Cancellation is decrease-only and is still protected below by the
|
|
2999
3143
|
// immutable owner/chat/app binding (or explicit canOperate). Keep it
|
|
@@ -3129,6 +3273,7 @@ function beginNewTurn(ds, title, turnId) {
|
|
|
3129
3273
|
ds.parkedStreamCardNonce = ds.streamCardNonce;
|
|
3130
3274
|
ds.frozenCards.set(ds.streamCardNonce, {
|
|
3131
3275
|
messageId: ds.streamCardId,
|
|
3276
|
+
replyTargetKey: ds.streamCardReplyTargetKey,
|
|
3132
3277
|
content: ds.lastScreenContent ?? '',
|
|
3133
3278
|
title: prevTitle,
|
|
3134
3279
|
displayMode: prevMode,
|
|
@@ -3686,10 +3831,16 @@ async function adoptCodexNotifierEvent(larkAppId, event, cardMessageId, ownerOpe
|
|
|
3686
3831
|
}
|
|
3687
3832
|
// 接管原生 Codex App 线程时固定为纯 codex-app 启动,不能继承通知 Bot 的
|
|
3688
3833
|
// wrapper/model;这些配置针对普通 CLI,会错误包装 app-server runner。
|
|
3834
|
+
// model 由 resolveSessionLaunchModel 在每次 spawn 时解析:这里把 cliId 钉成
|
|
3835
|
+
// codex-app 后,若通知 Bot 自己不是 codex-app,session 与 bot 的 cliId 不匹配
|
|
3836
|
+
// → 不会拿 bot 那个面向别的 CLI 的 model;清掉历史记录值让兜底也为空。
|
|
3837
|
+
// spawnModelOverride(trigger 的一次性 model)优先级最高且无条件,必须一并清掉,
|
|
3838
|
+
// 否则它会泄漏进接管后的 codex-app 启动。
|
|
3689
3839
|
ds.session.cliId = 'codex-app';
|
|
3690
3840
|
ds.session.cliPathOverride = botCfg.cliPathOverride;
|
|
3691
3841
|
delete ds.session.wrapperCli;
|
|
3692
3842
|
delete ds.session.model;
|
|
3843
|
+
ds.spawnModelOverride = undefined;
|
|
3693
3844
|
ds.session.agentFrozen = true;
|
|
3694
3845
|
sessionStore.updateSession(ds.session);
|
|
3695
3846
|
// 默认 flat DM(p2pMode=chat)下这条按钮回调复用同一私聊的现有会话。若该会话
|
|
@@ -3907,6 +4058,14 @@ workflowDaemonMutationRoute('start', async (reply, params, _body, identity) => {
|
|
|
3907
4058
|
const runId = params.runId;
|
|
3908
4059
|
if (!isValidV3RunId(runId))
|
|
3909
4060
|
return reply(400, { ok: false, error: 'bad_run_id' });
|
|
4061
|
+
// Machine-wide workflow kill-switch: refuse launching a NEW daemon-driven run
|
|
4062
|
+
// when the feature is off. This is the common sink for both `botmux workflow
|
|
4063
|
+
// start` and the grill `approve-dag` kick, so gating here closes the edge where
|
|
4064
|
+
// a run was grilled+approved before the flip. Restart recovery of an
|
|
4065
|
+
// already-started run (coldAttach / reconcileV3PendingGates) is a separate path
|
|
4066
|
+
// and is intentionally NOT gated, and `retry`/`grant`/`cancel` stay available.
|
|
4067
|
+
if (!isWorkflowFeatureEnabled())
|
|
4068
|
+
return reply(409, { ok: false, error: 'workflow_disabled' });
|
|
3910
4069
|
const runDir = join(v3DefaultBaseDir(), runId);
|
|
3911
4070
|
const preflight = preflightV3RunStart(runDir);
|
|
3912
4071
|
if (!preflight.ok) {
|
|
@@ -13697,12 +13856,14 @@ export const __testOnly_onQueuedActivationSubmitted = onQueuedActivationSubmitte
|
|
|
13697
13856
|
* deliberately no await between the final buffered-input snapshot, fork, and
|
|
13698
13857
|
* release: a later handler either buffers before this block or observes the
|
|
13699
13858
|
* live worker after it. */
|
|
13700
|
-
function forkReservedInitialSession(ds, availableBots) {
|
|
13859
|
+
function forkReservedInitialSession(ds, availableBots, trustedCaller) {
|
|
13701
13860
|
const userPrompt = ds.pendingPrompt ?? '';
|
|
13702
13861
|
const input = buildReservedInitialInput(ds, availableBots);
|
|
13862
|
+
if (trustedCaller)
|
|
13863
|
+
input.trustedCaller = trustedCaller;
|
|
13703
13864
|
rememberLastCliInput(ds, userPrompt, input);
|
|
13704
13865
|
const turnId = ds.pendingTurnId ?? ds.session.pendingRepoSetup?.turnId;
|
|
13705
|
-
forkWorker(ds, input, turnId ? { turnId } : false);
|
|
13866
|
+
forkWorker(ds, input, turnId ? { turnId, trustedCaller } : false);
|
|
13706
13867
|
ds.pendingTurnId = undefined;
|
|
13707
13868
|
// A no-project pendingRepo fallback enters forkWorker with `session.queued`
|
|
13708
13869
|
// still set. forkWorker materializes the exact opening as a tokened
|
|
@@ -13805,15 +13966,15 @@ function isInitialSessionPassthrough(larkAppId, cmd) {
|
|
|
13805
13966
|
/** `/fast` is a passthrough keystroke to Codex's native tier toggle — it only
|
|
13806
13967
|
* reaches the executor on a real paste TUI. In RPC input mode the pane is a
|
|
13807
13968
|
* pure viewer (turns go over JSON-RPC, keystrokes never reach the app-server),
|
|
13808
|
-
* and
|
|
13809
|
-
* those backends the toggle is a silent no-op (or worse), so fail closed:
|
|
13969
|
+
* and a remote backend (riff / mojo) turns the text+Enter into two independent
|
|
13970
|
+
* remote turns. On those backends the toggle is a silent no-op (or worse), so fail closed:
|
|
13810
13971
|
* reject with a clear message instead of pretending it worked. The read-only
|
|
13811
13972
|
* card badge is unaffected — it reflects whatever tier Codex actually runs. */
|
|
13812
13973
|
function fastToggleUnsupportedBackend(ds) {
|
|
13813
13974
|
if (!ds)
|
|
13814
13975
|
return false;
|
|
13815
13976
|
const backendType = ds.initConfig?.backendType ?? ds.session.backendType;
|
|
13816
|
-
if (backendType === 'riff')
|
|
13977
|
+
if (backendType === 'riff' || backendType === 'mojo')
|
|
13817
13978
|
return true;
|
|
13818
13979
|
return ds.initConfig?.codexRpcInput === true;
|
|
13819
13980
|
}
|
|
@@ -13888,6 +14049,9 @@ function deliverPassthroughToExistingSession(ds, cmd, commandContent, anchor, la
|
|
|
13888
14049
|
sendWorkerSessionInput(ds, {
|
|
13889
14050
|
type: 'raw_input',
|
|
13890
14051
|
content: commandContent,
|
|
14052
|
+
// Same reason as the worker-pool raw_input send: a passthrough is a real
|
|
14053
|
+
// mojo turn, so it needs the live credential snapshot too.
|
|
14054
|
+
...(mojoLivePatchForSession(ds) ?? {}),
|
|
13891
14055
|
turnId: turn.messageId,
|
|
13892
14056
|
});
|
|
13893
14057
|
turn.onDelivered?.();
|
|
@@ -14152,6 +14316,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14152
14316
|
// routing into thread-scope so the bot's first reply seeds a Lark thread.
|
|
14153
14317
|
let scope = ctx.scope;
|
|
14154
14318
|
let anchor = ctx.anchor;
|
|
14319
|
+
let quotaConsumedBeforeSessionGroupBirth = false;
|
|
14155
14320
|
// ─── p2pMode='group':会话群出生 ────────────────────────────────────────
|
|
14156
14321
|
// group 模式下,顶层 DM 消息在任何会话机制启动前先改道:建一个专属会话群
|
|
14157
14322
|
//(bot 保留群主),把本轮 context 重写到新群(chat-scope)后递归。返回 null
|
|
@@ -14167,10 +14332,32 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14167
14332
|
&& !substituteTrigger
|
|
14168
14333
|
&& scope === 'thread'
|
|
14169
14334
|
&& anchor === messageId
|
|
14170
|
-
|
|
14335
|
+
// 「话题内发送 + 同时发送到会话」的消息 root_id 为空但带 thread_id——
|
|
14336
|
+
// 语境属于既有话题,绝不当全新会话建群(回退 thread 旧行为)。
|
|
14337
|
+
&& !data?.message?.thread_id
|
|
14338
|
+
// 斜杠命令判定必须**早于扣费**:/help、/login、/close 本来就不进 CLI,既不该
|
|
14339
|
+
// 被预扣一次额度,也不该在额度耗尽时被这道闸静默丢掉(下面的 return 会让命令
|
|
14340
|
+
// 根本执行不到)。maybeBirthSessionGroup 对同一条消息本就返回 null(命令不建
|
|
14341
|
+
// 群),所以这里只是把它的结论提前一步,建群行为一字未改;命令随后照常走
|
|
14342
|
+
// parseSlashCommandInvocation 分支,真正会注入 CLI 的消息(含未注册的 /foo,
|
|
14343
|
+
// 它落不进命令分支)仍由下面 pre-worker 那道闸按原样扣一次费——净扣费不变。
|
|
14344
|
+
// 谓词刻意复用 birth 内部的同一个:两侧同源才能保证「跳过扣费」与「不建群」
|
|
14345
|
+
// 是同一个判断——窄于它会退回本 bug,宽于它则会让本该建群的消息不再建群。
|
|
14346
|
+
&& !declinesSessionGroupBirthAsSlashCommand(data)) {
|
|
14347
|
+
// A quota denial must have zero external side effects. Charge the original
|
|
14348
|
+
// DM before creating the real Feishu chat, then mark the rewritten turn so
|
|
14349
|
+
// the ordinary pre-worker gate below does not charge it a second time.
|
|
14350
|
+
const quotaSenderOpenId = data.sender?.sender_id?.open_id;
|
|
14351
|
+
const quotaSenderUnionId = data.sender?.sender_id?.union_id;
|
|
14352
|
+
const quotaTeamTrustUnionId = (data.sender?.sender_type === 'app' || data.sender?.sender_type === 'bot')
|
|
14353
|
+
? quotaSenderUnionId
|
|
14354
|
+
: undefined;
|
|
14355
|
+
if (!await enforceMessageQuotaForCliInput(larkAppId, chatId, quotaSenderOpenId, messageId, anchor, quotaTeamTrustUnionId, quotaSenderUnionId, chatType))
|
|
14356
|
+
return;
|
|
14357
|
+
quotaConsumedBeforeSessionGroupBirth = true;
|
|
14171
14358
|
const reborn = await maybeBirthSessionGroup(data, ctx);
|
|
14172
14359
|
if (reborn)
|
|
14173
|
-
return handleNewTopic(data, reborn);
|
|
14360
|
+
return handleNewTopic(data, { ...reborn, sessionGroupQuotaConsumed: true });
|
|
14174
14361
|
}
|
|
14175
14362
|
// ─── 会话群同群续聊 ─────────────────────────────────────────────────────
|
|
14176
14363
|
// 会话群里的新消息发现登记的会话已关闭时,自动 resume 原会话(与话题内续聊
|
|
@@ -14252,6 +14439,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14252
14439
|
}
|
|
14253
14440
|
// senderOpenId 已在上方(force-topic grant 限制前)声明;这里只补 master 新增的 senderUnionId。
|
|
14254
14441
|
const senderUnionId = data.sender?.sender_id?.union_id;
|
|
14442
|
+
const trustedCaller = trustedCallerForTurn(larkAppId, senderOpenId, senderUnionId);
|
|
14255
14443
|
// union_id 信任腿(canOperate/evaluateTalk 的 teamBot)只对**飞书盖章的 bot 发送方**
|
|
14256
14444
|
// 生效:平台 roster 是成员机器自报的,若不锁 sender_type,恶意成员把某个真人的
|
|
14257
14445
|
// union_id 报成"自家 bot",那个真人就会在全团队机器上被当队友 bot 放行(talk +
|
|
@@ -14328,6 +14516,10 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14328
14516
|
let workflowGrillPrompt;
|
|
14329
14517
|
const newTopicGrill = parseWorkflowGrillTrigger(cmdContent);
|
|
14330
14518
|
if (newTopicGrill) {
|
|
14519
|
+
if (!isWorkflowFeatureEnabled()) {
|
|
14520
|
+
await sessionReply(anchor, WORKFLOW_DISABLED_MESSAGE, 'text', larkAppId);
|
|
14521
|
+
return;
|
|
14522
|
+
}
|
|
14331
14523
|
if (await replyGrantRestrictionIfNeeded(larkAppId, chatId, senderOpenId, anchor, '/workflow')) {
|
|
14332
14524
|
return;
|
|
14333
14525
|
}
|
|
@@ -14551,9 +14743,20 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14551
14743
|
&& buildQuoteHint(parsed, scope, anchor, localeForBot(larkAppId)) === ''
|
|
14552
14744
|
&& !ctx.forwardSeedData
|
|
14553
14745
|
&& !messageListener;
|
|
14746
|
+
// Session-group birth charges the ORIGINAL DM before creating the Feishu chat
|
|
14747
|
+
// (a quota denial must have zero external side effects), so by the time the
|
|
14748
|
+
// rewritten group turn gets here THIS message is already authorized AND
|
|
14749
|
+
// already paid for — see `alreadyAuthorizedAndCharged` in
|
|
14750
|
+
// enforceMessageQuotaForCliInput for why re-deciding it here can only lose
|
|
14751
|
+
// the unit we just took. `skipCharge` stays set as well so that even if that
|
|
14752
|
+
// short-circuit is ever removed, the worst case is a redundant recheck, never
|
|
14753
|
+
// a double charge.
|
|
14754
|
+
const sessionGroupAlreadyCharged = !!ctx.sessionGroupQuotaConsumed
|
|
14755
|
+
|| quotaConsumedBeforeSessionGroupBirth;
|
|
14554
14756
|
if (!await enforceMessageQuotaForCliInput(larkAppId, chatId, senderOpenId, messageId, anchor, teamTrustUnionId, senderUnionId, chatType, isBotSenderType, {
|
|
14555
14757
|
listenerAuthorized: !!messageListener,
|
|
14556
|
-
skipCharge: isBareForceTopic,
|
|
14758
|
+
skipCharge: isBareForceTopic || sessionGroupAlreadyCharged,
|
|
14759
|
+
alreadyAuthorizedAndCharged: sessionGroupAlreadyCharged,
|
|
14557
14760
|
})) {
|
|
14558
14761
|
return;
|
|
14559
14762
|
}
|
|
@@ -14835,7 +15038,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14835
15038
|
// Ack reaction targets the ORIGINAL inbound message (2nd arg); the turn id
|
|
14836
15039
|
// (5th arg) is the reply anchor so provenance holds on session-group births.
|
|
14837
15040
|
await noteTurnReceived(ds, messageId, content, newTopicSender, replyAnchorId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
14838
|
-
forkReservedInitialSession(ds, availableBots);
|
|
15041
|
+
forkReservedInitialSession(ds, availableBots, trustedCaller);
|
|
14839
15042
|
// fork 成功即开场已交给 CLI;fork 抛错则开场只存在于内存,保持重发提示。
|
|
14840
15043
|
markIngressAdmitted(ctx);
|
|
14841
15044
|
const reason = oncallEntry
|
|
@@ -14887,7 +15090,7 @@ async function handleNewTopicAdmitted(data, ctx) {
|
|
|
14887
15090
|
// Ack reaction targets the ORIGINAL inbound message (2nd arg); the turn id
|
|
14888
15091
|
// (5th arg) is the reply anchor so provenance holds on session-group births.
|
|
14889
15092
|
await noteTurnReceived(ds, messageId, content, newTopicSender, replyAnchorId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
14890
|
-
forkReservedInitialSession(ds, availableBots);
|
|
15093
|
+
forkReservedInitialSession(ds, availableBots, trustedCaller);
|
|
14891
15094
|
logger.info(`Session ${session.sessionId} ready (no projects to select), total active: ${getActiveCount()}`);
|
|
14892
15095
|
}
|
|
14893
15096
|
}
|
|
@@ -15093,6 +15296,15 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15093
15296
|
anchor = chatId;
|
|
15094
15297
|
scope = 'chat';
|
|
15095
15298
|
}
|
|
15299
|
+
// bot.added 是成员变更事件,没有用户 message_id 可作首轮 turn 身份。非 shared
|
|
15300
|
+
// 路径没有 shared reply seed 兜底,若以 pendingTurnId=undefined 直接 fork,
|
|
15301
|
+
// worker 发布的 managed_turn_origin 不含 turnId,CLI 首轮 `botmux send` 的
|
|
15302
|
+
// managed-origin attestation 会被 daemon 以 origin_unproven 拒绝——首轮回复
|
|
15303
|
+
// 发不回飞书。这里自行铸造首轮 turn 身份:
|
|
15304
|
+
// - thread scope:seed 消息本身就是可见锚点且是真实 om_ id,直接复用;
|
|
15305
|
+
// - chat scope:没有任何消息存在,铸造 daemon-owned 合成 turn id(同 trigger
|
|
15306
|
+
// 会话的 trg_ 约定),仅作身份标识,不冒充用户消息 id。
|
|
15307
|
+
const joinTurnId = scope === 'thread' ? anchor : `join_${randomUUID()}`;
|
|
15096
15308
|
const dsKey = sessionKey(anchor, larkAppId);
|
|
15097
15309
|
if (activeSessions.has(dsKey)) {
|
|
15098
15310
|
logger.info(`[auto-start:入群] ${chatId.substring(0, 12)} 锚点已有会话,跳过`);
|
|
@@ -15135,7 +15347,9 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15135
15347
|
ownerOpenId: operatorOpenId,
|
|
15136
15348
|
currentTurnTitle: title,
|
|
15137
15349
|
workingDir: pinnedWorkingDir,
|
|
15138
|
-
|
|
15350
|
+
// 非 shared 路径的首轮 turn 身份(joinTurnId);shared 路径由
|
|
15351
|
+
// armSharedReplyTarget 用 shared seed id 覆盖。
|
|
15352
|
+
pendingTurnId: needsSharedReply ? undefined : joinTurnId,
|
|
15139
15353
|
};
|
|
15140
15354
|
const registration = await claimNewDaemonSession(activeSessions, ds);
|
|
15141
15355
|
if (!registration.accepted) {
|
|
@@ -15148,7 +15362,9 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15148
15362
|
stageClaimedPendingRepoSetup(activeSessions, ds, {
|
|
15149
15363
|
mode: autoWt ? 'auto_worktree' : 'picker',
|
|
15150
15364
|
...(autoWt && pinnedWorkingDir ? { baseDir: pinnedWorkingDir } : {}),
|
|
15151
|
-
|
|
15365
|
+
// 非 shared 路径复用首轮 turn 身份;shared 路径保留 anchor(随后被
|
|
15366
|
+
// armSharedReplyTarget 的 shared seed id 覆盖,此处仅作未 arm 时的兜底)。
|
|
15367
|
+
turnId: needsSharedReply ? anchor : joinTurnId,
|
|
15152
15368
|
});
|
|
15153
15369
|
}
|
|
15154
15370
|
const joinBootstrapExternallyTakenOver = () => (activeSessions.get(dsKey) !== ds
|
|
@@ -15195,6 +15411,11 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15195
15411
|
const closing = closeSessionHelper(session.sessionId);
|
|
15196
15412
|
if (activeSessions.get(dsKey) === ds)
|
|
15197
15413
|
activeSessions.delete(dsKey);
|
|
15414
|
+
// 入群去重锚点同样只清自己登记的那条:shared 路径在登记锚点之前就可能
|
|
15415
|
+
// 回滚(此时 get 为 undefined,no-op);非 shared 路径在锚点登记之后
|
|
15416
|
+
// 回滚,不清掉会让后续 bot.added 带着 stale 锚点走进来。
|
|
15417
|
+
if (groupJoinAnchorByChat.get(chatLiveKey) === dsKey)
|
|
15418
|
+
groupJoinAnchorByChat.delete(chatLiveKey);
|
|
15198
15419
|
await closing;
|
|
15199
15420
|
};
|
|
15200
15421
|
// Shared-mode seed/reply authority is externally visible. Publish it only
|
|
@@ -15245,6 +15466,28 @@ async function handleBotAdded(chatId, operatorOpenId, larkAppId, opts) {
|
|
|
15245
15466
|
// Register the anchor so a later duplicate bot.added for this chat is deduped
|
|
15246
15467
|
// even in 话题群 (where dsKey is the seed id, not chatId).
|
|
15247
15468
|
groupJoinAnchorByChat.set(chatLiveKey, dsKey);
|
|
15469
|
+
// 持久化非 shared 首轮的 turn provenance(shared 路径已由 armSharedReplyTarget
|
|
15470
|
+
// 写入)。thread scope 以 seed 为 reply root;chat scope 无根,落 plain chat
|
|
15471
|
+
// 目标且不写 sender——首轮无真人发送者,--mention 回指天然走 incomplete →
|
|
15472
|
+
// 显式指定的安全方向。没有这条记录,worker 虽带 turnId fork,daemon 侧的
|
|
15473
|
+
// 首轮回复目标/参与者窗口仍无据可查。
|
|
15474
|
+
if (!needsSharedReply) {
|
|
15475
|
+
try {
|
|
15476
|
+
beginReplyTargetTurn(ds, scope === 'thread' ? anchor : undefined, joinTurnId, new Date(now).toISOString());
|
|
15477
|
+
sessionStore.updateSession(ds.session);
|
|
15478
|
+
}
|
|
15479
|
+
catch (err) {
|
|
15480
|
+
// 持久化失败(文件系统/数据库瞬态错误)时必须回滚已发布的会话:此时
|
|
15481
|
+
// 会话已进 activeSessions 且 groupJoinAnchorByChat 已登记,finally 只
|
|
15482
|
+
// settle barrier 和释放 in-flight 锁——留下 active 但 worker-null 的会话
|
|
15483
|
+
// 会让后续 bot.added 被无限去重,自动开工无法重试。同
|
|
15484
|
+
// stageClaimedPendingRepoSetup 的 unpublish/close 回滚。
|
|
15485
|
+
logger.warn(`[auto-start:入群] ${chatId.substring(0, 12)} 首轮 turn provenance 持久化失败,回滚会话注册:`
|
|
15486
|
+
+ `${err instanceof Error ? err.message : String(err)}`);
|
|
15487
|
+
await rollbackRegisteredJoinSession();
|
|
15488
|
+
return;
|
|
15489
|
+
}
|
|
15490
|
+
}
|
|
15248
15491
|
// Auto-worktree: register PENDING, build worktree off-path, commit+fork later.
|
|
15249
15492
|
if (pinnedWorkingDir && autoWt) {
|
|
15250
15493
|
if (await replyInvalidWorkingDirs(anchor, larkAppId, ds) || joinBootstrapWasTakenOver()) {
|
|
@@ -15482,6 +15725,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
15482
15725
|
// 类型的话,把真人 union_id 报成 bot 就能让真人在全团队被当队友 bot 放行
|
|
15483
15726
|
//(talk + operate)。与旧联邦 team-bots「学习入口限 bot sender」同一不变量。
|
|
15484
15727
|
const threadTeamTrustUnionId = (isBotSenderType || isForeignBot) ? threadSenderUnionId : undefined;
|
|
15728
|
+
const threadTrustedCaller = trustedCallerForTurn(larkAppId, threadSenderOpenId, threadSenderUnionId);
|
|
15485
15729
|
const threadChatId = ctxChatId ?? data?.message?.chat_id;
|
|
15486
15730
|
const clearAgentAttentionForHumanInbound = () => {
|
|
15487
15731
|
if (isForeignBot || isBotSenderType)
|
|
@@ -15540,6 +15784,10 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
15540
15784
|
// `/template` 只保留退役提示。
|
|
15541
15785
|
const threadGrill = parseWorkflowGrillTrigger(cmdContent);
|
|
15542
15786
|
if (threadGrill) {
|
|
15787
|
+
if (!isWorkflowFeatureEnabled()) {
|
|
15788
|
+
await sessionReply(anchor, WORKFLOW_DISABLED_MESSAGE, 'text', larkAppId);
|
|
15789
|
+
return;
|
|
15790
|
+
}
|
|
15543
15791
|
if (await replyGrantRestrictionIfNeeded(larkAppId, threadChatId, threadSenderOpenId, anchor, '/workflow')) {
|
|
15544
15792
|
return;
|
|
15545
15793
|
}
|
|
@@ -15779,35 +16027,38 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
15779
16027
|
// 回调 URL 已在上方 return,可用来中止)。答复权限 = canTalk,由
|
|
15780
16028
|
// broker 在 submitCustomReply 内按注入的 canTalkChecker 判定:非授权人返回
|
|
15781
16029
|
// 'unauthorized',这里 fall through 到正常路由。卡片由 broker.onSettle 自动 PATCH。
|
|
15782
|
-
//
|
|
15783
|
-
//
|
|
15784
|
-
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
15790
|
-
|
|
15791
|
-
|
|
15792
|
-
|
|
15793
|
-
|
|
15794
|
-
|
|
15795
|
-
|
|
15796
|
-
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15807
|
-
|
|
15808
|
-
|
|
15809
|
-
|
|
16030
|
+
// 「哪些消息算纯文字答复」收口在 askCustomReplyCandidate(含带资源消息与 grill
|
|
16031
|
+
// 触发的排除理由),拦截器这里只负责拿着结果去 settle。
|
|
16032
|
+
const askCandidate = askCustomReplyCandidate({
|
|
16033
|
+
senderOpenId: threadSenderOpenId,
|
|
16034
|
+
chatId: threadChatId,
|
|
16035
|
+
cmdContent,
|
|
16036
|
+
resourceCount: resources.length,
|
|
16037
|
+
isWorkflowGrillTrigger: !!threadGrill,
|
|
16038
|
+
});
|
|
16039
|
+
if (askCandidate) {
|
|
16040
|
+
const pendingAsk = findPendingAskByAnchor({ larkAppId, chatId: askCandidate.chatId, anchor });
|
|
16041
|
+
if (pendingAsk) {
|
|
16042
|
+
const outcome = submitCustomReply({
|
|
16043
|
+
askId: pendingAsk.askId,
|
|
16044
|
+
by: askCandidate.senderOpenId,
|
|
16045
|
+
text: askCandidate.text,
|
|
16046
|
+
// Actor context so the broker's talk check uses the same predicate as
|
|
16047
|
+
// the dispatcher gate / quota recheck: a bot text-reply → evaluateBotTalk
|
|
16048
|
+
// (covers team-拉群 with no union_id), a platform teamMember human →
|
|
16049
|
+
// evaluateTalk's teamMember union leg. Omitting it (card clicks) degrades
|
|
16050
|
+
// to the plain evaluateTalk(openId, chatType).
|
|
16051
|
+
actor: {
|
|
16052
|
+
botSender: isBotSenderType || isForeignBot,
|
|
16053
|
+
senderUnionId: threadTeamTrustUnionId,
|
|
16054
|
+
memberUnionId: threadSenderUnionId,
|
|
16055
|
+
},
|
|
16056
|
+
});
|
|
16057
|
+
if (outcome === 'accepted') {
|
|
16058
|
+
logger.info(`[${anchor.substring(0, 12)}] ask custom reply accepted from ${askCandidate.senderOpenId.substring(0, 12)}`);
|
|
16059
|
+
return;
|
|
15810
16060
|
}
|
|
16061
|
+
logger.info(`[${anchor.substring(0, 12)}] ask custom reply not accepted (${outcome}); falling through to normal routing`);
|
|
15811
16062
|
}
|
|
15812
16063
|
}
|
|
15813
16064
|
logger.info(`Reply in ${scope}-scope session ${anchor.substring(0, 12)}: ${content.substring(0, 100)} (resources: ${resources.length})`);
|
|
@@ -16396,7 +16647,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16396
16647
|
ensureSessionWhiteboard(newDs);
|
|
16397
16648
|
const availableBots = await getAvailableBots(larkAppId, autoCreateChatId);
|
|
16398
16649
|
await noteTurnReceived(newDs, parsed.messageId, parsed.content, autoCreateSender, parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
16399
|
-
forkReservedInitialSession(newDs, availableBots);
|
|
16650
|
+
forkReservedInitialSession(newDs, availableBots, threadTrustedCaller);
|
|
16400
16651
|
// fork 成功即开场已交给 CLI;fork 抛错则开场只存在于内存,保持重发提示。
|
|
16401
16652
|
markIngressAdmitted(ctx);
|
|
16402
16653
|
const reason = oncallEntry
|
|
@@ -16436,7 +16687,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16436
16687
|
ensureSessionWhiteboard(newDs);
|
|
16437
16688
|
const availableBots = await getAvailableBots(larkAppId, autoCreateChatId);
|
|
16438
16689
|
await noteTurnReceived(newDs, parsed.messageId, parsed.content, autoCreateSender, parsed.messageId, substituteTrigger ? SUBSTITUTE_RECEIVED_REACTION_EMOJI_TYPE : undefined);
|
|
16439
|
-
forkReservedInitialSession(newDs, availableBots);
|
|
16690
|
+
forkReservedInitialSession(newDs, availableBots, threadTrustedCaller);
|
|
16440
16691
|
}
|
|
16441
16692
|
return;
|
|
16442
16693
|
}
|
|
@@ -16514,7 +16765,10 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16514
16765
|
// above (R4-B1); reuse the same frozen value here for the live-worker path.
|
|
16515
16766
|
let accepted = false;
|
|
16516
16767
|
try {
|
|
16517
|
-
accepted = sendWorkerInput(ds, cliInput, parsed.messageId,
|
|
16768
|
+
accepted = sendWorkerInput(ds, cliInput, parsed.messageId, {
|
|
16769
|
+
...(codexAppSteerable ? { codexAppSteerable: true } : {}),
|
|
16770
|
+
...(threadTrustedCaller ? { trustedCaller: threadTrustedCaller } : {}),
|
|
16771
|
+
});
|
|
16518
16772
|
// Record the input as the session's last real CLI turn ONLY after the
|
|
16519
16773
|
// worker accepted it. Recording before delivery (the old order) persisted
|
|
16520
16774
|
// lastCliInput / lastUserPrompt / Codex-App sidecar for a turn that never
|
|
@@ -16610,6 +16864,8 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16610
16864
|
// here, never re-inferred). System/recovery openings keep it absent.
|
|
16611
16865
|
if (codexAppSteerable)
|
|
16612
16866
|
currentFollowUp.codexAppSteerable = true;
|
|
16867
|
+
if (threadTrustedCaller)
|
|
16868
|
+
currentFollowUp.trustedCaller = threadTrustedCaller;
|
|
16613
16869
|
admitQueuedActivationTail(ds, {
|
|
16614
16870
|
userPrompt: promptContent,
|
|
16615
16871
|
cliInput: currentFollowUp,
|
|
@@ -16636,6 +16892,9 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16636
16892
|
resume: ds.session.queuedActivationResume ?? ds.hasHistory,
|
|
16637
16893
|
turnId: ds.session.queuedActivationTurnId,
|
|
16638
16894
|
dispatchAttempt: ds.session.queuedActivationDispatchAttempt,
|
|
16895
|
+
...(ds.session.queuedActivationInput?.trustedCaller
|
|
16896
|
+
? { trustedCaller: ds.session.queuedActivationInput.trustedCaller }
|
|
16897
|
+
: {}),
|
|
16639
16898
|
});
|
|
16640
16899
|
if (ownsInitialStartClaim())
|
|
16641
16900
|
retainInitialStartClaim = true;
|
|
@@ -16661,6 +16920,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16661
16920
|
resume: ds.hasHistory,
|
|
16662
16921
|
turnId: ds.session.queuedActivationTurnId,
|
|
16663
16922
|
dispatchAttempt: ds.session.queuedActivationDispatchAttempt,
|
|
16923
|
+
...(retainedQueuedActivation.trustedCaller ? { trustedCaller: retainedQueuedActivation.trustedCaller } : {}),
|
|
16664
16924
|
});
|
|
16665
16925
|
if (ownsInitialStartClaim())
|
|
16666
16926
|
retainInitialStartClaim = true;
|
|
@@ -16783,6 +17043,9 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16783
17043
|
if (codexAppSteerable && !queuedDashboardTurn && !queuedHasDurableTail) {
|
|
16784
17044
|
wrappedInput.codexAppSteerable = true;
|
|
16785
17045
|
}
|
|
17046
|
+
if (threadTrustedCaller && !queuedHasDurableTail) {
|
|
17047
|
+
wrappedInput.trustedCaller = threadTrustedCaller;
|
|
17048
|
+
}
|
|
16786
17049
|
reforkAccepted = forkWorker(ds, wrappedInput, {
|
|
16787
17050
|
// See `hadPriorCliInput` above — an opening on a CLI that never took any
|
|
16788
17051
|
// input cold-spawns rather than `--resume`-ing an empty session.
|
|
@@ -16790,6 +17053,7 @@ async function handleThreadReplyAdmitted(data, ctx, prepared) {
|
|
|
16790
17053
|
turnId: queuedHasDurableTail
|
|
16791
17054
|
? (ds.session.queuedActivationTurnId ?? `queued-opening:${ds.session.sessionId}`)
|
|
16792
17055
|
: parsed.messageId,
|
|
17056
|
+
...(wrappedInput.trustedCaller ? { trustedCaller: wrappedInput.trustedCaller } : {}),
|
|
16793
17057
|
});
|
|
16794
17058
|
}
|
|
16795
17059
|
}
|
|
@@ -17470,6 +17734,18 @@ async function waitForManagedActivationCommit(index, appId) {
|
|
|
17470
17734
|
}
|
|
17471
17735
|
}
|
|
17472
17736
|
export async function startDaemon(botIndex) {
|
|
17737
|
+
// Survive a fire-and-forget rejection instead of dying from it. Installed here
|
|
17738
|
+
// rather than in index-daemon.ts on purpose: startDaemon has TWO entry points
|
|
17739
|
+
// (index-daemon.ts and index-core-only.ts), so guarding the entry file would
|
|
17740
|
+
// leave the other one unprotected. Idempotent, so an entry point may also call
|
|
17741
|
+
// it earlier without harm.
|
|
17742
|
+
//
|
|
17743
|
+
// Node's default is to terminate the process, which is right for a worker (it
|
|
17744
|
+
// owns one session) and wrong for the daemon (it owns every session): one
|
|
17745
|
+
// missed `.catch` on one session's teardown would otherwise end every other
|
|
17746
|
+
// live Lark session too. The rejection is logged loudly at error level — this
|
|
17747
|
+
// is a backstop for the next missed `.catch`, not permission to omit them.
|
|
17748
|
+
installDaemonRejectionGuard(logger);
|
|
17473
17749
|
// Repair a shared tmux server polluted by an older botmux immediately on
|
|
17474
17750
|
// daemon startup. This must not depend on restoring/spawning a bmx-* session:
|
|
17475
17751
|
// a user-held tmux server can outlive every botmux pane and still leak stale
|
|
@@ -17886,8 +18162,7 @@ export async function startDaemon(botIndex) {
|
|
|
17886
18162
|
// status becomes `closed` → trigger-result resolves `failed` (soft terminal),
|
|
17887
18163
|
// and resolveIdempotencyHit sees a not-live session on retry. This is the
|
|
17888
18164
|
// observable fail-closed path the round-8 finding requires.
|
|
17889
|
-
void
|
|
17890
|
-
logger.error(`[idempotency] fail-closed session ${ds.session.sessionId.slice(0, 8)} after exit-convergence write failure`);
|
|
18165
|
+
void runIdempotencyFailClose(ds.session.sessionId, closeSessionForBackgroundCleanup, logger);
|
|
17891
18166
|
}
|
|
17892
18167
|
};
|
|
17893
18168
|
// Initialise worker pool with daemon callbacks
|
|
@@ -17908,9 +18183,7 @@ export async function startDaemon(botIndex) {
|
|
|
17908
18183
|
logger.info(`[${sessionId.substring(0, 8)}] Withdraw auto-close deferred: Codex App FIFO became unsettled`);
|
|
17909
18184
|
return false;
|
|
17910
18185
|
}
|
|
17911
|
-
|
|
17912
|
-
logger.info(`[${sessionId.substring(0, 8)}] Session auto-closed (message withdrawn)`);
|
|
17913
|
-
return true;
|
|
18186
|
+
return runWithdrawAutoClose(sessionId, closeSessionForBackgroundCleanup, logger);
|
|
17914
18187
|
}).catch((err) => {
|
|
17915
18188
|
logger.warn(`[${sessionId.substring(0, 8)}] Withdraw auto-close mutation failed; session retained: `
|
|
17916
18189
|
+ `${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -18033,6 +18306,20 @@ export async function startDaemon(botIndex) {
|
|
|
18033
18306
|
logger.error(`[idempotency] boot reconcile failed to converge — aborting bot startup (fail-closed): ${err instanceof Error ? err.message : err}`);
|
|
18034
18307
|
throw err instanceof Error ? err : new Error(String(err));
|
|
18035
18308
|
}
|
|
18309
|
+
// Release durable mojo containment handles a REBOOT provably killed, BEFORE the
|
|
18310
|
+
// device-isolation activation inventory ever synthesises a blocker from them —
|
|
18311
|
+
// otherwise a post-reboot handle keeps blocking activation forever (round-11
|
|
18312
|
+
// P1-1). Daemon-global and idempotent: guarded so it runs once no matter how
|
|
18313
|
+
// many bots start; any store/proc read failure fails closed inside the helper.
|
|
18314
|
+
if (!mojoContainmentReconciledThisBoot) {
|
|
18315
|
+
mojoContainmentReconciledThisBoot = true;
|
|
18316
|
+
try {
|
|
18317
|
+
reconcileContainmentHandlesOnBoot();
|
|
18318
|
+
}
|
|
18319
|
+
catch (err) {
|
|
18320
|
+
logger.warn(`[mojo] containment boot reconciliation threw (blockers retained): ${err instanceof Error ? err.message : String(err)}`);
|
|
18321
|
+
}
|
|
18322
|
+
}
|
|
18036
18323
|
// Seed dashboard IPC botName with the custom displayName (falling back to the
|
|
18037
18324
|
// bot's config id); the friendly name from /bot/v3/info is wired into the
|
|
18038
18325
|
// registry descriptor (below) but the IPC server also needs its own copy for
|
|
@@ -18395,6 +18682,12 @@ export async function startDaemon(botIndex) {
|
|
|
18395
18682
|
// Restore complete → /api/asks may now safely 403 unknown sessions again; a
|
|
18396
18683
|
// reconnecting ask hook that raced the restore got retryable 503s until here.
|
|
18397
18684
|
sessionsRestored = true;
|
|
18685
|
+
// Freeze the control plane of restored mojo sessions NOW, not at their next
|
|
18686
|
+
// worker fork. Restore completes before the dispatcher can deliver a message,
|
|
18687
|
+
// so this closes the window where an operator edits the bot's endpoint/workspace
|
|
18688
|
+
// between the restart and a session's next wake — which would otherwise let that
|
|
18689
|
+
// session adopt the NEW control plane as its original identity.
|
|
18690
|
+
migrateMojoSessionIdentities(activeSessions);
|
|
18398
18691
|
// Now that activeSessions is populated, release the forward-followup flush
|
|
18399
18692
|
// barrier. Persisted seeds were loaded into the buffer at dispatcher startup
|
|
18400
18693
|
// (so root-linked clarifications can pair with them), but their flushes wait
|
|
@@ -18523,6 +18816,45 @@ export async function startDaemon(botIndex) {
|
|
|
18523
18816
|
enforceLiveSessionCap('periodic');
|
|
18524
18817
|
}, 60_000);
|
|
18525
18818
|
idleWorkerSweepTimer.unref?.();
|
|
18819
|
+
const sessionOwnerReminder = new SessionOwnerReminderController({
|
|
18820
|
+
load: () => loadSessionOwnerReminderRecords(config.session.dataDir, cfg.larkAppId),
|
|
18821
|
+
save: records => saveSessionOwnerReminderRecords(config.session.dataDir, cfg.larkAppId, records),
|
|
18822
|
+
canSend: ds => larkTransportEnabled({
|
|
18823
|
+
chatId: ds.chatId,
|
|
18824
|
+
apiOnly: getBot(ds.larkAppId).config.apiOnly,
|
|
18825
|
+
}),
|
|
18826
|
+
send: async (ds, text, uuid) => {
|
|
18827
|
+
await sendSessionOwnerThreadNotification({
|
|
18828
|
+
larkAppId: ds.larkAppId,
|
|
18829
|
+
rootMessageId: ds.session.rootMessageId,
|
|
18830
|
+
ownerOpenId: ds.session.ownerOpenId,
|
|
18831
|
+
}, text, uuid);
|
|
18832
|
+
},
|
|
18833
|
+
onError: (ds, error) => logger.warn(`[session-owner-reminder] send failed session=${ds.session.sessionId}: `
|
|
18834
|
+
+ `${error instanceof Error ? error.message : String(error)}`),
|
|
18835
|
+
});
|
|
18836
|
+
let sessionOwnerReminderScanInFlight = false;
|
|
18837
|
+
const scanSessionOwnerReminders = async () => {
|
|
18838
|
+
if (sessionOwnerReminderScanInFlight)
|
|
18839
|
+
return;
|
|
18840
|
+
sessionOwnerReminderScanInFlight = true;
|
|
18841
|
+
try {
|
|
18842
|
+
const currentConfig = getBot(cfg.larkAppId).config.sessionOwnerReminder
|
|
18843
|
+
?? DEFAULT_SESSION_OWNER_REMINDER;
|
|
18844
|
+
await sessionOwnerReminder.scan(activeSessions.values(), currentConfig);
|
|
18845
|
+
}
|
|
18846
|
+
catch (error) {
|
|
18847
|
+
logger.warn(`[session-owner-reminder] scan failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
18848
|
+
}
|
|
18849
|
+
finally {
|
|
18850
|
+
sessionOwnerReminderScanInFlight = false;
|
|
18851
|
+
}
|
|
18852
|
+
};
|
|
18853
|
+
const sessionOwnerReminderTimer = setInterval(() => {
|
|
18854
|
+
void scanSessionOwnerReminders();
|
|
18855
|
+
}, 60_000);
|
|
18856
|
+
sessionOwnerReminderTimer.unref?.();
|
|
18857
|
+
void scanSessionOwnerReminders();
|
|
18526
18858
|
// Periodic sandbox reconciler: the daemon's SIGKILL straggler-reaper (and any
|
|
18527
18859
|
// worker SIGKILL) bypasses worker-side killCli(), so the pre-created deny-mask
|
|
18528
18860
|
// mountpoints + per-session tree of a killed-but-still-active sandboxed session
|
|
@@ -18701,8 +19033,8 @@ export async function startDaemon(botIndex) {
|
|
|
18701
19033
|
}, 30_000);
|
|
18702
19034
|
overloadTimer.unref?.();
|
|
18703
19035
|
}
|
|
18704
|
-
// Graceful shutdown.
|
|
18705
|
-
// that durably ACKs every exact final
|
|
19036
|
+
// Graceful shutdown. Remote owners first run a three-phase non-cancelling
|
|
19037
|
+
// drain that durably ACKs every exact final lineage as one fleet transaction.
|
|
18706
19038
|
// No worker exits until every participant is prepared and fresh-verified.
|
|
18707
19039
|
// Ordinary workers then receive SIGTERM / close IPC and the daemon waits up
|
|
18708
19040
|
// to DAEMON_WORKER_EXIT_GRACE_MS for them to exit
|
|
@@ -18729,23 +19061,23 @@ export async function startDaemon(botIndex) {
|
|
|
18729
19061
|
logger.error(`Daemon remains online: ${initialShutdownFleet.error}`);
|
|
18730
19062
|
return;
|
|
18731
19063
|
}
|
|
18732
|
-
// Preflight
|
|
19064
|
+
// Preflight all remote backends before stopping services/removing descriptors. A failed
|
|
18733
19065
|
// drain or persistence write aborts every successfully prepared peer, so a
|
|
18734
19066
|
// refused shutdown returns to a live fleet instead of leaving an early
|
|
18735
19067
|
// participant workerless.
|
|
18736
|
-
const
|
|
18737
|
-
.filter(ds => shutdownBackendDisposition(ds) === '
|
|
18738
|
-
const
|
|
19068
|
+
const remoteCandidates = initialShutdownFleet.sessions
|
|
19069
|
+
.filter(ds => shutdownBackendDisposition(ds) === 'remote-drain-detach');
|
|
19070
|
+
const remotePrepareResults = await prepareRemoteFleetForShutdown(remoteCandidates, {
|
|
18739
19071
|
deadlineMs: shutdownDeadlineMs,
|
|
18740
19072
|
});
|
|
18741
|
-
const
|
|
18742
|
-
const
|
|
18743
|
-
const
|
|
19073
|
+
const remotePrepared = remotePrepareResults.filter((entry) => entry.result.ok);
|
|
19074
|
+
const remoteFenced = remotePrepareResults.filter((entry) => entry.result.fence !== 'none');
|
|
19075
|
+
const abortRemoteFleet = async (reason, retainFenced = new Set()) => {
|
|
18744
19076
|
for (const ds of retainFenced) {
|
|
18745
|
-
logger.error(`[${ds.session.sessionId.slice(0, 8)}]
|
|
19077
|
+
logger.error(`[${ds.session.sessionId.slice(0, 8)}] Remote shutdown participant remains fenced: `
|
|
18746
19078
|
+ 'durable/runtime ownership could not be reconciled safely');
|
|
18747
19079
|
}
|
|
18748
|
-
const aborts = await
|
|
19080
|
+
const aborts = await abortRemoteShutdownFleet(remoteFenced
|
|
18749
19081
|
.filter(({ ds }) => !retainFenced.has(ds))
|
|
18750
19082
|
.map(({ ds, result }) => ({ ds, result })), {
|
|
18751
19083
|
deadlineMs: shutdownDeadlineMs,
|
|
@@ -18753,34 +19085,34 @@ export async function startDaemon(botIndex) {
|
|
|
18753
19085
|
for (const { ds, result } of aborts) {
|
|
18754
19086
|
if (result.ok)
|
|
18755
19087
|
continue;
|
|
18756
|
-
logger.error(`[${ds.session.sessionId.slice(0, 8)}]
|
|
19088
|
+
logger.error(`[${ds.session.sessionId.slice(0, 8)}] Remote shutdown rollback was not ACKed: `
|
|
18757
19089
|
+ `${result.error ?? 'unknown'}; admission remains fail-closed`);
|
|
18758
19090
|
}
|
|
18759
19091
|
setSessionLifecycleShutdown(false);
|
|
18760
19092
|
shuttingDown = false;
|
|
18761
19093
|
logger.error(`Daemon remains online: ${reason}`);
|
|
18762
19094
|
};
|
|
18763
|
-
const
|
|
18764
|
-
if (
|
|
18765
|
-
for (const { ds, result } of
|
|
19095
|
+
const remotePrepareFailures = remotePrepareResults.filter(entry => !entry.result.ok);
|
|
19096
|
+
if (remotePrepareFailures.length > 0) {
|
|
19097
|
+
for (const { ds, result } of remotePrepareFailures) {
|
|
18766
19098
|
if (result.ok)
|
|
18767
19099
|
continue;
|
|
18768
19100
|
logger.error(`[${ds.session.sessionId.slice(0, 8)}] Daemon shutdown prepare refused: `
|
|
18769
19101
|
+ `${result.error}${result.taskId ? ` (task ${result.taskId})` : ''}`);
|
|
18770
19102
|
}
|
|
18771
|
-
await
|
|
19103
|
+
await abortRemoteFleet(`${remotePrepareFailures.length} remote owner(s) could not be safely drained`);
|
|
18772
19104
|
return;
|
|
18773
19105
|
}
|
|
18774
|
-
const
|
|
19106
|
+
const remotePersistence = persistPreparedRemoteShutdownFleet(remotePrepared, {
|
|
18775
19107
|
deadlineMs: shutdownDeadlineMs,
|
|
18776
19108
|
});
|
|
18777
|
-
if (!
|
|
18778
|
-
const retainIds = new Set(
|
|
18779
|
-
const retainFenced = new Set(
|
|
19109
|
+
if (!remotePersistence.ok) {
|
|
19110
|
+
const retainIds = new Set(remotePersistence.retainFencedSessionIds);
|
|
19111
|
+
const retainFenced = new Set(remotePrepared
|
|
18780
19112
|
.filter(({ ds }) => retainIds.has(ds.session.sessionId))
|
|
18781
19113
|
.map(({ ds }) => ds));
|
|
18782
|
-
logger.error(`Daemon shutdown lineage verification refused: ${
|
|
18783
|
-
await
|
|
19114
|
+
logger.error(`Daemon shutdown lineage verification refused: ${remotePersistence.error}`);
|
|
19115
|
+
await abortRemoteFleet(`${remotePersistence.sessionIds.length} remote lineage row(s) could not be fresh-verified`, retainFenced);
|
|
18784
19116
|
return;
|
|
18785
19117
|
}
|
|
18786
19118
|
// Recheck generation ownership while every participant is still fenced and
|
|
@@ -18788,33 +19120,33 @@ export async function startDaemon(botIndex) {
|
|
|
18788
19120
|
const currentShutdownFleet = collectUniqueDaemonShutdownSessions(activeSessions.values());
|
|
18789
19121
|
if (!currentShutdownFleet.ok) {
|
|
18790
19122
|
const ambiguousSessionId = currentShutdownFleet.sessionId;
|
|
18791
|
-
await
|
|
19123
|
+
await abortRemoteFleet(`Remote ownership became ambiguous after shutdown preflight: ${currentShutdownFleet.error}`, new Set(remotePrepared
|
|
18792
19124
|
.filter(({ ds }) => ds.session.sessionId === ambiguousSessionId)
|
|
18793
19125
|
.map(({ ds }) => ds)));
|
|
18794
19126
|
return;
|
|
18795
19127
|
}
|
|
18796
|
-
const
|
|
18797
|
-
.filter(ds => shutdownBackendDisposition(ds) === '
|
|
18798
|
-
const
|
|
18799
|
-
const
|
|
18800
|
-
||
|
|
18801
|
-
if (
|
|
18802
|
-
const retainFenced = new Set(
|
|
18803
|
-
.filter(({ ds, result }) => (!
|
|
18804
|
-
&& !
|
|
19128
|
+
const currentRemoteOwners = currentShutdownFleet.sessions
|
|
19129
|
+
.filter(ds => shutdownBackendDisposition(ds) === 'remote-drain-detach');
|
|
19130
|
+
const remotePreparedOwners = new Set(remotePrepared.map(entry => entry.ds));
|
|
19131
|
+
const remoteGenerationMismatch = currentRemoteOwners.some(ds => !remotePreparedOwners.has(ds))
|
|
19132
|
+
|| remotePrepared.some(({ ds, result }) => !currentRemoteOwners.includes(ds) || !isPreparedRemoteSessionCurrent(ds, result));
|
|
19133
|
+
if (remoteGenerationMismatch) {
|
|
19134
|
+
const retainFenced = new Set(remotePrepared
|
|
19135
|
+
.filter(({ ds, result }) => (!currentRemoteOwners.includes(ds) || !isPreparedRemoteSessionCurrent(ds, result))
|
|
19136
|
+
&& !canAbortVerifiedExitedRemotePreparation(ds, result))
|
|
18805
19137
|
.map(({ ds }) => ds));
|
|
18806
|
-
await
|
|
19138
|
+
await abortRemoteFleet('Remote ownership changed after shutdown preflight', retainFenced);
|
|
18807
19139
|
return;
|
|
18808
19140
|
}
|
|
18809
19141
|
// Validate-all above, then commit-all synchronously with no await or
|
|
18810
19142
|
// callback boundary between peers.
|
|
18811
|
-
const
|
|
18812
|
-
for (const { ds, result } of
|
|
18813
|
-
if (!
|
|
18814
|
-
throw new Error(`
|
|
19143
|
+
const remoteRetiredWorkers = [];
|
|
19144
|
+
for (const { ds, result } of remotePrepared) {
|
|
19145
|
+
if (!commitPreparedRemoteShutdown(ds, result)) {
|
|
19146
|
+
throw new Error(`Remote shutdown commit invariant lost for ${ds.session.sessionId}`);
|
|
18815
19147
|
}
|
|
18816
19148
|
if (result.worker)
|
|
18817
|
-
|
|
19149
|
+
remoteRetiredWorkers.push(result.worker);
|
|
18818
19150
|
}
|
|
18819
19151
|
scheduler.stopScheduler();
|
|
18820
19152
|
// NOTE: turn-terminal queue drain + webhook dispatcher stop are deliberately
|
|
@@ -18854,6 +19186,7 @@ export async function startDaemon(botIndex) {
|
|
|
18854
19186
|
deleteVcMeetingPendingInvite(key);
|
|
18855
19187
|
clearInterval(descriptorHeartbeat);
|
|
18856
19188
|
clearInterval(idleWorkerSweepTimer);
|
|
19189
|
+
clearInterval(sessionOwnerReminderTimer);
|
|
18857
19190
|
if (memoryDiagnostics)
|
|
18858
19191
|
clearInterval(memoryDiagnostics);
|
|
18859
19192
|
removeDaemonDescriptor(cfg.larkAppId);
|
|
@@ -18899,7 +19232,10 @@ export async function startDaemon(botIndex) {
|
|
|
18899
19232
|
}
|
|
18900
19233
|
}
|
|
18901
19234
|
};
|
|
18902
|
-
|
|
19235
|
+
// Union of two renames: this branch generalised the collection
|
|
19236
|
+
// riffRetiredWorkers -> remoteRetiredWorkers (it now carries mojo too), while
|
|
19237
|
+
// master renamed the local helper trackWorkerExit -> trackWorker.
|
|
19238
|
+
for (const worker of remoteRetiredWorkers)
|
|
18903
19239
|
trackWorker(worker);
|
|
18904
19240
|
for (const ds of currentShutdownFleet.sessions) {
|
|
18905
19241
|
const w = ds.worker;
|
|
@@ -18916,8 +19252,8 @@ export async function startDaemon(botIndex) {
|
|
|
18916
19252
|
if (!w.killed) {
|
|
18917
19253
|
logger.info(`Shutting down worker for session ${ds.session.sessionId}`);
|
|
18918
19254
|
const disposition = shutdownBackendDisposition(ds);
|
|
18919
|
-
if (disposition === '
|
|
18920
|
-
throw new Error(`undrained
|
|
19255
|
+
if (disposition === 'remote-drain-detach') {
|
|
19256
|
+
throw new Error(`undrained remote generation after atomic commit: ${ds.session.sessionId}`);
|
|
18921
19257
|
}
|
|
18922
19258
|
// Branch by the session's FROZEN backend (stamped on Session.backendType
|
|
18923
19259
|
// at spawn), NOT the bot's live config — a dashboard backendType edit must
|
|
@@ -19066,6 +19402,7 @@ export async function startDaemon(botIndex) {
|
|
|
19066
19402
|
setSupervisorShutdownHandler(null);
|
|
19067
19403
|
clearInterval(descriptorHeartbeat);
|
|
19068
19404
|
clearInterval(idleWorkerSweepTimer);
|
|
19405
|
+
clearInterval(sessionOwnerReminderTimer);
|
|
19069
19406
|
clearInterval(docCommentPollTimer);
|
|
19070
19407
|
if (memoryDiagnostics)
|
|
19071
19408
|
clearInterval(memoryDiagnostics);
|