mixdog 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/scripts/build-shipped-history.mjs +115 -33
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +183 -63
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/gate-scheduler.mjs +138 -32
- package/scripts/lib/gate-timing-reporter.mjs +16 -0
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +91 -66
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +124 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/lib/test-failure-records.mjs +14 -1
- package/scripts/lib/test-failure-summary.mjs +16 -4
- package/scripts/lib/test-spawn-ledger.mjs +12 -3
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -5
- package/scripts/suite-health.mjs +115 -24
- package/scripts/test-data-dir.mjs +10 -7
- package/scripts/test.mjs +9 -14
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/explore/AGENT.md +22 -0
- package/src/agents/explore/agent.json +6 -0
- package/src/app.mjs +4 -0
- package/src/cli.mjs +7 -0
- package/src/defaults/agents.json +7 -0
- package/src/defaults/shipped-history.json +23 -2
- package/src/defaults/skills/browser-use/SKILL.md +10 -5
- package/src/defaults/skills/code-tidy/SKILL.md +71 -102
- package/src/defaults/skills/code-tidy/references/agent-cleanup.md +66 -114
- package/src/defaults/skills/code-tidy/references/cleanup-report.md +19 -35
- package/src/defaults/skills/code-tidy/references/dead-code.md +3 -9
- package/src/defaults/skills/code-tidy/references/test-suite-slop.md +16 -27
- package/src/defaults/skills/computer-use/SKILL.md +16 -4
- package/src/defaults/skills/goal-management/SKILL.md +1 -1
- package/src/defaults/skills/setup/references/actions.md +12 -6
- package/src/defaults/skills/setup/references/surfaces.md +2 -2
- package/src/defaults/skills/setup-guide/SKILL.md +5 -2
- package/src/defaults/skills/setup-guide/model-recommendations.json +13 -0
- package/src/defaults/skills/skill-creator/SKILL.md +85 -190
- package/src/defaults/skills/skill-creator/references/design.md +70 -162
- package/src/defaults/skills/skill-creator/references/evaluation.md +33 -92
- package/src/defaults/skills/test-suite/SKILL.md +194 -0
- package/src/defaults/skills/test-suite/references/case-management.md +51 -0
- package/src/defaults/skills/test-suite/references/flaky-policy.md +39 -0
- package/src/defaults/skills/test-suite/references/reliability.md +49 -0
- package/src/defaults/skills/test-suite/references/suite-design.md +78 -0
- package/src/defaults/skills/test-suite/scripts/inventory.mjs +335 -0
- package/src/defaults/skills/visualize/SKILL.md +6 -2
- package/src/lib/rules-builder.cjs +35 -42
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +12 -7
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/20-research.md +3 -6
- package/src/rules/shared/40-editing.md +1 -0
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/60-verification.md +10 -9
- package/src/rules/shared/70-delivery.md +8 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/abort-link.mjs +5 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +10 -1
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +156 -24
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +13 -0
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +4 -1
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/config.mjs +12 -7
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +8 -8
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +5 -26
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +3 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +122 -12
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +5 -3
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +13 -2
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +152 -58
- package/src/runtime/agent/orchestrator/mcp/client.mjs +51 -18
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +88 -54
- package/src/runtime/agent/orchestrator/mcp/oauth.mjs +42 -26
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +54 -8
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +37 -31
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +31 -21
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +40 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider-keys.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-auth.mjs +14 -7
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/gemini-response.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +248 -41
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +0 -18
- package/src/runtime/agent/orchestrator/providers/lib/oauth-token-utils.mjs +138 -6
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/mimo-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/model-cache.mjs +100 -33
- package/src/runtime/agent/orchestrator/providers/muse-code-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/oauth-secret-fields.fixtures.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +160 -31
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +22 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +49 -22
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/registry.mjs +45 -2
- package/src/runtime/agent/orchestrator/providers/vertex-ai-auth.mjs +622 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-maas.mjs +185 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai-models.mjs +445 -0
- package/src/runtime/agent/orchestrator/providers/vertex-ai.mjs +567 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/builtin-features.mjs +2 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +8 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-data.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +6 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +14 -5
- package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +1 -0
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +30 -5
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +171 -37
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +102 -12
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +164 -23
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +139 -19
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +100 -22
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +36 -6
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +23 -4
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/loop/turn-limits.mjs +13 -8
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +50 -28
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +1 -0
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +30 -13
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +63 -6
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +35 -13
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +24 -14
- package/src/runtime/agent/orchestrator/session/manager/session-scratch-environment.mjs +70 -0
- package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +0 -3
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +10 -6
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +56 -29
- package/src/runtime/agent/orchestrator/session/manager/turn-reap.mjs +125 -0
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +11 -5
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +252 -39
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +163 -64
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +164 -4
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +142 -18
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +67 -31
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +58 -20
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.mjs +20 -15
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +96 -20
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +59 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.mjs +99 -2
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +103 -13
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +49 -15
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-spawn.mjs +45 -27
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +34 -10
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +28 -4
- package/src/runtime/agent/orchestrator/tools/lib/wait-until-fixture.mjs +26 -0
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +29 -11
- package/src/runtime/channels/lib/whisper-server.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/connectors/connector-accounts-mcp.mjs +236 -103
- package/src/runtime/connectors/gmail-app-password.mjs +3 -3
- package/src/runtime/explore/explorer.mjs +93 -0
- package/src/runtime/explore/tool-defs.mjs +35 -0
- package/src/runtime/explore/tool.mjs +123 -0
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/index.mjs +4 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +4 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +10 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +4 -2
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/agent-route-config.mjs +17 -2
- package/src/runtime/shared/atomic-file.mjs +103 -2
- package/src/runtime/shared/background-tasks.mjs +15 -6
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/connector-accounts.mjs +5 -5
- package/src/runtime/shared/connector-catalog.d.mts +11 -4
- package/src/runtime/shared/connector-catalog.mjs +60 -52
- package/src/runtime/shared/custom-provider-keys.mjs +20 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/file-has-data.mjs +26 -2
- package/src/runtime/shared/file-lock.mjs +13 -15
- package/src/runtime/shared/git-launch.d.mts +9 -0
- package/src/runtime/shared/git-launch.mjs +213 -0
- package/src/runtime/shared/git-runner-worker.mjs +2 -1
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +11 -2
- package/src/runtime/shared/llm/http-agent.mjs +313 -29
- package/src/runtime/shared/llm/model-catalog-projection.mjs +3 -2
- package/src/runtime/shared/llm/model-catalog.mjs +46 -6
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +3 -0
- package/src/runtime/shared/llm/system-proxy.mjs +452 -0
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/provider-accounts.mjs +52 -2
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/staged-install-worker.mjs +5 -0
- package/src/runtime/shared/staged-update.mjs +47 -2
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +113 -36
- package/src/runtime/shared/tool-work-units.mjs +6 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +414 -54
- package/src/runtime/shared/worktrees/activity-gate.mjs +215 -318
- package/src/runtime/shared/worktrees/activity-ledger-worker.mjs +56 -0
- package/src/runtime/shared/worktrees/activity-ledger.mjs +391 -0
- package/src/runtime/shared/worktrees/branch-management.mjs +9 -3
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +72 -0
- package/src/runtime/shared/worktrees/manager.mjs +285 -168
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/tidy/install.mjs +95 -15
- package/src/runtime/tidy/languages.mjs +17 -15
- package/src/runtime/tidy/process.mjs +7 -4
- package/src/runtime/tidy/resolve.mjs +19 -16
- package/src/runtime/tidy/runners/biome.mjs +3 -3
- package/src/runtime/tidy/tool.mjs +1 -1
- package/src/runtime/tidy/worktree.mjs +10 -6
- package/src/runtime/visualize-bridge/client.mjs +6 -1
- package/src/runtime/visualize-bridge/tool-defs.mjs +7 -2
- package/src/runtime/web-search/index.mjs +1 -1
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +458 -312
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +7 -1
- package/src/session-runtime/bot-status.mjs +107 -101
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/connector-merge-migration.mjs +18 -15
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +401 -36
- package/src/session-runtime/conversation-import/service.mjs +35 -8
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/held-requests.mjs +3 -1
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/feature-tools.mjs +2 -0
- package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +8 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +145 -112
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +6 -1
- package/src/session-runtime/lifecycle/teardown.mjs +1 -1
- package/src/session-runtime/mcp-glue/server-catalog.mjs +16 -10
- package/src/session-runtime/mcp-glue/server-input.mjs +4 -1
- package/src/session-runtime/mixy-heartbeat.mjs +1 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-auth/login.mjs +2 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-mcp-api.mjs +98 -35
- package/src/session-runtime/resource-mcp-connector-accounts.mjs +44 -31
- package/src/session-runtime/resource-mcp-secrets.mjs +28 -11
- package/src/session-runtime/resource-mcp-servers.mjs +5 -4
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/send-flow.mjs +10 -2
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +8 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/agent-watchdog-registry.mjs +32 -4
- package/src/session-runtime/services/channel-worker/daemon-spawn.mjs +2 -0
- package/src/session-runtime/services/daemon-candidate.mjs +4 -1
- package/src/session-runtime/services/memory-runtime-proxy/daemon-spawn.mjs +4 -0
- package/src/session-runtime/services/plugin-admin.mjs +10 -6
- package/src/session-runtime/services/provider-admin.mjs +283 -11
- package/src/session-runtime/session-turn-api.mjs +2 -0
- package/src/session-runtime/settings-builtin-tools-api.mjs +4 -1
- package/src/session-runtime/settings-system-api.mjs +1 -1
- package/src/session-runtime/setup-tool/agent-settings-actions.mjs +13 -3
- package/src/session-runtime/setup-tool/connector-widen-approval.mjs +96 -0
- package/src/session-runtime/setup-tool/executor.mjs +6 -2
- package/src/session-runtime/setup-tool/tool-defs.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/turn/agent-ops.mjs +23 -0
- package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +49 -11
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +25 -5
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/activity-guards.mjs +176 -0
- package/src/session-runtime/workspace/session-view.mjs +149 -0
- package/src/session-runtime/workspace/side-checkouts.mjs +203 -0
- package/src/session-runtime/workspace/transition-runner.mjs +188 -0
- package/src/session-runtime/workspace/transitions.mjs +108 -1041
- package/src/session-runtime/workspace/workspace-merge.mjs +132 -0
- package/src/session-runtime/workspace/worktree-intents.mjs +242 -0
- package/src/session-runtime/workspace/worktree-maintenance.mjs +80 -0
- package/src/session-runtime/workspace/worktree-setup.mjs +85 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +73 -56
- package/src/standalone/daemon-desktop-runtime.mjs +2 -0
- package/src/standalone/daemon-session-control.mjs +169 -138
- package/src/standalone/daemon.mjs +7 -0
- package/src/standalone/desktop-service-registry.mjs +9 -0
- package/src/standalone/local-session-runtime.mjs +5 -1
- package/src/standalone/session-client/daemon-unavailable.mjs +3 -0
- package/src/standalone/session-client.mjs +5 -1
- package/src/standalone/session-frame-stream.mjs +83 -11
- package/src/standalone/session-protocol.mjs +4 -0
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/agent-tree.mjs +45 -9
- package/src/standalone/session-service/projection/transcript-window.mjs +700 -64
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-service/session-calls/session-views.mjs +160 -104
- package/src/standalone/session-service/stored-reader.mjs +127 -40
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/App.jsx +154 -164
- package/src/tui/app/app-view/floating-panel.jsx +10 -4
- package/src/tui/app/app-view/text-entry-labels.mjs +1 -0
- package/src/tui/app/clipboard.mjs +21 -10
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/prompt-handlers/use-prompt-history-nav.mjs +1 -1
- package/src/tui/app/prompt-handlers/use-prompt-interrupt.mjs +3 -0
- package/src/tui/app/prompt-submit/provider-prompts.mjs +3 -1
- package/src/tui/app/provider-setup/api-key-actions.mjs +31 -1
- package/src/tui/app/provider-setup/oauth-actions.mjs +58 -21
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +29 -18
- package/src/tui/app/shell-layout/row-budgets.mjs +12 -10
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch/session-commands.mjs +46 -0
- package/src/tui/app/slash-dispatch.mjs +1 -1
- package/src/tui/app/use-btw-panel.mjs +29 -0
- package/src/tui/app/use-context-panel-refresh.mjs +31 -0
- package/src/tui/app/use-model-catalog-cache.mjs +13 -10
- package/src/tui/app/use-mouse-input.mjs +11 -0
- package/src/tui/app/use-onboarding-start.mjs +8 -3
- package/src/tui/app/use-panel-transition.mjs +10 -1
- package/src/tui/app/use-pasted-buffers.mjs +28 -20
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -0
- package/src/tui/app/use-prompt-layout-rows.mjs +3 -3
- package/src/tui/app/use-prompt-queue-history.mjs +3 -2
- package/src/tui/app/use-selection-focus.mjs +11 -2
- package/src/tui/app/use-selection-geometry.mjs +18 -9
- package/src/tui/app/use-selection-paint.mjs +4 -4
- package/src/tui/app/use-selection-stitch.mjs +3 -3
- package/src/tui/app/use-slash-palette.mjs +62 -0
- package/src/tui/app/use-terminal-chrome.mjs +2 -2
- package/src/tui/app/use-transcript-activity.mjs +47 -32
- package/src/tui/app/use-transcript-follow.mjs +12 -4
- package/src/tui/app/use-transcript-scroll.mjs +46 -17
- package/src/tui/app/use-transcript-swap-reset.mjs +27 -0
- package/src/tui/app/use-transcript-window/geometry.mjs +19 -5
- package/src/tui/app/use-transcript-window/instance-state.mjs +4 -0
- package/src/tui/app/use-transcript-window/selection-shift.mjs +5 -1
- package/src/tui/app/use-transcript-window.mjs +21 -11
- package/src/tui/app/use-tui-ready.mjs +18 -0
- package/src/tui/app/use-welcome-prompt-hint.mjs +5 -0
- package/src/tui/app/use-workflow-tab-cycle.mjs +5 -3
- package/src/tui/components/Picker.jsx +27 -3
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/components/SignInUrl.jsx +68 -0
- package/src/tui/components/TextEntryPanel.jsx +76 -46
- package/src/tui/components/sign-in-url-layout.mjs +24 -0
- package/src/tui/dist/index.mjs +1963 -1361
- package/src/tui/session/goal-turn-state.mjs +6 -2
- package/src/tui/session/session-api/controls.mjs +4 -0
- package/src/tui/session/session-api/extensions.mjs +8 -0
- package/src/tui/session/session-api/intake/abort.mjs +2 -1
- package/src/tui/session/session-api/intake.mjs +2 -0
- package/src/tui/session/session-api/integrations.mjs +2 -2
- package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
- package/src/tui/session/session-api/settings.mjs +2 -2
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/tui/session/transcript-spill/spill-writer.mjs +15 -0
- package/src/tui/session/transcript-spill.mjs +92 -4
- package/src/tui/session/transcript-store.mjs +2 -0
- package/src/ui/statusline-agents.mjs +1 -3
- package/src/defaults/skills/skill-creator/references/source-review.md +0 -94
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
} from './file-recovery.mjs';
|
|
41
41
|
import { lstat, mkdir, readdir, readFile, rm, rmdir, stat } from 'node:fs/promises';
|
|
42
42
|
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
43
|
+
import { isPidAlive } from '../pid-liveness.mjs';
|
|
43
44
|
import {
|
|
44
45
|
managedWorktreePath,
|
|
45
46
|
managedWorktreeRoot,
|
|
@@ -49,6 +50,7 @@ import {
|
|
|
49
50
|
WORKTREE_SNAPSHOT_KIND,
|
|
50
51
|
worktreeBranchName,
|
|
51
52
|
worktreeError,
|
|
53
|
+
worktreeRefusal,
|
|
52
54
|
} from './contract.mjs';
|
|
53
55
|
import {
|
|
54
56
|
assertCarryable,
|
|
@@ -68,6 +70,7 @@ import {
|
|
|
68
70
|
listWorktrees,
|
|
69
71
|
localBranches,
|
|
70
72
|
parseStatusPaths,
|
|
73
|
+
remoteDefaultBranches,
|
|
71
74
|
runGit,
|
|
72
75
|
throwIfAborted,
|
|
73
76
|
validBranchName,
|
|
@@ -84,7 +87,7 @@ import {
|
|
|
84
87
|
} from './include.mjs';
|
|
85
88
|
import { linkWorktreeDependencies } from './dependencies.mjs';
|
|
86
89
|
import { withRepoLock as withRepoMutationLock } from './lock.mjs';
|
|
87
|
-
import {
|
|
90
|
+
import { holdWorkspaceActivityAsync } from './activity-gate.mjs';
|
|
88
91
|
import { withAdvisoryLocks } from '../../agent/orchestrator/tools/builtin/advisory-lock.mjs';
|
|
89
92
|
import { mergeBranchIntoCheckout, operationInProgress } from './merge.mjs';
|
|
90
93
|
import { readOwnerLease, removeOwnerLease, sameOwner, writeOwnerLease } from './owner.mjs';
|
|
@@ -122,17 +125,7 @@ function sessionRootOf(record) {
|
|
|
122
125
|
// ---------------------------------------------------------------------------
|
|
123
126
|
// Host configuration (settings source, free-space probe); tests override it.
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
function processAlive(pid) {
|
|
127
|
-
try {
|
|
128
|
-
process.kill(pid, 0);
|
|
129
|
-
return true;
|
|
130
|
-
} catch (error) {
|
|
131
|
-
return error?.code === 'EPERM';
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const DEFAULT_CONFIG = Object.freeze({ settings: null, freeBytes: freeBytesAt, processAlive });
|
|
128
|
+
const DEFAULT_CONFIG = Object.freeze({ settings: null, freeBytes: freeBytesAt, processAlive: isPidAlive });
|
|
136
129
|
let config = { ...DEFAULT_CONFIG };
|
|
137
130
|
|
|
138
131
|
/**
|
|
@@ -757,6 +750,11 @@ export async function resolveBranchWorkspace({
|
|
|
757
750
|
repoCommonDir: repo.repoCommonDir,
|
|
758
751
|
};
|
|
759
752
|
}
|
|
753
|
+
// Checked out in a managed worktree, the branch a remote declares its
|
|
754
|
+
// default would stay locked away from the project folder.
|
|
755
|
+
if (!create && (await remoteDefaultBranches(repo.projectPath)).includes(branch)) {
|
|
756
|
+
throw worktreeError('WORKTREE_DEFAULT_BRANCH', undefined, { branch });
|
|
757
|
+
}
|
|
760
758
|
const entry = await createManagedWorktree({
|
|
761
759
|
projectPath,
|
|
762
760
|
sessionId,
|
|
@@ -770,10 +768,6 @@ export async function resolveBranchWorkspace({
|
|
|
770
768
|
confirmLarge,
|
|
771
769
|
signal,
|
|
772
770
|
});
|
|
773
|
-
const record = await getRecord(entry.id);
|
|
774
|
-
record.mergeTarget = repo.currentBranch;
|
|
775
|
-
await putRecord(record);
|
|
776
|
-
entry.mergeTarget = repo.currentBranch;
|
|
777
771
|
return { path: entry.path, branch, entry, created: true, repoCommonDir: repo.repoCommonDir };
|
|
778
772
|
});
|
|
779
773
|
}
|
|
@@ -976,6 +970,174 @@ async function snapshotHolderLive(record, live) {
|
|
|
976
970
|
return !!lease && lease.pid !== process.pid && leaseProcessAlive(lease);
|
|
977
971
|
}
|
|
978
972
|
|
|
973
|
+
/** The project folder's uncommitted changes under the requested `carryChanges` mode; `ask` refuses while there are any. */
|
|
974
|
+
async function judgePendingChanges(repo, projectSubdir, carryChanges) {
|
|
975
|
+
// A carry is judged by the same status read that counts the changes.
|
|
976
|
+
let pendingChanges = [];
|
|
977
|
+
if (carryChanges === 'carry') pendingChanges = await assertCarryable(repo.topLevel, projectSubdir);
|
|
978
|
+
else if (carryChanges) pendingChanges = await uncommittedChanges(repo.topLevel, projectSubdir);
|
|
979
|
+
if (pendingChanges.length && carryChanges === 'ask') {
|
|
980
|
+
throw worktreeError('WORKTREE_DIRTY_CHOICE', undefined, {
|
|
981
|
+
count: pendingChanges.length,
|
|
982
|
+
paths: pendingChanges.slice(0, DIRTY_CHOICE_PREVIEW),
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
return pendingChanges;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/** The commit a new worktree starts from and the branch a merge targets by default. */
|
|
989
|
+
async function resolveStartPoint(repo, { baseBranch, startCommit, signal }) {
|
|
990
|
+
let baseCommit = repo.headCommit;
|
|
991
|
+
let mergeTarget = repo.currentBranch;
|
|
992
|
+
if (baseBranch) {
|
|
993
|
+
baseCommit = await branchCommit(repo.projectPath, baseBranch, { signal });
|
|
994
|
+
if (!baseCommit) {
|
|
995
|
+
throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Base branch ${baseBranch} does not exist.`, { baseBranch });
|
|
996
|
+
}
|
|
997
|
+
mergeTarget = baseBranch;
|
|
998
|
+
}
|
|
999
|
+
// A new branch at an explicit start point (`git worktree add -b <b> <path> <commit-ish>`).
|
|
1000
|
+
if (startCommit) baseCommit = await resolveCommit(repo.projectPath, startCommit, signal);
|
|
1001
|
+
return { baseCommit, mergeTarget };
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
/** The record a creation reserves before git is asked to add the checkout. */
|
|
1005
|
+
function newCreationRecord({
|
|
1006
|
+
slug,
|
|
1007
|
+
branch,
|
|
1008
|
+
repo,
|
|
1009
|
+
owner,
|
|
1010
|
+
txId,
|
|
1011
|
+
baseCommit,
|
|
1012
|
+
mergeTarget,
|
|
1013
|
+
existingBranch,
|
|
1014
|
+
exactBranch,
|
|
1015
|
+
tracked,
|
|
1016
|
+
includePlan,
|
|
1017
|
+
}) {
|
|
1018
|
+
return {
|
|
1019
|
+
id: slug,
|
|
1020
|
+
txId,
|
|
1021
|
+
repoCommonDir: repo.repoCommonDir,
|
|
1022
|
+
projectPath: repo.projectPath,
|
|
1023
|
+
projectSubdir: projectSubdirOf(repo.topLevel, repo.projectPath),
|
|
1024
|
+
path: managedWorktreePath(repo.repoCommonDir, slug),
|
|
1025
|
+
branch,
|
|
1026
|
+
baseCommit,
|
|
1027
|
+
// An existing branch has no base it branched from: it merges where a
|
|
1028
|
+
// merge first takes it (recorded then), and until that its own work is
|
|
1029
|
+
// what it gained here since baseCommit.
|
|
1030
|
+
mergeTarget: existingBranch ? null : mergeTarget,
|
|
1031
|
+
createdAt: Date.now(),
|
|
1032
|
+
ownerSessionId: owner.sessionId,
|
|
1033
|
+
existingBranch,
|
|
1034
|
+
exactBranch,
|
|
1035
|
+
state: 'creating',
|
|
1036
|
+
disposable: false,
|
|
1037
|
+
warnings: [...(tracked.submodules ? ['submodules'] : []), ...includePlan.warnings],
|
|
1038
|
+
resources: { worktree: null, lock: null, owner: null, includes: [] },
|
|
1039
|
+
deleting: null,
|
|
1040
|
+
recovery: null,
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/**
|
|
1045
|
+
* Locks the fresh checkout, binds its owner lease, moves or leaves the
|
|
1046
|
+
* project folder's changes, applies the includes and links dependencies.
|
|
1047
|
+
* `carry.moved` is set as soon as changes were carried, so a later failure
|
|
1048
|
+
* can put them back.
|
|
1049
|
+
*/
|
|
1050
|
+
async function populateCheckout({
|
|
1051
|
+
record,
|
|
1052
|
+
owner,
|
|
1053
|
+
repo,
|
|
1054
|
+
projectSubdir,
|
|
1055
|
+
signal,
|
|
1056
|
+
pendingChanges,
|
|
1057
|
+
carryChanges,
|
|
1058
|
+
baseCommit,
|
|
1059
|
+
includePlan,
|
|
1060
|
+
carry,
|
|
1061
|
+
}) {
|
|
1062
|
+
await setResource(record, 'worktree', 'created');
|
|
1063
|
+
throwIfAborted(signal);
|
|
1064
|
+
await setResource(record, 'lock', 'pending');
|
|
1065
|
+
await runGit(repo.projectPath, ['worktree', 'lock', '--reason', `mixdog session=${owner.sessionId}`, record.path]);
|
|
1066
|
+
await setResource(record, 'lock', 'created');
|
|
1067
|
+
await setResource(record, 'owner', 'pending');
|
|
1068
|
+
await writeOwnerLease(record, owner);
|
|
1069
|
+
await setResource(record, 'owner', 'created');
|
|
1070
|
+
// Carried before the include entries are copied, so an include never
|
|
1071
|
+
// stands in the way of a carried file; the status is read again here,
|
|
1072
|
+
// right before acting.
|
|
1073
|
+
let changes = pendingChanges.length ? { mode: 'left', count: pendingChanges.length } : null;
|
|
1074
|
+
if (carryChanges === 'carry') {
|
|
1075
|
+
carry.moved = await carryUncommittedChanges({
|
|
1076
|
+
topLevel: repo.topLevel,
|
|
1077
|
+
projectSubdir,
|
|
1078
|
+
worktreePath: record.path,
|
|
1079
|
+
baseCommit,
|
|
1080
|
+
label: record.id,
|
|
1081
|
+
});
|
|
1082
|
+
// The recovery ref stays until the caller has committed the move
|
|
1083
|
+
// (dropCarryRecoveryRef) or put the changes back (restoreCarriedChanges).
|
|
1084
|
+
changes = carry.moved.count
|
|
1085
|
+
? { mode: 'carried', count: carry.moved.count, recoveryRef: carry.moved.recoveryRef }
|
|
1086
|
+
: null;
|
|
1087
|
+
}
|
|
1088
|
+
const applied = await applyIncludes(includePlan, record.path, (ledger) => recordInclude(record, ledger));
|
|
1089
|
+
throwIfAborted(signal);
|
|
1090
|
+
// After the includes: one that already brought a node_modules wins.
|
|
1091
|
+
const linkedDependencies = await linkWorktreeDependencies({
|
|
1092
|
+
mainDir: repo.projectPath,
|
|
1093
|
+
worktreeDir: projectSubdir ? join(record.path, ...projectSubdir.split('/')) : record.path,
|
|
1094
|
+
worktreeRel: projectSubdir,
|
|
1095
|
+
signal,
|
|
1096
|
+
record: (ledger) => recordInclude(record, ledger),
|
|
1097
|
+
});
|
|
1098
|
+
throwIfAborted(signal);
|
|
1099
|
+
record.warnings = [...record.warnings, ...applied.warnings];
|
|
1100
|
+
const made = (record.resources.includes || []).filter((item) => item.status === 'created');
|
|
1101
|
+
const rels = (predicate) => made.filter(predicate).map((item) => item.rel);
|
|
1102
|
+
// What creation did, for the agent's note at the first turn there (transitions.mjs).
|
|
1103
|
+
const prepared = {
|
|
1104
|
+
root: repo.topLevel,
|
|
1105
|
+
copied: rels((item) => item.mode === 'copy'),
|
|
1106
|
+
linked: rels((item) => item.mode === 'link' && !item.dependency),
|
|
1107
|
+
dependencies: linkedDependencies,
|
|
1108
|
+
skipped: [...includePlan.warnings, ...applied.warnings],
|
|
1109
|
+
};
|
|
1110
|
+
// Whichever path made it (a worktree task, a branch selection, `git
|
|
1111
|
+
// worktree add`), the first turn a session runs here prepares its
|
|
1112
|
+
// dependencies (claimWorktreeSetup).
|
|
1113
|
+
record.setup = { pending: true, prepared };
|
|
1114
|
+
record.state = 'ready';
|
|
1115
|
+
await putRecord(record);
|
|
1116
|
+
return { ...entryView(record), prepared, ...(changes ? { changes } : {}) };
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
/** The error a failed creation throws, after its carried changes and partial checkout are undone. */
|
|
1120
|
+
async function failCreation(error, { record, carried, repo, projectSubdir, needed, root }) {
|
|
1121
|
+
// Carried already: the changes go back to the project folder before the
|
|
1122
|
+
// worktree that holds them is rolled back (the recovery ref keeps them
|
|
1123
|
+
// either way).
|
|
1124
|
+
let carryRestore = null;
|
|
1125
|
+
if (carried?.recoveryRef) {
|
|
1126
|
+
carryRestore = await restoreFromRecoveryRef(repo.topLevel, projectSubdir, carried.recoveryRef)
|
|
1127
|
+
.then(() => ({ restored: true, recoveryRef: carried.recoveryRef }))
|
|
1128
|
+
.catch((restoreError) => ({
|
|
1129
|
+
restored: false,
|
|
1130
|
+
recoveryRef: carried.recoveryRef,
|
|
1131
|
+
error: String(restoreError?.message || restoreError),
|
|
1132
|
+
}));
|
|
1133
|
+
}
|
|
1134
|
+
const rollback = await rollbackCreation(record, error);
|
|
1135
|
+
const failure = isDiskFullError(error) ? await diskFullFailure(error, { needed, root }) : error;
|
|
1136
|
+
if (!rollback.complete) failure.rollback = rollback;
|
|
1137
|
+
if (carryRestore) failure.carryRestore = carryRestore;
|
|
1138
|
+
return failure;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
979
1141
|
/**
|
|
980
1142
|
* `carryChanges` decides the project folder's uncommitted changes (tracked
|
|
981
1143
|
* and untracked, ignored excluded), judged under the repository lock:
|
|
@@ -1031,29 +1193,10 @@ export async function createManagedWorktree({
|
|
|
1031
1193
|
throwIfAborted(signal);
|
|
1032
1194
|
|
|
1033
1195
|
const projectSubdir = projectSubdirOf(repo.topLevel, repo.projectPath);
|
|
1034
|
-
|
|
1035
|
-
let pendingChanges = [];
|
|
1036
|
-
if (carryChanges === 'carry') pendingChanges = await assertCarryable(repo.topLevel, projectSubdir);
|
|
1037
|
-
else if (carryChanges) pendingChanges = await uncommittedChanges(repo.topLevel, projectSubdir);
|
|
1038
|
-
if (pendingChanges.length && carryChanges === 'ask') {
|
|
1039
|
-
throw worktreeError('WORKTREE_DIRTY_CHOICE', undefined, {
|
|
1040
|
-
count: pendingChanges.length,
|
|
1041
|
-
paths: pendingChanges.slice(0, DIRTY_CHOICE_PREVIEW),
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1196
|
+
const pendingChanges = await judgePendingChanges(repo, projectSubdir, carryChanges);
|
|
1044
1197
|
|
|
1045
1198
|
const settings = await currentWorktreeSettings();
|
|
1046
|
-
|
|
1047
|
-
let mergeTarget = repo.currentBranch;
|
|
1048
|
-
if (baseBranch) {
|
|
1049
|
-
baseCommit = await branchCommit(repo.projectPath, baseBranch, { signal });
|
|
1050
|
-
if (!baseCommit) {
|
|
1051
|
-
throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Base branch ${baseBranch} does not exist.`, { baseBranch });
|
|
1052
|
-
}
|
|
1053
|
-
mergeTarget = baseBranch;
|
|
1054
|
-
}
|
|
1055
|
-
// A new branch at an explicit start point (`git worktree add -b <b> <path> <commit-ish>`).
|
|
1056
|
-
if (startCommit) baseCommit = await resolveCommit(repo.projectPath, startCommit, signal);
|
|
1199
|
+
const { baseCommit, mergeTarget } = await resolveStartPoint(repo, { baseBranch, startCommit, signal });
|
|
1057
1200
|
|
|
1058
1201
|
// The main checkout's local env files come along on their own;
|
|
1059
1202
|
// `.worktreeinclude` applies on top.
|
|
@@ -1096,7 +1239,7 @@ export async function createManagedWorktree({
|
|
|
1096
1239
|
}
|
|
1097
1240
|
);
|
|
1098
1241
|
let record = await reserve();
|
|
1099
|
-
|
|
1242
|
+
const carry = { moved: null };
|
|
1100
1243
|
|
|
1101
1244
|
try {
|
|
1102
1245
|
await mkdir(root, { recursive: true });
|
|
@@ -1117,84 +1260,20 @@ export async function createManagedWorktree({
|
|
|
1117
1260
|
await setResource(record, 'worktree', 'pending');
|
|
1118
1261
|
await addCheckout(record);
|
|
1119
1262
|
}
|
|
1120
|
-
await
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
'lock',
|
|
1126
|
-
'--reason',
|
|
1127
|
-
`mixdog session=${owner.sessionId}`,
|
|
1128
|
-
record.path,
|
|
1129
|
-
]);
|
|
1130
|
-
await setResource(record, 'lock', 'created');
|
|
1131
|
-
await setResource(record, 'owner', 'pending');
|
|
1132
|
-
await writeOwnerLease(record, owner);
|
|
1133
|
-
await setResource(record, 'owner', 'created');
|
|
1134
|
-
// Carried before the include entries are copied, so an include never
|
|
1135
|
-
// stands in the way of a carried file; the status is read again here,
|
|
1136
|
-
// right before acting.
|
|
1137
|
-
let changes = pendingChanges.length ? { mode: 'left', count: pendingChanges.length } : null;
|
|
1138
|
-
if (carryChanges === 'carry') {
|
|
1139
|
-
carried = await carryUncommittedChanges({
|
|
1140
|
-
topLevel: repo.topLevel,
|
|
1141
|
-
projectSubdir,
|
|
1142
|
-
worktreePath: record.path,
|
|
1143
|
-
baseCommit,
|
|
1144
|
-
label: record.id,
|
|
1145
|
-
});
|
|
1146
|
-
// The recovery ref stays until the caller has committed the move
|
|
1147
|
-
// (dropCarryRecoveryRef) or put the changes back (restoreCarriedChanges).
|
|
1148
|
-
changes = carried.count ? { mode: 'carried', count: carried.count, recoveryRef: carried.recoveryRef } : null;
|
|
1149
|
-
}
|
|
1150
|
-
const applied = await applyIncludes(includePlan, record.path, (ledger) => recordInclude(record, ledger));
|
|
1151
|
-
throwIfAborted(signal);
|
|
1152
|
-
// After the includes: one that already brought a node_modules wins.
|
|
1153
|
-
const linkedDependencies = await linkWorktreeDependencies({
|
|
1154
|
-
mainDir: repo.projectPath,
|
|
1155
|
-
worktreeDir: projectSubdir ? join(record.path, ...projectSubdir.split('/')) : record.path,
|
|
1156
|
-
worktreeRel: projectSubdir,
|
|
1263
|
+
return await populateCheckout({
|
|
1264
|
+
record,
|
|
1265
|
+
owner,
|
|
1266
|
+
repo,
|
|
1267
|
+
projectSubdir,
|
|
1157
1268
|
signal,
|
|
1158
|
-
|
|
1269
|
+
pendingChanges,
|
|
1270
|
+
carryChanges,
|
|
1271
|
+
baseCommit,
|
|
1272
|
+
includePlan,
|
|
1273
|
+
carry,
|
|
1159
1274
|
});
|
|
1160
|
-
throwIfAborted(signal);
|
|
1161
|
-
record.warnings = [...record.warnings, ...applied.warnings];
|
|
1162
|
-
const made = (record.resources.includes || []).filter((item) => item.status === 'created');
|
|
1163
|
-
const rels = (predicate) => made.filter(predicate).map((item) => item.rel);
|
|
1164
|
-
// What creation did, for the agent's note at the first turn there (transitions.mjs).
|
|
1165
|
-
const prepared = {
|
|
1166
|
-
root: repo.topLevel,
|
|
1167
|
-
copied: rels((item) => item.mode === 'copy'),
|
|
1168
|
-
linked: rels((item) => item.mode === 'link' && !item.dependency),
|
|
1169
|
-
dependencies: linkedDependencies,
|
|
1170
|
-
skipped: [...includePlan.warnings, ...applied.warnings],
|
|
1171
|
-
};
|
|
1172
|
-
// Whichever path made it (a worktree task, a branch selection, `git
|
|
1173
|
-
// worktree add`), the first turn a session runs here prepares its
|
|
1174
|
-
// dependencies (claimWorktreeSetup).
|
|
1175
|
-
record.setup = { pending: true, prepared };
|
|
1176
|
-
record.state = 'ready';
|
|
1177
|
-
await putRecord(record);
|
|
1178
|
-
return { ...entryView(record), prepared, ...(changes ? { changes } : {}) };
|
|
1179
1275
|
} catch (error) {
|
|
1180
|
-
|
|
1181
|
-
// worktree that holds them is rolled back (the recovery ref keeps them
|
|
1182
|
-
// either way).
|
|
1183
|
-
let carryRestore = null;
|
|
1184
|
-
if (carried?.recoveryRef) {
|
|
1185
|
-
carryRestore = await restoreFromRecoveryRef(repo.topLevel, projectSubdir, carried.recoveryRef)
|
|
1186
|
-
.then(() => ({ restored: true, recoveryRef: carried.recoveryRef }))
|
|
1187
|
-
.catch((restoreError) => ({
|
|
1188
|
-
restored: false,
|
|
1189
|
-
recoveryRef: carried.recoveryRef,
|
|
1190
|
-
error: String(restoreError?.message || restoreError),
|
|
1191
|
-
}));
|
|
1192
|
-
}
|
|
1193
|
-
const rollback = await rollbackCreation(record, error);
|
|
1194
|
-
const failure = isDiskFullError(error) ? await diskFullFailure(error, { needed, root }) : error;
|
|
1195
|
-
if (!rollback.complete) failure.rollback = rollback;
|
|
1196
|
-
if (carryRestore) failure.carryRestore = carryRestore;
|
|
1197
|
-
throw failure;
|
|
1276
|
+
throw await failCreation(error, { record, carried: carry.moved, repo, projectSubdir, needed, root });
|
|
1198
1277
|
}
|
|
1199
1278
|
|
|
1200
1279
|
async function reserveName() {
|
|
@@ -1210,27 +1289,19 @@ export async function createManagedWorktree({
|
|
|
1210
1289
|
if (!(await validBranchName(repo.projectPath, branch))) {
|
|
1211
1290
|
throw worktreeError('WORKTREE_UNSUPPORTED_REPO', `Branch name ${branch} is not valid.`, { branch });
|
|
1212
1291
|
}
|
|
1213
|
-
const candidate = {
|
|
1214
|
-
|
|
1215
|
-
txId,
|
|
1216
|
-
repoCommonDir: repo.repoCommonDir,
|
|
1217
|
-
projectPath: repo.projectPath,
|
|
1218
|
-
projectSubdir: projectSubdirOf(repo.topLevel, repo.projectPath),
|
|
1219
|
-
path: managedWorktreePath(repo.repoCommonDir, slug),
|
|
1292
|
+
const candidate = newCreationRecord({
|
|
1293
|
+
slug,
|
|
1220
1294
|
branch,
|
|
1295
|
+
repo,
|
|
1296
|
+
owner,
|
|
1297
|
+
txId,
|
|
1221
1298
|
baseCommit,
|
|
1222
1299
|
mergeTarget,
|
|
1223
|
-
createdAt: Date.now(),
|
|
1224
|
-
ownerSessionId: owner.sessionId,
|
|
1225
1300
|
existingBranch,
|
|
1226
1301
|
exactBranch: requestedBranch !== null,
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
resources: { worktree: null, lock: null, owner: null, includes: [] },
|
|
1231
|
-
deleting: null,
|
|
1232
|
-
recovery: null,
|
|
1233
|
-
};
|
|
1302
|
+
tracked,
|
|
1303
|
+
includePlan,
|
|
1304
|
+
});
|
|
1234
1305
|
return (await insertRecord(candidate)) ? candidate : null;
|
|
1235
1306
|
}
|
|
1236
1307
|
});
|
|
@@ -1356,9 +1427,12 @@ export async function createSnapshotWorktree({
|
|
|
1356
1427
|
* one is admitted there until the returned release. A folder no longer a
|
|
1357
1428
|
* checkout admits no consumer (activity-gate tracks git checkouts only).
|
|
1358
1429
|
*/
|
|
1359
|
-
function holdSnapshotFolder(record) {
|
|
1430
|
+
async function holdSnapshotFolder(record) {
|
|
1360
1431
|
if (!existsSync(join(record.path, '.git'))) return () => {};
|
|
1361
|
-
|
|
1432
|
+
const release = await holdWorkspaceActivityAsync([record.path]);
|
|
1433
|
+
// Settles once the removal was attempted. It fails only when workspace
|
|
1434
|
+
// admission stopped (reported there), which keeps the folder held.
|
|
1435
|
+
return () => release().catch(() => {});
|
|
1362
1436
|
}
|
|
1363
1437
|
|
|
1364
1438
|
/** A refusal that only says "something still runs there" (retry once it ends). */
|
|
@@ -1400,9 +1474,7 @@ export async function removeSessionSnapshots(sessionId, { txIds = null } = {}) {
|
|
|
1400
1474
|
const only = txIds ? new Set(txIds) : null;
|
|
1401
1475
|
const held = Object.values((await readRegistry()).entries).filter(
|
|
1402
1476
|
(record) =>
|
|
1403
|
-
record.kind === WORKTREE_SNAPSHOT_KIND &&
|
|
1404
|
-
record.holderSessionId === sessionId &&
|
|
1405
|
-
(!only || only.has(record.txId))
|
|
1477
|
+
record.kind === WORKTREE_SNAPSHOT_KIND && record.holderSessionId === sessionId && (!only || only.has(record.txId))
|
|
1406
1478
|
);
|
|
1407
1479
|
for (const record of held) {
|
|
1408
1480
|
const row = { id: record.id, txId: record.txId };
|
|
@@ -1854,19 +1926,59 @@ export async function removeManagedWorktree({
|
|
|
1854
1926
|
if (!current && !expected) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1855
1927
|
return skipped;
|
|
1856
1928
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1929
|
+
return removeLocked(current, { force, sessionId, preserveBranch, safeOnly });
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/** The removal of `current`, under its repository lock. */
|
|
1934
|
+
async function removeLocked(current, { force, sessionId, preserveBranch = false, safeOnly = false }) {
|
|
1935
|
+
assertNotShared(current, sessionId);
|
|
1936
|
+
if (current.state === 'creating' || current.state === 'recovery') {
|
|
1937
|
+
const rollback = await rollbackCreation(current);
|
|
1938
|
+
return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
|
|
1939
|
+
}
|
|
1940
|
+
// Every deletion attempt of a snapshot, a resumed one included, waits
|
|
1941
|
+
// for (refuses on) its consumers.
|
|
1942
|
+
const release = current.kind === WORKTREE_SNAPSHOT_KIND ? await holdSnapshotFolder(current) : () => {};
|
|
1943
|
+
try {
|
|
1944
|
+
return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
|
|
1945
|
+
} finally {
|
|
1946
|
+
await release();
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* Remove a worktree whose owner is gone, on an explicit request: under the
|
|
1952
|
+
* repository lock its retention is read again right before anything moves,
|
|
1953
|
+
* so an owner that came back (a live session, a running lease holder) or a
|
|
1954
|
+
* session the store still keeps it for refuses (WORKTREE_BUSY_JOBS). Then
|
|
1955
|
+
* the ordinary removal guards apply (dirty or unmerged work needs `force`).
|
|
1956
|
+
* @param {{ entryId: string, force?: boolean, liveSessionIds?: string[], retainedSessionIds?: string[] }} input
|
|
1957
|
+
*/
|
|
1958
|
+
export async function removeOrphanedWorktree({
|
|
1959
|
+
entryId,
|
|
1960
|
+
force = false,
|
|
1961
|
+
liveSessionIds = [],
|
|
1962
|
+
retainedSessionIds = [],
|
|
1963
|
+
} = {}) {
|
|
1964
|
+
const record = await getRecord(entryId);
|
|
1965
|
+
if (!record) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1966
|
+
return withRepoLock(record.repoCommonDir, async () => {
|
|
1967
|
+
const current = await getRecord(entryId);
|
|
1968
|
+
if (!current || current.kind === WORKTREE_SNAPSHOT_KIND) {
|
|
1969
|
+
throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1861
1970
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1971
|
+
const { ownerLive, removable } = await retentionOf(current, new Set(liveSessionIds), new Set(retainedSessionIds));
|
|
1972
|
+
if (ownerLive) throw worktreeRefusal('workspace-lease', { entryId });
|
|
1973
|
+
if (!removable) {
|
|
1974
|
+
// Retained recovery data names itself; otherwise sessions still keep it.
|
|
1975
|
+
await assertRecoveryStoresClear(current);
|
|
1976
|
+
throw worktreeRefusal('workspace-retained', {
|
|
1977
|
+
entryId,
|
|
1978
|
+
sessions: [current.ownerSessionId, ...(current.sharedSessionIds ?? [])].filter(Boolean),
|
|
1979
|
+
});
|
|
1869
1980
|
}
|
|
1981
|
+
return removeLocked(current, { force });
|
|
1870
1982
|
});
|
|
1871
1983
|
}
|
|
1872
1984
|
|
|
@@ -1900,25 +2012,7 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1900
2012
|
const retained = new Set(retainedSessionIds);
|
|
1901
2013
|
const rows = [];
|
|
1902
2014
|
for (const record of Object.values((await readRegistry()).entries)) {
|
|
1903
|
-
const
|
|
1904
|
-
const ownerLive = snapshot
|
|
1905
|
-
? await snapshotHolderLive(record, live)
|
|
1906
|
-
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) ||
|
|
1907
|
-
leaseProcessAlive(await readOwnerLease(record));
|
|
1908
|
-
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
1909
|
-
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
1910
|
-
let removable = snapshot
|
|
1911
|
-
? !ownerLive
|
|
1912
|
-
: !record.sharedSessionIds?.length &&
|
|
1913
|
-
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
1914
|
-
if (removable) {
|
|
1915
|
-
try {
|
|
1916
|
-
await assertRecoveryStoresClear(record);
|
|
1917
|
-
} catch (error) {
|
|
1918
|
-
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
1919
|
-
removable = false;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
2015
|
+
const { ownerLive, retained: isRetained, removable } = await retentionOf(record, live, retained);
|
|
1922
2016
|
rows.push({
|
|
1923
2017
|
...entryView(record),
|
|
1924
2018
|
projectPath: record.projectPath,
|
|
@@ -1930,6 +2024,29 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1930
2024
|
return rows;
|
|
1931
2025
|
}
|
|
1932
2026
|
|
|
2027
|
+
/** Who keeps `record` (listManagedWorktrees): `live` and `retained` are session id sets. */
|
|
2028
|
+
async function retentionOf(record, live, retained) {
|
|
2029
|
+
const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
|
|
2030
|
+
const ownerLive = snapshot
|
|
2031
|
+
? await snapshotHolderLive(record, live)
|
|
2032
|
+
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) || leaseProcessAlive(await readOwnerLease(record));
|
|
2033
|
+
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
2034
|
+
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
2035
|
+
let removable = snapshot
|
|
2036
|
+
? !ownerLive
|
|
2037
|
+
: !record.sharedSessionIds?.length &&
|
|
2038
|
+
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
2039
|
+
if (removable) {
|
|
2040
|
+
try {
|
|
2041
|
+
await assertRecoveryStoresClear(record);
|
|
2042
|
+
} catch (error) {
|
|
2043
|
+
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
2044
|
+
removable = false;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
return { ownerLive, retained: isRetained, removable };
|
|
2048
|
+
}
|
|
2049
|
+
|
|
1933
2050
|
/**
|
|
1934
2051
|
* Conservative reconcile (daemon startup, and the manual prune). Always:
|
|
1935
2052
|
* resumes interrupted deletions, rolls back interrupted creations of no
|
|
@@ -1995,7 +2112,7 @@ export async function reconcileManagedWorktrees({
|
|
|
1995
2112
|
// surviving folder since still keeps it.
|
|
1996
2113
|
let release;
|
|
1997
2114
|
try {
|
|
1998
|
-
release = holdSnapshotFolder(record);
|
|
2115
|
+
release = await holdSnapshotFolder(record);
|
|
1999
2116
|
} catch (error) {
|
|
2000
2117
|
if (!snapshotInUse(error)) throw error;
|
|
2001
2118
|
report.kept.push({ id: record.id, reason: 'snapshot-in-use' });
|
|
@@ -2004,7 +2121,7 @@ export async function reconcileManagedWorktrees({
|
|
|
2004
2121
|
try {
|
|
2005
2122
|
reportDeletion(record, await finishDeletion(record));
|
|
2006
2123
|
} finally {
|
|
2007
|
-
release();
|
|
2124
|
+
await release();
|
|
2008
2125
|
}
|
|
2009
2126
|
continue;
|
|
2010
2127
|
}
|
|
@@ -2020,7 +2137,7 @@ export async function reconcileManagedWorktrees({
|
|
|
2020
2137
|
let release = null;
|
|
2021
2138
|
if (!(await snapshotHolderLive(record, live))) {
|
|
2022
2139
|
try {
|
|
2023
|
-
release = holdSnapshotFolder(record);
|
|
2140
|
+
release = await holdSnapshotFolder(record);
|
|
2024
2141
|
} catch (error) {
|
|
2025
2142
|
if (!snapshotInUse(error)) throw error;
|
|
2026
2143
|
}
|
|
@@ -2036,7 +2153,7 @@ export async function reconcileManagedWorktrees({
|
|
|
2036
2153
|
await putRecord(record);
|
|
2037
2154
|
reportDeletion(record, await finishDeletion(record));
|
|
2038
2155
|
} finally {
|
|
2039
|
-
release();
|
|
2156
|
+
await release();
|
|
2040
2157
|
}
|
|
2041
2158
|
continue;
|
|
2042
2159
|
}
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
// Temporary git repositories and data dirs for the worktree suites.
|
|
2
2
|
import '../git-direct.test-support.mjs';
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
|
-
import { appendFileSync, chmodSync, cpSync, existsSync,
|
|
5
|
-
import { tmpdir } from 'node:os';
|
|
4
|
+
import { appendFileSync, chmodSync, cpSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
6
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { makeTempDirSync, removeTempDirSync } from '../../../../scripts/lib/scoped-temp.mjs';
|
|
7
7
|
|
|
8
8
|
const created = [];
|
|
9
9
|
|
|
10
|
+
// A suite that never calls cleanupTempDirs still has its directories removed
|
|
11
|
+
// when the process exits.
|
|
10
12
|
export function tempDir(prefix = 'mixdog-wt-') {
|
|
11
|
-
const dir =
|
|
13
|
+
const dir = makeTempDirSync(prefix);
|
|
12
14
|
created.push(dir);
|
|
13
15
|
return dir;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function cleanupTempDirs() {
|
|
17
|
-
for (const dir of created.splice(0))
|
|
18
|
-
try {
|
|
19
|
-
rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
|
20
|
-
} catch {
|
|
21
|
-
/* best effort */
|
|
22
|
-
}
|
|
23
|
-
}
|
|
19
|
+
for (const dir of created.splice(0)) removeTempDirSync(dir);
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' };
|