mixdog 1.2.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/package.json +2 -1
- package/scripts/gate-local.mjs +19 -3
- package/scripts/model-catalog-audit.mjs +1 -15
- package/scripts/provider-pingpong-live.mjs +509 -0
- package/src/agents/advisor/AGENT.md +1 -1
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +3 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +6 -1
- package/src/defaults/skills/setup/references/actions.md +44 -22
- package/src/defaults/skills/setup/references/surfaces.md +10 -8
- package/src/headless-exec.mjs +15 -8
- package/src/lib/keychain-cjs.cjs +7 -4
- package/src/output-styles/common.md +11 -10
- package/src/repl/slash-commands.mjs +16 -1
- package/src/rules/agent/AGENT.md +5 -5
- package/src/rules/lead/LEAD.md +5 -5
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -4
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +10 -0
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +92 -61
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +10 -1
- package/src/runtime/agent/orchestrator/config-providers-merge.mjs +7 -0
- package/src/runtime/agent/orchestrator/config.mjs +5 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +26 -7
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +112 -7
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +36 -7
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +49 -10
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +40 -3
- package/src/runtime/agent/orchestrator/mcp/client.mjs +230 -96
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +103 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +150 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +111 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-probe.mjs +87 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +95 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-request.mjs +122 -0
- package/src/runtime/agent/orchestrator/mcp/oauth-shared.mjs +9 -0
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +229 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +188 -29
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +48 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +94 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-error-contract.mjs +98 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.mjs +39 -18
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +55 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +48 -37
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +10 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-midstream-recovery.mjs +18 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +13 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-midstream.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-recovery.mjs +23 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +46 -20
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request.mjs +14 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +102 -45
- package/src/runtime/agent/orchestrator/providers/anthropic-overload-fallback.mjs +69 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-blocks.mjs +20 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-delta.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/message-events.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +12 -5
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-outcome.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-state.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +10 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +40 -7
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-request.mjs +88 -21
- package/src/runtime/agent/orchestrator/providers/antigravity-response.mjs +30 -10
- package/src/runtime/agent/orchestrator/providers/antigravity-retry-policy.mjs +106 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-stream.mjs +10 -61
- package/src/runtime/agent/orchestrator/providers/antigravity-transport.mjs +94 -15
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +117 -72
- package/src/runtime/agent/orchestrator/providers/compat-request-policy.mjs +78 -2
- package/src/runtime/agent/orchestrator/providers/cursor-auth.mjs +75 -10
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor-wire-guards.mjs +97 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-bridge.mjs +103 -23
- package/src/runtime/agent/orchestrator/providers/cursor-wire-stream-messages.mjs +43 -2
- package/src/runtime/agent/orchestrator/providers/cursor-wire-transport.mjs +103 -33
- package/src/runtime/agent/orchestrator/providers/cursor-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +27 -3
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +64 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +70 -6
- package/src/runtime/agent/orchestrator/providers/custom-reasoning.mjs +34 -7
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +32 -6
- package/src/runtime/agent/orchestrator/providers/deepseek.mjs +67 -0
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +80 -18
- package/src/runtime/agent/orchestrator/providers/gemini-cache-policy.mjs +11 -4
- package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +46 -8
- package/src/runtime/agent/orchestrator/providers/gemini-error-contract.mjs +273 -0
- package/src/runtime/agent/orchestrator/providers/gemini-family.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/gemini-history-signatures.mjs +9 -4
- package/src/runtime/agent/orchestrator/providers/gemini-request-body.mjs +41 -5
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-retry-policy.mjs +180 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +369 -112
- package/src/runtime/agent/orchestrator/providers/gemini-sdk-request.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +140 -35
- package/src/runtime/agent/orchestrator/providers/gemini-thinking.mjs +70 -24
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +80 -29
- package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +69 -19
- package/src/runtime/agent/orchestrator/providers/lib/action-input-contract.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +246 -42
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-server-tool-usage.mjs +18 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-system-blocks.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/lib/claude-bridge-schema.mjs +388 -0
- package/src/runtime/agent/orchestrator/providers/lib/inclusive-usage.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/lib/origin-bound-fetch.mjs +16 -0
- package/src/runtime/agent/orchestrator/providers/lib/responses-terminal-fields.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/lib/wire-pairing.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +119 -18
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-profile.mjs +13 -15
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +1 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-provider.mjs +33 -1
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +4 -9
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +123 -61
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +35 -14
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-result.mjs +27 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +37 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/tool-call-acc.mjs +2 -9
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-error-contract.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +47 -25
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-reasoning-field.mjs +151 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-response-normalization.mjs +64 -23
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +79 -33
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-head-parity.json +2901 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-parity.fixtures.mjs +172 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-state.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +144 -15
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +193 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +66 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +109 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +27 -6
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +34 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +23 -4
- package/src/runtime/agent/orchestrator/providers/openai-direct-request.mjs +37 -28
- package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +274 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-request.mjs +72 -32
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +23 -10
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/terminal-frames.mjs +43 -15
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +10 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-items.mjs +18 -7
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-outcome.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-stamps.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-state.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/text-relay.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +1 -3
- package/src/runtime/agent/orchestrator/providers/openai-model-capabilities.mjs +80 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-dispatch.mjs +37 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +22 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +76 -33
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload-parity.fixture.json +323 -0
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +44 -16
- package/src/runtime/agent/orchestrator/providers/openai-retry-policy.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +7 -16
- package/src/runtime/agent/orchestrator/providers/openai-ws-handshake.mjs +16 -8
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/refusals.mjs +60 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state/tool-calls.mjs +51 -35
- package/src/runtime/agent/orchestrator/providers/openai-ws-response-state.mjs +30 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/attempt-context.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-send-attempts/policy.mjs +25 -14
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/terminal-frames.mjs +25 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-terminal.mjs +18 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +41 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-gemini.mjs +170 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +75 -70
- package/src/runtime/agent/orchestrator/providers/openrouter.mjs +75 -0
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +720 -0
- package/src/runtime/agent/orchestrator/providers/registry.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/retry-backoff.mjs +46 -7
- package/src/runtime/agent/orchestrator/providers/retry-classification.mjs +123 -219
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +148 -45
- package/src/runtime/agent/orchestrator/providers/retry-midstream.mjs +81 -16
- package/src/runtime/agent/orchestrator/providers/transport-scope.d.mts +6 -0
- package/src/runtime/agent/orchestrator/providers/transport-scope.mjs +28 -0
- package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +157 -0
- package/src/runtime/agent/orchestrator/providers/wire-route.mjs +512 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search-head-parity.json +1131 -0
- package/src/runtime/agent/orchestrator/providers/xai-tool-search.fixtures.mjs +183 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +100 -0
- package/src/runtime/agent/orchestrator/runtime-core/config-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/deferred-tool-availability.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +15 -0
- package/src/runtime/agent/orchestrator/runtime-core/goal-reminder.mjs +0 -18
- package/src/runtime/agent/orchestrator/runtime-core/model-capabilities.mjs +57 -28
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +19 -16
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -97
- package/src/runtime/agent/orchestrator/runtime-core/provider-request-snapshot.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/session-title.mjs +21 -1
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +14 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +526 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +10 -7
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +176 -71
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +62 -10
- package/src/runtime/agent/orchestrator/runtime-core/tool-exposure.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/compact/constants.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +14 -93
- package/src/runtime/agent/orchestrator/session/compact/summary-anchor.mjs +5 -0
- package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +120 -0
- package/src/runtime/agent/orchestrator/session/context-tool-schema.mjs +17 -2
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +8 -4
- package/src/runtime/agent/orchestrator/session/eager-dispatch/admission.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +6 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +91 -1
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +56 -0
- package/src/runtime/agent/orchestrator/session/loop/deferred-call-through.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +21 -10
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +132 -0
- package/src/runtime/agent/orchestrator/session/loop/request-boundary.mjs +30 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +67 -20
- package/src/runtime/agent/orchestrator/session/loop/step-auto-effort.mjs +104 -19
- package/src/runtime/agent/orchestrator/session/loop/tool-call-resolution.mjs +95 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +15 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +150 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-phase.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +30 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +34 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +57 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +8 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +5 -10
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +208 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +16 -4
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +25 -3
- package/src/runtime/agent/orchestrator/session/manager/session-fallback-title.mjs +82 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -2
- package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +18 -7
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +168 -29
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +96 -0
- package/src/runtime/agent/orchestrator/session/side-question.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +17 -3
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/store/paths-heartbeat.mjs +58 -2
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +6 -3
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +41 -28
- package/src/runtime/agent/orchestrator/session/store/session-observers.mjs +4 -2
- package/src/runtime/agent/orchestrator/session/store/sweep/sweep-finish.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/store/write-admission.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +22 -10
- package/src/runtime/agent/orchestrator/session/store-summary-archived-agent.mjs +34 -15
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +10 -2
- package/src/runtime/agent/orchestrator/session/store.mjs +19 -3
- package/src/runtime/agent/orchestrator/session/tool-batch/execute-call.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/tool-batch/finalize.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/record-outcome.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/state.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/tool-schema-rejection.mjs +77 -0
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +20 -1
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +8 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/command-preflight.mjs +3 -3
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +12 -15
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +14 -10
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/ui-diff.mjs +73 -39
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +18 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -4
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +88 -12
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +2 -0
- package/src/runtime/computer-bridge/action-schema.mjs +44 -21
- package/src/runtime/github/tool.mjs +92 -2
- package/src/runtime/memory/index.mjs +1 -0
- package/src/runtime/memory/lib/http-router/ingest-routes.mjs +22 -1
- package/src/runtime/memory/lib/ingest/transcript-offsets.mjs +2 -0
- package/src/runtime/memory/lib/pg/adapter.mjs +98 -1
- package/src/runtime/memory/lib/pg/process.mjs +65 -50
- package/src/runtime/memory/lib/pg/run-child.mjs +49 -0
- package/src/runtime/memory/lib/pg/supervisor.mjs +124 -16
- package/src/runtime/memory/lib/runtime-fetcher.mjs +12 -13
- package/src/runtime/memory/lib/transcript-ingest.mjs +14 -0
- package/src/runtime/office/README.md +2 -2
- package/src/runtime/office/authoring/html-document-author.mjs +2 -0
- package/src/runtime/office/authoring/pptx-contact-sheet.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-measure.mjs +2 -0
- package/src/runtime/office/authoring/pptx-html-runner.mjs +2 -0
- package/src/runtime/office/authoring/xlsx-html-runner.mjs +2 -0
- package/src/runtime/office/core/office-actions-read.mjs +3 -0
- package/src/runtime/office/core/office-render-preview.mjs +2 -0
- package/src/runtime/office/core/office-session-dispatch.mjs +7 -0
- package/src/runtime/office/core/office-sessionless-actions.mjs +8 -0
- package/src/runtime/office/core/office-sessions.mjs +5 -0
- package/src/runtime/office/core/office-transactions.mjs +3 -0
- package/src/runtime/office/core/office-write-ledger.mjs +98 -0
- package/src/runtime/office/design/library/templates/mixdog-executive.mixdog-edit.pptx +0 -0
- package/src/runtime/office/index.mjs +30 -0
- package/src/runtime/office/pdf/pdf-edit-document.mjs +2 -0
- package/src/runtime/office/pdf/pdf-render.mjs +23 -7
- package/src/runtime/office/pdf/pdf-security.mjs +2 -0
- package/src/runtime/office/portable/portable-opc.mjs +4 -1
- package/src/runtime/office/quality/visual-diff.mjs +2 -0
- package/src/runtime/office/shared/values.mjs +0 -5
- package/src/runtime/shared/background-tasks.mjs +92 -14
- package/src/runtime/shared/bounded-file-read.mjs +13 -0
- package/src/runtime/shared/bounded-line-diff.mjs +182 -0
- package/src/runtime/shared/buffered-appender.mjs +18 -0
- package/src/runtime/shared/config.mjs +78 -18
- package/src/runtime/shared/err-text.mjs +31 -0
- package/src/runtime/shared/error-presentation.mjs +159 -19
- package/src/runtime/shared/file-permissions.d.mts +6 -1
- package/src/runtime/shared/file-permissions.mjs +54 -6
- package/src/runtime/shared/llm/anthropic-betas.mjs +4 -3
- package/src/runtime/shared/llm/anthropic-effort.mjs +129 -134
- package/src/runtime/shared/llm/anthropic-thinking-contract.mjs +50 -14
- package/src/runtime/shared/llm/model-catalog.mjs +53 -40
- package/src/runtime/shared/llm/openai-daybreak.mjs +4 -16
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +11 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +13 -4
- package/src/runtime/shared/llm/usage-accounting.mjs +5 -2
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +3 -0
- package/src/runtime/shared/llm/usage-rollup.mjs +0 -1
- package/src/runtime/shared/loopback-listener.mjs +9 -0
- package/src/runtime/shared/model-display.mjs +13 -0
- package/src/runtime/shared/provider-api-key.mjs +2 -0
- package/src/runtime/shared/quota-resume-store.mjs +11 -0
- package/src/runtime/shared/review-diff.mjs +52 -0
- package/src/runtime/shared/session-baseline-store.mjs +960 -0
- package/src/runtime/shared/session-sidebar-host.d.mts +4 -0
- package/src/runtime/shared/session-sidebar-host.mjs +38 -0
- package/src/runtime/shared/slow-span.mjs +114 -0
- package/src/runtime/shared/statusline/statusline-format.mjs +4 -4
- package/src/runtime/shared/statusline/statusline-segments.mjs +28 -4
- package/src/runtime/shared/task-notification-envelope.mjs +2 -2
- package/src/runtime/shared/tool-card-model/card-header.mjs +6 -1
- package/src/runtime/shared/tool-card-model/generic-detail.mjs +39 -5
- package/src/runtime/shared/tool-card-model.mjs +5 -2
- package/src/runtime/shared/tool-output-limit.mjs +4 -0
- package/src/runtime/shared/tool-primitives.mjs +13 -0
- package/src/runtime/shared/tool-result-summary.mjs +8 -1
- package/src/runtime/shared/tool-surface.mjs +18 -3
- package/src/runtime/shared/tool-work-units.mjs +40 -4
- package/src/runtime/shared/transcript-writer/purge.mjs +74 -0
- package/src/runtime/shared/transcript-writer.mjs +10 -2
- package/src/runtime/shared/turn-changes.mjs +670 -274
- package/src/runtime/shared/turn-review-reply.mjs +8 -39
- package/src/runtime/shared/turn-snapshot-store.mjs +94 -2
- package/src/runtime/shared/turn-snapshot.mjs +986 -690
- package/src/runtime/shared/turn-worktree-snapshot.mjs +279 -262
- package/src/runtime/shared/user-data-guard.mjs +262 -49
- package/src/runtime/shared/worktrees/carry.mjs +531 -0
- package/src/runtime/shared/worktrees/contract.mjs +34 -24
- package/src/runtime/shared/worktrees/file-recovery.mjs +68 -0
- package/src/runtime/shared/worktrees/git-head.mjs +205 -0
- package/src/runtime/shared/worktrees/git.mjs +8 -3
- package/src/runtime/shared/worktrees/maintenance.mjs +1 -1
- package/src/runtime/shared/worktrees/manager.mjs +156 -8
- package/src/runtime/shared/worktrees/merge.mjs +31 -21
- package/src/runtime/shared/worktrees/paths.d.mts +6 -0
- package/src/runtime/shared/worktrees/test-support.mjs +19 -4
- package/src/runtime/terminal-bridge/client.mjs +44 -11
- package/src/runtime/terminal-bridge/tool-defs.mjs +13 -6
- package/src/runtime/tidy/apply.mjs +47 -2
- package/src/runtime/tidy/run-engines.mjs +11 -5
- package/src/session-runtime/agent-tool-routing.mjs +19 -13
- package/src/session-runtime/boot/apis.mjs +19 -5
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +12 -1
- package/src/session-runtime/boot/session.mjs +0 -1
- package/src/session-runtime/boot/tools.mjs +4 -1
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +12 -5
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +65 -0
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +11 -4
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +115 -18
- package/src/session-runtime/internal-tool-executor.mjs +6 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +188 -0
- package/src/session-runtime/lifecycle/inheritance.mjs +71 -27
- package/src/session-runtime/lifecycle/session-catalog.mjs +14 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +6 -0
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +29 -6
- package/src/session-runtime/lifecycle/teardown.mjs +73 -8
- package/src/session-runtime/lifecycle-api.mjs +1 -0
- package/src/session-runtime/mcp-glue/connect.mjs +46 -14
- package/src/session-runtime/mcp-glue/server-catalog.mjs +20 -3
- package/src/session-runtime/mcp-glue.mjs +3 -0
- package/src/session-runtime/mcp-oauth-login.mjs +174 -0
- package/src/session-runtime/model-route/model-switch-target.mjs +34 -0
- package/src/session-runtime/model-route/set-route.mjs +85 -17
- package/src/session-runtime/model-route/web-search-route.mjs +1 -1
- package/src/session-runtime/native-web-search/routes.mjs +22 -3
- package/src/session-runtime/native-web-search-usage.mjs +51 -0
- package/src/session-runtime/native-web-search.mjs +10 -1
- package/src/session-runtime/new-session-config.mjs +4 -2
- package/src/session-runtime/provider-auth/login.mjs +4 -0
- package/src/session-runtime/provider-models/model-meta.mjs +12 -3
- package/src/session-runtime/quick-model-rows/web-search-rows.mjs +13 -8
- package/src/session-runtime/quick-web-search-models.mjs +13 -38
- package/src/session-runtime/resource-extension-sync.mjs +4 -0
- package/src/session-runtime/resource-mcp-api.mjs +98 -2
- package/src/session-runtime/resource-scope-decorate.mjs +10 -3
- package/src/session-runtime/runtime-review-api.mjs +21 -2
- package/src/session-runtime/services/agent-tool/index-write-queue.mjs +81 -20
- package/src/session-runtime/services/agent-tool/job-task-reconcile.mjs +13 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +7 -2
- package/src/session-runtime/services/agent-tool/lead-worker-index/forgotten-leads.mjs +29 -0
- package/src/session-runtime/services/agent-tool/lead-worker-index/index-file.mjs +1 -1
- package/src/session-runtime/services/agent-tool/lead-worker-index.mjs +73 -7
- package/src/session-runtime/services/agent-tool/send-flow.mjs +22 -4
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +2 -0
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +22 -5
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +15 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-liveness.mjs +8 -1
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +2 -2
- package/src/session-runtime/services/agent-tool/worker-index/row-store.mjs +10 -1
- package/src/session-runtime/services/agent-tool/worker-index.mjs +46 -7
- package/src/session-runtime/services/agent-tool/worker-rows.mjs +17 -0
- package/src/session-runtime/services/agent-tool.mjs +3 -0
- package/src/session-runtime/services/channel-admin.mjs +19 -3
- package/src/session-runtime/services/memory-runtime-proxy/calls.mjs +4 -0
- package/src/session-runtime/services/memory-runtime-proxy.mjs +1 -0
- package/src/session-runtime/services/provider-admin.mjs +81 -15
- package/src/session-runtime/session-transcript-purge.mjs +32 -0
- package/src/session-runtime/session-turn-api.mjs +14 -5
- package/src/session-runtime/settings-builtin-tools-api.mjs +9 -0
- package/src/session-runtime/settings-compaction-api.mjs +1 -0
- package/src/session-runtime/setup-tool/executor.mjs +36 -6
- package/src/session-runtime/setup-tool/extended-actions.mjs +86 -6
- package/src/session-runtime/setup-tool/settings-contract.mjs +13 -3
- package/src/session-runtime/setup-tool/tool-defs.mjs +13 -4
- package/src/session-runtime/skills-api.mjs +3 -5
- package/src/session-runtime/tool-surface.mjs +5 -1
- package/src/session-runtime/turn/compaction-gate.mjs +25 -0
- package/src/session-runtime/turn/session-ops.mjs +7 -5
- package/src/session-runtime/turn/side-question-ops.mjs +22 -0
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +5 -1
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +8 -3
- package/src/session-runtime/turn/turn-run/turn-settle.mjs +10 -0
- package/src/session-runtime/turn/turn-run/turn-timing.mjs +4 -3
- package/src/session-runtime/turn/turn-run.mjs +25 -9
- package/src/session-runtime/usage-stats-api.mjs +43 -11
- package/src/session-runtime/workspace/project-branches.mjs +7 -5
- package/src/session-runtime/workspace/transition-steps.mjs +129 -31
- package/src/session-runtime/workspace/transitions.mjs +190 -15
- package/src/standalone/daemon-agent-control.mjs +9 -1
- package/src/standalone/daemon-drain-policy.mjs +8 -0
- package/src/standalone/daemon-local-session-bridge.mjs +14 -1
- package/src/standalone/daemon-owner.mjs +17 -4
- package/src/standalone/daemon-pg-stop.mjs +51 -0
- package/src/standalone/daemon-stop-budget.d.mts +2 -0
- package/src/standalone/daemon-stop-budget.mjs +18 -0
- package/src/standalone/daemon-stored-session-views.mjs +2 -0
- package/src/standalone/daemon-telemetry.mjs +74 -0
- package/src/standalone/daemon.mjs +64 -8
- package/src/standalone/desktop-service-registry.mjs +5 -0
- package/src/standalone/local-session-runtime.mjs +70 -19
- package/src/standalone/session-client.mjs +42 -0
- package/src/standalone/session-protocol.mjs +14 -0
- package/src/standalone/session-proxy/projection.mjs +41 -4
- package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +15 -1
- package/src/standalone/session-runtime-inline-host.mjs +1 -0
- package/src/standalone/session-service/agent-tree/agent-cancel.mjs +33 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +26 -10
- package/src/standalone/session-service/agent-tree.mjs +12 -0
- package/src/standalone/session-service/quota-resume.mjs +8 -0
- package/src/standalone/session-service/retention/busy.mjs +15 -1
- package/src/standalone/session-service/session-calls/session-action.mjs +18 -3
- package/src/standalone/session-service-api.mjs +11 -1
- package/src/standalone/session-service.mjs +1 -0
- package/src/standalone/session-state-patch.d.mts +2 -1
- package/src/standalone/session-state-patch.mjs +41 -1
- package/src/tui/App.jsx +25 -0
- package/src/tui/app/app-view/floating-panel.jsx +26 -1
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/btw-controller.mjs +118 -0
- package/src/tui/app/create-app-pickers.mjs +6 -0
- package/src/tui/app/extension-pickers/mcp-login.mjs +107 -0
- package/src/tui/app/extension-pickers/mcp-servers-picker.mjs +2 -1
- package/src/tui/app/extension-pickers.mjs +2 -1
- package/src/tui/app/model-options.mjs +11 -16
- package/src/tui/app/shell-layout/row-budgets.mjs +11 -1
- package/src/tui/app/shell-layout/surfaces.mjs +3 -1
- package/src/tui/app/slash-commands.mjs +20 -5
- package/src/tui/app/slash-dispatch/panel-commands.mjs +16 -1
- package/src/tui/app/slash-dispatch/session-commands.mjs +19 -6
- package/src/tui/app/use-global-key-input/approval-shortcut.mjs +12 -0
- package/src/tui/app/use-global-key-input.mjs +5 -12
- package/src/tui/app/use-prompt-handlers.mjs +11 -0
- package/src/tui/components/BtwPanel.jsx +53 -0
- package/src/tui/components/QuestionPanel.jsx +275 -0
- package/src/tui/components/StatusLine.jsx +2 -0
- package/src/tui/components/question-panel-model.mjs +156 -0
- package/src/tui/components/status-line/local-line.mjs +5 -2
- package/src/tui/components/status-line/use-statusline-text.mjs +7 -1
- package/src/tui/dist/index.mjs +3221 -1500
- package/src/tui/session/context-state.mjs +4 -2
- package/src/tui/session/quota-resume.mjs +46 -14
- package/src/tui/session/session-api/commands.mjs +43 -24
- package/src/tui/session/session-api/controls.mjs +2 -2
- package/src/tui/session/session-api/extensions.mjs +22 -0
- package/src/tui/session/session-api/integrations.mjs +16 -2
- package/src/tui/session/session-api/lifecycle/dispose.mjs +1 -0
- package/src/tui/session/session-api/lifecycle.mjs +7 -2
- package/src/tui/session/session-api/routes.mjs +71 -7
- package/src/tui/session/session-api/settings.mjs +11 -14
- package/src/tui/session/session-api.mjs +1 -0
- package/src/tui/session/session-flow/drain.mjs +7 -1
- package/src/tui/session/session-flow/failed-turn-rewind.mjs +10 -4
- package/src/tui/session/tool-approval.mjs +10 -7
- package/src/tui/session/transcript-spill.mjs +14 -7
- package/src/tui/session/turn-stream.mjs +174 -31
- package/src/tui/session/turn.mjs +46 -16
- package/src/tui/statusline-ansi-bridge.mjs +1 -1
- package/src/ui/statusline-agents.mjs +15 -4
- package/src/ui/statusline.mjs +7 -3
- package/src/ui/streaming-markdown-heal.mjs +34 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +14 -4
- package/src/workflows/default/WORKFLOW.md +3 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +0 -32
- package/src/runtime/shared/llm/usage-session-history.mjs +0 -266
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
* (runtime/shared/worktrees/manager.mjs), loaded on first use.
|
|
13
13
|
*/
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
15
16
|
import {
|
|
17
|
+
WORKTREE_CARRY_CHOICES,
|
|
16
18
|
branchMenuEntries,
|
|
17
19
|
isWorktreeBound,
|
|
18
20
|
isWorktreeError,
|
|
@@ -24,6 +26,7 @@ import { normalizeWorktreeSettings } from '../../runtime/shared/worktrees/settin
|
|
|
24
26
|
import * as maintenance from '../../runtime/shared/worktrees/maintenance.mjs';
|
|
25
27
|
import { inspectRepo, throwIfAborted } from '../../runtime/shared/worktrees/git.mjs';
|
|
26
28
|
import { isWithin, samePath } from '../../runtime/shared/worktrees/paths.mjs';
|
|
29
|
+
import { readGitHead } from '../../runtime/shared/worktrees/git-head.mjs';
|
|
27
30
|
import { sessionHasConversationMessages } from '../../runtime/agent/orchestrator/runtime-core/session-text.mjs';
|
|
28
31
|
import { buildWorkspacePromptContext } from '../../runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs';
|
|
29
32
|
import {
|
|
@@ -53,6 +56,9 @@ async function defaultOwnShellJobCount(sessionIds) {
|
|
|
53
56
|
|
|
54
57
|
const lower = (value) => String(value || '').toLowerCase();
|
|
55
58
|
|
|
59
|
+
const WORKTREE_BOUND_SWITCH =
|
|
60
|
+
'The session works in a managed worktree; exit the worktree first (switch to a project-folder branch, or merge or remove the worktree) before moving it to another project.';
|
|
61
|
+
|
|
56
62
|
/** The registered Project (projects.json) at `path`, or null. */
|
|
57
63
|
async function defaultRegisteredProject(path) {
|
|
58
64
|
const { listProjectsStrict } = await import('../../runtime/shared/projects.mjs');
|
|
@@ -62,9 +68,12 @@ async function defaultRegisteredProject(path) {
|
|
|
62
68
|
/**
|
|
63
69
|
* Re-root one session's prompt at `cwd`: environment facts and instruction
|
|
64
70
|
* files for every session, project memory for the Lead only (workers never
|
|
65
|
-
* carried it).
|
|
71
|
+
* carried it). A session with a conversation keeps its system prompt (cache
|
|
72
|
+
* intact) and gets a tail notice instead (refreshSessionWorkspaceContext);
|
|
73
|
+
* `move` ({ from, changes }: the session left the project folder `from` for
|
|
74
|
+
* a worktree) adds the uncommitted-changes and path lines to that notice.
|
|
66
75
|
*/
|
|
67
|
-
export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext } = {}) {
|
|
76
|
+
export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryContext, move = null } = {}) {
|
|
68
77
|
const { environmentContext, instructionFilesContext } = buildWorkspacePromptContext(session, cwd);
|
|
69
78
|
const coreMemoryContext =
|
|
70
79
|
session?.owner === AGENT_OWNER || typeof loadCoreMemoryContext !== 'function'
|
|
@@ -75,6 +84,7 @@ export async function refreshWorkspacePrompt(session, cwd, { loadCoreMemoryConte
|
|
|
75
84
|
environmentContext,
|
|
76
85
|
coreMemoryContext,
|
|
77
86
|
instructionFilesContext,
|
|
87
|
+
...(move ? { move } : {}),
|
|
78
88
|
});
|
|
79
89
|
}
|
|
80
90
|
|
|
@@ -137,9 +147,10 @@ const TRANSITION_STATE = { worktree: 'provisioning', branch: 'switching', 'remov
|
|
|
137
147
|
* @param {object} deps
|
|
138
148
|
* @param {() => any} deps.getSession The Lead session this runtime hosts.
|
|
139
149
|
* @param {() => string} deps.getCurrentCwd
|
|
140
|
-
* @param {(cwd: string) => unknown} deps.applyResolvedCwd Retargets rt cwd, session.cwd and the cwd override.
|
|
150
|
+
* @param {(cwd: string, options?: { persistProjectSelection?: boolean }) => unknown} deps.applyResolvedCwd Retargets rt cwd, session.cwd and the cwd override (and, persisting, the Project selection).
|
|
151
|
+
* @param {(desktopSession: any) => unknown} [deps.setDesktopSession] Restores the runtime's desktop metadata on a rollback.
|
|
141
152
|
* @param {(session: any) => unknown} deps.persistSession
|
|
142
|
-
* @param {(session: any, cwd: string) => Promise<unknown>} deps.refreshWorkspaceContext
|
|
153
|
+
* @param {(session: any, cwd: string, move?: { from: string, changes: 'carried'|'left'|null }|null) => Promise<unknown>} deps.refreshWorkspaceContext
|
|
143
154
|
* @param {() => number} deps.getActiveTurnCount
|
|
144
155
|
* @param {() => { agentWorkers?: any[], agentJobs?: any[] }} deps.agentStatusState
|
|
145
156
|
* @param {(sessionId: string, cwd: string) => unknown} [deps.updateLeadWorkerCwd] Moves the Lead's pool row (lead-workers.json).
|
|
@@ -149,6 +160,7 @@ export function createWorkspaceTransitions({
|
|
|
149
160
|
getReservedSessionId = () => null,
|
|
150
161
|
getCurrentCwd,
|
|
151
162
|
getDesktopSession = () => null,
|
|
163
|
+
setDesktopSession = () => {},
|
|
152
164
|
getConfig = () => null,
|
|
153
165
|
createCurrentSession = null,
|
|
154
166
|
applyResolvedCwd,
|
|
@@ -207,6 +219,37 @@ export function createWorkspaceTransitions({
|
|
|
207
219
|
return normalizeSessionWorkspace({ projectPath, cwd: getCurrentCwd() || projectPath, revision: 0 });
|
|
208
220
|
}
|
|
209
221
|
|
|
222
|
+
let liveWorkspace = null;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* The workspace the session publishes: a worktree-bound record as stored; a
|
|
226
|
+
* project-folder session (never moved, back from a worktree, or carrying a
|
|
227
|
+
* transition stub) with the folder's checked-out branch / detached commit and
|
|
228
|
+
* repoCommonDir read straight from HEAD — no git process. Null outside a git
|
|
229
|
+
* repository for a session without a record. Identity-stable while equal.
|
|
230
|
+
*/
|
|
231
|
+
function getLiveWorkspace() {
|
|
232
|
+
const session = getSession();
|
|
233
|
+
const stored = readSessionWorkspace(session);
|
|
234
|
+
if (isWorktreeBound(stored)) return session.workspace;
|
|
235
|
+
let base;
|
|
236
|
+
try {
|
|
237
|
+
base = stored ?? currentWorkspace(session);
|
|
238
|
+
} catch {
|
|
239
|
+
return session?.workspace ?? null;
|
|
240
|
+
}
|
|
241
|
+
const head = readGitHead(base.cwd);
|
|
242
|
+
if (!head) return session?.workspace ?? null;
|
|
243
|
+
const next = {
|
|
244
|
+
...base,
|
|
245
|
+
repoCommonDir: head.repoCommonDir,
|
|
246
|
+
branch: head.branch,
|
|
247
|
+
baseCommit: head.branch ? base.baseCommit : head.commit,
|
|
248
|
+
};
|
|
249
|
+
if (!liveWorkspace || !isDeepStrictEqual(liveWorkspace, next)) liveWorkspace = next;
|
|
250
|
+
return liveWorkspace;
|
|
251
|
+
}
|
|
252
|
+
|
|
210
253
|
function isSessionActive(session) {
|
|
211
254
|
const runtime = sessionManager?.getSessionRuntime?.(session.id);
|
|
212
255
|
if (runtime?.controller?.signal && !runtime.controller.signal.aborted) return true;
|
|
@@ -223,8 +266,11 @@ export function createWorkspaceTransitions({
|
|
|
223
266
|
(candidate.ownerSessionId === session.id || candidate.parentSessionId === session.id)
|
|
224
267
|
);
|
|
225
268
|
|
|
226
|
-
/**
|
|
227
|
-
|
|
269
|
+
/**
|
|
270
|
+
* WORKTREE_BUSY_JOBS while this Lead has a turn, workers or background
|
|
271
|
+
* shells running (`shellJobs: false` tolerates background shells).
|
|
272
|
+
*/
|
|
273
|
+
async function assertLeadIdle(session, { ownTurn = false, shellJobs: checkShellJobs = true } = {}) {
|
|
228
274
|
if (!ownTurn && getActiveTurnCount() > 0) {
|
|
229
275
|
throw worktreeError('WORKTREE_BUSY_JOBS', 'The session is running a turn; wait for it to finish.', {
|
|
230
276
|
reason: 'turn',
|
|
@@ -240,6 +286,7 @@ export function createWorkspaceTransitions({
|
|
|
240
286
|
if (busyWorkers || busyJobs) {
|
|
241
287
|
throw worktreeError('WORKTREE_BUSY_JOBS', undefined, { reason: 'workers', workers: busyWorkers, jobs: busyJobs });
|
|
242
288
|
}
|
|
289
|
+
if (!checkShellJobs) return;
|
|
243
290
|
const ids = new Set([session.id, ...workers.map((row) => row?.sessionId).filter(Boolean)]);
|
|
244
291
|
for (const worker of workersOf(session)) ids.add(worker.id);
|
|
245
292
|
const shellJobs = await countOwnShellJobs([...ids]);
|
|
@@ -284,11 +331,44 @@ export function createWorkspaceTransitions({
|
|
|
284
331
|
}
|
|
285
332
|
}
|
|
286
333
|
|
|
334
|
+
/**
|
|
335
|
+
* Before a carry clears the shared checkout `folder` (held by the caller,
|
|
336
|
+
* so no new turn starts there): WORKTREE_BUSY_JOBS while any other session
|
|
337
|
+
* working in it — idle or not, this Lead's workers included — owns a
|
|
338
|
+
* running background shell (holdProjectFolder already refused running
|
|
339
|
+
* turns and agents there, assertLeadIdle this Lead's own). Processes
|
|
340
|
+
* outside Mixdog (editors, watchers) cannot be excluded.
|
|
341
|
+
*/
|
|
342
|
+
async function assertCheckoutQuiet(session, folder) {
|
|
343
|
+
const sharing = listLiveSessions()
|
|
344
|
+
.filter(
|
|
345
|
+
(candidate) =>
|
|
346
|
+
candidate?.id &&
|
|
347
|
+
candidate.id !== session.id &&
|
|
348
|
+
candidate.closed !== true &&
|
|
349
|
+
typeof candidate.cwd === 'string' &&
|
|
350
|
+
isWithin(folder, candidate.cwd)
|
|
351
|
+
)
|
|
352
|
+
.map((candidate) => candidate.id);
|
|
353
|
+
if (!sharing.length) return;
|
|
354
|
+
const shellJobs = await countOwnShellJobs(sharing);
|
|
355
|
+
if (shellJobs > 0) {
|
|
356
|
+
throw worktreeError(
|
|
357
|
+
'WORKTREE_BUSY_JOBS',
|
|
358
|
+
'Background shells of other sessions are running in the project folder; carrying the changes needs it quiet.',
|
|
359
|
+
{ reason: 'folder-shell-jobs', shellJobs }
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
287
364
|
const steps = createTransitionSteps({
|
|
365
|
+
assertCheckoutQuiet,
|
|
288
366
|
backend,
|
|
289
367
|
inspectProject,
|
|
290
368
|
runtimeToken,
|
|
291
369
|
getCurrentCwd,
|
|
370
|
+
getDesktopSession,
|
|
371
|
+
setDesktopSession,
|
|
292
372
|
applyResolvedCwd,
|
|
293
373
|
persistSession,
|
|
294
374
|
refreshWorkspaceContext,
|
|
@@ -331,6 +411,7 @@ export function createWorkspaceTransitions({
|
|
|
331
411
|
name: target.name,
|
|
332
412
|
nameHint: options.nameHint,
|
|
333
413
|
confirmLarge: options.confirmLarge,
|
|
414
|
+
changes: options.changes,
|
|
334
415
|
});
|
|
335
416
|
}
|
|
336
417
|
if (target.kind === 'branch') {
|
|
@@ -442,9 +523,22 @@ export function createWorkspaceTransitions({
|
|
|
442
523
|
});
|
|
443
524
|
// A session in the project folder (never moved, or back from a worktree)
|
|
444
525
|
// is on whatever that folder has checked out now.
|
|
445
|
-
|
|
526
|
+
// Its repository is the project's (a never-moved session has no stored
|
|
527
|
+
// record), and a detached checkout shows branch null with the commit in
|
|
528
|
+
// baseCommit — never mistaken for "not a repository".
|
|
529
|
+
let view = workspace;
|
|
530
|
+
if (!isWorktreeBound(workspace)) {
|
|
531
|
+
const project = await inspectProject(workspace.projectPath);
|
|
532
|
+
const checkedOut = project.currentBranch ?? null;
|
|
533
|
+
view = {
|
|
534
|
+
...workspace,
|
|
535
|
+
repoCommonDir: project.repoCommonDir ?? workspace.repoCommonDir,
|
|
536
|
+
branch: checkedOut,
|
|
537
|
+
baseCommit: checkedOut ? workspace.baseCommit : (project.headCommit ?? null),
|
|
538
|
+
};
|
|
539
|
+
}
|
|
446
540
|
return {
|
|
447
|
-
workspace:
|
|
541
|
+
workspace: view,
|
|
448
542
|
pendingWorktree: pendingIntent ? { name: pendingIntent.name } : null,
|
|
449
543
|
branches: branchMenuEntries(menu.branches, menu.occupancy),
|
|
450
544
|
occupancy: menu.occupancy,
|
|
@@ -510,17 +604,28 @@ export function createWorkspaceTransitions({
|
|
|
510
604
|
* reuse it. Typed failures (large repository, disk, busy) therefore reach
|
|
511
605
|
* the sender while its draft is still unsent, and the turn that follows
|
|
512
606
|
* finds the session already bound.
|
|
607
|
+
*
|
|
608
|
+
* A provisioning that creates a new worktree decides the project folder's
|
|
609
|
+
* uncommitted changes (tracked and untracked): none → it proceeds; without
|
|
610
|
+
* `carryChanges` it refuses with WORKTREE_DIRTY_CHOICE (`details.count`);
|
|
611
|
+
* `leave` starts the worktree at HEAD and leaves them; `carry` moves them
|
|
612
|
+
* into it (the result's `changes` reports which). Re-entering a retained
|
|
613
|
+
* worktree never touches them.
|
|
513
614
|
*/
|
|
514
615
|
async function requestWorktree({
|
|
515
616
|
name = null,
|
|
516
617
|
confirmLarge = false,
|
|
517
618
|
provision = false,
|
|
619
|
+
carryChanges,
|
|
518
620
|
prompt = '',
|
|
519
621
|
txId = '',
|
|
520
622
|
expectedRevision,
|
|
521
623
|
} = {}) {
|
|
522
624
|
const nameHint = validName(name);
|
|
523
625
|
const expected = validRevision(expectedRevision);
|
|
626
|
+
if (carryChanges !== undefined && carryChanges !== null && !WORKTREE_CARRY_CHOICES.includes(carryChanges)) {
|
|
627
|
+
throw new TypeError(`carryChanges must be one of ${WORKTREE_CARRY_CHOICES.join(', ')}.`);
|
|
628
|
+
}
|
|
524
629
|
const session = provision === true ? await ensureSession() : getSession();
|
|
525
630
|
// No session yet: the menu it was read from had revision 0.
|
|
526
631
|
const current = session?.id ? currentWorkspace(session) : null;
|
|
@@ -536,6 +641,7 @@ export function createWorkspaceTransitions({
|
|
|
536
641
|
return { ...entered, pending: false };
|
|
537
642
|
}
|
|
538
643
|
}
|
|
644
|
+
const priorIntent = pendingIntent;
|
|
539
645
|
pendingIntent = {
|
|
540
646
|
name: nameHint ?? pendingIntent?.name ?? null,
|
|
541
647
|
confirmLarge: confirmLarge === true || pendingIntent?.confirmLarge === true,
|
|
@@ -544,10 +650,21 @@ export function createWorkspaceTransitions({
|
|
|
544
650
|
txId: pendingIntent?.txId ?? null,
|
|
545
651
|
};
|
|
546
652
|
if (provision === true) {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
653
|
+
const intent = pendingIntent;
|
|
654
|
+
try {
|
|
655
|
+
return {
|
|
656
|
+
...(await provisionIntent(session, intent, txId, prompt, {
|
|
657
|
+
expectedRevision: expected,
|
|
658
|
+
changes: carryChanges ?? 'ask',
|
|
659
|
+
})),
|
|
660
|
+
pending: false,
|
|
661
|
+
};
|
|
662
|
+
} catch (error) {
|
|
663
|
+
// A refused move (uncommitted changes to decide, busy, …) is never
|
|
664
|
+
// re-armed for the next turn, where nobody could answer it.
|
|
665
|
+
if (pendingIntent === intent) pendingIntent = priorIntent;
|
|
666
|
+
throw error;
|
|
667
|
+
}
|
|
551
668
|
}
|
|
552
669
|
const workspace = session?.id ? currentWorkspace(session) : null;
|
|
553
670
|
return { revision: workspace?.revision ?? 0, workspace, pending: true };
|
|
@@ -570,15 +687,35 @@ export function createWorkspaceTransitions({
|
|
|
570
687
|
if (cleanup !== true || merged.merged !== true) return merged;
|
|
571
688
|
// "Merge and clean up": with autoCleanup on, the merged worktree goes now
|
|
572
689
|
// (a dirty one stays, reported); off, nothing is removed automatically.
|
|
690
|
+
// The merge is committed: a failed or refused cleanup (dirty, retained
|
|
691
|
+
// file recovery data, ...) is a cleanup notice, never a merge failure.
|
|
573
692
|
if (worktreeSettings().autoCleanup !== true) {
|
|
574
|
-
return {
|
|
693
|
+
return {
|
|
694
|
+
...merged,
|
|
695
|
+
cleanup: { removed: false, reason: 'auto-cleanup-off', message: 'Auto cleanup is off; the worktree is kept.' },
|
|
696
|
+
};
|
|
575
697
|
}
|
|
576
698
|
try {
|
|
577
699
|
const removed = await removeWorktree({ force: false }, { ownTurn });
|
|
578
700
|
return { ...merged, cleanup: removed.removed, revision: removed.revision, workspace: removed.workspace };
|
|
579
701
|
} catch (error) {
|
|
580
|
-
|
|
581
|
-
|
|
702
|
+
// The merge stands: a refused or incomplete cleanup (dirty, unmerged,
|
|
703
|
+
// retained file recovery data, partly removed, …) is reported, never
|
|
704
|
+
// thrown, with the workspace as it is now (an incomplete removal already
|
|
705
|
+
// returned to the project folder).
|
|
706
|
+
const workspace = currentWorkspace(session);
|
|
707
|
+
const code = typeof error?.code === 'string' ? error.code : '';
|
|
708
|
+
return {
|
|
709
|
+
...merged,
|
|
710
|
+
cleanup: {
|
|
711
|
+
removed: false,
|
|
712
|
+
reason: code || 'WORKTREE_CLEANUP_FAILED',
|
|
713
|
+
...(code ? { code } : {}),
|
|
714
|
+
message: String(error?.message || error),
|
|
715
|
+
},
|
|
716
|
+
revision: workspace.revision,
|
|
717
|
+
workspace,
|
|
718
|
+
};
|
|
582
719
|
}
|
|
583
720
|
}
|
|
584
721
|
|
|
@@ -620,6 +757,41 @@ export function createWorkspaceTransitions({
|
|
|
620
757
|
}
|
|
621
758
|
}
|
|
622
759
|
|
|
760
|
+
/**
|
|
761
|
+
* Move the hosted Lead to another Project folder (session set-project, the
|
|
762
|
+
* desktop/remote setCwd): the one authority for a Project switch, admitted
|
|
763
|
+
* like a workspace transition. Refused while a turn runs (`ownTurn`: the
|
|
764
|
+
* Lead's own tool call tolerates its calling turn), while workers run, and
|
|
765
|
+
* while the session works in a managed worktree. Serialized with turns and
|
|
766
|
+
* other workspace changes; the prompt refresh of the Lead and its idle
|
|
767
|
+
* workers completes (or rolls the switch back) before it resolves. Without
|
|
768
|
+
* a session (a draft) only the runtime cwd and the selection move.
|
|
769
|
+
* `classifyByMembership` (the desktop/remote move): a folder outside every
|
|
770
|
+
* registered Project is classified as a task (cwd-apply).
|
|
771
|
+
* @returns {Promise<string>} the runtime cwd after the switch
|
|
772
|
+
*/
|
|
773
|
+
async function switchProject(cwd, { ownTurn = false, classifyByMembership = false } = {}) {
|
|
774
|
+
const selection = { classifyByMembership: classifyByMembership === true };
|
|
775
|
+
const session = getSession();
|
|
776
|
+
if (!session?.id) {
|
|
777
|
+
applyResolvedCwd(cwd, { persistProjectSelection: true, ...selection });
|
|
778
|
+
return getCurrentCwd();
|
|
779
|
+
}
|
|
780
|
+
const leave = beginWorkspaceTransition(session.id, `project:${newTxId()}`);
|
|
781
|
+
const journal = [];
|
|
782
|
+
try {
|
|
783
|
+
await assertLeadIdle(session, { ownTurn: ownTurn === true, shellJobs: false });
|
|
784
|
+
if (isWorktreeBound(readSessionWorkspace(session))) throw new Error(WORKTREE_BOUND_SWITCH);
|
|
785
|
+
await steps.switchProject(session, cwd, journal, selection);
|
|
786
|
+
return getCurrentCwd();
|
|
787
|
+
} catch (error) {
|
|
788
|
+
await undoAll(journal, error);
|
|
789
|
+
throw error;
|
|
790
|
+
} finally {
|
|
791
|
+
leave();
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
623
795
|
async function removeWorktree({ force = false, expectedRevision } = {}, { ownTurn = false } = {}) {
|
|
624
796
|
const expected = validRevision(expectedRevision);
|
|
625
797
|
const session = hostedSession(null);
|
|
@@ -636,6 +808,8 @@ export function createWorkspaceTransitions({
|
|
|
636
808
|
admitTurnWorkspace,
|
|
637
809
|
/** The durable workspace record of the hosted session (null: project folder, never moved). */
|
|
638
810
|
getWorkspace: () => getSession()?.workspace ?? null,
|
|
811
|
+
/** What the session snapshot publishes (see getLiveWorkspace). */
|
|
812
|
+
getLiveWorkspace,
|
|
639
813
|
getBranchMenu,
|
|
640
814
|
getProjectBranchMenu: projectBranches.getProjectBranchMenu,
|
|
641
815
|
selectBranch,
|
|
@@ -644,6 +818,7 @@ export function createWorkspaceTransitions({
|
|
|
644
818
|
requestWorktree,
|
|
645
819
|
mergeWorkspace,
|
|
646
820
|
removeWorktree,
|
|
821
|
+
switchProject,
|
|
647
822
|
listWorktrees,
|
|
648
823
|
pruneWorktrees,
|
|
649
824
|
cleanupDeletedSession,
|
|
@@ -68,5 +68,13 @@ export function createCanonicalAgentControl({ getSessionService, getSessionRunti
|
|
|
68
68
|
return await tool.execute(args, scopedContext);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
/** Graceful shutdown: drain and release the canonical agent's index writers.
|
|
72
|
+
* Never builds the tool just to dispose it. */
|
|
73
|
+
async function dispose() {
|
|
74
|
+
if (!canonicalAgentToolPromise) return;
|
|
75
|
+
const tool = await canonicalAgentToolPromise.catch(() => null);
|
|
76
|
+
await tool?.disposeAsync?.({ settle: true });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { canonicalAgentTool, execute, dispose };
|
|
72
80
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/** Whether an idle GC sweep may start: no service call and no running turn
|
|
2
|
+
* (provider stream / tool call). Background-task-only sessions and memory
|
|
3
|
+
* agents do not block it — unlike drainDeferral, which guards shutdown. */
|
|
4
|
+
export function idleGcEligible(work) {
|
|
5
|
+
const { activeCalls = 0, queuedCalls = 0, turnBusySessions = 0 } = work || {};
|
|
6
|
+
return !(activeCalls > 0 || queuedCalls > 0 || turnBusySessions > 0);
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
/** Whether self-shutdown must wait for in-flight work. A forced replacement
|
|
2
10
|
* never waits: shutdown() aborts busy sessions, service calls and agent runs. */
|
|
3
11
|
export function drainDeferral(work, { force = false } = {}) {
|
|
@@ -22,9 +22,22 @@ export function createLocalSessionBridge({ getSessionService, log, pid = process
|
|
|
22
22
|
return createSessionProtocolClient({
|
|
23
23
|
call(name, args = {}, options = {}) {
|
|
24
24
|
if (closed) throw new Error('daemon-local session client is closed');
|
|
25
|
-
|
|
25
|
+
const signal = options?.signal;
|
|
26
|
+
signal?.throwIfAborted();
|
|
27
|
+
const result = getSessionService().handleCall(name, args, {
|
|
26
28
|
clientToken,
|
|
27
29
|
...(options?.callId ? { callId: String(options.callId) } : {}),
|
|
30
|
+
...(signal ? { signal } : {}),
|
|
31
|
+
});
|
|
32
|
+
if (!signal) return result;
|
|
33
|
+
// The in-process service has no cancellation of its own: an abort
|
|
34
|
+
// frees the caller, whose late reply is dropped.
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
const onAbort = () => reject(signal.reason);
|
|
37
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
38
|
+
Promise.resolve(result)
|
|
39
|
+
.then(resolve, reject)
|
|
40
|
+
.finally(() => signal.removeEventListener('abort', onAbort));
|
|
28
41
|
});
|
|
29
42
|
},
|
|
30
43
|
async close(reason = 'local session view closed') {
|
|
@@ -246,6 +246,7 @@ export function daemonOwnerIsStale(
|
|
|
246
246
|
* - No successful refresh for `fenceMs`: fenced, never renewed (`onFenced`).
|
|
247
247
|
* - The record names another pid: `onSuperseded(record)`.
|
|
248
248
|
* - A turn gap over `stallMs`: `admit()` refuses work until a refresh succeeds.
|
|
249
|
+
* The gap is logged once, with `describeStall(fromMono, toMono)` appended.
|
|
249
250
|
* Both callbacks must make this process stop serving.
|
|
250
251
|
*/
|
|
251
252
|
export function createOwnerHeartbeat({
|
|
@@ -259,6 +260,7 @@ export function createOwnerHeartbeat({
|
|
|
259
260
|
monoNow = () => performance.now(),
|
|
260
261
|
refresh = refreshSingletonOwner,
|
|
261
262
|
log = () => {},
|
|
263
|
+
describeStall = null,
|
|
262
264
|
onBeat = () => {},
|
|
263
265
|
onSuperseded,
|
|
264
266
|
onFenced,
|
|
@@ -290,11 +292,22 @@ export function createOwnerHeartbeat({
|
|
|
290
292
|
}
|
|
291
293
|
|
|
292
294
|
function noteTurn(t) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
295
|
+
const from = lastTurnAt;
|
|
296
|
+
// Rebased before reporting: one long block is one gap, however many
|
|
297
|
+
// callers (tick, admit) observe it afterwards.
|
|
297
298
|
lastTurnAt = t;
|
|
299
|
+
if (t - from <= stallMs) return;
|
|
300
|
+
needsVerify = true;
|
|
301
|
+
let detail = '';
|
|
302
|
+
try {
|
|
303
|
+
detail = describeStall?.(from, t) || '';
|
|
304
|
+
} catch {
|
|
305
|
+
/* attribution must not disturb the lease */
|
|
306
|
+
}
|
|
307
|
+
log(
|
|
308
|
+
`event loop stalled ${Math.round(t - from)}ms — owner lease must be re-verified before serving` +
|
|
309
|
+
(detail ? ` | ${detail}` : '')
|
|
310
|
+
);
|
|
298
311
|
}
|
|
299
312
|
|
|
300
313
|
function beat() {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// The daemon's PostgreSQL stop inside its shutdown. The normal teardown stops
|
|
2
|
+
// PostgreSQL after every user of it has closed, letting durable writes still in
|
|
3
|
+
// flight commit first; a fallback timer stops it regardless just before the
|
|
4
|
+
// launcher's kill (PG_FORCED_STOP_AT_MS), because a daemon killed before
|
|
5
|
+
// `pg_ctl stop` leaves the daemonized postmaster running.
|
|
6
|
+
import { PG_FORCED_STOP_AT_MS } from './daemon-stop-budget.mjs';
|
|
7
|
+
|
|
8
|
+
const ADAPTER = '../runtime/memory/lib/pg/adapter.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Arm at shutdown start. `finish()` is the ordered teardown step: it drains
|
|
12
|
+
* durable writes until the fallback point, then stops. Idempotent: whichever
|
|
13
|
+
* of finish/fallback comes first runs the one stop; the other joins it.
|
|
14
|
+
*/
|
|
15
|
+
export function createDaemonPgStop({
|
|
16
|
+
log,
|
|
17
|
+
stopTimeoutMs,
|
|
18
|
+
forcedStopAtMs = PG_FORCED_STOP_AT_MS,
|
|
19
|
+
loadAdapter = () => import(ADAPTER),
|
|
20
|
+
}) {
|
|
21
|
+
const startedAt = Date.now();
|
|
22
|
+
let stopping = null;
|
|
23
|
+
// The drain budget is what remains until the fallback point once the adapter
|
|
24
|
+
// has loaded, so a slow load never stretches the drain past that point.
|
|
25
|
+
const drainBudget = () => Math.max(0, startedAt + forcedStopAtMs - Date.now());
|
|
26
|
+
const run = (drain) => {
|
|
27
|
+
stopping ??= loadAdapter()
|
|
28
|
+
.then(({ shutdownOwnedPg }) =>
|
|
29
|
+
shutdownOwnedPg({ timeoutMs: stopTimeoutMs, drainMs: drain ? drainBudget() : 0 })
|
|
30
|
+
)
|
|
31
|
+
.then(
|
|
32
|
+
(stopped) => {
|
|
33
|
+
if (stopped) log('postgres stopped');
|
|
34
|
+
},
|
|
35
|
+
(e) => log(`postgres stop failed: ${e?.message || e}`)
|
|
36
|
+
);
|
|
37
|
+
return stopping;
|
|
38
|
+
};
|
|
39
|
+
const fallback = setTimeout(() => {
|
|
40
|
+
if (stopping) return; // the ordered stop is draining; its bound is this same point
|
|
41
|
+
log(`teardown still running ${forcedStopAtMs}ms into shutdown; stopping postgres before the launcher's kill`);
|
|
42
|
+
void run(false);
|
|
43
|
+
}, forcedStopAtMs);
|
|
44
|
+
fallback.unref?.();
|
|
45
|
+
return {
|
|
46
|
+
finish() {
|
|
47
|
+
clearTimeout(fallback);
|
|
48
|
+
return run(true);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Time budget of an in-tree daemon's stop, shared by the launcher that waits
|
|
2
|
+
// for it (desktop quit) and the daemon that has to finish inside it.
|
|
3
|
+
|
|
4
|
+
/** How long a launcher waits for an in-tree daemon to exit after asking it to
|
|
5
|
+
* stop. Past this the launcher exits and the daemon dies with its process
|
|
6
|
+
* tree — on Windows without any exit hook. A healthy daemon stop (PostgreSQL
|
|
7
|
+
* included) measures ~0.6 s; the rest is room for a slow teardown to finish
|
|
8
|
+
* its writes. The desktop window is hidden before this wait begins. */
|
|
9
|
+
export const IN_TREE_DAEMON_STOP_GRACE_MS = 5_000;
|
|
10
|
+
|
|
11
|
+
/** `pg_ctl stop` spawn + signal delivery. Once signalled, the postmaster
|
|
12
|
+
* finishes its shutdown on its own even if the daemon is then killed. */
|
|
13
|
+
const PG_STOP_SIGNAL_MARGIN_MS = 800;
|
|
14
|
+
|
|
15
|
+
/** Fallback point (from shutdown start) at which the daemon stops PostgreSQL
|
|
16
|
+
* even while earlier teardown steps still run: just before the launcher's
|
|
17
|
+
* kill, so a slow-but-healthy teardown keeps its writes until then. */
|
|
18
|
+
export const PG_FORCED_STOP_AT_MS = IN_TREE_DAEMON_STOP_GRACE_MS - PG_STOP_SIGNAL_MARGIN_MS;
|
|
@@ -38,6 +38,8 @@ export function createStoredSessionViews({ desktopRuntime, dataDir }) {
|
|
|
38
38
|
const review = createRuntimeReviewApi({ getCwd: () => metadata.cwd || '', getSessionId: () => sessionId });
|
|
39
39
|
// The runtime review API answers `known`/`summary` itself (turnReviewReply).
|
|
40
40
|
if (action === 'getSessionReviewDiff') return review.getSessionReviewDiff();
|
|
41
|
+
if (action === 'getSessionReviewFilePatch') return review.getSessionReviewFilePatch(args[0], args[1]);
|
|
42
|
+
if (action === 'getTurnReviewFilePatch') return review.getTurnReviewFilePatch(args[0]);
|
|
41
43
|
// A cold session runs no turn: its change record is final.
|
|
42
44
|
if (action === 'getTurnChanges') return review.getTurnChanges(args[0]);
|
|
43
45
|
return review.getTurnReviewDiff(args[0]);
|
|
@@ -93,6 +93,71 @@ export function collectDaemonTelemetry({
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Tracks the smallest heapUsed observed right after a major GC (mark-sweep-
|
|
98
|
+
* compact) — the retained-set size, which heapUsed at an arbitrary instant
|
|
99
|
+
* hides. Sampled per telemetry interval; no per-GC logging. Returns null when
|
|
100
|
+
* PerformanceObserver is unavailable.
|
|
101
|
+
*/
|
|
102
|
+
export function createPostGcHeapTracker({
|
|
103
|
+
heapUsed = () => v8.getHeapStatistics().used_heap_size,
|
|
104
|
+
observe = (onGc) => {
|
|
105
|
+
const obs = new PerformanceObserver((list) => {
|
|
106
|
+
for (const entry of list.getEntries()) onGc(entry);
|
|
107
|
+
});
|
|
108
|
+
obs.observe({ entryTypes: ['gc'] });
|
|
109
|
+
return () => obs.disconnect();
|
|
110
|
+
},
|
|
111
|
+
} = {}) {
|
|
112
|
+
let min = -1;
|
|
113
|
+
let disconnect = null;
|
|
114
|
+
try {
|
|
115
|
+
disconnect = observe((entry) => {
|
|
116
|
+
// NODE_PERFORMANCE_GC_MAJOR = 4 (older Node: entry.kind); newer: entry.detail.kind.
|
|
117
|
+
const kind = entry?.detail?.kind ?? entry?.kind;
|
|
118
|
+
if (kind !== 4) return;
|
|
119
|
+
const used = byteCount(heapUsed());
|
|
120
|
+
if (used >= 0 && (min < 0 || used < min)) min = used;
|
|
121
|
+
});
|
|
122
|
+
} catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
/** Min post-major-GC heap since the last take; -1 when none ran. */
|
|
127
|
+
take() {
|
|
128
|
+
const value = min;
|
|
129
|
+
min = -1;
|
|
130
|
+
return value;
|
|
131
|
+
},
|
|
132
|
+
stop() {
|
|
133
|
+
try {
|
|
134
|
+
disconnect?.();
|
|
135
|
+
} catch {
|
|
136
|
+
/* already gone */
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Builds the `describeStall(fromMono, toMono)` the owner heartbeat appends to
|
|
144
|
+
* its stall line: the spans that overlapped the stall window plus the in-flight
|
|
145
|
+
* work snapshot at report time. Counters and labels only.
|
|
146
|
+
*/
|
|
147
|
+
export function createStallDescriber({ spans, getWork = () => ({}), limit = 3 } = {}) {
|
|
148
|
+
return (fromMono, toMono) => {
|
|
149
|
+
const parts = [];
|
|
150
|
+
const overlapping = spans?.describe(fromMono, toMono, limit);
|
|
151
|
+
if (overlapping) parts.push(overlapping);
|
|
152
|
+
const work = workCounts(getWork());
|
|
153
|
+
parts.push(
|
|
154
|
+
`in-flight: activeCalls=${work.activeCalls} queuedCalls=${work.queuedCalls}` +
|
|
155
|
+
` busySessions=${work.busySessions} busyMemoryAgents=${work.busyMemoryAgents}`
|
|
156
|
+
);
|
|
157
|
+
return parts.join(' | ');
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
96
161
|
export function formatDaemonTelemetry(record, reason = 'periodic') {
|
|
97
162
|
const row = record && typeof record === 'object' ? record : collectDaemonTelemetry();
|
|
98
163
|
return [
|
|
@@ -110,6 +175,8 @@ export function formatDaemonTelemetry(record, reason = 'periodic') {
|
|
|
110
175
|
`queuedCalls=${row.queuedCalls}`,
|
|
111
176
|
`busySessions=${row.busySessions}`,
|
|
112
177
|
`busyMemoryAgents=${row.busyMemoryAgents}`,
|
|
178
|
+
// Present only when a major GC ran since the previous line.
|
|
179
|
+
...(byteCount(row.postGcHeapMinBytes) >= 0 ? [`postGcHeapMinBytes=${row.postGcHeapMinBytes}`] : []),
|
|
113
180
|
].join(' ');
|
|
114
181
|
}
|
|
115
182
|
|
|
@@ -123,8 +190,10 @@ export function createDaemonTelemetry({
|
|
|
123
190
|
heapStatistics,
|
|
124
191
|
setIntervalFn = setInterval,
|
|
125
192
|
clearIntervalFn = clearInterval,
|
|
193
|
+
createGcTracker = createPostGcHeapTracker,
|
|
126
194
|
} = {}) {
|
|
127
195
|
let timer = null;
|
|
196
|
+
let gcTracker = null;
|
|
128
197
|
|
|
129
198
|
function emit(reason = 'periodic') {
|
|
130
199
|
try {
|
|
@@ -141,6 +210,8 @@ export function createDaemonTelemetry({
|
|
|
141
210
|
heapStatistics,
|
|
142
211
|
work,
|
|
143
212
|
});
|
|
213
|
+
const postGc = gcTracker?.take() ?? -1;
|
|
214
|
+
if (postGc >= 0) record.postGcHeapMinBytes = postGc;
|
|
144
215
|
log(formatDaemonTelemetry(record, reason));
|
|
145
216
|
return record;
|
|
146
217
|
} catch {
|
|
@@ -159,6 +230,7 @@ export function createDaemonTelemetry({
|
|
|
159
230
|
|
|
160
231
|
function start(intervalMs = DAEMON_TELEMETRY_INTERVAL_MS) {
|
|
161
232
|
if (timer) return timer;
|
|
233
|
+
gcTracker ??= createGcTracker();
|
|
162
234
|
const delay = Number(intervalMs);
|
|
163
235
|
const ms = Number.isFinite(delay) && delay > 0 ? delay : DAEMON_TELEMETRY_INTERVAL_MS;
|
|
164
236
|
const handle = setIntervalFn(() => {
|
|
@@ -174,6 +246,8 @@ export function createDaemonTelemetry({
|
|
|
174
246
|
if (!timer) return;
|
|
175
247
|
clearIntervalFn(timer);
|
|
176
248
|
timer = null;
|
|
249
|
+
gcTracker?.stop();
|
|
250
|
+
gcTracker = null;
|
|
177
251
|
}
|
|
178
252
|
|
|
179
253
|
return { emit, start, stop };
|