mixdog 1.3.5 → 1.4.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/NOTICE.md +2 -2
- package/README.md +2 -2
- package/package.json +2 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/gate-local.mjs +4 -2
- package/scripts/native-release-status.mjs +2 -2
- package/scripts/recall-history-cases.json +1 -1
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test.mjs +7 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +17 -1
- package/src/defaults/skills/browser-use/SKILL.md +59 -11
- package/src/defaults/skills/code-tidy/SKILL.md +142 -270
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +4 -4
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +31 -76
- package/src/defaults/skills/code-tidy/references/dead-code.md +6 -12
- package/src/defaults/skills/computer-use/SKILL.md +33 -9
- package/src/defaults/skills/setup/SKILL.md +22 -0
- package/src/defaults/skills/setup/references/actions.md +39 -5
- package/src/defaults/skills/setup/references/surfaces.md +11 -2
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/lead/LEAD.md +18 -20
- package/src/rules/shared/05-tool-calls.md +5 -6
- package/src/rules/shared/10-tool-workflow.md +2 -0
- package/src/rules/shared/60-verification.md +7 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +3 -1
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +3 -1
- package/src/runtime/agent/orchestrator/config.mjs +17 -1
- package/src/runtime/agent/orchestrator/context/collect.mjs +3 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +72 -67
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +54 -1
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +3 -3
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +176 -72
- package/src/runtime/agent/orchestrator/mcp/client.mjs +19 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +181 -133
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +42 -6
- package/src/runtime/agent/orchestrator/providers/anthropic-cache-warm.mjs +165 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/gzip-post.mjs +14 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +145 -66
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +25 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +64 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +135 -87
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +123 -102
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -13
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +52 -10
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +8 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/npm-cli-version.mjs +11 -3
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-send/send-context.mjs +22 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +43 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/handshake-failure.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/stream-failure.mjs +6 -3
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +65 -1
- package/src/runtime/agent/orchestrator/providers/quota-reading.mjs +38 -12
- package/src/runtime/agent/orchestrator/providers/registry.mjs +26 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +39 -7
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +6 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/compaction-config-keys.mjs +62 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +37 -16
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-delta.mjs +100 -23
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +19 -4
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +133 -22
- package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +475 -58
- package/src/runtime/agent/orchestrator/session/compaction-archive.mjs +42 -17
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +0 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +18 -22
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +32 -3
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/after-hook.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +16 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -10
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +19 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-state.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -18
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +23 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +129 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +20 -2
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +102 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +18 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/prompt-cache-idle-gaps.mjs +113 -0
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +36 -9
- package/src/runtime/agent/orchestrator/session/sensitive-projection.mjs +100 -0
- package/src/runtime/agent/orchestrator/session/sensitive-values.mjs +257 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +20 -7
- package/src/runtime/agent/orchestrator/session/side-question.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/skill-update-notice.mjs +60 -0
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/save-delta.mjs +9 -5
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +9 -8
- package/src/runtime/agent/orchestrator/session/store/session-persistence-events.mjs +29 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +8 -6
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +12 -2
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -14
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +84 -3
- package/src/runtime/agent/orchestrator/session/stored-attachment-history.mjs +32 -0
- package/src/runtime/agent/orchestrator/session/thinking-binding.mjs +108 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-status.mjs +9 -7
- package/src/runtime/agent/orchestrator/session/transcript-restore/tool-result-text.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/turn-failure.mjs +5 -1
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +5 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/misuse-guard.mjs +240 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/result-format.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/shell-cwd.mjs +38 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +25 -5
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +65 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +36 -13
- package/src/runtime/browser-bridge/action-schema.mjs +13 -2
- package/src/runtime/browser-bridge/client.mjs +73 -8
- package/src/runtime/browser-bridge/input-fields.mjs +8 -9
- package/src/runtime/browser-bridge/mail-links.mjs +107 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +1 -1
- package/src/runtime/channels/lib/config.mjs +6 -61
- package/src/runtime/channels/lib/crash-log.mjs +1 -1
- package/src/runtime/channels/lib/event-pipeline.mjs +4 -19
- package/src/runtime/channels/lib/event-queue.mjs +3 -18
- package/src/runtime/channels/lib/owned-runtime/automation-services.mjs +2 -2
- package/src/runtime/channels/lib/owned-runtime/automation-start.mjs +3 -4
- package/src/runtime/channels/lib/owned-runtime/config-reload.mjs +4 -59
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +33 -115
- package/src/runtime/channels/lib/owned-runtime/owned-stop.mjs +5 -22
- package/src/runtime/channels/lib/owned-runtime/state.mjs +2 -8
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -23
- package/src/runtime/channels/lib/parent-bridge.mjs +2 -2
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -43
- package/src/runtime/channels/lib/scheduler.mjs +33 -147
- package/src/runtime/channels/lib/schedules-db.mjs +34 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +1 -2
- package/src/runtime/channels/lib/webhooks-db.mjs +5 -9
- package/src/runtime/channels/lib/worker-bootstrap.mjs +0 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +0 -1
- package/src/runtime/channels/lib/worker-main.mjs +10 -34
- package/src/runtime/computer-bridge/action-schema.mjs +42 -1
- package/src/runtime/computer-bridge/actions.mjs +9 -1
- package/src/runtime/computer-bridge/client.mjs +180 -8
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +27 -2
- package/src/runtime/computer-bridge/linux-readiness.mjs +65 -23
- package/src/runtime/computer-bridge/pending-continuation.mjs +1 -1
- package/src/runtime/connectors/connector-accounts-mcp.mjs +230 -0
- package/src/runtime/connectors/gmail-app-password.mjs +172 -39
- package/src/runtime/connectors/google-mcp.mjs +10 -12
- package/src/runtime/memory/lib/pg/adapter.mjs +77 -70
- package/src/runtime/memory/lib/pg/supervisor.mjs +24 -12
- package/src/runtime/memory/lib/runtime-fetcher.mjs +23 -5
- package/src/runtime/session-search/session-search-db.mjs +73 -9
- package/src/runtime/session-search/session-search-ingest.mjs +110 -20
- package/src/runtime/shared/abort-race.mjs +89 -0
- package/src/runtime/shared/agent-avatar.d.mts +0 -1
- package/src/runtime/shared/agent-kind.mjs +4 -3
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +2 -13
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +29 -0
- package/src/runtime/shared/connector-catalog.mjs +150 -0
- package/src/runtime/shared/connector-triggers.mjs +22 -19
- package/src/runtime/shared/defaults-separation.mjs +2 -14
- package/src/runtime/shared/delegated-approval-host.mjs +103 -11
- package/src/runtime/shared/err-text.mjs +24 -15
- package/src/runtime/shared/file-permissions.d.mts +0 -8
- package/src/runtime/shared/file-permissions.mjs +0 -11
- package/src/runtime/shared/git-direct.test-support.mjs +19 -0
- package/src/runtime/shared/heartbeat-interval.d.mts +4 -0
- package/src/runtime/shared/heartbeat-interval.mjs +19 -0
- package/src/runtime/shared/idle-auto-clear-gate.mjs +104 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/mixy-presence.mjs +22 -0
- package/src/runtime/shared/orchestration.d.mts +2 -0
- package/src/runtime/shared/pg-schema-db.mjs +27 -16
- package/src/runtime/shared/profile-config.cjs +1 -1
- package/src/runtime/shared/prompt-origin.d.mts +4 -0
- package/src/runtime/shared/prompt-origin.mjs +21 -0
- package/src/runtime/shared/provider-accounts.mjs +7 -1
- package/src/runtime/shared/provider-display-name.mjs +29 -0
- package/src/runtime/shared/provider-timeout-phase.mjs +2 -0
- package/src/runtime/shared/routine-trigger.d.mts +2 -0
- package/src/runtime/shared/routine-trigger.mjs +10 -0
- package/src/runtime/shared/sensitive-path-rules.d.mts +2 -10
- package/src/runtime/shared/sensitive-path-rules.mjs +19 -41
- package/src/runtime/shared/session-activity-signal.mjs +34 -1
- package/src/runtime/shared/session-sidebar-host.d.mts +1 -1
- package/src/runtime/shared/session-sidebar-host.mjs +7 -3
- package/src/runtime/shared/session-turn-prelude.mjs +18 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/worktrees/test-support.mjs +9 -4
- package/src/runtime/terminal-bridge/client.mjs +10 -1
- package/src/runtime/visualize-bridge/client.mjs +27 -8
- package/src/runtime/visualize-bridge/tool-defs.mjs +22 -8
- package/src/runtime/visualize-bridge/tool-meta.d.mts +5 -0
- package/src/runtime/visualize-bridge/tool-meta.mjs +22 -0
- package/src/runtime/web-search/lib/fetch-pipeline.mjs +2 -2
- package/src/session-runtime/agent-home-delivery.mjs +448 -185
- package/src/session-runtime/agent-task-sessions.mjs +329 -180
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/infrastructure.mjs +4 -0
- package/src/session-runtime/boot/providers.mjs +3 -0
- package/src/session-runtime/boot/tools.mjs +6 -1
- package/src/session-runtime/config-lifecycle.mjs +6 -0
- package/src/session-runtime/connector-merge-migration.mjs +305 -0
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +132 -28
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +2 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +16 -3
- package/src/session-runtime/lifecycle/session-catalog.mjs +3 -1
- package/src/session-runtime/lifecycle/teardown/runtime-stops.mjs +50 -4
- package/src/session-runtime/lifecycle/teardown.mjs +23 -5
- package/src/session-runtime/mcp-glue/server-catalog.mjs +55 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +153 -33
- package/src/session-runtime/notification-bus.mjs +31 -117
- package/src/session-runtime/notification-completion-queue.mjs +54 -0
- package/src/session-runtime/notification-listeners.mjs +76 -0
- package/src/session-runtime/owned-automation-run.mjs +2 -1
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/resource-mcp-api.mjs +143 -224
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +163 -0
- package/src/session-runtime/resource-mcp-oauth-api.mjs +217 -0
- package/src/session-runtime/resource-mcp-secrets.mjs +82 -0
- package/src/session-runtime/resource-mcp-servers.mjs +78 -0
- package/src/session-runtime/resource-mcp-store.mjs +49 -0
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +7 -2
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +1 -0
- package/src/session-runtime/services/agent-tool/worker-index/awaiting-user-sync.mjs +51 -0
- package/src/session-runtime/services/agent-tool/worker-index/disposal.mjs +55 -0
- package/src/session-runtime/services/agent-tool/worker-index/released-store.mjs +123 -0
- package/src/session-runtime/services/agent-tool/worker-index/restart-settlement.mjs +112 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-reads.mjs +36 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +17 -4
- package/src/session-runtime/services/agent-tool/worker-index/row-writes.mjs +58 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +41 -241
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +7 -13
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +1 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +11 -0
- package/src/session-runtime/settings-compaction-api.mjs +2 -40
- package/src/session-runtime/settings-system-api.mjs +13 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +145 -22
- package/src/session-runtime/setup-tool/extended-actions.mjs +8 -3
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +4 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +64 -5
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +16 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/standalone/channel-transport/client-registry/client-records.mjs +65 -0
- package/src/standalone/channel-transport/client-registry/client-registration.mjs +118 -0
- package/src/standalone/channel-transport/client-registry.mjs +24 -163
- package/src/standalone/channel-transport.mjs +1 -1
- package/src/standalone/daemon-channels-loader.mjs +10 -8
- package/src/standalone/daemon-session-control/list-page.mjs +72 -0
- package/src/standalone/daemon-session-control/request.mjs +51 -0
- package/src/standalone/daemon-session-control/room-host.mjs +57 -0
- package/src/standalone/daemon-session-control/route-control.mjs +48 -0
- package/src/standalone/daemon-session-control/send-turn.mjs +60 -0
- package/src/standalone/daemon-session-control/worktree-control.mjs +40 -0
- package/src/standalone/daemon-session-control.mjs +124 -188
- package/src/standalone/daemon.mjs +26 -3
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/agent-tree/agent-child.mjs +1 -0
- package/src/standalone/session-service/quota-resume.mjs +3 -0
- package/src/standalone/session-service/retention/busy.mjs +65 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +23 -2
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-tool-output.mjs +15 -7
- package/src/tui/app/model-options.mjs +3 -28
- package/src/tui/dist/index.mjs +58 -64
- package/src/tui/session/agent-job-feed/model-notification.mjs +3 -0
- package/src/tui/session/initial-state.mjs +3 -0
- package/src/tui/session/notice-surface.mjs +7 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/routes-agent-definitions.mjs +14 -2
- package/src/tui/session/session-api/routes-write.mjs +5 -1
- package/src/tui/session/session-api/routes.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +17 -1
- package/src/tui/session/session-flow/auto-clear.mjs +4 -33
- package/src/tui/session/session-flow/drain-closed-queue.mjs +38 -0
- package/src/tui/session/session-flow/drain-enqueue.mjs +86 -0
- package/src/tui/session/session-flow/drain-retry.mjs +35 -0
- package/src/tui/session/session-flow/drain.mjs +118 -149
- package/src/tui/session/session-flow/queue/entry-shape.mjs +5 -0
- package/src/tui/session/session-flow/queue/take-entries.mjs +5 -2
- package/src/tui/session/tool-approval-delegation.mjs +64 -0
- package/src/tui/session/tool-approval-request.mjs +39 -0
- package/src/tui/session/tool-approval-settle.mjs +62 -0
- package/src/tui/session/tool-approval.mjs +69 -115
- package/src/tui/session/tui-steering-persist.mjs +8 -1
- package/src/tui/session/turn-stream.mjs +19 -2
- package/src/tui/session/turn.mjs +1 -0
- package/src/vendor/statusline/bin/statusline-route.mjs +1 -219
- package/src/vendor/statusline/src/gateway/route-meta.mjs +35 -13
- package/scripts/code-graph-description-contract.mjs +0 -188
- package/src/runtime/channels/lib/owned-runtime/ownership-refresh.mjs +0 -36
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// worker-index/released-store.mjs
|
|
2
|
+
// Which agent sessions their owner closed (the agent tool's `close`): session
|
|
3
|
+
// id → when. A closed session stays open and resumable, so a session scan
|
|
4
|
+
// (also after a daemon restart) would list it again; the marker is what keeps
|
|
5
|
+
// its rows `released` until a new turn starts on it. It lives in a file of its
|
|
6
|
+
// own beside the worker index, so a writer that rebuilds the index document
|
|
7
|
+
// (an older daemon) can never drop it. Entries expire after the tombstone TTL,
|
|
8
|
+
// judged on every read, not only when the file changes.
|
|
9
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
10
|
+
|
|
11
|
+
import { parseJsonText } from '../../../../runtime/shared/atomic-file.mjs';
|
|
12
|
+
import { createIndexWriteQueue } from '../index-write-queue.mjs';
|
|
13
|
+
import { TAG_TOMBSTONE_TTL_MS } from '../worker-rows.mjs';
|
|
14
|
+
|
|
15
|
+
export const RELEASED_FILE = 'agent-workers-released.json';
|
|
16
|
+
|
|
17
|
+
/** id → epoch ms of every entry of a raw document (expired ones included). */
|
|
18
|
+
function parseReleased(doc) {
|
|
19
|
+
const raw = doc?.released && typeof doc.released === 'object' ? doc.released : {};
|
|
20
|
+
return new Map(
|
|
21
|
+
Object.entries(raw)
|
|
22
|
+
.map(([sessionId, at]) => [sessionId, Date.parse(String(at)) || 0])
|
|
23
|
+
.filter(([sessionId]) => sessionId)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The next document: unexpired entries plus the mutator's changes. */
|
|
28
|
+
function rewriteReleased(cur, mutator) {
|
|
29
|
+
const cutoff = Date.now() - TAG_TOMBSTONE_TTL_MS;
|
|
30
|
+
const entries = new Map();
|
|
31
|
+
for (const [sessionId, at] of parseReleased(cur)) {
|
|
32
|
+
if (at >= cutoff) entries.set(sessionId, new Date(at).toISOString());
|
|
33
|
+
}
|
|
34
|
+
mutator(entries);
|
|
35
|
+
return { version: 1, released: Object.fromEntries(entries) };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** `file` may be null (no data dir): reads are empty and writes are no-ops. */
|
|
39
|
+
export function createReleasedStore(file) {
|
|
40
|
+
let cache = null; // { mtimeMs, size, doc, at }
|
|
41
|
+
let dirty = true;
|
|
42
|
+
// Unpersisted writes are read from the queue's projection.
|
|
43
|
+
let projected = null; // { version, at }
|
|
44
|
+
|
|
45
|
+
const queue = createIndexWriteQueue({
|
|
46
|
+
file,
|
|
47
|
+
rewrite: rewriteReleased,
|
|
48
|
+
readDoc: () => {
|
|
49
|
+
dirty = true;
|
|
50
|
+
entries();
|
|
51
|
+
return cache?.doc ?? null;
|
|
52
|
+
},
|
|
53
|
+
onPersisted: () => {
|
|
54
|
+
dirty = true;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/** id → epoch ms, as written (not yet filtered by expiry). */
|
|
59
|
+
function entries() {
|
|
60
|
+
const doc = queue.projection();
|
|
61
|
+
if (doc) {
|
|
62
|
+
if (!projected || projected.version !== queue.version()) {
|
|
63
|
+
projected = { version: queue.version(), at: parseReleased(doc) };
|
|
64
|
+
}
|
|
65
|
+
return projected.at;
|
|
66
|
+
}
|
|
67
|
+
if (!file) return new Map();
|
|
68
|
+
// Only a missing file is an empty store; any other read error propagates
|
|
69
|
+
// (queue.write reports it and queues nothing; a reader sees it thrown).
|
|
70
|
+
let st;
|
|
71
|
+
try {
|
|
72
|
+
st = statSync(file);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
75
|
+
cache = null;
|
|
76
|
+
return new Map();
|
|
77
|
+
}
|
|
78
|
+
if (!dirty && cache && cache.mtimeMs === st.mtimeMs && cache.size === st.size) return cache.at;
|
|
79
|
+
let parsed = null;
|
|
80
|
+
let text = null;
|
|
81
|
+
try {
|
|
82
|
+
text = readFileSync(file, 'utf8');
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
85
|
+
}
|
|
86
|
+
if (text !== null) {
|
|
87
|
+
try {
|
|
88
|
+
parsed = parseJsonText(text);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
// Left on disk and reported; the next save moves it aside to
|
|
91
|
+
// `<file>.corrupt-<ts>` (atomic-file's damaged-state recovery) instead
|
|
92
|
+
// of overwriting it.
|
|
93
|
+
process.stderr.write(`[released-store] ${file} is malformed (${error.message}); markers unreadable\n`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
cache = { mtimeMs: st.mtimeMs, size: st.size, doc: parsed, at: parseReleased(parsed) };
|
|
97
|
+
dirty = false;
|
|
98
|
+
return cache.at;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
/** Whether the owner closed this session less than the TTL ago. */
|
|
103
|
+
isReleased: (sessionId) => entries().get(sessionId) >= Date.now() - TAG_TOMBSTONE_TTL_MS,
|
|
104
|
+
mark(sessionIds) {
|
|
105
|
+
const at = new Date().toISOString();
|
|
106
|
+
queue.write((entriesById) => {
|
|
107
|
+
for (const sessionId of sessionIds) entriesById.set(sessionId, at);
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
clear(sessionId) {
|
|
111
|
+
if (!entries().has(sessionId)) return;
|
|
112
|
+
queue.write((entriesById) => {
|
|
113
|
+
entriesById.delete(sessionId);
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
flush: queue.flush,
|
|
117
|
+
flushSync: queue.flushSync,
|
|
118
|
+
hasUnpersisted: queue.hasUnpersisted,
|
|
119
|
+
invalidate: () => {
|
|
120
|
+
dirty = true;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// worker-index/restart-settlement.mjs
|
|
2
|
+
// Rows whose turn a process exit or restart ended: this process's active rows
|
|
3
|
+
// settled as failed on exit, stale active rows and approval waits settled at
|
|
4
|
+
// startup and on later sweeps, and the owner's restart-failure notification
|
|
5
|
+
// stamped once queued. Owns the keys of the rows this process marked active.
|
|
6
|
+
import { positiveInt } from '../helpers.mjs';
|
|
7
|
+
import { workerRowKey } from '../worker-rows.mjs';
|
|
8
|
+
import { clearAwaitingUser } from './approval-wait.mjs';
|
|
9
|
+
import {
|
|
10
|
+
createRowLiveness,
|
|
11
|
+
isActiveWorkerRow,
|
|
12
|
+
isStaleApprovalWait,
|
|
13
|
+
isUnnotifiedRestartFailure,
|
|
14
|
+
PROCESS_RESTART_FAILURE,
|
|
15
|
+
runtimeDied,
|
|
16
|
+
} from './row-liveness.mjs';
|
|
17
|
+
|
|
18
|
+
export function createRestartSettlement({ store, cfgMod, mgr }) {
|
|
19
|
+
const liveness = createRowLiveness({
|
|
20
|
+
cfgMod,
|
|
21
|
+
isSessionRunning: (sessionId) => mgr.isSessionTurnInFlight?.(sessionId) === true,
|
|
22
|
+
});
|
|
23
|
+
// Rows this process marked active; settled as failed on exit (their turn
|
|
24
|
+
// dies with the process) so a crash of the host never leaves them
|
|
25
|
+
// "running" forever.
|
|
26
|
+
const activeWorkerKeys = new Set();
|
|
27
|
+
|
|
28
|
+
/** Track whether the row written under `key` is one this process runs. */
|
|
29
|
+
function trackActiveRow(key, row) {
|
|
30
|
+
if (isActiveWorkerRow(row)) activeWorkerKeys.add(key);
|
|
31
|
+
else activeWorkerKeys.delete(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function flushActiveWorkerRows() {
|
|
35
|
+
if (!activeWorkerKeys.size) return;
|
|
36
|
+
const keys = [...activeWorkerKeys];
|
|
37
|
+
activeWorkerKeys.clear();
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
store.write((byKey) => {
|
|
40
|
+
for (const key of keys) {
|
|
41
|
+
const current = byKey.get(key);
|
|
42
|
+
if (!current || positiveInt(current.runtimePid) !== process.pid) continue;
|
|
43
|
+
if (isActiveWorkerRow(current)) {
|
|
44
|
+
byKey.set(key, liveness.failedRow(current, now, PROCESS_RESTART_FAILURE, true));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Startup recovery: stale active rows settle — as failed when another
|
|
51
|
+
// process ran their turn (it is gone, or is the predecessor still shutting
|
|
52
|
+
// down: either way the turn never finished), otherwise to idle — and an
|
|
53
|
+
// approval wait left behind by a runtime that is gone (daemon restart) is
|
|
54
|
+
// cleared. `deadOnly` (later sweeps) settles only rows whose runtime is
|
|
55
|
+
// provably dead, never a live process's quiet turn.
|
|
56
|
+
function recoverStaleWorkerRows({ deadOnly = false } = {}) {
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
const rows = store.readAll();
|
|
59
|
+
const isStale = deadOnly
|
|
60
|
+
? (row) => isActiveWorkerRow(row) && runtimeDied(row)
|
|
61
|
+
: (row) => liveness.isStaleActive(row, now);
|
|
62
|
+
const staleActive = rows.filter(isStale);
|
|
63
|
+
const staleWaits = rows.some(isStaleApprovalWait);
|
|
64
|
+
if (!staleActive.length && !staleWaits) return false;
|
|
65
|
+
if (staleActive.length) {
|
|
66
|
+
store.write((byKey) => {
|
|
67
|
+
for (const row of staleActive) {
|
|
68
|
+
const key = workerRowKey(row);
|
|
69
|
+
const current = byKey.get(key);
|
|
70
|
+
if (!current || !isStale(current)) continue;
|
|
71
|
+
const ranElsewhere = positiveInt(current.runtimePid) && positiveInt(current.runtimePid) !== process.pid;
|
|
72
|
+
byKey.set(
|
|
73
|
+
key,
|
|
74
|
+
ranElsewhere ? liveness.failedRow(current, now, PROCESS_RESTART_FAILURE) : liveness.idleRow(current, now)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (staleWaits) store.update((byKey) => clearAwaitingUser(byKey, isStaleApprovalWait));
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Rows whose turn a process restart ended and whose owner has not been told
|
|
84
|
+
* yet — whoever settled the row (this process at startup, or the
|
|
85
|
+
* predecessor's exit flush). Read-only: the caller enqueues the owner's
|
|
86
|
+
* notification durably, THEN calls `markRestartNotified`, so a crash in
|
|
87
|
+
* between retries (the notification's stable id makes the retry exactly-once). */
|
|
88
|
+
function pendingRestartFailures() {
|
|
89
|
+
return store.readAll().filter(isUnnotifiedRestartFailure);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Stamp these rows as told, once their notification is durably queued. */
|
|
93
|
+
function markRestartNotified(rows) {
|
|
94
|
+
const stamp = new Date().toISOString();
|
|
95
|
+
store.write((byKey) => {
|
|
96
|
+
for (const row of rows) {
|
|
97
|
+
const key = workerRowKey(row);
|
|
98
|
+
const current = byKey.get(key);
|
|
99
|
+
if (!current || !isUnnotifiedRestartFailure(current)) continue;
|
|
100
|
+
byKey.set(key, { ...current, restartNotified: stamp });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
trackActiveRow,
|
|
107
|
+
flushActiveWorkerRows,
|
|
108
|
+
recoverStaleWorkerRows,
|
|
109
|
+
pendingRestartFailures,
|
|
110
|
+
markRestartNotified,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// worker-index/row-reads.mjs
|
|
2
|
+
// Scoped reads of the worker rows and tag tombstones: a row a tombstone still
|
|
3
|
+
// blocks never reads as work, and a legacy tombstone without an owner takes
|
|
4
|
+
// the one its session resolves to.
|
|
5
|
+
import { clean, rowMatchesContext } from '../helpers.mjs';
|
|
6
|
+
import { recoverTagTombstoneOwner } from '../worker-rows.mjs';
|
|
7
|
+
import {
|
|
8
|
+
findTagTombstone,
|
|
9
|
+
tagTombstoneKey,
|
|
10
|
+
tombstoneBlocksWork,
|
|
11
|
+
} from '../../../../runtime/shared/agent-reap-state.mjs';
|
|
12
|
+
|
|
13
|
+
export function createWorkerRowReads(store, mgr) {
|
|
14
|
+
function readWorkerRows(context = {}) {
|
|
15
|
+
const { rows, tombstones: savedTombstones } = store.readSnapshot();
|
|
16
|
+
if (rows.length === 0) return rows;
|
|
17
|
+
const tombstones = new Map(recoverTombstoneOwners(savedTombstones).map((row) => [tagTombstoneKey(row), row]));
|
|
18
|
+
return rows.filter(
|
|
19
|
+
(row) => rowMatchesContext(row, context) && !tombstoneBlocksWork(row, findTagTombstone(row, tombstones))
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readAllTagTombstones() {
|
|
24
|
+
return recoverTombstoneOwners(store.readTombstones());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function recoverTombstoneOwners(rows) {
|
|
28
|
+
if (!rows.some((row) => !clean(row.parentSessionId || row.ownerSessionId))) return rows;
|
|
29
|
+
const sessions = typeof mgr.listSessions === 'function' ? mgr.listSessions({ includeClosed: true }) : [];
|
|
30
|
+
// Resolve legacy ownership against all sessions, never just the caller's
|
|
31
|
+
// scope: filtering first would conceal an ambiguous sibling owner.
|
|
32
|
+
return rows.map((row) => recoverTagTombstoneOwner(row, sessions));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { readWorkerRows, readAllTagTombstones };
|
|
36
|
+
}
|
|
@@ -65,6 +65,8 @@ export function normalizeWorkerRows(value) {
|
|
|
65
65
|
// Additive and transient: present only while the worker's turn waits on
|
|
66
66
|
// a user approval (worker-index setAwaitingUser).
|
|
67
67
|
...(row.awaitingUser === 'approval' ? { awaitingUser: 'approval' } : {}),
|
|
68
|
+
// Present only on an agent its owner closed (the agent tool's `close`).
|
|
69
|
+
...(row.released === true ? { released: true } : {}),
|
|
68
70
|
}))
|
|
69
71
|
.filter((row) => !isLeadPoolAgent(row.agent) && keepWorkerRow(row));
|
|
70
72
|
}
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
// worker index of a process over one file shares one store (acquireWorkerRowStore),
|
|
5
5
|
// so all of them serialize through the same projection and queue.
|
|
6
6
|
import { readFileSync, statSync } from 'node:fs';
|
|
7
|
-
import { resolve } from 'node:path';
|
|
7
|
+
import { dirname, join, resolve } from 'node:path';
|
|
8
8
|
|
|
9
9
|
import { createIndexWriteQueue } from '../index-write-queue.mjs';
|
|
10
10
|
import { normalizeTagTombstones, tagTombstoneKey, workerRowKey } from '../worker-rows.mjs';
|
|
11
|
+
import { RELEASED_FILE, createReleasedStore } from './released-store.mjs';
|
|
11
12
|
import { settleAwaitingUser } from './approval-wait.mjs';
|
|
12
13
|
import { keepWorkerRow, normalizeWorkerRows } from './row-shape.mjs';
|
|
13
14
|
|
|
@@ -62,6 +63,9 @@ function rewriteIndexDocument(cur, mutator) {
|
|
|
62
63
|
|
|
63
64
|
/** `file` may be null (no data dir): reads are empty and writes are no-ops. */
|
|
64
65
|
export function createWorkerRowStore(file) {
|
|
66
|
+
// The release markers live in their own file beside the index, so a writer
|
|
67
|
+
// that rebuilds the index document never drops them.
|
|
68
|
+
const released = createReleasedStore(file ? join(dirname(file), RELEASED_FILE) : null);
|
|
65
69
|
// Mtime-keyed parse cache. A single spawn calls refreshTagsFromSessions /
|
|
66
70
|
// resolveTag / nextTag, which each re-read and re-parse this file; across a
|
|
67
71
|
// parallel fanout that is O(spawns^2) synchronous reads of the same bytes.
|
|
@@ -148,18 +152,27 @@ export function createWorkerRowStore(file) {
|
|
|
148
152
|
readAll,
|
|
149
153
|
readSnapshot,
|
|
150
154
|
readTombstones,
|
|
155
|
+
isReleased: released.isReleased,
|
|
156
|
+
markReleased: released.mark,
|
|
157
|
+
clearReleased: released.clear,
|
|
151
158
|
write,
|
|
152
159
|
/** Conditional field update: `mutator` runs now on the projection and again
|
|
153
160
|
* on the locked document when persisted, so its condition is re-checked
|
|
154
161
|
* against what is on disk. The one writer of `awaitingUser`. */
|
|
155
162
|
update: (mutator) => queue.write(mutator, { rerun: true }),
|
|
156
163
|
/** Resolves once every write so far is on disk. */
|
|
157
|
-
flush:
|
|
164
|
+
flush: async () => {
|
|
165
|
+
await Promise.all([queue.flush(), released.flush()]);
|
|
166
|
+
},
|
|
158
167
|
/** Exit path: persist what is still queued, synchronously. */
|
|
159
|
-
flushSync:
|
|
160
|
-
|
|
168
|
+
flushSync: () => {
|
|
169
|
+
const flushed = [queue.flushSync(), released.flushSync()];
|
|
170
|
+
return flushed.every(Boolean);
|
|
171
|
+
},
|
|
172
|
+
hasUnpersisted: () => queue.hasUnpersisted() || released.hasUnpersisted(),
|
|
161
173
|
invalidate: () => {
|
|
162
174
|
dirty = true;
|
|
175
|
+
released.invalidate();
|
|
163
176
|
},
|
|
164
177
|
};
|
|
165
178
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// worker-index/row-writes.mjs
|
|
2
|
+
// Row upserts (immediate or batched), removal, and the owner's release mark:
|
|
3
|
+
// every upsert projects the row into the tag maps (`bindTag`), tracks whether
|
|
4
|
+
// this process runs it, and brings its approval wait in step.
|
|
5
|
+
import { clean } from '../helpers.mjs';
|
|
6
|
+
import { applyWorkerRowUpsert, workerRowKey } from '../worker-rows.mjs';
|
|
7
|
+
import { isUnnotifiedRestartFailure } from './row-liveness.mjs';
|
|
8
|
+
import { normalizeWorkerRows, workerRowFromSession } from './row-shape.mjs';
|
|
9
|
+
|
|
10
|
+
export function createWorkerRowWrites({ file, store, batch, mgr, bindTag, settlement, awaitingUser }) {
|
|
11
|
+
function upsertWorkerRow(row, { defer = false } = {}) {
|
|
12
|
+
const normalized = normalizeWorkerRows({ workers: [row] })[0];
|
|
13
|
+
if (!normalized) return false;
|
|
14
|
+
const key = workerRowKey(normalized);
|
|
15
|
+
settlement.trackActiveRow(key, normalized);
|
|
16
|
+
bindTag(normalized);
|
|
17
|
+
if (defer) {
|
|
18
|
+
if (!file) return false;
|
|
19
|
+
awaitingUser.deferReconcile(normalized.sessionId);
|
|
20
|
+
return batch.queue((byKey) => applyWorkerRowUpsert(byKey, normalized));
|
|
21
|
+
}
|
|
22
|
+
store.write((byKey) => {
|
|
23
|
+
applyWorkerRowUpsert(byKey, normalized);
|
|
24
|
+
});
|
|
25
|
+
awaitingUser.reconcileAwaitingUser(normalized.sessionId);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// A session its owner closed keeps `released` on every row written for it,
|
|
30
|
+
// until a turn starts on it.
|
|
31
|
+
const rowFromSession = (session, fallbackTag = '', extra = {}) => {
|
|
32
|
+
const row = workerRowFromSession(session, fallbackTag, extra, (sessionId) => mgr.getSessionRuntime?.(sessionId));
|
|
33
|
+
return row && store.isReleased(row.sessionId) ? { ...row, released: true } : row;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/** Persist that the owner closed these sessions (survives a restart). */
|
|
37
|
+
function markReleased(sessionIds) {
|
|
38
|
+
store.markReleased(sessionIds.map(clean).filter(Boolean));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// A row whose owner is still owed its restart failure stays: closing the
|
|
42
|
+
// worker (a process exit closes every one) must not lose that result.
|
|
43
|
+
function removeWorkerRow({ tag = '', sessionId = '' } = {}) {
|
|
44
|
+
const targetTag = clean(tag);
|
|
45
|
+
const targetSessionId = clean(sessionId);
|
|
46
|
+
batch.flush();
|
|
47
|
+
store.write((byKey) => {
|
|
48
|
+
for (const [key, row] of [...byKey.entries()]) {
|
|
49
|
+
if (isUnnotifiedRestartFailure(row)) continue;
|
|
50
|
+
if ((targetSessionId && row.sessionId === targetSessionId) || (targetTag && row.tag === targetTag)) {
|
|
51
|
+
byKey.delete(key);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { upsertWorkerRow, rowFromSession, markReleased, removeWorkerRow };
|
|
58
|
+
}
|