mixdog 1.3.4 → 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/LICENSES/oh-my-pi-MIT.txt +23 -0
- package/NOTICE.md +17 -2
- package/README.md +11 -0
- package/package.json +3 -11
- package/scripts/daemon-stub.mjs +1 -1
- package/scripts/embed-google-oauth-client.mjs +49 -0
- package/scripts/gate-local.mjs +4 -2
- package/scripts/lib/test-spawn-ledger.mjs +46 -1
- 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 +12 -11
- package/src/agents/reviewer/AGENT.md +7 -11
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +25 -1
- package/src/defaults/skills/browser-use/SKILL.md +77 -17
- 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 +29 -2
- package/src/defaults/skills/setup/references/actions.md +117 -28
- package/src/defaults/skills/setup/references/surfaces.md +77 -35
- package/src/defaults/skills/setup-guide/SKILL.md +3 -3
- package/src/defaults/skills/visualize/SKILL.md +2 -1
- package/src/lib/keychain-cjs.cjs +359 -29
- package/src/lib/rules-builder.cjs +10 -8
- package/src/rules/agent/AGENT.md +6 -6
- package/src/rules/agent-mode/AGENT_MODE.md +10 -2
- package/src/rules/agent-mode/MIXY.md +12 -0
- 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/heartbeat-completion.mjs +193 -0
- 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 +34 -0
- 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 +177 -73
- package/src/runtime/agent/orchestrator/mcp/client.mjs +25 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +31 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +16 -3
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +42 -7
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +21 -2
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +23 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +11 -1
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +230 -137
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +64 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +18 -5
- 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 +160 -69
- 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-oauth-catalog.mjs +52 -8
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +15 -4
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +17 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +142 -104
- package/src/runtime/agent/orchestrator/providers/cache-warm-admission.mjs +90 -0
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-normalization.mjs +10 -4
- package/src/runtime/agent/orchestrator/providers/cursor-wire-protobuf.mjs +10 -217
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +25 -9
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +22 -6
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +409 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-families.mjs +187 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-identity.mjs +342 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-models.mjs +541 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-protobuf.mjs +305 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-request.mjs +558 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-schema.mjs +880 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-session.mjs +190 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-tool-args.mjs +351 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +560 -0
- package/src/runtime/agent/orchestrator/providers/devin.mjs +491 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-output-limit.mjs +46 -0
- package/src/runtime/agent/orchestrator/providers/gemini-reasoning-relay.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +7 -11
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +61 -22
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +71 -4
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +96 -5
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +17 -3
- package/src/runtime/agent/orchestrator/providers/lib/tail-reminder-split.mjs +23 -5
- 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 +19 -1
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +39 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +6 -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/opencode-go-gemini.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/provider-availability.mjs +19 -0
- 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 +43 -3
- 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/providers/wire-protobuf-codec.mjs +368 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +12 -7
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- 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/orchestration.mjs +1 -1
- package/src/runtime/agent/orchestrator/runtime-core/reaction-tool-defs.mjs +133 -0
- 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-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +125 -30
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +23 -5
- package/src/runtime/agent/orchestrator/runtime-core/tool-profile.mjs +35 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +57 -10
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +9 -6
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +18 -0
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +0 -3
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +10 -4
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +792 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +148 -25
- 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 +8 -0
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +47 -9
- package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -4
- package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +14 -2
- package/src/runtime/agent/orchestrator/session/loop/assistant-commit.mjs +8 -0
- 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 +11 -2
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/segments.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +51 -3
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +10 -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 +14 -4
- 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 +23 -5
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +60 -0
- 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-commit.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +133 -90
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -1
- 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/session-tool-surface.mjs +13 -0
- 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/message-ids.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/message-reactions.mjs +89 -0
- package/src/runtime/agent/orchestrator/session/message-reactions.test-support.mjs +75 -0
- 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.d.mts +0 -2
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +47 -11
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +20 -2
- 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-header-cache.mjs +85 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +133 -18
- 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/tail-reminder-rules.mjs +11 -5
- 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/tool-batch/state.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +25 -2
- 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/schedule-errors.mjs +51 -0
- package/src/runtime/channels/lib/scheduler.mjs +135 -154
- package/src/runtime/channels/lib/schedules-db.mjs +83 -11
- package/src/runtime/channels/lib/status-snapshot.mjs +1 -1
- package/src/runtime/channels/lib/tool-dispatch.mjs +14 -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 +19 -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/office/com/com-adapter.mjs +17 -1
- package/src/runtime/office/com/office-com-host.ps1 +51 -1
- package/src/runtime/office/pdf/cfb-fixture.mjs +328 -0
- package/src/runtime/office/pdf/cfb-protection.mjs +311 -0
- package/src/runtime/office/pdf/document-preview.mjs +326 -8
- package/src/runtime/office/pdf/ooxml-crypto.mjs +469 -0
- package/src/runtime/office/pdf/ooxml-key-worker.mjs +14 -0
- package/src/runtime/office/portable/portable-soffice.mjs +45 -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/bot-hops.mjs +62 -2
- package/src/runtime/shared/bounded-download.mjs +8 -3
- package/src/runtime/shared/config.mjs +51 -35
- package/src/runtime/shared/connector-accounts.mjs +20 -10
- package/src/runtime/shared/connector-catalog.d.mts +33 -2
- package/src/runtime/shared/connector-catalog.mjs +166 -8
- 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/developer-options.mjs +32 -1
- 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/google-oauth-client.generated.json +4 -0
- package/src/runtime/shared/google-oauth-client.mjs +34 -9
- 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/anthropic-betas.mjs +7 -0
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +12 -0
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +1 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +1 -1
- package/src/runtime/shared/llm/well-formed.mjs +66 -0
- 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 +231 -59
- package/src/runtime/shared/provider-api-key.mjs +19 -8
- 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 +52 -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-execution-contract.mjs +2 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -14
- package/src/runtime/shared/transcript-metadata.mjs +38 -0
- package/src/runtime/shared/user-data-guard.mjs +30 -2
- package/src/runtime/shared/worktrees/activity-gate.mjs +12 -5
- 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 +486 -179
- package/src/session-runtime/agent-room-delivery.mjs +28 -1
- package/src/session-runtime/agent-task-sessions.mjs +561 -199
- package/src/session-runtime/boot/apis.mjs +9 -0
- package/src/session-runtime/boot/begin.mjs +3 -2
- 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 +8 -1
- package/src/session-runtime/bot-chain.mjs +32 -0
- package/src/session-runtime/bot-status.mjs +7 -4
- package/src/session-runtime/channel-config-api.mjs +63 -17
- 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/internal-tool-executor/reaction-tool.mjs +45 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +72 -5
- package/src/session-runtime/internal-tool-executor.mjs +4 -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 +61 -3
- package/src/session-runtime/mcp-oauth-login.mjs +5 -3
- package/src/session-runtime/mixy-heartbeat.mjs +927 -0
- package/src/session-runtime/model-route/route-tuning.mjs +10 -6
- 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 +35 -13
- package/src/session-runtime/prewarm/channel-start.mjs +3 -7
- package/src/session-runtime/provider-auth/login.mjs +7 -0
- package/src/session-runtime/provider-models/row-hydration.mjs +13 -2
- 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-home-turn.mjs +33 -6
- package/src/session-runtime/routine-owner.mjs +40 -9
- package/src/session-runtime/schedule-session-run.mjs +7 -3
- package/src/session-runtime/services/agent-tool/close-flow.mjs +3 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +8 -12
- 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 +73 -31
- package/src/session-runtime/services/channel-session-router.mjs +4 -2
- package/src/session-runtime/services/channel-worker.mjs +1 -1
- package/src/session-runtime/services/provider-admin.mjs +128 -25
- package/src/session-runtime/services/schedule-access.mjs +14 -0
- package/src/session-runtime/services/seeds.mjs +0 -28
- package/src/session-runtime/services/usage-dashboard-model.mjs +1 -0
- package/src/session-runtime/session-compaction-sync.mjs +27 -0
- package/src/session-runtime/session-create/session-options.mjs +8 -4
- 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 +28 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +65 -0
- package/src/session-runtime/setup-tool/executor.mjs +187 -29
- package/src/session-runtime/setup-tool/extended-actions.mjs +33 -2
- package/src/session-runtime/setup-tool/session-route-actions.mjs +152 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +68 -6
- package/src/session-runtime/setup-tool/tool-defs.mjs +92 -6
- package/src/session-runtime/task-session-route.mjs +99 -0
- package/src/session-runtime/tool-policy/agent-profile-fold.mjs +17 -13
- package/src/session-runtime/tool-policy/policy-stage.mjs +21 -4
- package/src/session-runtime/tool-policy/surface-helpers.mjs +2 -3
- package/src/session-runtime/tool-surface.mjs +4 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +98 -21
- package/src/session-runtime/workflow-agents-api/style-and-mode.mjs +4 -0
- package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +6 -1
- package/src/session-runtime/workspace/transitions.mjs +10 -2
- 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 +161 -157
- package/src/standalone/daemon.mjs +33 -2
- package/src/standalone/session-client.mjs +7 -3
- package/src/standalone/session-protocol.mjs +10 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +6 -2
- 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-turns.mjs +6 -0
- package/src/standalone/session-service/session-calls/session-views.mjs +8 -0
- package/src/standalone/session-service.mjs +13 -0
- package/src/standalone/session-tool-output.mjs +21 -10
- package/src/tui/app/model-options.mjs +4 -27
- package/src/tui/dist/index.mjs +81 -65
- 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 +23 -1
- package/src/tui/session/queue-helpers.mjs +3 -42
- package/src/tui/session/session-api/integrations.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +8 -0
- 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 +30 -2
- 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 +36 -3
- package/src/tui/session/turn.mjs +23 -2
- 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
|
@@ -20,9 +20,8 @@ import { resolveAgentSpawnPreset } from '../spawn-preset.mjs';
|
|
|
20
20
|
import { AGENT_OWNER } from '../../../../runtime/agent/orchestrator/agent-owner.mjs';
|
|
21
21
|
import { workspaceCwdLock } from '../../../workspace/admission-gate.mjs';
|
|
22
22
|
import { isContactAgentId } from '../../../../runtime/agent/orchestrator/runtime-core/workflow-ids.mjs';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import { mixyDisplayName } from '../../../../runtime/agent/orchestrator/session/mixy-name.mjs';
|
|
23
|
+
import { assertBotChainTarget } from '../../../../runtime/shared/bot-hops.mjs';
|
|
24
|
+
import { actingAgentOf, delegationChainOf } from '../../../bot-chain.mjs';
|
|
26
25
|
|
|
27
26
|
export function createSpawnPlanner({
|
|
28
27
|
mgr = null,
|
|
@@ -50,17 +49,14 @@ export function createSpawnPlanner({
|
|
|
50
49
|
if (isAgentDisabled(config, agent)) {
|
|
51
50
|
throw new Error(`agent spawn: agent "${agent}" is turned off`);
|
|
52
51
|
}
|
|
53
|
-
//
|
|
54
|
-
//
|
|
52
|
+
// Any agent-mode Lead (Mixy or a bot) may hand work to a contact agent,
|
|
53
|
+
// never to one already in its delegation chain (itself included): the
|
|
54
|
+
// session's ancestry and the bot chain its turn was handed (bot-chain.mjs).
|
|
55
55
|
if (isContactAgentId(agent, readAgentFrontmatterKind(agent, dataDir, STANDALONE_SOURCE_ROOT))) {
|
|
56
56
|
const callerId = clean(context?.callerSessionId || context?.sessionId);
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
throw new Error(
|
|
61
|
-
`agent spawn: only ${mixyDisplayName()} (the representative agent) can hand work to the contact agent "${agent}"; delegate to a sub-agent instead`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
57
|
+
const getSession = (id) => mgr?.getSession?.(id) || null;
|
|
58
|
+
const chain = delegationChainOf(callerId, getSession);
|
|
59
|
+
assertBotChainTarget(agent, { chain, self: actingAgentOf(getSession(callerId), callerId) }, 'agent spawn');
|
|
64
60
|
}
|
|
65
61
|
const agentPermission = readAgentFrontmatterPermission(agent, dataDir, STANDALONE_SOURCE_ROOT);
|
|
66
62
|
const agentPerm = normalizeAgentPermission(agentPermission) || null;
|
|
@@ -31,6 +31,9 @@ export function resolveAgentSpawnPreset(config, args = {}) {
|
|
|
31
31
|
const candidates = !clean(args.preset) ? configuredAgentRouteCandidates(config, agentName) : [];
|
|
32
32
|
const agentRoute = candidates.map((candidate) => normalizeAgentRoute(candidate)).find(Boolean) || null;
|
|
33
33
|
const storedFallbacks = candidates.find((candidate) => normalizeAgentRoute(candidate))?.fallbacks;
|
|
34
|
+
// Where the spawned session reads its fallback chain at each hop
|
|
35
|
+
// (route-fallback-chain.mjs): this agent's route, else Main's.
|
|
36
|
+
const fallbackSource = { agent: agentName };
|
|
34
37
|
if (agentRoute) {
|
|
35
38
|
return {
|
|
36
39
|
presetName: agentPresetName(agentName),
|
|
@@ -41,6 +44,7 @@ export function resolveAgentSpawnPreset(config, args = {}) {
|
|
|
41
44
|
provider: agentRoute.provider,
|
|
42
45
|
model: agentRoute.model,
|
|
43
46
|
...(storedFallbacks?.length ? { fallbacks: storedFallbacks.map(normalizeAgentRoute) } : {}),
|
|
47
|
+
fallbackSource,
|
|
44
48
|
effort: agentRoute.effort,
|
|
45
49
|
fast: agentRoute.fast === true,
|
|
46
50
|
...(agentRoute.autoEffort === false ? { autoEffort: false } : {}),
|
|
@@ -54,12 +58,13 @@ export function resolveAgentSpawnPreset(config, args = {}) {
|
|
|
54
58
|
|
|
55
59
|
const mainPreset = !clean(args.preset) ? findPreset(config, config?.default) : null;
|
|
56
60
|
if (normalizeAgentRoute(mainPreset)) {
|
|
57
|
-
return { presetName: mainPreset.id || mainPreset.name, preset: mainPreset };
|
|
61
|
+
return { presetName: mainPreset.id || mainPreset.name, preset: { ...mainPreset, fallbackSource } };
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
const presetName = clean(args.preset);
|
|
61
65
|
if (!presetName) throw new Error(`agent: agent "${agentName}" has no Main model assignment`);
|
|
62
|
-
const
|
|
66
|
+
const stored = findPreset(config, presetName);
|
|
67
|
+
const preset = stored ? { ...stored, fallbackSource: { preset: presetName } } : synthesizePreset(config, presetName);
|
|
63
68
|
if (!preset) throw new Error(`agent: preset "${presetName}" not found`);
|
|
64
69
|
if (!normalizeAgentRoute(preset)) throw new Error(`agent: preset "${presetName}" has no complete route`);
|
|
65
70
|
return { presetName, preset };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// worker-index/awaiting-user-sync.mjs
|
|
2
|
+
// A worker row's approval wait (`awaitingUser`), fenced to its session's turn
|
|
3
|
+
// and kept in step with the runtime this process runs for that session. Owns
|
|
4
|
+
// the sessions whose deferred rows still wait in the mutation batch.
|
|
5
|
+
import { clean } from '../helpers.mjs';
|
|
6
|
+
import { applyAwaitingUser, awaitingUserWouldChange } from './approval-wait.mjs';
|
|
7
|
+
|
|
8
|
+
export function createAwaitingUserSync(store, mgr) {
|
|
9
|
+
// Sessions whose deferred rows still wait in the batch; reconciled once the
|
|
10
|
+
// batch lands in the store.
|
|
11
|
+
const unreconciled = new Set();
|
|
12
|
+
|
|
13
|
+
/** Persist (or clear) a worker's approval wait as a field update fenced to
|
|
14
|
+
* the session and its turn (`turnAt`, ms): a row whose turn started later is
|
|
15
|
+
* left alone. Writes only when a row of that session exists and would
|
|
16
|
+
* change, so a Lead's own approvals cost nothing; a row that is not in the
|
|
17
|
+
* store yet takes the wait when it lands (reconcileAwaitingUser). */
|
|
18
|
+
function setAwaitingUser(sessionId, awaitingUser, { turnAt = 0 } = {}) {
|
|
19
|
+
const fence = {
|
|
20
|
+
sessionId: clean(sessionId),
|
|
21
|
+
awaitingUser: awaitingUser === 'approval' ? 'approval' : null,
|
|
22
|
+
turnAt: Number(turnAt) || 0,
|
|
23
|
+
};
|
|
24
|
+
if (!fence.sessionId || !awaitingUserWouldChange(store.readAll(), fence)) return false;
|
|
25
|
+
store.update((byKey) => applyAwaitingUser(byKey, fence));
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The runtime of a session this process runs is the authority on its
|
|
30
|
+
* approval wait (the runtime-liveness counter behind `awaitingUser`): every
|
|
31
|
+
* row it creates or refreshes takes that state, so a missed or stale
|
|
32
|
+
* transition heals on the next write. No runtime here: not ours to judge. */
|
|
33
|
+
function reconcileAwaitingUser(sessionId) {
|
|
34
|
+
const runtime = mgr.getSessionRuntime?.(sessionId);
|
|
35
|
+
if (runtime) setAwaitingUser(sessionId, runtime.awaitingUser, { turnAt: runtime.askStartedAt });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A deferred row of `sessionId` is queued; reconciled when its batch lands. */
|
|
39
|
+
function deferReconcile(sessionId) {
|
|
40
|
+
unreconciled.add(sessionId);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The batch landed: reconcile every session whose deferred row it carried. */
|
|
44
|
+
function reconcileDeferred() {
|
|
45
|
+
const ids = [...unreconciled];
|
|
46
|
+
unreconciled.clear();
|
|
47
|
+
for (const id of ids) reconcileAwaitingUser(id);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { setAwaitingUser, reconcileAwaitingUser, deferReconcile, reconcileDeferred };
|
|
51
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// worker-index/disposal.mjs
|
|
2
|
+
// Disposing a worker index: queued rows persist first, then `teardown`
|
|
3
|
+
// releases its registrations; a failed drain leaves them for a retry. Owns
|
|
4
|
+
// the disposed / in-flight dispose state.
|
|
5
|
+
export function createIndexDisposal({ batch, store, teardown }) {
|
|
6
|
+
let disposed = false;
|
|
7
|
+
let disposePromise = null;
|
|
8
|
+
|
|
9
|
+
async function drainThenTeardown() {
|
|
10
|
+
batch.flush();
|
|
11
|
+
await store.flush();
|
|
12
|
+
teardown();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Persist queued rows, then release the exit registration. Active rows are
|
|
16
|
+
* NOT settled: they are keyed by process pid, which every inline runtime in
|
|
17
|
+
* the daemon shares, so settling here would idle other runtimes' workers.
|
|
18
|
+
* When the sync flush cannot run (this process's async writer holds the
|
|
19
|
+
* lock) the exit hook and store ref stay until the async drain settles. */
|
|
20
|
+
function dispose() {
|
|
21
|
+
if (disposed) return;
|
|
22
|
+
disposed = true;
|
|
23
|
+
let flushed = false;
|
|
24
|
+
try {
|
|
25
|
+
batch.flush();
|
|
26
|
+
flushed = store.flushSync();
|
|
27
|
+
} catch {}
|
|
28
|
+
if (flushed) {
|
|
29
|
+
teardown();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
disposePromise = drainThenTeardown().catch(reopenAfterFailedDrain);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A failed drain tears nothing down; allow a later dispose to retry it. */
|
|
36
|
+
function reopenAfterFailedDrain() {
|
|
37
|
+
disposed = false;
|
|
38
|
+
disposePromise = null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Awaitable dispose: drain everything, then tear down. A failed drain
|
|
42
|
+
* rejects and leaves the registrations in place. */
|
|
43
|
+
function disposeAsync() {
|
|
44
|
+
if (!disposePromise) {
|
|
45
|
+
disposed = true;
|
|
46
|
+
disposePromise = drainThenTeardown().catch((error) => {
|
|
47
|
+
reopenAfterFailedDrain();
|
|
48
|
+
throw error;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return disposePromise;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { dispose, disposeAsync };
|
|
55
|
+
}
|
|
@@ -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
|
+
}
|