mixdog 1.3.1 → 1.3.2
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.md +8 -4
- package/package.json +2 -2
- package/scripts/native-release-status.mjs +238 -0
- package/src/defaults/shipped-history.json +5 -1
- package/src/defaults/skills/pptx/scripts/qc-pages.mjs +3 -2
- package/src/defaults/skills/setup/SKILL.md +23 -1
- package/src/defaults/skills/setup/references/actions.md +50 -3
- package/src/defaults/skills/setup/references/surfaces.md +23 -3
- package/src/defaults/skills/setup-guide/SKILL.md +7 -3
- package/src/defaults/skills/visualize/SKILL.md +9 -6
- package/src/defaults/skills/visualize/references/craft.md +8 -1
- package/src/help.mjs +1 -1
- package/src/lib/keychain-cjs.cjs +4 -1
- package/src/lib/rules-builder.cjs +14 -7
- package/src/rules/agent-mode/AGENT_MODE.md +8 -5
- package/src/rules/agent-mode/MIXY.md +6 -8
- package/src/rules/lead/LEAD.md +2 -2
- package/src/rules/shared/10-tool-workflow.md +4 -0
- package/src/rules/shared/20-research.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +5 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/session-prep.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +6 -1
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +114 -26
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +8 -0
- package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +5 -4
- package/src/runtime/agent/orchestrator/agent-trace.mjs +3 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +4 -0
- package/src/runtime/agent/orchestrator/config-presets.mjs +2 -0
- package/src/runtime/agent/orchestrator/config-storage.mjs +10 -3
- package/src/runtime/agent/orchestrator/config.mjs +11 -0
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +9 -2
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +97 -5
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +6 -10
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +80 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +67 -38
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +27 -8
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +31 -4
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +11 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +16 -1
- package/src/runtime/agent/orchestrator/providers/mixdog-local.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +5 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +9 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +30 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +61 -8
- package/src/runtime/agent/orchestrator/providers/registry.mjs +9 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +90 -24
- package/src/runtime/agent/orchestrator/runtime-core/fs-utils.mjs +8 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-mutations.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/goal-storage.mjs +68 -22
- package/src/runtime/agent/orchestrator/runtime-core/goal-tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -6
- package/src/runtime/agent/orchestrator/runtime-core/route-context-state.mjs +81 -0
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +12 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/packs.mjs +8 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/agent-mode.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +1 -1
- package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +22 -4
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +17 -2
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +133 -38
- package/src/runtime/agent/orchestrator/session/attachment-preflight.mjs +80 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +14 -11
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +68 -18
- package/src/runtime/agent/orchestrator/session/compact/summary-mode.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/compact/summary-route.mjs +87 -0
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +41 -10
- package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +230 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +136 -32
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +21 -9
- package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +73 -0
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/human-gate/unattended-port.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +189 -105
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +5 -5
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +38 -5
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +13 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +44 -18
- package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +99 -0
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +42 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +3 -9
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-file.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-spool-shard.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +40 -1
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-state.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +55 -27
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -8
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +6 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +24 -8
- package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +94 -13
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +42 -10
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +21 -3
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +18 -3
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +120 -9
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/canonical-reader.mjs +41 -7
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +8 -3
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +36 -1
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +40 -5
- package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +47 -2
- package/src/runtime/agent/orchestrator/session/tail-reminder-rules.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +78 -43
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +35 -5
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +42 -2
- package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +35 -13
- package/src/runtime/agent/orchestrator/tools/builtin/atomic-write.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +13 -14
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/transport-artifacts.mjs +9 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -14
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -14
- package/src/runtime/agent/orchestrator/tools/builtin/pdf-test-fixtures.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-media.mjs +47 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +264 -87
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +10 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +34 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +9 -30
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +24 -12
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/patch/delete-quarantine.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/patch/replay-capture.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/patch/rollback-state.mjs +33 -2
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +3 -1
- package/src/runtime/attachments/attachment-reference.mjs +155 -0
- package/src/runtime/attachments/limits.mjs +5 -1
- package/src/runtime/attachments/office-extract.mjs +3 -6
- package/src/runtime/attachments/pdf-extract.mjs +84 -10
- package/src/runtime/attachments/store.mjs +49 -30
- package/src/runtime/browser-bridge/client.mjs +73 -20
- package/src/runtime/channels/lib/runtime-paths.mjs +1 -1
- package/src/runtime/channels/lib/scheduler.mjs +14 -7
- package/src/runtime/channels/lib/state-file.mjs +15 -15
- package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +14 -13
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +22 -18
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +14 -36
- package/src/runtime/channels/lib/worker-main.mjs +3 -2
- package/src/runtime/effort-judge/compact-tokenizer.mjs +8 -2
- package/src/runtime/effort-judge/judge-client.mjs +5 -2
- package/src/runtime/effort-judge/model-install.mjs +16 -8
- package/src/runtime/local-provider/asset-installer.mjs +10 -4
- package/src/runtime/local-provider/catalog.mjs +5 -2
- package/src/runtime/local-provider/registered-models.mjs +64 -27
- package/src/runtime/local-provider/server.mjs +2 -3
- package/src/runtime/media/adapters/image-api.mjs +89 -0
- package/src/runtime/media/auth.mjs +64 -1
- package/src/runtime/media/catalog.mjs +66 -4
- package/src/runtime/media/jobs.mjs +4 -0
- package/src/runtime/media/lanes.mjs +46 -5
- package/src/runtime/media/media-usage.mjs +17 -0
- package/src/runtime/media/renditions.mjs +15 -15
- package/src/runtime/media/store.mjs +36 -35
- package/src/runtime/media/tool.mjs +8 -1
- package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +8 -2
- package/src/runtime/memory/lib/embedding-model-files.mjs +30 -7
- package/src/runtime/memory/lib/ingest/transcript-tail.mjs +16 -7
- package/src/runtime/memory/lib/pg/process.mjs +8 -4
- package/src/runtime/memory/lib/project-id-resolver.mjs +5 -1
- package/src/runtime/memory/lib/runtime-fetcher.mjs +6 -1
- package/src/runtime/office/core/journal.mjs +7 -14
- package/src/runtime/office/design/library/design-library-core.mjs +4 -16
- package/src/runtime/office/pdf/ocr-engine-worker.mjs +37 -0
- package/src/runtime/office/pdf/ocr-engine.mjs +146 -0
- package/src/runtime/office/pdf/pdf-ocr.mjs +51 -21
- package/src/runtime/office/pdf/pdf-render.mjs +30 -18
- package/src/runtime/office/portable/ooxml-validator.mjs +2 -2
- package/src/runtime/office/portable/portable-soffice.mjs +4 -0
- package/src/runtime/shared/agent-kind-migration.mjs +200 -0
- package/src/runtime/shared/agent-message-envelope.d.mts +6 -0
- package/src/runtime/shared/agent-message-envelope.mjs +44 -0
- package/src/runtime/shared/agent-reap-state.d.mts +4 -0
- package/src/runtime/shared/agent-store.mjs +24 -7
- package/src/runtime/shared/agent-task-starts.mjs +27 -0
- package/src/runtime/shared/atomic-file.d.mts +50 -0
- package/src/runtime/shared/atomic-file.mjs +394 -132
- package/src/runtime/shared/background-tasks.mjs +7 -4
- package/src/runtime/shared/bot-hops.mjs +30 -0
- package/src/runtime/shared/bot-split-migration.mjs +1 -1
- package/src/runtime/shared/bounded-download.mjs +4 -2
- package/src/runtime/shared/config.mjs +39 -9
- package/src/runtime/shared/defaults-separation.mjs +6 -2
- package/src/runtime/shared/delegated-approval-host.mjs +74 -0
- package/src/runtime/shared/err-text.mjs +4 -0
- package/src/runtime/shared/error-presentation.mjs +22 -4
- package/src/runtime/shared/file-has-data.mjs +28 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +37 -18
- package/src/runtime/shared/pending-agent-work.mjs +54 -0
- package/src/runtime/shared/process-lifecycle.mjs +8 -12
- package/src/runtime/shared/projects.mjs +50 -41
- package/src/runtime/shared/provider-accounts.mjs +17 -12
- package/src/runtime/shared/routine-trigger.d.mts +6 -1
- package/src/runtime/shared/routine-trigger.mjs +14 -6
- package/src/runtime/shared/run-child.d.mts +3 -0
- package/src/runtime/shared/run-child.mjs +24 -3
- package/src/runtime/shared/session-baseline-store.mjs +8 -2
- package/src/runtime/shared/singleton-owner.mjs +7 -6
- package/src/runtime/shared/skill-tool-dependencies.mjs +4 -10
- package/src/runtime/shared/staged-update.mjs +4 -2
- package/src/runtime/shared/statusline/statusline-segments.mjs +4 -15
- package/src/runtime/shared/tool-execution-contract.mjs +6 -0
- package/src/runtime/shared/transcript-metadata.mjs +28 -3
- package/src/runtime/shared/transcript-writer/session-record.mjs +7 -6
- package/src/runtime/shared/turn-snapshot-store.mjs +5 -4
- package/src/runtime/shared/turn-snapshot.mjs +44 -2
- package/src/runtime/shared/user-cwd.mjs +9 -4
- package/src/runtime/shared/user-data-guard.mjs +41 -42
- package/src/runtime/shared/utf8-cut.mjs +10 -0
- package/src/runtime/shared/worktrees/activity-gate.mjs +269 -61
- package/src/runtime/shared/worktrees/registry.mjs +26 -26
- package/src/runtime/tidy/core-install.mjs +26 -4
- package/src/runtime/tidy/install.mjs +91 -23
- package/src/runtime/web-search/lib/config.mjs +4 -16
- package/src/session-runtime/agent-home-delivery.mjs +555 -199
- package/src/session-runtime/agent-room-delivery.mjs +143 -36
- package/src/session-runtime/agent-task-sessions.mjs +667 -165
- package/src/session-runtime/agent-tool-routing.mjs +1 -0
- package/src/session-runtime/boot/apis.mjs +45 -24
- package/src/session-runtime/boot/config.mjs +1 -0
- package/src/session-runtime/boot/facade.mjs +11 -1
- package/src/session-runtime/boot/infrastructure.mjs +14 -2
- package/src/session-runtime/boot/providers.mjs +2 -2
- package/src/session-runtime/boot/shared.mjs +12 -6
- package/src/session-runtime/boot/tools.mjs +2 -2
- package/src/session-runtime/bot-status.mjs +432 -0
- package/src/session-runtime/config-lifecycle/lead-route-sync.mjs +29 -0
- package/src/session-runtime/config-lifecycle.mjs +60 -55
- package/src/session-runtime/cwd-plugins/core-memory-context.mjs +2 -4
- package/src/session-runtime/held-requests.mjs +36 -33
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +10 -1
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -2
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +19 -4
- package/src/session-runtime/lifecycle/session-catalog.mjs +12 -2
- package/src/session-runtime/lifecycle/teardown.mjs +11 -3
- package/src/session-runtime/mcp-glue/connect.mjs +100 -186
- package/src/session-runtime/mcp-glue/initial-connect-gate.mjs +57 -0
- package/src/session-runtime/mcp-glue/server-connection.mjs +71 -0
- package/src/session-runtime/media-api.mjs +5 -2
- package/src/session-runtime/model-route/route-tuning.mjs +4 -1
- package/src/session-runtime/model-route/set-route.mjs +61 -1
- package/src/session-runtime/owned-automation-run.mjs +8 -1
- package/src/session-runtime/room-member-gate.mjs +16 -3
- package/src/session-runtime/route-resolution.mjs +16 -8
- package/src/session-runtime/route-state.mjs +1 -59
- package/src/session-runtime/routine-home-turn.mjs +5 -3
- package/src/session-runtime/runtime-bootstrap.mjs +5 -3
- package/src/session-runtime/runtime-paths.mjs +11 -5
- package/src/session-runtime/runtime-tunables.mjs +6 -0
- package/src/session-runtime/services/agent-tool/close-flow/close-all.mjs +11 -2
- package/src/session-runtime/services/agent-tool/close-flow.mjs +4 -2
- package/src/session-runtime/services/agent-tool/execute-send.mjs +1 -0
- package/src/session-runtime/services/agent-tool/execute-spawn.mjs +1 -0
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +10 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +25 -21
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +6 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +8 -5
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +22 -2
- package/src/session-runtime/services/agent-tool/worker-index.mjs +4 -6
- package/src/session-runtime/services/agent-tool.mjs +6 -0
- package/src/session-runtime/services/daemon-crash-capture/daemon-exit-record.mjs +1 -1
- package/src/session-runtime/services/daemon-crash-capture/retention.mjs +4 -3
- package/src/session-runtime/services/hook-bus/config-loader.mjs +14 -5
- package/src/session-runtime/services/hook-bus/rule-file.mjs +49 -11
- package/src/session-runtime/services/plugin-admin.mjs +26 -26
- package/src/session-runtime/services/provider-admin.mjs +14 -4
- package/src/session-runtime/services/schedule-access.mjs +33 -4
- package/src/session-runtime/services/seeds.mjs +4 -3
- package/src/session-runtime/services/usage-dashboard.mjs +1 -1
- package/src/session-runtime/services/usage-stats-model.mjs +2 -1
- package/src/session-runtime/session-create/materialize.mjs +2 -3
- package/src/session-runtime/session-create/session-options.mjs +15 -2
- package/src/session-runtime/settings-builtin-tools-api.mjs +63 -1
- package/src/session-runtime/settings-compaction-api.mjs +86 -39
- package/src/session-runtime/setup-tool/executor.mjs +8 -2
- package/src/session-runtime/setup-tool/settings-contract.mjs +31 -1
- package/src/session-runtime/setup-tool/tool-defs.mjs +20 -3
- package/src/session-runtime/skills-api.mjs +12 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +265 -0
- package/src/session-runtime/tool-policy/mode-switch.mjs +54 -0
- package/src/session-runtime/tool-policy/pending-switches.mjs +59 -0
- package/src/session-runtime/tool-policy/policy-stage.mjs +165 -0
- package/src/session-runtime/tool-policy/session-switches.mjs +169 -0
- package/src/session-runtime/tool-policy/surface-helpers.mjs +114 -0
- package/src/session-runtime/tool-policy/workflow-overlay.mjs +145 -0
- package/src/session-runtime/tool-policy-refresh.mjs +47 -369
- package/src/session-runtime/tool-surface.mjs +5 -3
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +95 -88
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +2 -1
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +54 -7
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +519 -333
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +46 -46
- package/src/session-runtime/workflow-agents-api/shared.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +14 -1
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -3
- package/src/session-runtime/workspace/workspace-state.mjs +7 -6
- package/src/standalone/daemon-agent-control.mjs +4 -1
- package/src/standalone/daemon-session-control.mjs +51 -10
- package/src/standalone/daemon.mjs +28 -10
- package/src/standalone/local-session-runtime.mjs +22 -14
- package/src/standalone/session-client.mjs +7 -2
- package/src/standalone/session-protocol.mjs +7 -0
- package/src/standalone/session-service.mjs +11 -0
- package/src/standalone/session-state-projection.mjs +19 -9
- package/src/standalone/session-tool-output.mjs +35 -9
- package/src/tui/app/maintenance-pickers/auto-clear-picker.mjs +19 -13
- package/src/tui/app/settings-picker/settings-rows.mjs +2 -2
- package/src/tui/app/slash-commands.mjs +1 -1
- package/src/tui/app/usage-context-panels/context-model.mjs +8 -2
- package/src/tui/dist/index.mjs +529 -333
- package/src/tui/prompt-history-store.mjs +16 -21
- package/src/tui/session/context-state.mjs +4 -0
- package/src/tui/session/session-api/intake/abort.mjs +19 -1
- package/src/tui/session/session-api/media.mjs +2 -1
- package/src/tui/session/session-api/routes-agent-definitions.mjs +75 -0
- package/src/tui/session/session-api/routes-write.mjs +203 -0
- package/src/tui/session/session-api/routes.mjs +23 -247
- package/src/tui/session/session-api/settings.mjs +14 -1
- package/src/tui/session/session-flow/drain.mjs +28 -3
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +4 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +8 -3
- package/src/tui/session/tool-approval.mjs +185 -20
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn.mjs +23 -14
- package/src/tui/transcript-tool-failures.mjs +8 -2
- package/src/vendor/statusline/src/gateway/route-meta.mjs +7 -8
- package/src/vendor/statusline/src/gateway/session-routes.mjs +6 -7
- package/src/rules/agent-mode/ROUTINE.md +0 -6
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The turn gate on the initial MCP connect: a bounded wait, never a rejection.
|
|
2
|
+
|
|
3
|
+
// Turn gate: await the in-flight INITIAL connect, bounded by both the global
|
|
4
|
+
// server startup budget and the caller's TTFT grace. A server still
|
|
5
|
+
// connecting after the grace flows through the existing late-tool deferred
|
|
6
|
+
// announcement path unchanged.
|
|
7
|
+
export async function awaitInitialConnect({ state, mcpClient, resolveEffectiveMcpServers }, maxWaitMs = undefined) {
|
|
8
|
+
const inFlight = state.mcpConnectInFlight;
|
|
9
|
+
if (!inFlight) return;
|
|
10
|
+
let budgetMs = 10000;
|
|
11
|
+
try {
|
|
12
|
+
// The gate must outlast the slowest enabled server's own startup budget;
|
|
13
|
+
// a server with its budget disabled (0) means the connect may never
|
|
14
|
+
// settle, so the whole gate is disabled (handled below).
|
|
15
|
+
const configs = Object.values(resolveEffectiveMcpServers().servers).filter((cfg) => cfg?.enabled !== false);
|
|
16
|
+
const budgets = (configs.length > 0 ? configs : [{}])
|
|
17
|
+
.map((cfg) => mcpClient.resolveMcpStartupTimeoutMs?.(cfg))
|
|
18
|
+
.filter((value) => Number.isFinite(value));
|
|
19
|
+
if (budgets.length > 0) budgetMs = budgets.includes(0) ? 0 : Math.max(...budgets);
|
|
20
|
+
} catch {
|
|
21
|
+
/* fall back to default budget */
|
|
22
|
+
}
|
|
23
|
+
if (maxWaitMs !== null && maxWaitMs !== undefined) {
|
|
24
|
+
const requestedMaxWaitMs = Number(maxWaitMs);
|
|
25
|
+
if (Number.isFinite(requestedMaxWaitMs) && requestedMaxWaitMs >= 0) {
|
|
26
|
+
budgetMs = Math.min(budgetMs, requestedMaxWaitMs);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// Budget disabled (0/off) = no per-server startup timeout, so the connect
|
|
30
|
+
// promise may never settle; never gate the turn on it — fall back to the
|
|
31
|
+
// legacy fire-and-forget behavior (late servers use the deferred path).
|
|
32
|
+
if (!(budgetMs > 0)) return;
|
|
33
|
+
let timer = null;
|
|
34
|
+
let expired = false;
|
|
35
|
+
const budget = new Promise((resolveBudget) => {
|
|
36
|
+
timer = setTimeout(() => {
|
|
37
|
+
expired = true;
|
|
38
|
+
resolveBudget();
|
|
39
|
+
}, budgetMs);
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
// Follow replacement connects (a reconnect queued behind the captured
|
|
43
|
+
// run installs a new in-flight promise) inside ONE fixed deadline.
|
|
44
|
+
// Failures are already captured in state.mcpFailures, so rejections are
|
|
45
|
+
// swallowed: this gate must never reject the turn.
|
|
46
|
+
let current = inFlight;
|
|
47
|
+
while (current && !expired) {
|
|
48
|
+
await Promise.race([Promise.resolve(current).catch(() => {}), budget]);
|
|
49
|
+
if (expired) break;
|
|
50
|
+
// Let a queued reconnect install its promise before re-checking.
|
|
51
|
+
await Promise.race([new Promise((resolveTick) => setImmediate(resolveTick)), budget]);
|
|
52
|
+
current = state.mcpConnectInFlight;
|
|
53
|
+
}
|
|
54
|
+
} finally {
|
|
55
|
+
if (timer) clearTimeout(timer);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Connecting, disconnecting and reconciling individual MCP servers in the live
|
|
2
|
+
// registry. The caller (connect.mjs) owns the serialization and the shared state.
|
|
3
|
+
import { clean } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
4
|
+
import { ensurePluginServerData } from './plugin-servers.mjs';
|
|
5
|
+
|
|
6
|
+
export function createServerConnection({
|
|
7
|
+
mcpClient,
|
|
8
|
+
state,
|
|
9
|
+
resolveEffectiveMcpServers,
|
|
10
|
+
getMcpScopeId,
|
|
11
|
+
scopeOptions,
|
|
12
|
+
applied,
|
|
13
|
+
fingerprint,
|
|
14
|
+
syncScopeRoot,
|
|
15
|
+
}) {
|
|
16
|
+
// Connect/disconnect exactly one server in the live registry, leaving all
|
|
17
|
+
// others untouched. Used by the enable/disable toggle so a single-server
|
|
18
|
+
// change never triggers a full disconnectAll()/reconnect freeze. Only an
|
|
19
|
+
// explicit sign-in passes `login` ({ openBrowser }): every other connect is
|
|
20
|
+
// non-interactive and reports a server that needs one as sign-in required.
|
|
21
|
+
async function applyMcpServerConnection(name, enabled, servers = resolveEffectiveMcpServers().servers, login = null) {
|
|
22
|
+
const target = clean(name);
|
|
23
|
+
if (!target) return;
|
|
24
|
+
// Changing this server's state clears any stale failure record for it.
|
|
25
|
+
if (Array.isArray(state.mcpFailures)) {
|
|
26
|
+
state.mcpFailures = state.mcpFailures.filter((row) => row.name !== target);
|
|
27
|
+
}
|
|
28
|
+
const cfg = servers[target];
|
|
29
|
+
if (enabled === false || !cfg || cfg.enabled === false) {
|
|
30
|
+
applied().delete(target);
|
|
31
|
+
await mcpClient.disconnectMcpServer?.(target, scopeOptions());
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
applied().set(target, fingerprint(cfg));
|
|
35
|
+
// Close-then-connect as one generation-guarded op: a shutdown landing
|
|
36
|
+
// between the close and the connect never resurrects the server.
|
|
37
|
+
try {
|
|
38
|
+
ensurePluginServerData(cfg);
|
|
39
|
+
await mcpClient.reconnectSingleMcpServer(
|
|
40
|
+
getMcpScopeId(),
|
|
41
|
+
target,
|
|
42
|
+
cfg,
|
|
43
|
+
login ? { interactive: true, openBrowser: login.openBrowser } : {}
|
|
44
|
+
);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const failure = { name: target, msg: error?.message || String(error) };
|
|
47
|
+
if (error?.authRequired) failure.authRequired = true;
|
|
48
|
+
const failures = Array.isArray(error?.failures) ? error.failures : [failure];
|
|
49
|
+
state.mcpFailures = [...(state.mcpFailures || []), ...failures];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Bring the registry in line with the effective set: drop servers that are
|
|
54
|
+
// gone or disabled, (re)connect servers that are new or whose resolved
|
|
55
|
+
// config changed; untouched servers keep their connection.
|
|
56
|
+
async function reconcileServers() {
|
|
57
|
+
syncScopeRoot();
|
|
58
|
+
const { servers } = resolveEffectiveMcpServers();
|
|
59
|
+
const known = applied();
|
|
60
|
+
const drops = [...known.keys()].filter((name) => !servers[name] || servers[name].enabled === false);
|
|
61
|
+
const connects = Object.entries(servers)
|
|
62
|
+
.filter(([name, cfg]) => cfg?.enabled !== false && known.get(name) !== fingerprint(cfg))
|
|
63
|
+
.map(([name]) => name);
|
|
64
|
+
await Promise.allSettled([
|
|
65
|
+
...drops.map((name) => applyMcpServerConnection(name, false, servers)),
|
|
66
|
+
...connects.map((name) => applyMcpServerConnection(name, true, servers)),
|
|
67
|
+
]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { applyMcpServerConnection, reconcileServers };
|
|
71
|
+
}
|
|
@@ -41,8 +41,11 @@ export function createMediaApi() {
|
|
|
41
41
|
});
|
|
42
42
|
return { status: await module.getVoiceStatus(), error };
|
|
43
43
|
},
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
// `budgetMs` (Studio) caps the per-lane catalog wait; slower lanes come
|
|
45
|
+
// back `catalogPending`. Capped so a caller cannot park the call.
|
|
46
|
+
async listMediaLanes(options) {
|
|
47
|
+
const budgetMs = Math.min(30_000, Math.max(0, Math.trunc(Number(options?.budgetMs) || 0)));
|
|
48
|
+
return (await lanes()).listMediaLanes({ budgetMs });
|
|
46
49
|
},
|
|
47
50
|
// The Studio's current selection is the runtime's default: a tool call
|
|
48
51
|
// that omits lane/model follows it. Studio pushes on every settled change.
|
|
@@ -67,7 +67,10 @@ export function createRouteTuning(deps, persist) {
|
|
|
67
67
|
},
|
|
68
68
|
async setEffort(value) {
|
|
69
69
|
const normalized = normalizeEffortInput(value);
|
|
70
|
-
|
|
70
|
+
// An explicit level is the user's choice for this route: Auto effort
|
|
71
|
+
// would replace it on the next turn (its base is fixed), so the pick
|
|
72
|
+
// turns the route's Auto off until it is switched back on.
|
|
73
|
+
setRouteState({ ...getRoute(), effort: normalized, ...(normalized ? { autoEffort: false } : {}) });
|
|
71
74
|
const modelMeta = await lookupModelMeta(getRoute().provider, getRoute().model);
|
|
72
75
|
const fastCapable = selectionFastCapable(getRoute().provider, modelMeta, normalized, getRoute().modelParameters);
|
|
73
76
|
await commitRouteTuning(fastCapable, modelMeta);
|
|
@@ -24,6 +24,11 @@ import {
|
|
|
24
24
|
} from '../../runtime/agent/orchestrator/runtime-core/session-route-policy.mjs';
|
|
25
25
|
import { rebuildToolSurfaceForProviderWithMigration } from '../../runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs';
|
|
26
26
|
import { UNOWNED_LEASE, openRouteLease } from './route-ownership.mjs';
|
|
27
|
+
import { resolveSessionMode } from '../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
28
|
+
import { ownerRouteFallbacks } from '../../runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs';
|
|
29
|
+
import { normalizeWorkflowRoute } from '../../runtime/agent/orchestrator/runtime-core/workflow.mjs';
|
|
30
|
+
import { routeChain, validateRouteChainProviders } from '../../runtime/shared/model-route-chain.mjs';
|
|
31
|
+
import { resolveChainEntry } from '../workflow-agents-api/agent-route.mjs';
|
|
27
32
|
|
|
28
33
|
/** The request, completed from the live route where the caller left gaps. */
|
|
29
34
|
function completeRequest(deps, next) {
|
|
@@ -105,6 +110,32 @@ async function recreateEmptySession(deps, lease) {
|
|
|
105
110
|
if (closed) await createCurrentSession('model-switch-empty');
|
|
106
111
|
}
|
|
107
112
|
|
|
113
|
+
/** The fallback chain a Lead-class session follows on `route`: its owner's chain
|
|
114
|
+
* while the route is the owner's primary model, none otherwise (see
|
|
115
|
+
* owner-route-fallbacks.mjs). Nothing for an agent's session, which keeps its own. */
|
|
116
|
+
export function sessionRouteFallbackFields(deps, session, route) {
|
|
117
|
+
const { mode, agentId } = resolveSessionMode({ session });
|
|
118
|
+
if (!agentId) return {};
|
|
119
|
+
return {
|
|
120
|
+
routeFallbacks: ownerRouteFallbacks({
|
|
121
|
+
sessionMode: mode,
|
|
122
|
+
agentId,
|
|
123
|
+
provider: route.provider,
|
|
124
|
+
model: route.model,
|
|
125
|
+
config: deps.getConfig(),
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** A same-model selection (a bot profile saved with new fallbacks) restarts the
|
|
131
|
+
* addressed session's chain when the owner's chain no longer matches it. */
|
|
132
|
+
function refreshSessionFallbacks(deps, session) {
|
|
133
|
+
const fields = sessionRouteFallbackFields(deps, session, deps.getRoute());
|
|
134
|
+
if (!fields.routeFallbacks) return;
|
|
135
|
+
if (JSON.stringify(fields.routeFallbacks) === JSON.stringify(session.routeFallbacks || [])) return;
|
|
136
|
+
deps.mgr.updateSessionRoute?.(session.id, fields, { session });
|
|
137
|
+
}
|
|
138
|
+
|
|
108
139
|
/** Rewrite the addressed empty session to the route it was asked to run on. */
|
|
109
140
|
function updateSessionInPlace(deps, session, updateOptions) {
|
|
110
141
|
const { getRoute, getSession, setSession, mgr, statusRoutes } = deps;
|
|
@@ -119,6 +150,7 @@ function updateSessionInPlace(deps, session, updateOptions) {
|
|
|
119
150
|
contextPercent: route.contextPercent,
|
|
120
151
|
contextTokens: route.contextTokens || null,
|
|
121
152
|
selectedContextWindow: route.selectedContextWindow || null,
|
|
153
|
+
...sessionRouteFallbackFields(deps, session, route),
|
|
122
154
|
};
|
|
123
155
|
const updated = mgr.updateSessionRoute?.(session.id, fields, updateOptions);
|
|
124
156
|
if (updated) setSession(updated);
|
|
@@ -183,6 +215,27 @@ function switchSessionInPlace(deps, session) {
|
|
|
183
215
|
return recorded ? boundary : null;
|
|
184
216
|
}
|
|
185
217
|
|
|
218
|
+
/** The Lead's fallback models after this selection, checked like an agent's
|
|
219
|
+
* chain (leaf routes, distinct providers): an explicit list replaces the
|
|
220
|
+
* stored one ([] clears it), a selection without one keeps it. */
|
|
221
|
+
async function leadFallbackChain(deps, next, primary) {
|
|
222
|
+
const storedPreset = findPreset(deps.getConfig(), workflowPresetId('lead'));
|
|
223
|
+
const requested = hasOwn(next || {}, 'fallbacks') ? next.fallbacks : storedPreset?.fallbacks;
|
|
224
|
+
if (!Array.isArray(requested) || !requested.length) return [];
|
|
225
|
+
const chain = routeChain({ provider: primary.provider, model: primary.model, fallbacks: requested });
|
|
226
|
+
validateRouteChainProviders(chain);
|
|
227
|
+
const storedChain = routeChain(storedPreset || {});
|
|
228
|
+
// Each entry goes through the agents' normalizer (fast clamp, context window).
|
|
229
|
+
const resolved = [];
|
|
230
|
+
for (const entry of chain.slice(1)) {
|
|
231
|
+
const previous = storedChain.find((c) => c.provider === entry.provider && c.model === entry.model);
|
|
232
|
+
resolved.push(await resolveChainEntry(deps, entry, previous || {}));
|
|
233
|
+
}
|
|
234
|
+
return (
|
|
235
|
+
normalizeWorkflowRoute({ provider: primary.provider, model: primary.model, fallbacks: resolved })?.fallbacks || []
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
186
239
|
/** Validate, persist and adopt the requested route as the runtime's route. */
|
|
187
240
|
async function adoptRoute(deps, persist, next, options, lease) {
|
|
188
241
|
const {
|
|
@@ -195,6 +248,12 @@ async function adoptRoute(deps, persist, next, options, lease) {
|
|
|
195
248
|
scheduleStatuslineUsageRefresh,
|
|
196
249
|
} = deps;
|
|
197
250
|
const { selectedRoute, fastCapable, modelMeta } = await resolveSelectedRoute(deps, next);
|
|
251
|
+
// The Lead's fallback chain travels with an explicit main-model choice only
|
|
252
|
+
// (the Lead editor, the setup tool); a session's own pick never touches it.
|
|
253
|
+
const persistedRoute =
|
|
254
|
+
options?.keepMainModel === false && options?.sessionOnly !== true
|
|
255
|
+
? { ...selectedRoute, fallbacks: await leadFallbackChain(deps, next, selectedRoute) }
|
|
256
|
+
: selectedRoute;
|
|
198
257
|
// The Lead route a conditional fill wrote, until the file confirms it.
|
|
199
258
|
let filled = null;
|
|
200
259
|
// Provider readiness may outlast the session the selection was made for.
|
|
@@ -222,7 +281,7 @@ async function adoptRoute(deps, persist, next, options, lease) {
|
|
|
222
281
|
// The main model changes only on an explicit main-model choice
|
|
223
282
|
// (keepMainModel: false, e.g. the setup tool); every other selection
|
|
224
283
|
// — the session surface's model pick, an heir — keeps it.
|
|
225
|
-
const leadRoute = persist.persistAdoptedModelSettings(
|
|
284
|
+
const leadRoute = persist.persistAdoptedModelSettings(persistedRoute, {
|
|
226
285
|
keepMainModel: options?.keepMainModel !== false,
|
|
227
286
|
onlyIfAbsent: options?.onlyIfEmpty === true,
|
|
228
287
|
});
|
|
@@ -340,6 +399,7 @@ export function createSetRoute(deps, persist) {
|
|
|
340
399
|
return modelSwitch ? { ...getRoute(), modelSwitch } : getRoute();
|
|
341
400
|
}
|
|
342
401
|
persist.applySessionTuning();
|
|
402
|
+
refreshSessionFallbacks(deps, session);
|
|
343
403
|
return getRoute();
|
|
344
404
|
}
|
|
345
405
|
// An addressed runtime keeps its durable id: the empty session is updated
|
|
@@ -101,7 +101,7 @@ async function queueResult(row, item, entry, { deliver, recordDelivery, onDelive
|
|
|
101
101
|
/**
|
|
102
102
|
* `row` is `{ name, ownerAgentId }`; `run({ signal })` resolves `{ sessionId,
|
|
103
103
|
* result }` (`signal` is the caller's cancellation, if any). Resolves the
|
|
104
|
-
* outcome, or `{ skipped: true, reason: 'owner' | 'overlap' | 'backoff' }`
|
|
104
|
+
* outcome, or `{ skipped: true, reason: 'owner' | 'overlap' | 'backoff' | 'paused' }`
|
|
105
105
|
* (an owner skip also names `ownerProblem` and its `message`); a failed run
|
|
106
106
|
* rejects.
|
|
107
107
|
*/
|
|
@@ -141,6 +141,13 @@ export async function runOwnedAutomation(kind, row, run, deps = {}) {
|
|
|
141
141
|
const state = await Promise.resolve()
|
|
142
142
|
.then(() => record.state(name))
|
|
143
143
|
.catch(() => null);
|
|
144
|
+
// Switched off (by the user, or by the failure limit): the cron claim and
|
|
145
|
+
// the webhook handler already refuse it, but a one-shot timer or a
|
|
146
|
+
// dispatch that raced the pause must not run it either.
|
|
147
|
+
if (state?.enabled === false) {
|
|
148
|
+
log(`${kind} "${name}": skipped, switched off`);
|
|
149
|
+
return await skip('paused');
|
|
150
|
+
}
|
|
144
151
|
const wait = routineBackoffRemaining(state, now(), limits);
|
|
145
152
|
if (wait > 0) {
|
|
146
153
|
log(`${kind} "${name}": skipped, backing off ${Math.ceil(wait / 1000)}s after failures in a row`);
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
// anything that can change files or state asks the user through the ordinary
|
|
3
3
|
// approval flow, whatever the agent's own permission or hook rules say — even
|
|
4
4
|
// an agent that normally runs auto-approved. A hook's deny still wins.
|
|
5
|
+
// Opening a task session (`session create`) runs as freely as in the agent's
|
|
6
|
+
// home thread: it changes nothing itself, and the task session is the user's
|
|
7
|
+
// own coding Lead, whose every side effect follows its usual approval rules.
|
|
5
8
|
import { analyzeShellCommandEffects } from '../runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs';
|
|
6
9
|
|
|
7
10
|
const READ_ONLY_TOOLS = new Set([
|
|
@@ -37,12 +40,22 @@ export async function isReadOnlyRoomCall({ name, args, cwd }, analyze = analyzeS
|
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
/** Whether `name(args)` opens a task session (session create). */
|
|
44
|
+
export function isTaskSessionCreate({ name, args }) {
|
|
45
|
+
return (
|
|
46
|
+
name === 'session' &&
|
|
47
|
+
String(args?.action ?? '')
|
|
48
|
+
.trim()
|
|
49
|
+
.toLowerCase() === 'create'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
40
53
|
/** The PreToolUse decision for a room member's call: the hook's own `decision`
|
|
41
|
-
* when it denies
|
|
42
|
-
* any rewrite the hook made. */
|
|
54
|
+
* when it denies, the call only reads, or it opens a task session; otherwise
|
|
55
|
+
* an approval ask that keeps any rewrite the hook made. */
|
|
43
56
|
export async function roomMemberToolDecision(call, decision, analyze) {
|
|
44
57
|
const action = String(decision?.action || decision?.decision || '').toLowerCase();
|
|
45
58
|
if (action === 'deny' || action === 'block') return decision;
|
|
46
|
-
if (await isReadOnlyRoomCall(call, analyze)) return decision;
|
|
59
|
+
if (isTaskSessionCreate(call) || (await isReadOnlyRoomCall(call, analyze))) return decision;
|
|
47
60
|
return { ...(decision && typeof decision === 'object' ? decision : {}), action: 'ask', reason: ROOM_APPROVAL_REASON };
|
|
48
61
|
}
|
|
@@ -22,6 +22,10 @@ export function createRouteResolution({ rt, collectProviderModels, ensureProvide
|
|
|
22
22
|
if (routeHasModel()) return rt.route;
|
|
23
23
|
const models = await runAbortable(signal, () => collectProviderModels());
|
|
24
24
|
throwIfAborted(signal);
|
|
25
|
+
// A model chosen during the catalog read stands: a new task's reservation
|
|
26
|
+
// prewarm starts on the empty route, its draft model lands meanwhile, and
|
|
27
|
+
// the first prompt joins this very prewarm.
|
|
28
|
+
if (routeHasModel()) return rt.route;
|
|
25
29
|
if (!models?.length) {
|
|
26
30
|
throw new Error('No provider models available. Open /providers to sign in, then /model to choose a model.');
|
|
27
31
|
}
|
|
@@ -47,15 +51,19 @@ export function createRouteResolution({ rt, collectProviderModels, ensureProvide
|
|
|
47
51
|
.find((option) => option?.id === 'context')
|
|
48
52
|
?.options?.find((option) => clean(option?.value) === contextValue);
|
|
49
53
|
const modelDisplay = routeModelDisplay(rt.config, targetRoute, modelMeta);
|
|
50
|
-
|
|
54
|
+
// Without a known window the selection (share, exact tokens, resolved
|
|
55
|
+
// window) is kept as requested — the session sizes it from the provider's
|
|
56
|
+
// window; dropping it silently put the route back on the model's default.
|
|
57
|
+
// With one it is the clamped value, absent when it is the default window.
|
|
58
|
+
const windowKnown = contextState.contextDefaultPercent !== undefined;
|
|
59
|
+
const selectedContextWindow = [
|
|
60
|
+
contextState.selectedContextWindow,
|
|
61
|
+
contextOption?.contextWindow,
|
|
62
|
+
windowKnown ? undefined : targetRoute.selectedContextWindow,
|
|
63
|
+
]
|
|
51
64
|
.map(Number)
|
|
52
65
|
.find((value) => value > 0);
|
|
53
|
-
|
|
54
|
-
// one it is the clamped value, absent when it is the default window.
|
|
55
|
-
const contextTokens =
|
|
56
|
-
contextState.contextDefaultPercent === undefined
|
|
57
|
-
? normalizeContextTokens(targetRoute.contextTokens)
|
|
58
|
-
: contextState.contextTokens;
|
|
66
|
+
const contextTokens = windowKnown ? contextState.contextTokens : normalizeContextTokens(targetRoute.contextTokens);
|
|
59
67
|
const { contextTokens: _requestedTokens, ...routeFields } = targetRoute;
|
|
60
68
|
rt.route = {
|
|
61
69
|
...routeFields,
|
|
@@ -63,7 +71,7 @@ export function createRouteResolution({ rt, collectProviderModels, ensureProvide
|
|
|
63
71
|
fastCapable,
|
|
64
72
|
effectiveEffort,
|
|
65
73
|
effortOptions: effortItemsFor(rt.route.provider, modelMeta, effectiveEffort),
|
|
66
|
-
contextPercent: contextState.contextPercent,
|
|
74
|
+
contextPercent: windowKnown ? contextState.contextPercent : targetRoute.contextPercent,
|
|
67
75
|
contextDefaultPercent: contextState.contextDefaultPercent,
|
|
68
76
|
...(contextTokens ? { contextTokens } : {}),
|
|
69
77
|
...(selectedContextWindow ? { selectedContextWindow } : {}),
|
|
@@ -7,8 +7,6 @@ import {
|
|
|
7
7
|
import { clean, hasOwn } from '../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
8
8
|
import { coerceEffortFor } from '../runtime/agent/orchestrator/runtime-core/effort.mjs';
|
|
9
9
|
import { fastCapableFor } from '../runtime/agent/orchestrator/runtime-core/model-capabilities.mjs';
|
|
10
|
-
import { providerCachedModelMetadataSync } from '../runtime/agent/orchestrator/providers/provider-catalog-cache.mjs';
|
|
11
|
-
import { contextWindowRange, normalizeContextTokens } from '../runtime/shared/llm/default-context-window.mjs';
|
|
12
10
|
|
|
13
11
|
export function resolveRouteEffortState(targetRoute = {}, modelMeta = null) {
|
|
14
12
|
const requested = hasOwn(targetRoute, 'effort') ? targetRoute.effort : targetRoute.preset?.effort || null;
|
|
@@ -36,63 +34,7 @@ export function selectionFastCapable(provider, modelMeta, effort, modelParameter
|
|
|
36
34
|
return !modelMetaLooksResolved(modelMeta) || fastCapableFor(provider, modelMeta, effort, modelParameters);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
// slider against, so they carry both windows (openai-oauth: 272k default /
|
|
41
|
-
// 1M max). Reading them keeps a percentage saved against the picker's scale
|
|
42
|
-
// meaningful; anything that only knows a single window would silently rescale
|
|
43
|
-
// it (30% of 272k instead of 30% of 1M).
|
|
44
|
-
function cachedRouteWindows(provider, model) {
|
|
45
|
-
const row = providerCachedModelMetadataSync(provider, model)?.rawProviderModel || null;
|
|
46
|
-
if (!row) return null;
|
|
47
|
-
const contextWindow = Number(row.contextWindow ?? row.context_window ?? row.max_input_tokens) || 0;
|
|
48
|
-
const maxContextWindow = Number(row.maxContextWindow ?? row.max_context_window) || 0;
|
|
49
|
-
return contextWindow > 0 || maxContextWindow > 0 ? { contextWindow, maxContextWindow } : null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function resolveRouteContextState(targetRoute = {}, modelMeta = null, windowLookup = cachedRouteWindows) {
|
|
53
|
-
// Only providers that implement getCachedModelInfo (openai-oauth, cursor,
|
|
54
|
-
// openai-compat, opencode-go) hand lookupModelMeta a window; every other one
|
|
55
|
-
// (anthropic-oauth, grok-oauth, gemini, …) gets the bare `{ id, provider }`
|
|
56
|
-
// placeholder. Reading the window from that alone yields 0, which dropped the
|
|
57
|
-
// saved context percentage for the entire session — while resolveSessionContextMeta
|
|
58
|
-
// went on to size that session from the provider/catalog window (Claude Opus 5:
|
|
59
|
-
// a full 1M rather than the selected 500k). Read the cached provider row here so
|
|
60
|
-
// the percentage and the session boundary cannot disagree.
|
|
61
|
-
const windowMeta =
|
|
62
|
-
Number(modelMeta?.contextWindow) > 0 || Number(modelMeta?.maxContextWindow) > 0
|
|
63
|
-
? modelMeta
|
|
64
|
-
: windowLookup?.(clean(targetRoute?.provider), clean(targetRoute?.model)) || modelMeta;
|
|
65
|
-
const { defaultWindow, maxWindow } = contextWindowRange({
|
|
66
|
-
provider: clean(targetRoute?.provider),
|
|
67
|
-
contextWindow: windowMeta?.contextWindow,
|
|
68
|
-
maxContextWindow: windowMeta?.maxContextWindow,
|
|
69
|
-
});
|
|
70
|
-
if (!maxWindow) {
|
|
71
|
-
return { contextPercent: undefined, contextDefaultPercent: undefined, selectedContextWindow: undefined };
|
|
72
|
-
}
|
|
73
|
-
const contextDefaultPercent = Math.max(10, Math.min(100, Math.round((defaultWindow / maxWindow) * 10) * 10));
|
|
74
|
-
// An exact token selection overrides the 10% stops. It is clamped to the
|
|
75
|
-
// selectable range; one that lands on the default window is the default.
|
|
76
|
-
const requestedTokens = normalizeContextTokens(targetRoute?.contextTokens);
|
|
77
|
-
if (requestedTokens) {
|
|
78
|
-
const contextTokens = Math.max(Math.ceil(maxWindow * 0.1), Math.min(maxWindow, requestedTokens));
|
|
79
|
-
if (contextTokens === defaultWindow) {
|
|
80
|
-
return { contextPercent: contextDefaultPercent, contextDefaultPercent, selectedContextWindow: defaultWindow };
|
|
81
|
-
}
|
|
82
|
-
const contextPercent = Math.max(10, Math.min(100, Math.round((contextTokens / maxWindow) * 10) * 10));
|
|
83
|
-
return { contextPercent, contextDefaultPercent, selectedContextWindow: contextTokens, contextTokens };
|
|
84
|
-
}
|
|
85
|
-
const requested = Number(targetRoute?.contextPercent);
|
|
86
|
-
const contextPercent =
|
|
87
|
-
Number.isFinite(requested) && requested > 0
|
|
88
|
-
? Math.max(10, Math.min(100, Math.round(requested / 10) * 10))
|
|
89
|
-
: contextDefaultPercent;
|
|
90
|
-
const selectedContextWindow =
|
|
91
|
-
contextPercent === contextDefaultPercent
|
|
92
|
-
? defaultWindow
|
|
93
|
-
: Math.max(1, Math.floor((maxWindow * contextPercent) / 100));
|
|
94
|
-
return { contextPercent, contextDefaultPercent, selectedContextWindow };
|
|
95
|
-
}
|
|
37
|
+
export { resolveRouteContextState } from '../runtime/agent/orchestrator/runtime-core/route-context-state.mjs';
|
|
96
38
|
|
|
97
39
|
/**
|
|
98
40
|
* Human label for the statusline. A display-only user alias
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* it rides the thread's queue as its own `routine` entry (one per turn, never
|
|
10
10
|
* merged or steered into another), shows as a routine marker row, and selects
|
|
11
11
|
* skills only from the routine's instructions (`skillSelection`), never from a
|
|
12
|
-
* webhook payload. While it runs the thread counts as unattended
|
|
13
|
-
*
|
|
12
|
+
* webhook payload. While it runs the thread counts as an unattended run
|
|
13
|
+
* (held-requests.mjs): the saved routine is the user's grant, so it never asks
|
|
14
|
+
* (outbound actions are allowed within the bot's permissions; payments and
|
|
15
|
+
* permanent deletes are refused, human-gate/run-policy.mjs). Resolves with the
|
|
14
16
|
* reply once the turn ends; rejects when the turn fails, is cancelled, or the
|
|
15
17
|
* caller's `signal` aborts (which also aborts the turn once it runs).
|
|
16
18
|
*/
|
|
@@ -126,7 +128,7 @@ export async function runRoutineTurn(
|
|
|
126
128
|
onCommitted: () => {
|
|
127
129
|
if (started) return;
|
|
128
130
|
started = true;
|
|
129
|
-
// Nobody watches this turn:
|
|
131
|
+
// Nobody watches this turn: it never asks (run-policy.mjs).
|
|
130
132
|
unmark = markUnattendedRun(homeId, { kind, agentId, name });
|
|
131
133
|
if (aborted) void abortTurn();
|
|
132
134
|
},
|
|
@@ -13,22 +13,24 @@ import {
|
|
|
13
13
|
CODE_GRAPH_TOOL_DEFS,
|
|
14
14
|
STATUSLINE_SESSION_ROUTES,
|
|
15
15
|
STANDALONE_ROOT,
|
|
16
|
-
|
|
16
|
+
standaloneDataDir,
|
|
17
17
|
} from './runtime-paths.mjs';
|
|
18
18
|
|
|
19
19
|
export function prepareStandaloneEnvironment() {
|
|
20
20
|
process.env.MIXDOG_QUIET_SESSION_LOG ??= '1';
|
|
21
21
|
const startedAt = performance.now();
|
|
22
|
+
// Resolved per runtime start: this start's data folder, not the first one's.
|
|
23
|
+
const dataDir = standaloneDataDir();
|
|
22
24
|
ensureStandaloneEnvironment({
|
|
23
25
|
rootDir: STANDALONE_ROOT,
|
|
24
|
-
dataDir
|
|
26
|
+
dataDir,
|
|
25
27
|
});
|
|
26
28
|
// Office journals exist only for cross-process crash recovery, so startup just
|
|
27
29
|
// prunes expired ones in the background. Surfacing them as session context made
|
|
28
30
|
// every new session (agents included) re-announce unrelated leftovers for the
|
|
29
31
|
// full 30-day retention window; recovery stays reachable on demand through
|
|
30
32
|
// office action=transactions / action=recover.
|
|
31
|
-
listOfficeJournals(
|
|
33
|
+
listOfficeJournals(dataDir).catch(() => {});
|
|
32
34
|
bootProfile('standalone-env:ready', { ms: (performance.now() - startedAt).toFixed(1) });
|
|
33
35
|
}
|
|
34
36
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
1
|
+
import { dirname } from 'node:path';
|
|
3
2
|
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { resolvePluginData } from '../runtime/shared/plugin-paths.mjs';
|
|
4
4
|
|
|
5
5
|
export const RUNTIME = '../runtime/agent/orchestrator';
|
|
6
6
|
export const WEB_SEARCH_RUNTIME = '../runtime/web-search/index.mjs';
|
|
@@ -12,10 +12,16 @@ export const STATUSLINE_SESSION_ROUTES = '../vendor/statusline/src/gateway/sessi
|
|
|
12
12
|
|
|
13
13
|
const SESSION_RUNTIME_DIR = dirname(fileURLToPath(import.meta.url));
|
|
14
14
|
export const STANDALONE_ROOT = dirname(SESSION_RUNTIME_DIR);
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The standalone data directory, resolved from the environment on every call.
|
|
18
|
+
* A runtime start (a pristine boundary, a second page session) retargets
|
|
19
|
+
* MIXDOG_DATA_DIR, so a load-time constant would point every later start back
|
|
20
|
+
* at the first run's folder.
|
|
21
|
+
*/
|
|
22
|
+
export const standaloneDataDir = resolvePluginData;
|
|
17
23
|
|
|
18
24
|
/** The data directory a runtime writes to: its config module's plugin data dir, else the standalone default. */
|
|
19
25
|
export function pluginDataDir(cfgMod) {
|
|
20
|
-
return cfgMod.getPluginData?.() ||
|
|
26
|
+
return cfgMod.getPluginData?.() || standaloneDataDir();
|
|
21
27
|
}
|
|
@@ -36,6 +36,12 @@ export function readRuntimeTunables() {
|
|
|
36
36
|
// connected tools fold synchronously; in-flight servers join through the
|
|
37
37
|
// late-tool announcement path. Operators may opt back into a grace window.
|
|
38
38
|
mcpTurnGraceMs: envDelayMs('MIXDOG_MCP_TURN_GRACE_MS', 0, { min: 0, max: 2_000 }),
|
|
39
|
+
// A spawned agent's first turn may be its only one, so it waits for the
|
|
40
|
+
// initial connect — but only this long: a slow-but-alive server (a
|
|
41
|
+
// 20 s handshake is seen in the wild) must not hold the first model
|
|
42
|
+
// request for its whole startup budget. Later servers join through the
|
|
43
|
+
// late-tool announcement path on the agent's next turn.
|
|
44
|
+
mcpAgentGraceMs: envDelayMs('MIXDOG_MCP_AGENT_GRACE_MS', 3_000, { min: 0, max: 30_000 }),
|
|
39
45
|
// Boot-time remote start is deferred past the first frame; see the caller.
|
|
40
46
|
remoteAutoStartDelayMs: envDelayMs('MIXDOG_REMOTE_AUTOSTART_DELAY_MS', 1_500, { min: 0, max: 60_000 }),
|
|
41
47
|
providerWarmupEnabled:
|
|
@@ -5,6 +5,7 @@ import { cancelBackgroundTask, listBackgroundTasks } from '../../../../runtime/s
|
|
|
5
5
|
import { presentErrorText } from '../../../../runtime/shared/err-text.mjs';
|
|
6
6
|
import { clean } from '../helpers.mjs';
|
|
7
7
|
import { isLeadPoolAgent } from '../worker-rows.mjs';
|
|
8
|
+
import { isUnnotifiedRestartFailure } from '../worker-index/row-liveness.mjs';
|
|
8
9
|
|
|
9
10
|
export function createCloseAll({ registry, close }) {
|
|
10
11
|
const { tags, tagAgents, tagCwds } = registry;
|
|
@@ -17,11 +18,13 @@ export function createCloseAll({ registry, close }) {
|
|
|
17
18
|
|
|
18
19
|
// Drop the closed workers' rows: every non-Lead row for an unscoped
|
|
19
20
|
// teardown, only this owner's (plus the rows just closed) for a scoped one.
|
|
21
|
+
// A row whose owner is still owed its restart failure stays (a process exit
|
|
22
|
+
// closes every worker; the next process tells the owner).
|
|
20
23
|
function purgeWorkerRows(ownerSessionId, closedSessionIds) {
|
|
21
24
|
registry.flushWorkerIndexMutations();
|
|
22
25
|
registry.writeWorkerRows((byKey, tombstonesByKey) => {
|
|
23
26
|
for (const [key, row] of [...byKey.entries()]) {
|
|
24
|
-
if (isLeadPoolAgent(row.agent)) continue;
|
|
27
|
+
if (isLeadPoolAgent(row.agent) || isUnnotifiedRestartFailure(row)) continue;
|
|
25
28
|
if (
|
|
26
29
|
ownerSessionId &&
|
|
27
30
|
clean(row.ownerSessionId) !== ownerSessionId &&
|
|
@@ -38,15 +41,20 @@ export function createCloseAll({ registry, close }) {
|
|
|
38
41
|
// Lead's workers: the worker index and task registry are shared by every
|
|
39
42
|
// Lead in the process, and an unscoped sweep wiped sibling Leads' idle
|
|
40
43
|
// workers mid-window.
|
|
44
|
+
// A process exit (`scope.processExit`) closes the workers but keeps their
|
|
45
|
+
// rows: the next process lists the finished ones for their pane window and
|
|
46
|
+
// settles the ones the exit cut off (restart-notify), exactly as after a
|
|
47
|
+
// crash. Dropping them emptied every sub-agent list after a daemon restart.
|
|
41
48
|
return async function closeAll(reason = 'cli-agent-close-all', scope = {}) {
|
|
42
49
|
const ownerSessionId = clean(scope.callerSessionId);
|
|
50
|
+
const keepRows = scope.processExit === true;
|
|
43
51
|
const context = ownerSessionId ? { callerSessionId: ownerSessionId } : {};
|
|
44
52
|
registry.refreshTagsFromSessions({ scanSessions: false, context });
|
|
45
53
|
const closed = [];
|
|
46
54
|
const failed = [];
|
|
47
55
|
for (const { tag, session } of registry.agentSessionEntries({ scanSessions: false, context })) {
|
|
48
56
|
try {
|
|
49
|
-
closed.push(await close({ sessionId: session.id }, context));
|
|
57
|
+
closed.push(await close({ sessionId: session.id }, context, { keepRow: keepRows }));
|
|
50
58
|
} catch (err) {
|
|
51
59
|
failed.push({ tag, error: presentErrorText(err, { surface: 'agent' }) });
|
|
52
60
|
}
|
|
@@ -57,6 +65,7 @@ export function createCloseAll({ registry, close }) {
|
|
|
57
65
|
closed.push({ closed: true, tag: task.tag || null, sessionId: task.sessionId || null, task_id: task.task_id });
|
|
58
66
|
}
|
|
59
67
|
if (!ownerSessionId) resetLocalTagState();
|
|
68
|
+
if (keepRows) return { closed, failed };
|
|
60
69
|
const closedSessionIds = new Set(closed.map((row) => clean(row.sessionId)).filter(Boolean));
|
|
61
70
|
purgeWorkerRows(ownerSessionId, closedSessionIds);
|
|
62
71
|
return { closed, failed };
|
|
@@ -37,7 +37,9 @@ export function createCloseFlow({ mgr, registry, views }) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
/** `keepRow`: a process exit closes the worker but leaves its row (and its
|
|
41
|
+
* descendants') for the next process (close-all.mjs). */
|
|
42
|
+
async function close(args, context = {}, { keepRow = false } = {}) {
|
|
41
43
|
const scopedContext = agentScope(args, context);
|
|
42
44
|
registry.refreshTagsFromSessions({ scanSessions: registry.wantsSessionScan(args), context: scopedContext });
|
|
43
45
|
const taskId = taskIdFromArgs(args);
|
|
@@ -73,7 +75,7 @@ export function createCloseFlow({ mgr, registry, views }) {
|
|
|
73
75
|
if (task?.taskId) cancelBackgroundTask(task.taskId, CLOSE_REASON);
|
|
74
76
|
// Drop the row only once the cancellation is DURABLY recorded: a failed
|
|
75
77
|
// close that still forgot the row would leave no cancelled state behind.
|
|
76
|
-
if (ok) {
|
|
78
|
+
if (ok && !keepRow) {
|
|
77
79
|
registry.forgetTerminalSession(tag, sessionId);
|
|
78
80
|
for (const descendantSessionId of descendantSessionIds) {
|
|
79
81
|
registry.removeWorkerRow({ sessionId: descendantSessionId });
|
|
@@ -70,6 +70,7 @@ export function createSendDispatch({ registry, defaultCwd, sendFlow, spawnFlow,
|
|
|
70
70
|
async function send(args, { scopedContext, callerCwd, context, notifyContext }) {
|
|
71
71
|
try {
|
|
72
72
|
const prepared = await sendFlow.prepareSend(args, scopedContext);
|
|
73
|
+
await sendFlow.adoptCaller(prepared, notifyContext);
|
|
73
74
|
return sendFlow.dispatchToExistingSession(prepared, notifyContext);
|
|
74
75
|
} catch (err) {
|
|
75
76
|
return await respawnDeadTagSend(err, args, { callerCwd, context, notifyContext });
|
|
@@ -51,6 +51,7 @@ export function createSpawnDispatch({
|
|
|
51
51
|
}
|
|
52
52
|
if (liveSessionId && registry.getLiveSession(liveSessionId)) {
|
|
53
53
|
const prepared = await sendFlow.prepareSend({ ...args, tag: explicitTag }, scopedContext);
|
|
54
|
+
await sendFlow.adoptCaller(prepared, notifyContext);
|
|
54
55
|
const route = requestedRoute(args);
|
|
55
56
|
return {
|
|
56
57
|
reused: sendFlow.dispatchToExistingSession(route ? { ...prepared, route } : prepared, notifyContext, {
|