diff --git a/.github/workflows/wsl-orcad-e2e.yml b/.github/workflows/wsl-orcad-e2e.yml index fe091d4d45d..41e79cd885f 100644 --- a/.github/workflows/wsl-orcad-e2e.yml +++ b/.github/workflows/wsl-orcad-e2e.yml @@ -35,7 +35,6 @@ on: - '!**/*.test.ts' - '!**/*.test.tsx' - 'src/main/wsl/orcad/wsl-orcad-real-distro-lane.test.ts' - - 'src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts' - 'src/main/wsl/orcad/wsl-orcad-real-distro-idle-release-lane.test.ts' - '.github/workflows/wsl-orcad-e2e.yml' - 'config/ci/wsl-lifecycle/**' @@ -343,18 +342,6 @@ jobs: run: | node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/wsl/orcad/wsl-orcad-real-distro-lane.test.ts --reporter=verbose 2>&1 | Tee-Object (Join-Path $env:ORCA_WSL_ORCAD_LANE_RECEIPTS 'survive.log') if ($global:LASTEXITCODE -ne 0) { throw "survive phase failed: $global:LASTEXITCODE" } - # The WSL move's pause on real distro shells: Sleep ends them, the daemon proves the exit, - # the journal keeps each pane's folder, and a new shell opens there. - - name: 'WSL move: pause real distro terminals' - if: ${{ !cancelled() && steps.import.outcome == 'success' }} - timeout-minutes: 10 - env: - ORCA_WSL_MOVE_REAL_PAUSE_DISTRO: ${{ env.PLAIN_DISTRO }} - run: | - New-Item -ItemType Directory -Force $env:ORCA_WSL_ORCAD_LANE_RECEIPTS | Out-Null - node node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts --reporter=verbose 2>&1 | Tee-Object (Join-Path $env:ORCA_WSL_ORCAD_LANE_RECEIPTS 'wsl-move-real-pause.log') - if ($global:LASTEXITCODE -ne 0) { throw "WSL move real pause failed: $global:LASTEXITCODE" } - wsl.exe --terminate $env:PLAIN_DISTRO # R40: with no terminal left, orcad idle-exits and the holder lets the distro stop on its own. - name: 'Phase 3: idle orcad releases the distro' timeout-minutes: 30 diff --git a/config/main-layout-writer-baseline.txt b/config/main-layout-writer-baseline.txt index 328778605b1..1dec6b9a0d4 100644 --- a/config/main-layout-writer-baseline.txt +++ b/config/main-layout-writer-baseline.txt @@ -30,18 +30,18 @@ 2 src/main/persistence/loading-store/profile-writing/state-serialization-secret-handling.ts 4 src/main/persistence/loading-store/workspace-sessions/workspace-session-snapshot-publication.ts 4 src/main/persistence/loading-store/workspace-sessions/workspace-session-terminal-binding-replay.ts -2 src/main/persistence/migrating-orcad-catalog/orcad-destination-client-state.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.ts -3 src/main/persistence/migrating-orcad-catalog/orcad-dormant-state-records.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.ts -2 src/main/persistence/migrating-orcad-catalog/orcad-source-client-subtraction.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-state.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-eligibility.ts -3 src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-layout.ts -4 src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-subtraction.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session.ts -2 src/main/persistence/moving-wsl-projects/wsl-move-main-rewrite-stores.ts +2 src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-client-state.ts +1 src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.ts +3 src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-state-records.ts +1 src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.ts +2 src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-subtraction.ts +1 src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state.ts +1 src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.ts +1 src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-eligibility.ts +3 src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-layout.ts +4 src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-subtraction.ts +1 src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session.ts +2 src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores.ts 1 src/main/persistence/restoring-sessions/folder-workspace-operations.ts 1 src/main/persistence/restoring-sessions/invalid-workspace-layout-purge.ts 5 src/main/persistence/restoring-sessions/session-owner-fields.ts diff --git a/config/main-sync-fs-baseline.txt b/config/main-sync-fs-baseline.txt index 0f9c05a98e5..2d542ec02e7 100644 --- a/config/main-sync-fs-baseline.txt +++ b/config/main-sync-fs-baseline.txt @@ -375,18 +375,18 @@ 1 src/main/orcad/serve-profile-ssh-targets.ts 6 src/main/persistence/atomic-snapshot-writer.ts 5 src/main/persistence/loading-store/user-data-path.ts -9 src/main/persistence/migrating-orcad-catalog/migration-journal-directory.ts -4 src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-installers.ts -3 src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.ts -17 src/main/persistence/migrating-orcad-catalog/orcad-migration-staged-file.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.ts -11 src/main/persistence/migrating-orcad-catalog/orcad-shell-history-installer.ts -7 src/main/persistence/migrating-orcad-catalog/orcad-terminal-history-installer.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-terminal-restore-hint-store.ts -1 src/main/persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite.ts -1 src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-store.ts -6 src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.ts -2 src/main/persistence/moving-wsl-projects/wsl-move-slept-spool-sweep.ts +9 src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.ts +4 src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-installers.ts +3 src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.ts +17 src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-staged-file.ts +1 src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.ts +11 src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-shell-history-installer.ts +7 src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer.ts +1 src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store.ts +1 src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite.ts +1 src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-store.ts +6 src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.ts +2 src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-spool-sweep.ts 5 src/main/persistence/preferences/active-view-preference.ts 4 src/main/persistence/profile-state/legacy-json/profile-state-authority-exports.ts 2 src/main/persistence/profile-state/legacy-json/profile-state-export-path.ts diff --git a/config/repo-host-read-baseline.txt b/config/repo-host-read-baseline.txt index 19d04c4aa1c..7fcaeb3c4b7 100644 --- a/config/repo-host-read-baseline.txt +++ b/config/repo-host-read-baseline.txt @@ -26,7 +26,7 @@ 2 src/main/orca-profiles/project-transfer/profile-project-transfer-payload.ts 1 src/main/orca-profiles/project-transfer/profile-project-worktree-identity.ts 1 src/main/persistence/leasing-ssh-ptys/ssh-target-reassignment.ts -1 src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.ts +1 src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.ts 2 src/main/persistence/restoring-sessions/folder-scope-migration.ts 1 src/main/persistence/restoring-sessions/tab-terminal-pane-binding-repair.ts 1 src/main/persistence/tracking-repos/local-worktree-metadata-scan-expectation.ts diff --git a/config/scripts/ci/sharding/ci-shard-timings.json b/config/scripts/ci/sharding/ci-shard-timings.json index ae3d0757cf4..a21f29d2d5b 100644 --- a/config/scripts/ci/sharding/ci-shard-timings.json +++ b/config/scripts/ci/sharding/ci-shard-timings.json @@ -2619,7 +2619,6 @@ "src/main/orca-profiles/project-transfer/profile-project-transfer-migration.test.ts": 1642, "src/main/orca-profiles/project-transfer/profile-project-transfer.test.ts": 1456, "src/main/orca-profiles/profile-telemetry-consent-seed.test.ts": 536, - "src/main/persistence/migrating-orcad-catalog/orcad-migration-export-holds.test.ts": 231, "src/main/orcad/electron-serve-provider-selection.test.ts": 554, "src/main/orcad/electron-sidecar-tab-registry.test.ts": 105, "src/main/orcad/external-chromium-browser-session.test.ts": 152, @@ -2660,9 +2659,8 @@ "src/main/orcad/orcad-startup-qualification.test.ts": 102, "src/main/orcad/orcad-stop-request-shutdown.integration.test.ts": 293, "src/main/orcad/orcad-windows-conpty-breakaway.integration.test.ts": 79, - "src/main/persistence/migrating-orcad-catalog/persistence-local-only-worktree-meta.test.ts": 1948, "src/main/persistence/preferences/persistence-onboarding-language-cohort.test.ts": 1760, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-wsl-generation-reuse.test.ts": 1658, + "src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-wsl-generation-reuse.test.ts": 1658, "src/main/persistence/applying-settings/persistence-automation-extra-agent-args.test.ts": 2268, "src/main/persistence/applying-settings/persistence-automation-mode-precondition.test.ts": 1595, "src/main/persistence/applying-settings/persistence-automations.test.ts": 2573, @@ -2697,54 +2695,45 @@ "src/main/persistence/loading-store/workspace-sessions/workspace-session-partitions.test.ts": 545, "src/main/persistence/loading-store/workspace-sessions/workspace-session-terminal-binding-replay.test.ts": 95, "src/main/persistence/loading-store/worktree-metadata/worktree-meta-write-normalization.test.ts": 127, - "src/main/persistence/migrating-orcad-catalog/migration-journal-directory.test.ts": 91, - "src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.test.ts": 296, - "src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.test.ts": 466, - "src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.test.ts": 375, - "src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.test.ts": 518, - "src/main/persistence/migrating-orcad-catalog/orcad-source-export.test.ts": 1898, - "src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.test.ts": 380, - "src/main/persistence/migrating-orcad-catalog/orcad-source-partial-partition.test.ts": 808, - "src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.test.ts": 303, - "src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-ambiguity.test.ts": 275, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-blobs.test.ts": 1840, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog.test.ts": 2232, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-received-blob-durability.test.ts": 1796, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-install-safety.test.ts": 1886, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-login-shell.test.ts": 2041, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history.test.ts": 2085, - "src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-terminal-restore-hints.test.ts": 2098, - "src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.test.ts": 795, - "src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.test.ts": 774, - "src/main/persistence/moving-wsl-projects/wsl-move-driver-commit-reproof.test.ts": 1159, - "src/main/persistence/moving-wsl-projects/wsl-move-driver-fault-injection.test.ts": 7608, - "src/main/persistence/moving-wsl-projects/wsl-move-driver-preview-settle.test.ts": 1031, - "src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.test.ts": 92, - "src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.test.ts": 145, - "src/main/persistence/moving-wsl-projects/wsl-move-gate-stub-agent-hooks.test.ts": 743, - "src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.test.ts": 260, - "src/main/persistence/moving-wsl-projects/wsl-move-guest-process-table-cost.test.ts": 323, - "src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.test.ts": 863, + "src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.test.ts": 91, + "src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.test.ts": 296, + "src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.test.ts": 466, + "src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.test.ts": 375, + "src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.test.ts": 518, + "src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.test.ts": 1898, + "src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.test.ts": 380, + "src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-partial-partition.test.ts": 808, + "src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.test.ts": 303, + "src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-ambiguity.test.ts": 275, + "src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-blobs.test.ts": 1840, + "src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog.test.ts": 2232, + "src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-received-blob-durability.test.ts": 1796, + "src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-install-safety.test.ts": 1886, + "src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-login-shell.test.ts": 2041, + "src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history.test.ts": 2085, + "src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-terminal-restore-hints.test.ts": 2098, + "src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.test.ts": 795, + "src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.test.ts": 774, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.test.ts": 92, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.test.ts": 145, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.test.ts": 260, + "src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.test.ts": 863, "src/main/persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite.test.ts": 1245, - "src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-stage1.test.ts": 338, - "src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-user-choices.test.ts": 638, + "src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-stage1.test.ts": 338, + "src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-user-choices.test.ts": 638, "src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test.ts": 567, - "src/main/persistence/moving-wsl-projects/wsl-move-quiesce.test.ts": 413, - "src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts": 1939, - "src/main/persistence/moving-wsl-projects/wsl-move-reset.test.ts": 891, - "src/main/persistence/moving-wsl-projects/wsl-move-retention.test.ts": 2285, - "src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts": 641, - "src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.test.ts": 639, - "src/main/persistence/moving-wsl-projects/wsl-move-scope.test.ts": 104, - "src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.test.ts": 398, - "src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.test.ts": 2013, - "src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.test.ts": 411, - "src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.test.ts": 194, - "src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.test.ts": 466, - "src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.test.ts": 137, - "src/main/persistence/moving-wsl-projects/wsl-move-two-desktops.test.ts": 2512, - "src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.test.ts": 465, - "src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.test.ts": 691, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.test.ts": 413, + "src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.test.ts": 891, + "src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-ledger.test.ts": 641, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.test.ts": 639, + "src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.test.ts": 104, + "src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.test.ts": 398, + "src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.test.ts": 2013, + "src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.test.ts": 411, + "src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.test.ts": 194, + "src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.test.ts": 466, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.test.ts": 137, + "src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.test.ts": 465, "src/main/persistence/persistence-async-write-syscalls.test.ts": 3419, "src/main/persistence/persistence-cohort-and-identity-migration.test.ts": 2224, "src/main/persistence/persistence-flush-and-save-scheduling.test.ts": 3361, @@ -4046,18 +4035,18 @@ "src/main/managed-server/migration/catalog/orcad-migration-catalog-client-source-kind.test.ts": 400, "src/main/managed-server/migration/catalog/orcad-migration-catalog-client.test.ts": 400, "src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.test.ts": 2408, - "src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.test.ts": 369, + "src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.test.ts": 369, "src/main/managed-server/migration/cutover/orcad-migration-delta-move.test.ts": 3812, "src/main/managed-server/migration/cutover/orcad-migration-delta-snapshot.test.ts": 2611, "src/main/managed-server/migration/linking/orcad-migration-repository-link.test.ts": 4281, "src/main/managed-server/migration/transfers/orcad-migration-snapshot-coordinator.test.ts": 309, "src/main/ssh/migration-source/orcad-migration-source-fence.test.ts": 2000, - "src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.test.ts": 2297, + "src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.test.ts": 2297, "src/main/managed-server/migration/cutover/orcad-migration-stuck-host-profiles.test.ts": 2402, "src/main/ssh/migration-source/orcad-migration-terminal-gate.test.ts": 63, "src/main/managed-server/install/orcad-remote-deploy.test.ts": 537, "src/main/managed-server/activation/orcad-retained-fence-takeover.test.ts": 210, - "src/main/persistence/migrating-orcad-catalog/orcad-retained-source-changes.test.ts": 2185, + "src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-changes.test.ts": 2185, "src/main/managed-server/lifecycle/orcad-runtime-maintenance.test.ts": 916, "src/main/managed-server/host-state/orcad-snapshot-room.test.ts": 402, "src/main/managed-server/lifecycle/orcad-stdio-bridge.test.ts": 627, @@ -4373,7 +4362,7 @@ "src/main/workspaces/removal/retirement/worktree-retirement-discovery-wsl.test.ts": 355, "src/main/workspaces/creation/worktree-root-preparation.test.ts": 180, "src/main/workspaces/removal/worktree-trash.test.ts": 126, - "src/main/persistence/moving-wsl-projects/wsl-approved-root-race.wsl.test.ts": 102, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-approved-root-race.wsl.test.ts": 102, "src/main/wsl/discovery/wsl-background-distro-gate.test.ts": 674, "src/main/wsl/discovery/wsl-console-running-distros.test.ts": 57, "src/main/wsl/discovery/wsl-distro-list-output.test.ts": 43, @@ -4381,7 +4370,7 @@ "src/main/wsl/execution/wsl-interop-spawn-directory.test.ts": 52, "src/main/wsl/discovery/wsl-last-seen-running-age.test.ts": 84, "src/main/wsl/execution/wsl-managed-cli-path-restore.test.ts": 68, - "src/main/persistence/moving-wsl-projects/wsl-move-incidental-writes.test.ts": 1170, + "src/main/persistence/moving-wsl-projects/quiescence/wsl-move-incidental-writes.test.ts": 1170, "src/main/wsl/discovery/wsl-running-distro-stop.test.ts": 42, "src/main/wsl/discovery/wsl-running-distros.test.ts": 201, "src/main/wsl/filesystem/wsl-running-path-filter.test.ts": 57, diff --git a/config/scripts/workflow/source-routing/pr-e2e-source-routing.mjs b/config/scripts/workflow/source-routing/pr-e2e-source-routing.mjs index 7da6a6823ae..9563c85d9a6 100644 --- a/config/scripts/workflow/source-routing/pr-e2e-source-routing.mjs +++ b/config/scripts/workflow/source-routing/pr-e2e-source-routing.mjs @@ -35,7 +35,7 @@ const MANAGED_SSH_HARNESS = // An enabled SSH automation moves with its host and is re-enabled on the server (#29083). const ENABLED_AUTOMATION_MOVE = - /^src\/(?:main\/(?:persistence\/(?:migrating-orcad-catalog\/orcad-(?:source-automation-state|source-dormant-state|source-dependency-census|destination-automation-state)|scheduling-automations\/automation-schedule-operations)|automations\/(?:run-target-resolution|automation-dispatch-request|orcad-fenced-automation)|ssh\/orcad-migration-(?:moved-automations|source-retention))|shared\/orcad-migration\/orcad-migration-(?:dormant-automation-validation|source-cutover))\.ts$/ + /^src\/(?:main\/(?:persistence\/(?:migrating-orcad-catalog\/(?:source\/(?:automations\/orcad-source-automation-state|dormancy\/orcad-source-dormant-state|sessions\/orcad-source-dependency-census)|destination\/orcad-destination-automation-state)|scheduling-automations\/automation-schedule-operations)|automations\/(?:run-target-resolution|automation-dispatch-request|orcad-fenced-automation)|persistence\/migrating-orcad-catalog\/retained-source\/orcad-migration-(?:moved-automations|source-retention))|shared\/orcad-migration\/orcad-migration-(?:dormant-automation-validation|source-cutover))\.ts$/ export const PR_E2E_SOURCE_ROUTES = [ ...PR_BROWSER_E2E_SOURCE_ROUTES, @@ -174,7 +174,7 @@ export const PR_E2E_SOURCE_ROUTES = [ MANAGED_SSH_HARNESS.test(file) || ENABLED_AUTOMATION_MOVE.test(file) || (isProductSource(file) && - /^src\/(?:main\/(?:ipc\/ssh\/(?:ssh-connect-flow|ssh-host-server-)|ssh\/(?:ssh-session-start-failure|ssh-host-server-|connection\/ssh-connection-manager|orcad-migration-refusal-reason|targets\/ssh-target-orcad-preflight)|managed-server\/lifecycle\/orcad-runtime-conversion|persistence\/migrating-orcad-catalog\/orcad-source-(?:automation-state|leave-behind-view))|renderer\/src\/(?:ssh\/(?:ssh-host-server-status-copy|ssh-connect-failure-toast)|components\/settings\/(?:SshTargetServerStatus|SshHostMoveAnywayAction|SshTargetCard)))/.test( + /^src\/(?:main\/(?:ipc\/ssh\/(?:ssh-connect-flow|ssh-host-server-)|ssh\/(?:ssh-session-start-failure|ssh-host-server-|connection\/ssh-connection-manager|orcad-migration-refusal-reason|targets\/ssh-target-orcad-preflight)|managed-server\/lifecycle\/orcad-runtime-conversion|persistence\/migrating-orcad-catalog\/source\/(?:automations\/orcad-source-automation-state|catalog\/orcad-source-leave-behind-view))|renderer\/src\/(?:ssh\/(?:ssh-host-server-status-copy|ssh-connect-failure-toast)|components\/settings\/(?:SshTargetServerStatus|SshHostMoveAnywayAction|SshTargetCard)))/.test( file )) }, @@ -352,7 +352,7 @@ export const PR_E2E_SOURCE_ROUTES = [ matches: (file) => MANAGED_SSH_HARNESS.test(file) || (isProductSource(file) && - /^src\/main\/(?:persistence\/migrating-orcad-catalog\/orcad-source-(?:draft-rename|workspace-session|session-copy-resolution|export)|ssh\/orcad-migration-source-retention|ipc\/ssh\/ssh)\.ts$/.test( + /^src\/main\/(?:persistence\/migrating-orcad-catalog\/source\/(?:worktrees\/orcad-source-draft-rename|sessions\/orcad-source-(?:workspace-session|session-copy-resolution)|catalog\/orcad-source-export)|persistence\/migrating-orcad-catalog\/retained-source\/orcad-migration-source-retention|ipc\/ssh\/ssh)\.ts$/.test( file )) }, diff --git a/config/scripts/workflow/source-routing/pr-wsl-e2e-source-routes.mjs b/config/scripts/workflow/source-routing/pr-wsl-e2e-source-routes.mjs index 02911e9b506..45090505483 100644 --- a/config/scripts/workflow/source-routing/pr-wsl-e2e-source-routes.mjs +++ b/config/scripts/workflow/source-routing/pr-wsl-e2e-source-routes.mjs @@ -22,7 +22,7 @@ export const PR_WSL_E2E_SOURCE_ROUTES = [ id: 'wsl-move.fence', specs: ['tests/e2e/wsl-move-fence.spec.ts'], matches: (file) => - /^src\/(?:main\/(?:persistence\/moving-wsl-projects\/wsl-move-(?:scope-guard|fence|reset|startup|startup-rewrite|cutover-journal)|ipc\/pty\/host-env\/spawn-cwd|wsl\/host-lifecycle\/wsl-host-gate(?:-startup)?)|shared\/wsl-move\/wsl-move-cutover)\.ts$/.test( + /^src\/(?:main\/(?:persistence\/moving-wsl-projects\/(?:quiescence\/wsl-move-(?:scope-guard|fence)|cutover-recovery\/wsl-move-(?:reset|cutover-journal)|startup\/wsl-move-(?:startup|startup-rewrite))|ipc\/pty\/host-env\/spawn-cwd|wsl\/host-lifecycle\/wsl-host-gate(?:-startup)?)|shared\/wsl-move\/wsl-move-cutover)\.ts$/.test( file ) }, diff --git a/src/main/agent-hooks/first-work/first-work-branch-rename.ts b/src/main/agent-hooks/first-work/first-work-branch-rename.ts index b0be745b23a..d75e0cdeb0d 100644 --- a/src/main/agent-hooks/first-work/first-work-branch-rename.ts +++ b/src/main/agent-hooks/first-work/first-work-branch-rename.ts @@ -30,7 +30,7 @@ import type { CommitMessageAgentEnvironmentResolvers } from '../../text-generati import type { AgentGenerationFailureOutput } from '../../text-generation/agent-failure-output' import { resolveGenerationTarget } from './first-work-generation-target' import { runFolderWorkspaceTitleAutoRename } from './first-work-workspace-title-rename' -import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { clearFirstWorkGenerationFailures, isFirstWorkGenerationBackingOff, diff --git a/src/main/agent-hooks/first-work/first-work-rename-runtime.ts b/src/main/agent-hooks/first-work/first-work-rename-runtime.ts index 42152d68a16..38efbe7aace 100644 --- a/src/main/agent-hooks/first-work/first-work-rename-runtime.ts +++ b/src/main/agent-hooks/first-work/first-work-rename-runtime.ts @@ -6,7 +6,7 @@ import type { FirstWorkBranchRenameDeps } from './first-work-branch-rename' import { rememberBranchRenameFailureOutput } from './branch-rename-failure-output' import { renameWorktreeFolderOnFirstWork } from './first-work-folder-rename' import { moveWorktree } from '../../git/worktrees/movement/worktree-move' -import { isWslMoveFolderWorkspaceBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveFolderWorkspaceBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import type { Store } from '../../persistence/loading-store/store' import type { RuntimeStore } from '../../runtime/construction/runtime-store-contract' import type { OrcaRuntimeService } from '../../runtime/orca-runtime' diff --git a/src/main/automations/automation-wsl-move-refusal.test.ts b/src/main/automations/automation-wsl-move-refusal.test.ts index 591c5934418..fe93ebf04f0 100644 --- a/src/main/automations/automation-wsl-move-refusal.test.ts +++ b/src/main/automations/automation-wsl-move-refusal.test.ts @@ -12,11 +12,11 @@ import { seedWslMoveCutover } from '../persistence/__fixtures__/wsl-mover/wsl-mo import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { runWslMoveDesktopRewritePass } from '../persistence/moving-wsl-projects/wsl-move-desktop-rewrite' -import { resetWslMoveDesktopRewriteStoresForTests } from '../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' -import { registerWslMoveMainRewriteStores } from '../persistence/moving-wsl-projects/wsl-move-main-rewrite-stores' -import { registerWslMoveOrchestrationHistoryStore } from '../persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite' +} from '../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { runWslMoveDesktopRewritePass } from '../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' +import { resetWslMoveDesktopRewriteStoresForTests } from '../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' +import { registerWslMoveMainRewriteStores } from '../persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores' +import { registerWslMoveOrchestrationHistoryStore } from '../persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite' import { orchestrationDbFile } from '../runtime/orchestration/db/orchestration-db-file' import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../shared/wsl-host-internal-gate' import { OrchestrationDb } from '../runtime/orchestration/db/orchestration-db' diff --git a/src/main/automations/dispatch-refusal-wsl-move.test.ts b/src/main/automations/dispatch-refusal-wsl-move.test.ts index b4731618cad..01d20ec5bf1 100644 --- a/src/main/automations/dispatch-refusal-wsl-move.test.ts +++ b/src/main/automations/dispatch-refusal-wsl-move.test.ts @@ -8,7 +8,7 @@ import { seedWslMoveCutover } from '../persistence/__fixtures__/wsl-mover/wsl-mo import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { NO_DISPATCH_HOST, WSL_MOVE_IN_PROGRESS, diff --git a/src/main/automations/dispatch-refusal.ts b/src/main/automations/dispatch-refusal.ts index 7c371b5b1c2..a6674abcfa5 100644 --- a/src/main/automations/dispatch-refusal.ts +++ b/src/main/automations/dispatch-refusal.ts @@ -3,7 +3,7 @@ import type { Store } from '../persistence/loading-store/store' import type { Automation } from '../../shared/automations/automation-definition' import { resolveAutomationRunTarget, type AutomationRunTargetResult } from './run-target-resolution' import type { AutomationRunWriter } from './automation-run-writer' -import { wslMoveRepoBackoff } from '../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { wslMoveRepoBackoff } from '../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { isOrcadFencedAutomation } from './orcad-fenced-automation' import { blockedWslDistroForPath } from '../wsl/filesystem/wsl-unc-access-gate' import { getLocalProjectWorktreeGitOptions } from '../workspaces/execution-host/project-runtime-git-options' diff --git a/src/main/automations/orcad-fenced-automation.ts b/src/main/automations/orcad-fenced-automation.ts index e5f5262726c..d2e7045c076 100644 --- a/src/main/automations/orcad-fenced-automation.ts +++ b/src/main/automations/orcad-fenced-automation.ts @@ -4,7 +4,7 @@ import type { SshTarget } from '../../shared/ssh-types' import type { Store } from '../persistence/loading-store/store' import { isManagedOrcadSshTarget } from '../ssh/targets/ssh-target-runtime-ownership' import { moveProjectToManagedHostFirst } from '../../shared/managed-orcad-ssh-owner' -import { listOrcadMigrationCutoverChainForTarget } from '../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { listOrcadMigrationCutoverChainForTarget } from '../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' export const ORCAD_FENCED_AUTOMATION = "This automation now runs on its SSH host's Orca server." diff --git a/src/main/ipc/hooks/register-worktree-hook-file-handlers.ts b/src/main/ipc/hooks/register-worktree-hook-file-handlers.ts index 8d36601f2aa..6ae2f5b4ae7 100644 --- a/src/main/ipc/hooks/register-worktree-hook-file-handlers.ts +++ b/src/main/ipc/hooks/register-worktree-hook-file-handlers.ts @@ -10,7 +10,7 @@ import { import { broadcastWhenWslDistroRunning } from '../preflight-wsl-refusal-retry' import { resolveRepoForExecutionHost } from '../worktrees/repo-host-ownership' import type { WorktreeIpcContext } from '../worktrees/worktree-ipc-context' -import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' /** Route private command overrides to the owning host without changing shared hook settings. */ export function registerWorktreeHookFileHandlers(context: WorktreeIpcContext): void { diff --git a/src/main/ipc/pty/host-env/spawn-cwd-wsl-move.test.ts b/src/main/ipc/pty/host-env/spawn-cwd-wsl-move.test.ts index 1fb8d8d0e46..d89b5d3fd62 100644 --- a/src/main/ipc/pty/host-env/spawn-cwd-wsl-move.test.ts +++ b/src/main/ipc/pty/host-env/spawn-cwd-wsl-move.test.ts @@ -8,7 +8,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { assertWorkspaceAcceptsNewPty } from './spawn-cwd' const { listLiveDaemonPtyIds } = vi.hoisted(() => ({ diff --git a/src/main/ipc/pty/host-env/spawn-cwd.ts b/src/main/ipc/pty/host-env/spawn-cwd.ts index 50560daeacc..356a2be11f2 100644 --- a/src/main/ipc/pty/host-env/spawn-cwd.ts +++ b/src/main/ipc/pty/host-env/spawn-cwd.ts @@ -23,7 +23,7 @@ import { wslMoveHostDistro, wslMoveProjectRefForWorkspace, WslMoveProjectFencedError -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { listLiveDaemonPtyIds } from '../../../daemon/providers/lifecycle/daemon-provider-state' import { wslDistroHoldMessage } from '../../../../shared/wsl-distro-stopped-hold' import { diff --git a/src/main/ipc/pty/ipc/spawn-push-target-materialization.ts b/src/main/ipc/pty/ipc/spawn-push-target-materialization.ts index 41ebff35ae5..423abdbc816 100644 --- a/src/main/ipc/pty/ipc/spawn-push-target-materialization.ts +++ b/src/main/ipc/pty/ipc/spawn-push-target-materialization.ts @@ -2,7 +2,7 @@ import { splitWorktreeIdForFilesystem } from '../../../../shared/worktree/id' import { triggerTerminalSpawnPushTargetMaterialization } from '../../../runtime/terminal/launch/runtime-terminal-spawn-push-target-materialization' import type { PtySpawnIpcArgs, PtySpawnIpcDeps } from './spawn-types' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' -import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' // GUI terminals can run Git before Orca sync; request deferred push-target setup on spawn and reattach (#17828). export function triggerPtySpawnPushTargetMaterialization( diff --git a/src/main/ipc/renderer-shutdown-checkpoint.ts b/src/main/ipc/renderer-shutdown-checkpoint.ts index b0fb0a9b5e0..ba7e49055cc 100644 --- a/src/main/ipc/renderer-shutdown-checkpoint.ts +++ b/src/main/ipc/renderer-shutdown-checkpoint.ts @@ -9,8 +9,8 @@ import { applyCommandToSession } from '../persistence/terminal-topology/terminal import type { PersistedUIState } from '../../shared/persisted-ui-state-types' import type { WorkspaceSessionState } from '../../shared/workspace-session/workspace-session-state-types' import type { Store } from '../persistence/loading-store/store' -import { isFrozenOrcadSourceSessionPartition } from '../persistence/migrating-orcad-catalog/orcad-source-visibility' -import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/wsl-move-window-write-hold' +import { isFrozenOrcadSourceSessionPartition } from '../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' +import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import { windowViewSaveForMain, type ReconnectFactsFor } from '../persistence/window-save-view' import { reportWindowSaveDrift } from '../persistence/window-save-divergence' import { ORCA_LAYOUT_OWNER_IS_MAIN } from '../../shared/layout-owner-switch' diff --git a/src/main/ipc/repos-execution-host-catalog.test.ts b/src/main/ipc/repos-execution-host-catalog.test.ts index 301376c8904..7d3312a4276 100644 --- a/src/main/ipc/repos-execution-host-catalog.test.ts +++ b/src/main/ipc/repos-execution-host-catalog.test.ts @@ -60,7 +60,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' const { handleMock, mockStore } = reposMocks diff --git a/src/main/ipc/repos/folder-workspace-handlers.ts b/src/main/ipc/repos/folder-workspace-handlers.ts index 84eca8181bc..715c9fe2de0 100644 --- a/src/main/ipc/repos/folder-workspace-handlers.ts +++ b/src/main/ipc/repos/folder-workspace-handlers.ts @@ -16,12 +16,12 @@ import { FolderWorkspaceUpdateArgs, parseProjectGroupIpcArgs } from './repo-ipc-arg-schemas' -import { visibleFolderWorkspaces } from '../../persistence/migrating-orcad-catalog/orcad-source-visibility' +import { visibleFolderWorkspaces } from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' import { createFolderWorkspaceWithPluginHooks } from '../../plugins/hooks/workspace-create-plugin-hook' import { isLocalWslMoveRow, shouldDropWslMoveProjectUpdate -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export function registerFolderWorkspaceHandlers( mainWindow: BrowserWindow, diff --git a/src/main/ipc/repos/project-group-handlers.ts b/src/main/ipc/repos/project-group-handlers.ts index bb9462b3349..17e89cc2575 100644 --- a/src/main/ipc/repos/project-group-handlers.ts +++ b/src/main/ipc/repos/project-group-handlers.ts @@ -1,5 +1,4 @@ -import type { BrowserWindow } from 'electron' -import { ipcMain } from 'electron' +import { type BrowserWindow, ipcMain } from 'electron' import type { Store } from '../../persistence/loading-store/store' import type { Repo } from '../../../shared/repo-types' import type { RepoHostTarget } from '../../../shared/repo-host-identity' @@ -18,9 +17,9 @@ import { import { assertWslMoveProjectWritable, assertWslMoveRepoWritable -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { activeNestedRepoScans, runNestedRepoScanForIpc } from './nested-repo-scan-ipc' -import { visibleProjectGroups } from '../../persistence/migrating-orcad-catalog/orcad-source-visibility' +import { visibleProjectGroups } from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' export function registerProjectGroupHandlers(mainWindow: BrowserWindow, store: Store): void { ipcMain.handle('projectGroups:list', () => visibleProjectGroups(store)) diff --git a/src/main/ipc/repos/project-host-setup-handlers.ts b/src/main/ipc/repos/project-host-setup-handlers.ts index 7326003eb2e..1e0cfb9f15c 100644 --- a/src/main/ipc/repos/project-host-setup-handlers.ts +++ b/src/main/ipc/repos/project-host-setup-handlers.ts @@ -1,5 +1,4 @@ -import type { BrowserWindow } from 'electron' -import { ipcMain } from 'electron' +import { type BrowserWindow, ipcMain } from 'electron' import type { Store } from '../../persistence/loading-store/store' import type { Repo } from '../../../shared/repo-types' import type { @@ -37,7 +36,7 @@ import { getSshTargetRegistryStore } from '../../ssh/targets/ssh-target-registry import { assertWslMoveHostSetupIdWritable, assertWslMoveHostSetupWritable -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' function buildProjectHostSetupResult(store: Store, repo: Repo): ProjectHostSetupResult { const setup = getProjectHostSetupForRepo(store.getProjectHostSetups(), repo) diff --git a/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts b/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts index 98cdb340348..0d8646de1a8 100644 --- a/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts +++ b/src/main/ipc/repos/project-host-setup-wsl-move-fence.test.ts @@ -12,7 +12,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { RuntimeProjectHostSetupController } from '../../runtime/repositories/runtime-project-host-setup-controller' import { RuntimeRepositoryIssueCommand } from '../../runtime/repositories/runtime-repository-issue-command' import { RuntimeRepositorySettingsController } from '../../runtime/repositories/runtime-repository-settings-controller' diff --git a/src/main/ipc/repos/repo-catalog-handlers.ts b/src/main/ipc/repos/repo-catalog-handlers.ts index 8142efccef8..1b8caa4b0ac 100644 --- a/src/main/ipc/repos/repo-catalog-handlers.ts +++ b/src/main/ipc/repos/repo-catalog-handlers.ts @@ -16,13 +16,13 @@ import { ProjectUpdateIpcArgs, parseProjectGroupIpcArgs } from './repo-ipc-arg-s import { visibleProjectHostSetups, visibleRepos -} from '../../persistence/migrating-orcad-catalog/orcad-source-visibility' +} from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' import { assertWslMoveProjectWritable, assertWslMoveReposWritable, isWslMoveSourceHost -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { listWslMovedProjects } from '../../persistence/moving-wsl-projects/wsl-moved-projects' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { listWslMovedProjects } from '../../persistence/moving-wsl-projects/desktop-state/wsl-moved-projects' import { listHostRepoCatalogSnapshots } from '../../host-repo-catalog-snapshot/host-repo-catalog-snapshot-recorder' import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' import { getRuntimeEnvironmentRegistryRoot } from '../runtime-environments/runtime-environment-registry-root' diff --git a/src/main/ipc/repos/repo-ipc-wsl-move-fence.test.ts b/src/main/ipc/repos/repo-ipc-wsl-move-fence.test.ts index 60c0195d880..f1c4874ba5a 100644 --- a/src/main/ipc/repos/repo-ipc-wsl-move-fence.test.ts +++ b/src/main/ipc/repos/repo-ipc-wsl-move-fence.test.ts @@ -12,7 +12,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { RuntimeRepositorySettingsController } from '../../runtime/repositories/runtime-repository-settings-controller' import { registerFolderWorkspaceHandlers } from './folder-workspace-handlers' import { runtimeRepoSelectorText } from '../../runtime/workspaces/catalog/runtime-repo-selector' diff --git a/src/main/ipc/repos/repo-update-handler.ts b/src/main/ipc/repos/repo-update-handler.ts index d4fea3f3571..ed2d613fa08 100644 --- a/src/main/ipc/repos/repo-update-handler.ts +++ b/src/main/ipc/repos/repo-update-handler.ts @@ -1,15 +1,21 @@ -import type { BrowserWindow } from 'electron' -import { ipcMain } from 'electron' +import { type BrowserWindow, ipcMain } from 'electron' import type { Store } from '../../persistence/loading-store/store' import type { Repo } from '../../../shared/repo-types' import type { RepoHostTarget } from '../../../shared/repo-host-identity' import { isFolderRepo } from '../../../shared/repo-kind' -import type { ExecutionHostId } from '../../../shared/execution-host' -import { getRepoExecutionHostId, normalizeExecutionHostId } from '../../../shared/execution-host' + +import { + type ExecutionHostId, + getRepoExecutionHostId, + normalizeExecutionHostId +} from '../../../shared/execution-host' import { normalizeRepoBadgeColor } from '../../../shared/repo-badge-color' import { sanitizeRepoIcon } from '../../../shared/repo-icon' -import { normalizeGhAccountBinding } from '../../../shared/github/account-binding' -import type { GhAccountBinding } from '../../../shared/github/account-binding' +import { + normalizeGhAccountBinding, + type GhAccountBinding +} from '../../../shared/github/account-binding' + import { normalizeRepoSourceControlAiOverrides } from '../../../shared/source-control/ai/settings/source-control-ai-repo-settings' import { normalizeCustomWorktreeVisibilitySources, @@ -23,7 +29,7 @@ import { notifyReposChanged } from './repos-changed-notification' import { assertWslMoveProjectWritable, isWslMoveSourceHost -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export function registerRepoUpdateHandler(mainWindow: BrowserWindow, store: Store): void { ipcMain.handle( diff --git a/src/main/ipc/repos/sparse-preset-handlers.ts b/src/main/ipc/repos/sparse-preset-handlers.ts index de8cf06445a..4be0a9eaf02 100644 --- a/src/main/ipc/repos/sparse-preset-handlers.ts +++ b/src/main/ipc/repos/sparse-preset-handlers.ts @@ -1,5 +1,4 @@ -import type { BrowserWindow } from 'electron' -import { ipcMain } from 'electron' +import { type BrowserWindow, ipcMain } from 'electron' import { randomUUID } from 'node:crypto' import type { Store } from '../../persistence/loading-store/store' import type { SparsePreset } from '../../../shared/worktree/create-types' @@ -11,7 +10,7 @@ import { SparsePresetValidationError, type SparsePresetFailure } from '../../../shared/worktree/sparse-preset-failure' -import { assertWslMoveProjectWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveProjectWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export function registerSparsePresetHandlers(mainWindow: BrowserWindow, store: Store): void { ipcMain.handle('sparsePresets:list', (_event, args: { repoId: string }) => { diff --git a/src/main/ipc/runtime-environments/orcad-delta-move-handlers.ts b/src/main/ipc/runtime-environments/orcad-delta-move-handlers.ts index 38b957d8f69..8db09eafd25 100644 --- a/src/main/ipc/runtime-environments/orcad-delta-move-handlers.ts +++ b/src/main/ipc/runtime-environments/orcad-delta-move-handlers.ts @@ -17,7 +17,7 @@ import { orcadMigrationDestinationFor, orcadServerAutomationEnablerFor } from '../../managed-server/lifecycle/orcad-runtime-conversion-wiring' -import { enableMovedOrcadAutomationsForTarget } from '../../persistence/migrating-orcad-catalog/orcad-migration-moved-automations' +import { enableMovedOrcadAutomationsForTarget } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations' import { requiredString } from './orcad-runtime-lifecycle-handlers' import { publishResolvedChangedHostStatus } from './runtime-environment-managed-tunnel' import { runTargetLifecycle } from '../ssh/ssh-target-lifecycle-queue' diff --git a/src/main/ipc/runtime-environments/runtime-environment-connectivity-handlers.ts b/src/main/ipc/runtime-environments/runtime-environment-connectivity-handlers.ts index c28731557b7..3fb21a36fee 100644 --- a/src/main/ipc/runtime-environments/runtime-environment-connectivity-handlers.ts +++ b/src/main/ipc/runtime-environments/runtime-environment-connectivity-handlers.ts @@ -54,7 +54,7 @@ import { assertWslHostReachable, isGatedOffWslHost } from '../../wsl/host-lifecy import { isHostSpawnFencedForWslMoveUndo, wslMoveUndoSpawnFencedResponse -} from '../../persistence/moving-wsl-projects/wsl-move-undo-spawn-fence' +} from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence' export { isRuntimeEnvironmentManuallyDisconnected } diff --git a/src/main/ipc/session.ts b/src/main/ipc/session.ts index 17f1072ff44..ea719873f26 100644 --- a/src/main/ipc/session.ts +++ b/src/main/ipc/session.ts @@ -2,9 +2,9 @@ import { ipcMain } from 'electron' import type { Store } from '../persistence/loading-store/store' import type { OrcaRuntimeService } from '../runtime/orca-runtime' import { parseTerminalSurfaceCloseTarget } from '../../shared/workspace-layout/terminal-surface-close-target' -import { isFrozenOrcadSourceSessionPartition } from '../persistence/migrating-orcad-catalog/orcad-source-visibility' -import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/wsl-move-window-write-hold' -import { visibleSessionHostIds } from '../persistence/migrating-orcad-catalog/orcad-retained-source-session' +import { isFrozenOrcadSourceSessionPartition } from '../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' +import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' +import { visibleSessionHostIds } from '../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-session' import { markAgentLaunchesClosedByUser } from '../agent-launch/agent-launch-pane-attachment' import { windowViewPatchForMain, windowViewSaveForMain } from '../persistence/window-save-view' import { reportWindowSaveDrift } from '../persistence/window-save-divergence' diff --git a/src/main/ipc/ssh/ssh-host-server-on-connect-wiring.ts b/src/main/ipc/ssh/ssh-host-server-on-connect-wiring.ts index fc49d4d4658..1287943e670 100644 --- a/src/main/ipc/ssh/ssh-host-server-on-connect-wiring.ts +++ b/src/main/ipc/ssh/ssh-host-server-on-connect-wiring.ts @@ -4,10 +4,10 @@ import { managedOrcadServerName } from '../../../shared/managed-orcad-ssh-owner' import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' -import { findOrcadMigrationSourceCutoverForTarget } from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { abandonOrcadConversion } from '../../managed-server/migration/cutover/orcad-conversion-abandon' -import { retainOrcadMigrationSource } from '../../persistence/migrating-orcad-catalog/orcad-migration-source-retention' -import { enableMovedOrcadAutomationsForTarget } from '../../persistence/migrating-orcad-catalog/orcad-migration-moved-automations' +import { retainOrcadMigrationSource } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention' +import { enableMovedOrcadAutomationsForTarget } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations' import { hasOrcadTemplate } from '../../orcad/orcad-artifact-materializer' import { isOrcadHostUnavailableFixableOnHost } from '../../orcad/orcad-host-unavailable' import { managedServerUpdateDeps } from '../../ssh/host-server/managed-server-update-deps' diff --git a/src/main/ipc/ssh/ssh.ts b/src/main/ipc/ssh/ssh.ts index 6a9bd3262c6..f06b7f3454a 100644 --- a/src/main/ipc/ssh/ssh.ts +++ b/src/main/ipc/ssh/ssh.ts @@ -65,9 +65,9 @@ import { resetSshShutdownDrain } from './ssh-shutdown-drain' import { registerSshTargetCrudHandlers } from './ssh-target-crud-handlers' import { targetLifecycleInFlight } from './ssh-target-lifecycle-queue' import { disposeOrcadManagedTunnels } from '../../managed-server/lifecycle/orcad-managed-tunnel' -import { retainUnretainedOrcadMigrationSources } from '../../persistence/migrating-orcad-catalog/orcad-migration-source-retention' -import { reconcileManagedOrcadSshTargets } from '../../persistence/migrating-orcad-catalog/orcad-retained-source' -import { installOrcadMigrationScrollbackRetention } from '../../persistence/migrating-orcad-catalog/orcad-migration-scrollback-retention-wiring' +import { retainUnretainedOrcadMigrationSources } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention' +import { reconcileManagedOrcadSshTargets } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source' +import { installOrcadMigrationScrollbackRetention } from '../../persistence/migrating-orcad-catalog/terminal-history/orcad-migration-scrollback-retention-wiring' import { getAppEnvironment } from '../../../shared/app-environment' import { registerLegacyRelayBridgeIpc } from '../../ssh/legacy-relay/bridge/legacy-relay-bridge-ipc' import { diff --git a/src/main/ipc/ui.ts b/src/main/ipc/ui.ts index 6b3acd1882e..a35b9a5c907 100644 --- a/src/main/ipc/ui.ts +++ b/src/main/ipc/ui.ts @@ -9,7 +9,7 @@ import { BrowserWindow, ipcMain, webContents, type WebContents } from 'electron' import type { Store } from '../persistence/loading-store/store' import type { PersistedUIState } from '../../shared/persisted-ui-state-types' import { isFeatureInteractionId } from '../../shared/feature-interactions' -import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/wsl-move-window-write-hold' +import { isWslMoveWindowWriteHeld } from '../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import { isTrustedMainRendererSender } from './main-renderer-sender-trust' let trustedUIRendererWebContentsId: number | null = null diff --git a/src/main/ipc/worktree-remote.ts b/src/main/ipc/worktree-remote.ts index 58a1a6d444b..ed33dd0cf6b 100644 --- a/src/main/ipc/worktree-remote.ts +++ b/src/main/ipc/worktree-remote.ts @@ -182,7 +182,7 @@ import { openWorktreeCreatePathClaim, type WorktreeCreatePathClaim } from '../workspaces/creation/worktree-create-in-flight' -import { isWslMoveWorktreeBlocked } from '../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveWorktreeBlocked } from '../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { hostWorktreeTarget, type HostWorktreeTarget diff --git a/src/main/ipc/worktrees/create/register-worktree-create-handlers.ts b/src/main/ipc/worktrees/create/register-worktree-create-handlers.ts index 60a43933f42..0050e90b84d 100644 --- a/src/main/ipc/worktrees/create/register-worktree-create-handlers.ts +++ b/src/main/ipc/worktrees/create/register-worktree-create-handlers.ts @@ -12,8 +12,8 @@ import { addWorktreeCreatePhaseAttributes, withWorktreeSpan } from '../../../observability/instrumentation' -import { workspaceSourceSchema } from '../../../../shared/telemetry-events' -import type { WorkspaceSource } from '../../../../shared/telemetry-events' +import { workspaceSourceSchema, type WorkspaceSource } from '../../../../shared/telemetry-events' + import { isFolderRepo } from '../../../../shared/repo-kind' import { createLocalWorktree, notifyWorktreesChanged } from '../../worktree-remote' import { SshHostNotServedError } from '../../../providers/ssh-host-not-served-error' @@ -29,7 +29,7 @@ import { getRepoExecutionHostId } from '../../../../shared/execution-host' import { workspaceLifecycleKey } from '../../../runtime/workspaces/lifecycle/workspace-lifecycle-commands' import type { WorktreeIpcContext } from '../worktree-ipc-context' import { beginWorkspaceCreateTelemetry } from '../../../workspaces/creation/workspace-create-telemetry' -import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { applyWorkspaceCreatePluginHook } from '../../../plugins/hooks/workspace-create-plugin-hook' import { withProjectWorktreeCreate } from '../../../workspaces/creation/worktree-create-in-flight' diff --git a/src/main/ipc/worktrees/listing/authoritative-local-worktree-metadata-pruning.ts b/src/main/ipc/worktrees/listing/authoritative-local-worktree-metadata-pruning.ts index d6105a76212..fdf3a15c73e 100644 --- a/src/main/ipc/worktrees/listing/authoritative-local-worktree-metadata-pruning.ts +++ b/src/main/ipc/worktrees/listing/authoritative-local-worktree-metadata-pruning.ts @@ -16,7 +16,7 @@ import { pruneWorkspaceSpaceAnalysisSnapshots } from '../../../workspaces/space- import { isLocalWorktreeScanGenerationCurrent } from '../../../workspaces/catalog/local-worktree-scan-generation' import { localWorktreePathsExistOrAreUnverifiable } from '../../../workspaces/catalog/local-worktree-path-presence' import { worktreeRetentionPathComparisonKey } from '../../../workspaces/catalog/worktree-retention-path-comparison' -import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' type AuthoritativeLocalMetadataPruneStore = Pick< Store, diff --git a/src/main/ipc/worktrees/listing/folder-workspace-catalog.ts b/src/main/ipc/worktrees/listing/folder-workspace-catalog.ts index 8a3086f5d03..d127bbc106f 100644 --- a/src/main/ipc/worktrees/listing/folder-workspace-catalog.ts +++ b/src/main/ipc/worktrees/listing/folder-workspace-catalog.ts @@ -4,7 +4,7 @@ import type { Worktree, DetectedWorktree } from '../../../../shared/worktree/typ import type { WorktreeMeta } from '../../../../shared/worktree/meta-types' import type { Store } from '../../../persistence/loading-store/store' import { mergeWorktreeMetaForWrite } from '../../../persistence/loading-store/worktree-metadata/worktree-meta-write-normalization' -import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { getRepoExecutionHostId } from '../../../../shared/execution-host' import { hostWorktreeTargetForRepo, diff --git a/src/main/ipc/worktrees/metadata/register-worktree-metadata-handlers.ts b/src/main/ipc/worktrees/metadata/register-worktree-metadata-handlers.ts index 21c66b863ac..b052e4cdef0 100644 --- a/src/main/ipc/worktrees/metadata/register-worktree-metadata-handlers.ts +++ b/src/main/ipc/worktrees/metadata/register-worktree-metadata-handlers.ts @@ -22,7 +22,7 @@ import { isWslMoveWorkspaceBlocked, shouldDropWslMoveProjectUpdate, wslMoveProjectRefForWorkspace -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export function registerWorktreeMetadataHandlers(context: WorktreeIpcContext): void { const { mainWindow, store, runtime } = context diff --git a/src/main/ipc/worktrees/removal/register-worktree-forget-handlers.ts b/src/main/ipc/worktrees/removal/register-worktree-forget-handlers.ts index 8c5d5c0c4e0..49cb9e3c145 100644 --- a/src/main/ipc/worktrees/removal/register-worktree-forget-handlers.ts +++ b/src/main/ipc/worktrees/removal/register-worktree-forget-handlers.ts @@ -5,8 +5,12 @@ import type { } from '../../../../shared/worktree/create-types' import { parseWorktreeId } from '../../worktree-logic' import { resolveWorktreeRemovalRepoOwner } from '../../../workspaces/removal/worktree-removal-repo-owner' -import { getRepoExecutionHostId, parseExecutionHostId } from '../../../../shared/execution-host' -import type { ExecutionHostId } from '../../../../shared/execution-host' +import { + getRepoExecutionHostId, + parseExecutionHostId, + type ExecutionHostId +} from '../../../../shared/execution-host' + import type { Repo } from '../../../../shared/repo-types' import { isFolderRepo } from '../../../../shared/repo-kind' import { getLocalPtyProvider } from '../../pty/provider/registry' @@ -39,7 +43,7 @@ import { assertWslMoveProjectWritable, assertWslMoveRepoWritable, isWslMoveSourceHost -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { teardownStops } from '../../../runtime/workspaces/removal/owned-session-teardown-policy' export function registerWorktreeForgetHandlers(context: WorktreeIpcContext): void { diff --git a/src/main/ipc/worktrees/removal/register-worktree-removal-handlers.ts b/src/main/ipc/worktrees/removal/register-worktree-removal-handlers.ts index 96c0db87264..eaa6eb3479f 100644 --- a/src/main/ipc/worktrees/removal/register-worktree-removal-handlers.ts +++ b/src/main/ipc/worktrees/removal/register-worktree-removal-handlers.ts @@ -23,7 +23,7 @@ import { waitForPendingWorktreeRemoval } from '../../../workspaces/removal/worktree-background-removal' import { runSerializedWorktreeRemovalAcceptance } from '../../../workspaces/removal/worktree-removal-acceptance-queue' -import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { deleteLostContact, observeTerminals, diff --git a/src/main/ipc/wsl/wsl-drive-unc-conversion-handlers.ts b/src/main/ipc/wsl/wsl-drive-unc-conversion-handlers.ts index bcc3113b0d6..516024bf23f 100644 --- a/src/main/ipc/wsl/wsl-drive-unc-conversion-handlers.ts +++ b/src/main/ipc/wsl/wsl-drive-unc-conversion-handlers.ts @@ -15,7 +15,7 @@ import { readProfileProjectTransferState } from '../../orca-profiles/project-tra import { getOrcaProfileListState } from '../../orca-profiles/profile-index-store' import { getProfileUserDataPath } from '../../orca-profiles/profile-storage-paths' import type { Store } from '../../persistence/loading-store/store' -import { pauseWslMoveScope } from '../../persistence/moving-wsl-projects/wsl-move-driver-pause' +import { pauseWslMoveScope } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-pause' import type { OrcaRuntimeService } from '../../runtime/orca-runtime' import { quitProcess } from '../../startup/process-quit-request' import { startWslDriveUncConversion } from '../../wsl/filesystem/wsl-drive-unc-conversion-run' diff --git a/src/main/ipc/wsl/wsl-move-driver-handlers.test.ts b/src/main/ipc/wsl/wsl-move-driver-handlers.test.ts index 399803d5d26..395610423a5 100644 --- a/src/main/ipc/wsl/wsl-move-driver-handlers.test.ts +++ b/src/main/ipc/wsl/wsl-move-driver-handlers.test.ts @@ -1,4 +1,4 @@ -import type * as WslMoveDriverPreviewModule from '../../persistence/moving-wsl-projects/wsl-move-driver-preview' +import type * as WslMoveDriverPreviewModule from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-preview' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' @@ -16,17 +16,19 @@ const driver = vi.hoisted(() => ({ moveProjectsToWslHost: vi.fn(async () => ({ outcome: 'moved' })), cancelWslMove: vi.fn(() => true) })) -vi.mock('../../persistence/moving-wsl-projects/wsl-move-driver', () => driver) +vi.mock('../../persistence/moving-wsl-projects/wsl-move-driver', () => ({ + moveProjectsToWslHost: driver.moveProjectsToWslHost +})) vi.mock( - '../../persistence/moving-wsl-projects/wsl-move-driver-preview', + '../../persistence/moving-wsl-projects/execution/wsl-move-driver-preview', async (importOriginal) => ({ ...(await importOriginal()), previewWslMove: driver.previewWslMove }) ) const running = vi.hoisted(() => ({ any: false })) -vi.mock('../../persistence/moving-wsl-projects/wsl-move-running-moves', () => ({ +vi.mock('../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves', () => ({ isAnyWslMoveRunning: () => running.any, cancelWslMove: driver.cancelWslMove })) diff --git a/src/main/ipc/wsl/wsl-move-driver-wiring.ts b/src/main/ipc/wsl/wsl-move-driver-wiring.ts index 68ed583e056..5ed63a7bb5c 100644 --- a/src/main/ipc/wsl/wsl-move-driver-wiring.ts +++ b/src/main/ipc/wsl/wsl-move-driver-wiring.ts @@ -22,42 +22,42 @@ import { import { HistoryReader } from '../../daemon/history/restoration/history-reader' import { orcadMigrationDestinationFor } from '../../managed-server/lifecycle/orcad-runtime-conversion-wiring' import type { Store } from '../../persistence/loading-store/store' -import { exportWslMoveManifest } from '../../persistence/moving-wsl-projects/wsl-move-manifest-export' -import { ensureWslMoveDestinationBrowserLogins } from '../../persistence/moving-wsl-projects/wsl-move-browser-cookie-copy' +import { exportWslMoveManifest } from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export' +import { ensureWslMoveDestinationBrowserLogins } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-copy' import { activeBrowserRoutePartitionOrcaProfileId } from '../../browser/routing/partitions/browser-route-partition-binding-runtime' import { wslHostBrowserRouteStorage } from '../../browser/routing/local-host-partitions/wsl-host-browser-route-partition' -import { runGatedWslMoveDesktopRewritePass } from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite' +import { runGatedWslMoveDesktopRewritePass } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import type { WslMoveDriverDeps, WslMoveHost -} from '../../persistence/moving-wsl-projects/wsl-move-driver-ports' -import { proveWslMoveTerminalsExited } from '../../persistence/moving-wsl-projects/wsl-move-exit-proof' +} from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-ports' +import { proveWslMoveTerminalsExited } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof' import { collectWslMoveGateInputs, listWslMovePanes, type WslMoveGateFactSources -} from '../../persistence/moving-wsl-projects/wsl-move-gate-facts' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts' import { classifyWslGuestPaneForeground, readWslGuestPaneShellCwd -} from '../../persistence/moving-wsl-projects/wsl-move-guest-foreground' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground' import { listWslMoveSleptSessionPanes, readWslMoveSleptScrollbackFromHistory, withSleptSessionPanes, wslMoveTabTitle, wslMoveSleptSpoolRoot -} from '../../persistence/moving-wsl-projects/wsl-move-slept-scrollback' -import { scheduleWslMoveRewriteRetry } from '../../persistence/moving-wsl-projects/wsl-move-rewrite-retry' +} from '../../persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback' +import { scheduleWslMoveRewriteRetry } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-retry' import { captureWslMoveRestoreHints, type WslMoveRestoreHintPane -} from '../../persistence/moving-wsl-projects/wsl-move-restore-hints' +} from '../../persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints' import { isWslMoveProjectFenced, wslMoveProjectRefForWorkspace -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { buildWslMoveShellHistoryBlobs } from '../../persistence/moving-wsl-projects/wsl-move-shell-history-blobs' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { buildWslMoveShellHistoryBlobs } from '../../persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs' import { inspectPtyProviderProcessForRenderer } from '../../providers/pty-process-inspection' import type { OrcaRuntimeService } from '../../runtime/orca-runtime' import { getTrustedUIRendererWebContents, getTrustedUIRendererWindow } from '../ui' @@ -72,7 +72,7 @@ import { import { setWslMoveReloadLanding, setWslMoveReloadableWindow -} from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import { commitRemoteOrcadMigrationCatalog } from '../../managed-server/migration/catalog/orcad-migration-catalog-client' import { listRemoteOrcadRepositories } from '../../managed-server/migration/linking/orcad-server-repositories' import { stageRemoteOrcadMigrationBlobChunk } from '../../managed-server/migration/transfers/orcad-migration-chunk-client' diff --git a/src/main/ipc/wsl/wsl-move-handlers-setting-off.test.ts b/src/main/ipc/wsl/wsl-move-handlers-setting-off.test.ts index 3912735acd1..6e23ca243aa 100644 --- a/src/main/ipc/wsl/wsl-move-handlers-setting-off.test.ts +++ b/src/main/ipc/wsl/wsl-move-handlers-setting-off.test.ts @@ -5,12 +5,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' import { wslMoveCutoverFixture as cutover } from '../../persistence/__fixtures__/wsl-mover/wsl-move-cutover-fixture' import { seedWslMoveCutover } from '../../persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/wsl-move-cutover-journal' +import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' type Handler = (event: unknown, request?: unknown) => unknown diff --git a/src/main/ipc/wsl/wsl-move-handlers.ts b/src/main/ipc/wsl/wsl-move-handlers.ts index 847c4ebcd1e..0a70de4e185 100644 --- a/src/main/ipc/wsl/wsl-move-handlers.ts +++ b/src/main/ipc/wsl/wsl-move-handlers.ts @@ -19,15 +19,15 @@ import type { WslMoveUseLocallyResult } from '../../../shared/wsl-move/wsl-moved import { listPendingWslMoveRendererRewrites, recordWslMoveRendererStoreRewritten -} from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite' +} from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import { cancelWslMove, isAnyWslMoveRunning -} from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import { moveProjectsToWslHost } from '../../persistence/moving-wsl-projects/wsl-move-driver' -import { previewWslMove } from '../../persistence/moving-wsl-projects/wsl-move-driver-preview' -import type { WslMoveDriverDeps } from '../../persistence/moving-wsl-projects/wsl-move-driver-ports' -import { listUnfinishedWslMoves } from '../../persistence/moving-wsl-projects/wsl-move-host-automations-rewrite' +import { previewWslMove } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-preview' +import type { WslMoveDriverDeps } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-ports' +import { listUnfinishedWslMoves } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-host-automations-rewrite' import { runTrackedWslMove } from '../../telemetry/wsl-move-telemetry' import { runTrackedWslMoveUndo } from '../../telemetry/wsl-move-undo-telemetry' diff --git a/src/main/ipc/wsl/wsl-move-orchestrator-wiring.ts b/src/main/ipc/wsl/wsl-move-orchestrator-wiring.ts index 14a7ad8ebb5..0f377dc8613 100644 --- a/src/main/ipc/wsl/wsl-move-orchestrator-wiring.ts +++ b/src/main/ipc/wsl/wsl-move-orchestrator-wiring.ts @@ -14,23 +14,23 @@ import { type WslMoveOrchestratorUserAction } from '../../../shared/wsl-move/wsl-move-orchestrator-types' import type { Store } from '../../persistence/loading-store/store' -import { listWslMoveCutoverChain } from '../../persistence/moving-wsl-projects/wsl-move-cutover-journal' +import { listWslMoveCutoverChain } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' import { moveProjectsToWslHost } from '../../persistence/moving-wsl-projects/wsl-move-driver' -import { previewWslMove } from '../../persistence/moving-wsl-projects/wsl-move-driver-preview' -import { wslMovedDistroVerdict } from '../../persistence/moving-wsl-projects/wsl-move-moved-distro-check' +import { previewWslMove } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-preview' +import { wslMovedDistroVerdict } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-moved-distro-check' import { WslMoveOrchestrator } from '../../persistence/moving-wsl-projects/wsl-move-orchestrator' import type { WslMoveFinishedMove, WslMoveHostReadiness -} from '../../persistence/moving-wsl-projects/wsl-move-orchestrator-ports' -import { prepareWslMoveHost } from '../../persistence/moving-wsl-projects/wsl-move-host-readiness' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-ports' +import { prepareWslMoveHost } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-host-readiness' import { readConfirmedRunningWslDistros } from '../../wsl/discovery/wsl-background-distro-gate' import { defaultWslOrcadEnvironmentId } from '../../wsl/orcad/wsl-orcad-deploy' import { readWslMoveOrchestratorRecords, writeWslMoveOrchestratorRecords -} from '../../persistence/moving-wsl-projects/wsl-move-orchestrator-store' -import type { WslMoveDriverDeps } from '../../persistence/moving-wsl-projects/wsl-move-driver-ports' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-store' +import type { WslMoveDriverDeps } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-ports' import { trackWslMoveOrchestrator, wslMoveOrchestratorEventProps @@ -49,7 +49,7 @@ import { onWslHostUserAction } from '../../wsl/host-lifecycle/wsl-host-user-acti import { getTrustedUIRendererWebContents, getTrustedUIRendererWindow } from '../ui' import { onWslMoveReleasedByUser, releaseWslMoveChainHere } from './wsl-move-release-here' import { createWslMoveUndoPorts } from './wsl-move-undo-wiring' -import { isDistroInUse } from '../../persistence/moving-wsl-projects/wsl-move-distro-in-use' +import { isDistroInUse } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-distro-in-use' import { answerWslMoveSleptPanes, requestSleptPanes } from './wsl-move-orchestrator-slept-panes' import { wslHostRemovalPending } from './wsl-move-host-connect' import { wslMoveAutoMovesBridgeProjects } from '../../../shared/wsl-move/wsl-move-rollout-stage' diff --git a/src/main/ipc/wsl/wsl-move-partial-undo.test.ts b/src/main/ipc/wsl/wsl-move-partial-undo.test.ts index 8ea87421582..884d904ea4e 100644 --- a/src/main/ipc/wsl/wsl-move-partial-undo.test.ts +++ b/src/main/ipc/wsl/wsl-move-partial-undo.test.ts @@ -6,17 +6,17 @@ import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' import { wslMoveCutoverFixture as cutover } from '../../persistence/__fixtures__/wsl-mover/wsl-move-cutover-fixture' import { seedWslMoveCutover } from '../../persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/wsl-move-cutover-journal' +import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' import { isWslMoveProjectBlocked, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import { registerWslMoveDesktopRewriteStore, resetWslMoveDesktopRewriteStoresForTests -} from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' +} from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' type Handler = (event: unknown, request?: unknown) => unknown diff --git a/src/main/ipc/wsl/wsl-move-release-here-move-race.test.ts b/src/main/ipc/wsl/wsl-move-release-here-move-race.test.ts index 9789c9dccaa..870ddfb9a7f 100644 --- a/src/main/ipc/wsl/wsl-move-release-here-move-race.test.ts +++ b/src/main/ipc/wsl/wsl-move-release-here-move-race.test.ts @@ -14,15 +14,15 @@ import { wslMoveRigRetentionStore, type WslMoveRig } from '../../persistence/__fixtures__/wsl-mover/wsl-move-kill-rig' -import { resetWslMoveDesktopRewriteStoresForTests } from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' +import { resetWslMoveDesktopRewriteStoresForTests } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' import { moveProjectsToWslHost } from '../../persistence/moving-wsl-projects/wsl-move-driver' -import { previewWslMove } from '../../persistence/moving-wsl-projects/wsl-move-driver-preview' -import { runWslMoveRetentionPass } from '../../persistence/moving-wsl-projects/wsl-move-retention' +import { previewWslMove } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-preview' +import { runWslMoveRetentionPass } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention' import { claimWslMoveRun, releaseWslMoveRun, type RunningWslMove -} from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import { releaseWslMovedProjectHere } from './wsl-move-release-here' vi.mock('electron', () => ({ diff --git a/src/main/ipc/wsl/wsl-move-release-here.ts b/src/main/ipc/wsl/wsl-move-release-here.ts index 1a2c6370f42..24f7d6e898b 100644 --- a/src/main/ipc/wsl/wsl-move-release-here.ts +++ b/src/main/ipc/wsl/wsl-move-release-here.ts @@ -9,26 +9,26 @@ import { type WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' import type { WslMoveUseLocallyResult } from '../../../shared/wsl-move/wsl-moved-project' -import { listWslMoveCutoverChain } from '../../persistence/moving-wsl-projects/wsl-move-cutover-journal' -import type { WslMoveProjectRef } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { fenceHostSpawnsForWslMoveUndo } from '../../persistence/moving-wsl-projects/wsl-move-undo-spawn-fence' +import { listWslMoveCutoverChain } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' +import type { WslMoveProjectRef } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { fenceHostSpawnsForWslMoveUndo } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence' import { findWslMovedProjectMove, releaseWslMove, wslMoveReleaseRefusal, wslMoveWorkspacesInScope -} from '../../persistence/moving-wsl-projects/wsl-move-use-locally' +} from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-use-locally' import { holdWslMoveWindowWrites, reloadWslMoveWindowWithWritesHeld -} from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import type { WslMoveUndoPorts } from './wsl-move-undo-wiring' import { wslMoveHostCopiesSlept, wslMoveHostCopyOutcome -} from '../../persistence/moving-wsl-projects/wsl-move-host-copy-stop' -import { beginWslMoveUndoRun } from '../../persistence/moving-wsl-projects/wsl-move-running-moves' -import { runWslMoveHostAutomationsExclusive } from '../../persistence/moving-wsl-projects/wsl-move-undo-host-automations' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-host-copy-stop' +import { beginWslMoveUndoRun } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' +import { runWslMoveHostAutomationsExclusive } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-host-automations' import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' import { wasWslHostKeptForPeers } from '../../wsl/host-lifecycle/wsl-host-kept-for-peers' diff --git a/src/main/ipc/wsl/wsl-move-reloadable-window.ts b/src/main/ipc/wsl/wsl-move-reloadable-window.ts index d7c11c37c57..fe5020d2140 100644 --- a/src/main/ipc/wsl/wsl-move-reloadable-window.ts +++ b/src/main/ipc/wsl/wsl-move-reloadable-window.ts @@ -1,7 +1,7 @@ /** The app window as the WSL move's write hold reloads it (wsl-move-window-write-hold.ts). */ import type { WebContents } from 'electron' import type { Store } from '../../persistence/loading-store/store' -import type { WslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +import type { WslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' /** * Settings cannot restore its page, so a reload from it would open General (and keep reopening diff --git a/src/main/ipc/wsl/wsl-move-undo-host-pane-open.test.ts b/src/main/ipc/wsl/wsl-move-undo-host-pane-open.test.ts index 3c54bdfacd6..c3cda29d81f 100644 --- a/src/main/ipc/wsl/wsl-move-undo-host-pane-open.test.ts +++ b/src/main/ipc/wsl/wsl-move-undo-host-pane-open.test.ts @@ -8,17 +8,17 @@ import { seedWslMoveCutover } from '../../persistence/__fixtures__/wsl-mover/wsl import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/wsl-move-window-write-hold' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { setWslMoveReloadableWindow } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold' import { registerWslMoveDesktopRewriteStore, resetWslMoveDesktopRewriteStoresForTests -} from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' +} from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' import { isHostSpawnFencedForWslMoveUndo, resetWslMoveUndoSpawnFencesForTests -} from '../../persistence/moving-wsl-projects/wsl-move-undo-spawn-fence' -import type { WslMoveHostCopyStop } from '../../persistence/moving-wsl-projects/wsl-move-host-copy-stop' +} from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence' +import type { WslMoveHostCopyStop } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-host-copy-stop' type Handler = (event: unknown, request?: unknown) => unknown diff --git a/src/main/ipc/wsl/wsl-move-undo-wiring.ts b/src/main/ipc/wsl/wsl-move-undo-wiring.ts index 139726a3b12..303337ac793 100644 --- a/src/main/ipc/wsl/wsl-move-undo-wiring.ts +++ b/src/main/ipc/wsl/wsl-move-undo-wiring.ts @@ -6,17 +6,17 @@ import { z } from 'zod' import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' import type { Store } from '../../persistence/loading-store/store' -import { wslMoveDesktopRewriteContext } from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite' +import { wslMoveDesktopRewriteContext } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import { probeWslMoveHostCopies, stopWslMoveHostCopies, type WslMoveHostCopyOutcome, type WslMoveHostCopyPort, type WslMoveHostCopyStop -} from '../../persistence/moving-wsl-projects/wsl-move-host-copy-stop' -import { wslMoveRewriteScope } from '../../persistence/moving-wsl-projects/wsl-move-rewrite-scope' -import { wslMoveReleasedSessionFocusPatch } from '../../persistence/moving-wsl-projects/wsl-move-session-rewrite' -import { applyWslMoveSessionFocus } from '../../persistence/moving-wsl-projects/wsl-move-main-rewrite-stores' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-host-copy-stop' +import { wslMoveRewriteScope } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-rewrite-scope' +import { wslMoveReleasedSessionFocusPatch } from '../../persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite' +import { applyWslMoveSessionFocus } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores' import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' import { callRuntimeEnvironment } from '../runtime-environments/runtime-environment-transport-routing' import { wasWslHostKeptForPeers } from '../../wsl/host-lifecycle/wsl-host-kept-for-peers' @@ -24,8 +24,8 @@ import { stopWslMoveHostAutomations, wslMoveMovedAutomationIds, type WslMoveHostAutomationStop -} from '../../persistence/moving-wsl-projects/wsl-move-undo-host-automations' -import { scheduleWslMoveRewriteRetry } from '../../persistence/moving-wsl-projects/wsl-move-rewrite-retry' +} from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-host-automations' +import { scheduleWslMoveRewriteRetry } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-retry' import { connectWslMoveHostService, wslHostRemovalPending } from './wsl-move-host-connect' import { getWslHostService } from '../../wsl/host-lifecycle/wsl-host-service-instance' import { diff --git a/src/main/managed-server/lifecycle/orcad-managed-migration-status.ts b/src/main/managed-server/lifecycle/orcad-managed-migration-status.ts index 7a95c32e6d0..6e1b472135a 100644 --- a/src/main/managed-server/lifecycle/orcad-managed-migration-status.ts +++ b/src/main/managed-server/lifecycle/orcad-managed-migration-status.ts @@ -6,7 +6,7 @@ import { getOrcadSshDeployment, type KnownRuntimeEnvironment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' -import { listOrcadMigrationSourceCutovers } from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { listOrcadMigrationSourceCutovers } from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' type OrcadManagedPendingMigration = { migrationId: string diff --git a/src/main/managed-server/lifecycle/orcad-managed-rollback.ts b/src/main/managed-server/lifecycle/orcad-managed-rollback.ts index 09615a1ac26..4481976d879 100644 --- a/src/main/managed-server/lifecycle/orcad-managed-rollback.ts +++ b/src/main/managed-server/lifecycle/orcad-managed-rollback.ts @@ -1,5 +1,8 @@ -import { redactRuntimeEnvironment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' -import type { KnownRuntimeEnvironment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' +import { + redactRuntimeEnvironment, + type KnownRuntimeEnvironment +} from '../../../shared/remote-runtime/host-catalog/runtime-environments' + import type { OrcadManagedRollbackResult } from '../../../shared/orcad-managed-runtime' import { probeActiveOrcadReadiness } from '../activation/orcad-active-readiness' import { CURRENT_ORCAD_DAEMON_PROTOCOL } from '../activation/orcad-daemon-protocol-crossing' @@ -14,10 +17,14 @@ import { rollbackOrcad } from '../install/orcad-remote-rollback' import { collectManagedTerminalCensus } from './orcad-terminal-census-client' import { updateTerminalCounts } from '../activation/orcad-fenced-stop' import { findIncompleteManagedOrcadMigration } from './orcad-managed-migration-status' -import { latestOrcadMigrationInto } from '../../persistence/migrating-orcad-catalog/orcad-migration-rollback-mark' +import { latestOrcadMigrationInto } from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-rollback-mark' import { refreshMaintainedOrcadPairing } from './orcad-maintenance-pairing-refresh' -import type { LifecycleArgs } from './orcad-managed-lifecycle' -import { withManagedOrcadLifecycle, followLaunchedServerPort } from './orcad-managed-lifecycle' + +import { + type LifecycleArgs, + withManagedOrcadLifecycle, + followLaunchedServerPort +} from './orcad-managed-lifecycle' export function rollbackManagedOrcadEnvironment( userDataPath: string, diff --git a/src/main/managed-server/lifecycle/orcad-runtime-conversion-wiring.ts b/src/main/managed-server/lifecycle/orcad-runtime-conversion-wiring.ts index 2d507361fb4..7511a99f6a5 100644 --- a/src/main/managed-server/lifecycle/orcad-runtime-conversion-wiring.ts +++ b/src/main/managed-server/lifecycle/orcad-runtime-conversion-wiring.ts @@ -11,7 +11,10 @@ import { readRemoteOrcadMigrationCatalogState, stageRemoteOrcadMigrationCatalog } from '../migration/catalog/orcad-migration-catalog-client' -import { listRemoteOrcadRepositories } from '../migration/linking/orcad-server-repositories' +import { + listRemoteOrcadRepositories, + type OrcadServerRepository +} from '../migration/linking/orcad-server-repositories' import { stageRemoteOrcadMigrationBlobChunk, stageRemoteOrcadMigrationSnapshotChunk @@ -21,11 +24,11 @@ import { abortRemoteOrcadMigrationCatalogByReference } from '../migration/catalo import { enableRemoteOrcadAutomation, type EnableServerAutomation -} from '../../persistence/migrating-orcad-catalog/orcad-migration-moved-automations' +} from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations' import { censusHostRelayTerminalsFor } from '../../ssh/legacy-relay/endpoints/ssh-host-relay-census-for-target' import { isBridgeableLease } from '../../ssh/legacy-relay/bridge/legacy-relay-bridge-leases' import type { OrcadManagedConversionArgs } from './orcad-runtime-conversion' -import type { OrcadServerRepository } from '../migration/linking/orcad-server-repositories' + import { listRemoteOrcadFolderCatalog, type OrcadServerFolderCatalog diff --git a/src/main/managed-server/lifecycle/orcad-runtime-conversion.ts b/src/main/managed-server/lifecycle/orcad-runtime-conversion.ts index 881853a5fdd..d2c8a52caf3 100644 --- a/src/main/managed-server/lifecycle/orcad-runtime-conversion.ts +++ b/src/main/managed-server/lifecycle/orcad-runtime-conversion.ts @@ -21,7 +21,7 @@ import { import { findOrcadMigrationSourceCutoverForTarget, removeOrcadMigrationJournalsForDestination -} from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import type { SshTarget } from '../../../shared/ssh-types' import type { CensusHostRelayTerminals } from '../../ssh/migration-source/orcad-migration-terminal-gate' import { createManagedOrcadEnvironment } from './orcad-runtime-deployment' @@ -32,11 +32,11 @@ import { } from '../../ssh/targets/ssh-target-orcad-preflight' import { ORCAD_MIGRATION_LEAVE_BEHIND_TERMINALS_REASON } from '../../ssh/migration-source/orcad-migration-source-fence' import type { OrcadMigrationPaneLeasePredicate } from '../../ssh/migration-source/orcad-migration-bridged-panes' -import { retainOrcadMigrationSource } from '../../persistence/migrating-orcad-catalog/orcad-migration-source-retention' +import { retainOrcadMigrationSource } from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention' import { enableMovedOrcadAutomations, type EnableServerAutomation -} from '../../persistence/migrating-orcad-catalog/orcad-migration-moved-automations' +} from '../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations' import { linkedOrcadMigrationCutoverPort, linkedOrcadMigrationProjects, diff --git a/src/main/managed-server/lifecycle/orcad-runtime-decommission.ts b/src/main/managed-server/lifecycle/orcad-runtime-decommission.ts index 998ee2cb6a3..accccc9c528 100644 --- a/src/main/managed-server/lifecycle/orcad-runtime-decommission.ts +++ b/src/main/managed-server/lifecycle/orcad-runtime-decommission.ts @@ -24,7 +24,7 @@ import { } from './orcad-managed-runtime-context' import { closeOrcadManagedTunnel, ensureOrcadManagedTunnel } from './orcad-managed-tunnel' import { clearManagedOrcadUpdateDeferral } from './orcad-managed-update-deferrals' -import { removeOrcadMigrationJournalsForDestination } from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { removeOrcadMigrationJournalsForDestination } from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { decommissionRemoteOrcad } from '../install/orcad-remote-decommission' import { withManagedOrcadLifecycle } from './orcad-managed-lifecycle' import { collectManagedTerminalCensus } from './orcad-terminal-census-client' diff --git a/src/main/managed-server/lifecycle/orcad-runtime-forget.test.ts b/src/main/managed-server/lifecycle/orcad-runtime-forget.test.ts index 7367a92ac0b..165a3084f32 100644 --- a/src/main/managed-server/lifecycle/orcad-runtime-forget.test.ts +++ b/src/main/managed-server/lifecycle/orcad-runtime-forget.test.ts @@ -5,7 +5,7 @@ import { listEnvironments } from '../../../shared/remote-runtime/host-store/runt import { listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { orcadMigrationCutoverFixture } from '../migration/cutover/testing/orcad-migration-cutover-fixture' import { createManagedLifecycleHarness } from './orcad-managed-lifecycle-test-fixture' import { isManagedOrcadSshTarget } from '../../ssh/targets/ssh-target-runtime-ownership' diff --git a/src/main/managed-server/lifecycle/orcad-runtime-maintenance.test.ts b/src/main/managed-server/lifecycle/orcad-runtime-maintenance.test.ts index f71ba338df6..b9483aed0c6 100644 --- a/src/main/managed-server/lifecycle/orcad-runtime-maintenance.test.ts +++ b/src/main/managed-server/lifecycle/orcad-runtime-maintenance.test.ts @@ -11,7 +11,7 @@ import { encodePairingOffer } from '../../../shared/remote-runtime/pairing/pairi import { PAIRING_OFFER_VERSION } from '../../../shared/remote-runtime/pairing/mobile-relay-pairing-offer' import { orcadMigrationCutoverFixture } from '../migration/cutover/testing/orcad-migration-cutover-fixture' -import { writeOrcadMigrationSourceCutover } from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { writeOrcadMigrationSourceCutover } from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { createManagedLifecycleHarness, MANAGED_LOCAL_PORT, diff --git a/src/main/managed-server/migration/cutover/orcad-conversion-abandon.ts b/src/main/managed-server/migration/cutover/orcad-conversion-abandon.ts index c03d3794252..12626ce768c 100644 --- a/src/main/managed-server/migration/cutover/orcad-conversion-abandon.ts +++ b/src/main/managed-server/migration/cutover/orcad-conversion-abandon.ts @@ -9,7 +9,7 @@ import { type OrcadMigrationCutoverContext, type OrcadMigrationDestinationCatalog } from './orcad-migration-cutover-coordinator' -import { findOrcadMigrationSourceCutoverForTarget } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { releaseOrcadMigrationFence, releaseUndeployedMigrationFence diff --git a/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.test.ts b/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.test.ts index 5357c01be18..c77915b7a71 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.test.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.test.ts @@ -20,9 +20,9 @@ import { ORCAD_MIGRATION_DESTINATION_UNSUPPORTED } from '../catalog/orcad-migrat import { listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { assertOrcadMigrationRequestFits } from '../catalog/orcad-migration-request-budget' -import { createOrcadMigrationManifest } from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import { createOrcadMigrationManifest } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { MAX_ORCAD_MIGRATION_MANIFEST_BYTES } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' import { fenceOrcadMigrationSource } from '../../../ssh/migration-source/orcad-migration-source-fence' import { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.ts b/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.ts index 657dfcfd930..4c3e3ac7cc6 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-cutover-coordinator.ts @@ -24,7 +24,7 @@ import { orcadMigrationRequestFits } from '../catalog/orcad-migration-request-bu import { listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import type { OrcadMigrationSourceCutoverPort } from './orcad-migration-source' import { transferOrcadMigrationSnapshots, @@ -34,7 +34,7 @@ import { exportedOrcadMigrationBlobSource, transferOrcadMigrationBlobs } from '../transfers/orcad-migration-blob-coordinator' -import type { OrcadMigrationExportedBlob } from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import type { OrcadMigrationExportedBlob } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import type { OrcadMigrationPreflightStore } from '../../../ssh/targets/ssh-target-orcad-preflight' import { sshRelayMigrationCutoverPort } from '../../../ssh/migration-source/orcad-migration-ssh-relay-source' import type { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-delta-move.test.ts b/src/main/managed-server/migration/cutover/orcad-migration-delta-move.test.ts index 23e07da08cd..9008fcd7add 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-delta-move.test.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-delta-move.test.ts @@ -26,19 +26,19 @@ import { listOrcadMigrationCutoverChainForTarget, listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { fakeOrcadMigrationDestination } from './testing/orcad-migration-destination-fake' import { keepOrcadServerVersion, runOrcadDeltaMove } from './orcad-migration-delta-move' import { orcadSourceStoreWithout, planOrcadDeltaMove } from './orcad-migration-delta-plan' import { createOrcadMigrationManifest, orcadMigrationCatalogIds -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +} from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { MAX_ORCAD_MIGRATION_MANIFEST_BYTES } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' -import { retainOrcadMigrationSource } from '../../../persistence/migrating-orcad-catalog/orcad-migration-source-retention' -import { reconcileManagedOrcadSshTargets } from '../../../persistence/migrating-orcad-catalog/orcad-retained-source' -import { visibleRepos } from '../../../persistence/migrating-orcad-catalog/orcad-source-visibility' +import { retainOrcadMigrationSource } from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention' +import { reconcileManagedOrcadSshTargets } from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source' +import { visibleRepos } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' import { SshConnectionStore } from '../../../ssh/targets/ssh-connection-store' import { resolveHostServerOnConnect } from '../../../ssh/host-server/ssh-host-server-on-connect' import { hostServerDepsStub } from '../../../ssh/host-server/testing/ssh-host-server-on-connect-test-deps' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-delta-move.ts b/src/main/managed-server/migration/cutover/orcad-migration-delta-move.ts index fea494d857d..54e45941944 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-delta-move.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-delta-move.ts @@ -19,7 +19,7 @@ import { listOrcadMigrationCutoverChainForTarget, removeOrcadMigrationSourceCutover, writeOrcadMigrationSourceCutover -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { committedOrcadMigrationChain, orcadDeltaSourceStore, @@ -28,7 +28,7 @@ import { type OrcadDeltaMovePlan } from './orcad-migration-delta-plan' import { assertOrcadMigrationRequestFits } from '../catalog/orcad-migration-request-budget' -import { retainOrcadMigrationSource } from '../../../persistence/migrating-orcad-catalog/orcad-migration-source-retention' +import { retainOrcadMigrationSource } from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention' import { assessOrcadMigrationTerminals, type OrcadMigrationTerminalVerdict, @@ -40,8 +40,8 @@ import { orcadCatalogFingerprint, unmovedOrcadSourceRows, withKeptOrcadSourceRows -} from '../../../persistence/migrating-orcad-catalog/orcad-retained-source' -import { collectOrcadMigrationSourceCatalog } from '../../../persistence/migrating-orcad-catalog/orcad-source-catalog' +} from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source' +import { collectOrcadMigrationSourceCatalog } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog' import type { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' import { orcadMigrationRefusalReason } from './orcad-migration-refusal-reason' import { errorMessage } from '../../../../shared/error-message' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-delta-plan.ts b/src/main/managed-server/migration/cutover/orcad-migration-delta-plan.ts index df8e5b6d98a..f818ed1b52d 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-delta-plan.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-delta-plan.ts @@ -7,17 +7,20 @@ import type { OrcadMigrationCatalogPayload, OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' -import { isRetainedOrcadMigrationSourceCutover } from '../../../../shared/orcad-migration/orcad-migration-source-cutover' -import type { OrcadMigrationSourceCutover } from '../../../../shared/orcad-migration/orcad-migration-source-cutover' +import { + isRetainedOrcadMigrationSourceCutover, + type OrcadMigrationSourceCutover +} from '../../../../shared/orcad-migration/orcad-migration-source-cutover' + import type { SshTarget } from '../../../../shared/ssh-types' import type { Store } from '../../../persistence/loading-store/store' -import { collectOrcadMigrationSourceCatalog } from '../../../persistence/migrating-orcad-catalog/orcad-source-catalog' -import { listOrcadMigrationCutoverChainForTarget } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { collectOrcadMigrationSourceCatalog } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog' +import { listOrcadMigrationCutoverChainForTarget } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { createOrcadMigrationManifest, orcadMigrationCatalogIds, type OrcadMigrationCatalogIds -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +} from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import type { OrcadMigrationSnapshotSource } from '../transfers/orcad-migration-snapshot-coordinator' import { collectUntransferredDependentBlockers } from '../../../ssh/targets/ssh-target-orcad-dependents' import type { OrcadMigrationPreflightStore } from '../../../ssh/targets/ssh-target-orcad-preflight' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-delta-snapshot.test.ts b/src/main/managed-server/migration/cutover/orcad-migration-delta-snapshot.test.ts index 30320f62a12..1bf10d5fa55 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-delta-snapshot.test.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-delta-snapshot.test.ts @@ -18,10 +18,10 @@ import { createSqliteTestStore } from '../../../persistence/persistence-test-harness' import { Store } from '../../../persistence/loading-store/store' -import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { fakeOrcadMigrationDestination } from './testing/orcad-migration-destination-fake' import { runOrcadDeltaMove } from './orcad-migration-delta-move' -import { reconcileManagedOrcadSshTargets } from '../../../persistence/migrating-orcad-catalog/orcad-retained-source' +import { reconcileManagedOrcadSshTargets } from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source' import { SshConnectionStore } from '../../../ssh/targets/ssh-connection-store' import { runTargetLifecycle } from '../../../ipc/ssh/ssh-target-lifecycle-queue' diff --git a/src/main/managed-server/migration/cutover/orcad-migration-source.ts b/src/main/managed-server/migration/cutover/orcad-migration-source.ts index 3af5dfb6301..423493adb35 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-source.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-source.ts @@ -8,7 +8,7 @@ import type { OrcadMigrationSourceCutover } from '../../../../shared/orcad-migra import type { OrcadMigrationExportedBlob, OrcadMigrationManifestExportOptions -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +} from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import type { OrcadMigrationFenceResult, OrcadMigrationFenceState diff --git a/src/main/managed-server/migration/cutover/orcad-migration-stuck-host-profiles.test.ts b/src/main/managed-server/migration/cutover/orcad-migration-stuck-host-profiles.test.ts index 2f8aa10f469..915d2710f37 100644 --- a/src/main/managed-server/migration/cutover/orcad-migration-stuck-host-profiles.test.ts +++ b/src/main/managed-server/migration/cutover/orcad-migration-stuck-host-profiles.test.ts @@ -23,7 +23,7 @@ import { } from '../../../ssh/migration-source/orcad-migration-terminal-gate' import { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' import { getManagedOrcadFenceEnvironmentId } from '../../../../shared/managed-orcad-ssh-owner' -import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { leaveBehindClearsOrcadMigrationBlockers, onlyLeavableOrcadMigrationBlockers diff --git a/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.test.ts b/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.test.ts index 47ae852d4b2..493ff7949b4 100644 --- a/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.test.ts +++ b/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.test.ts @@ -14,7 +14,7 @@ import { } from '../../../persistence/persistence-test-harness' import { Store } from '../../../persistence/loading-store/store' import { stageOrcadMigrationDestination } from './orcad-migration-cutover-coordinator' -import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { listOrcadMigrationSourceCutovers } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { fakeOrcadMigrationDestination } from './testing/orcad-migration-destination-fake' import { fenceOrcadMigrationSource } from '../../../ssh/migration-source/orcad-migration-source-fence' import { releaseUnreachableOrcadSetup } from './orcad-unreachable-setup-release' diff --git a/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.ts b/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.ts index 136915edcd7..0158053e44a 100644 --- a/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.ts +++ b/src/main/managed-server/migration/cutover/orcad-unreachable-setup-release.ts @@ -1,7 +1,7 @@ /** Release conversion setups stranded before staging by refused SSH forwarding. Stop any activated slot, unregister, then use undeployed-fence release; source rows remain intact for retry. */ import { listEnvironments } from '../../../../shared/remote-runtime/host-store/runtime-environment-store' import { removeManagedOrcadEnvironment } from '../../../../shared/remote-runtime/host-store/runtime-environment-managed-orcad-store' -import { findOrcadMigrationSourceCutoverForTarget } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { releaseUndeployedMigrationFence } from '../../../ssh/migration-source/orcad-migration-source-fence' import { closeOrcadManagedTunnel } from '../../lifecycle/orcad-managed-tunnel' import type { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' diff --git a/src/main/managed-server/migration/linking/orcad-migration-repository-link.test.ts b/src/main/managed-server/migration/linking/orcad-migration-repository-link.test.ts index 74f758ddbca..77b509693d8 100644 --- a/src/main/managed-server/migration/linking/orcad-migration-repository-link.test.ts +++ b/src/main/managed-server/migration/linking/orcad-migration-repository-link.test.ts @@ -22,7 +22,7 @@ import { import { Store } from '../../../persistence/loading-store/store' import type { OrcadMigrationDestinationCatalog } from '../cutover/orcad-migration-cutover-coordinator' import { storeBackedOrcadMigrationDestination } from '../cutover/testing/orcad-migration-destination-fake' -import { removeOrcadMigrationJournalsForDestination } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { removeOrcadMigrationJournalsForDestination } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { SshConnectionStore } from '../../../ssh/targets/ssh-connection-store' diff --git a/src/main/managed-server/migration/linking/orcad-migration-repository-link.ts b/src/main/managed-server/migration/linking/orcad-migration-repository-link.ts index bdbac2736c9..7fcca69093a 100644 --- a/src/main/managed-server/migration/linking/orcad-migration-repository-link.ts +++ b/src/main/managed-server/migration/linking/orcad-migration-repository-link.ts @@ -8,17 +8,26 @@ import type { SshManagedServerLinkedProject } from '../../../../shared/ssh-types import { parseWorkspaceKey } from '../../../../shared/workspace-scope' import { splitWorktreeId } from '../../../../shared/worktree/id' import type { Store } from '../../../persistence/loading-store/store' -import { abortOrcadMigrationCutover } from '../cutover/orcad-migration-cutover-coordinator' -import type { OrcadMigrationDestinationCatalog } from '../cutover/orcad-migration-cutover-coordinator' -import { writeOrcadMigrationSourceCutover } from '../../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' -import { orcadSourceStoreWithout } from '../cutover/orcad-migration-delta-plan' -import type { OrcadDeltaSourceStore } from '../cutover/orcad-migration-delta-plan' -import { createOrcadMigrationManifest } from '../../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import { + abortOrcadMigrationCutover, + type OrcadMigrationDestinationCatalog +} from '../cutover/orcad-migration-cutover-coordinator' + +import { writeOrcadMigrationSourceCutover } from '../../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' +import { + orcadSourceStoreWithout, + type OrcadDeltaSourceStore +} from '../cutover/orcad-migration-delta-plan' + +import { createOrcadMigrationManifest } from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import type { OrcadMigrationSourceCutoverPort } from '../cutover/orcad-migration-source' import { sshRelayMigrationCutoverPort } from '../../../ssh/migration-source/orcad-migration-ssh-relay-source' -import { orcadCatalogFingerprint } from '../../../persistence/migrating-orcad-catalog/orcad-retained-source' -import { folderWorkspacesHeldByServer } from './orcad-server-folder-workspaces' -import type { OrcadServerFolderCatalog } from './orcad-server-folder-workspaces' +import { orcadCatalogFingerprint } from '../../../persistence/migrating-orcad-catalog/retained-source/orcad-retained-source' +import { + folderWorkspacesHeldByServer, + type OrcadServerFolderCatalog +} from './orcad-server-folder-workspaces' + import { projectGroupsHeldByServer, serverHeldProjectGroups } from './orcad-server-project-groups' import type { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' diff --git a/src/main/managed-server/migration/transfers/orcad-migration-blob-coordinator.test.ts b/src/main/managed-server/migration/transfers/orcad-migration-blob-coordinator.test.ts index 082076f86c8..1a7f67e4fe7 100644 --- a/src/main/managed-server/migration/transfers/orcad-migration-blob-coordinator.test.ts +++ b/src/main/managed-server/migration/transfers/orcad-migration-blob-coordinator.test.ts @@ -17,7 +17,7 @@ import { ORCAD_MIGRATION_BLOB_CHANNEL_RUNTIME_CAPABILITY } from '../../../../sha import { inspectOrcadMigrationBlobUploads, stageOrcadMigrationBlobChunk -} from '../../../persistence/migrating-orcad-catalog/orcad-migration-blob-staging' +} from '../../../persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging' import { transferOrcadMigrationBlobs, type OrcadMigrationBlobDestination diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-driver-world.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-driver-world.ts index e33e6125a9c..c2513c54719 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-driver-world.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-driver-world.ts @@ -3,11 +3,12 @@ * blob staging and commit can fail at named points (the fault-injection pattern of #29826), and * terminals that pause on request. The journal is the real one, in a temp directory. */ -import type { - OrcadMigrationBlobDescriptor, - OrcadMigrationBlobUploadState + +import { + type OrcadMigrationBlobDescriptor, + type OrcadMigrationBlobUploadState, + ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' import type { OrcadMigrationCatalogState, OrcadMigrationManifest @@ -20,19 +21,22 @@ import { getDefaultPersistedState } from '../../../../shared/constants' import { terminalTab } from './wsl-mover-profile-rows' import type { Repo } from '../../../../shared/repo-types' import type { WslMoveProgressEvent } from '../../../../shared/wsl-move/wsl-move-driver-types' -import { collectOrcadMigrationSourceDormantState } from '../../migrating-orcad-catalog/orcad-source-dormant-state' -import { exportWslMoveManifest } from '../../moving-wsl-projects/wsl-move-manifest-export' -import { runWslMoveDesktopRewritePass } from '../../moving-wsl-projects/wsl-move-desktop-rewrite' +import { collectOrcadMigrationSourceDormantState } from '../../migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state' +import { + exportWslMoveManifest, + type WslMoveManifestExport +} from '../../moving-wsl-projects/manifest-scope/wsl-move-manifest-export' +import { runWslMoveDesktopRewritePass } from '../../moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import { readWslMoveSleptScrollbackFromHistory, wslMoveSleptSpoolRoot -} from '../../moving-wsl-projects/wsl-move-slept-scrollback' +} from '../../moving-wsl-projects/terminal-state/wsl-move-slept-scrollback' import type { WslMoveDriverDeps, - WslMoveHost, - WslMoveManifestExport -} from '../../moving-wsl-projects/wsl-move-driver-ports' -import type { WslMoveGateInputs } from '../../moving-wsl-projects/wsl-move-terminal-gate' + WslMoveHost +} from '../../moving-wsl-projects/execution/wsl-move-driver-ports' + +import type { WslMoveGateInputs } from '../../moving-wsl-projects/quiescence/wsl-move-terminal-gate' export class WslMoveWorldCrash extends Error {} diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding.ts index 4014da056d6..743289cce4c 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding.ts @@ -6,8 +6,8 @@ import { import { listWslMoveCutovers, writeWslMoveCutover -} from '../../moving-wsl-projects/wsl-move-cutover-journal' -import { setWslMoveDesktopRewriteRegistryCompleteForTests } from '../../moving-wsl-projects/wsl-move-desktop-rewrite-stores' +} from '../../moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' +import { setWslMoveDesktopRewriteRegistryCompleteForTests } from '../../moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' export function seedWslMoveCutover(userDataPath: string, cutover: WslMoveCutover): void { const existing = listWslMoveCutovers(userDataPath).find( diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-kill-rig.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-kill-rig.ts index 139c84669ec..b7a9eb13c90 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-kill-rig.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-kill-rig.ts @@ -12,23 +12,23 @@ import type { Store } from '../../loading-store/store' import { listWslMoveCutoverChain, listWslMoveCutovers -} from '../../moving-wsl-projects/wsl-move-cutover-journal' -import { runWslMoveDesktopRewritePass } from '../../moving-wsl-projects/wsl-move-desktop-rewrite' +} from '../../moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' +import { runWslMoveDesktopRewritePass } from '../../moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import { registerWslMoveDesktopRewriteStore, resetWslMoveDesktopRewriteStoresForTests, setWslMoveDesktopRewriteRegistryCompleteForTests -} from '../../moving-wsl-projects/wsl-move-desktop-rewrite-stores' -import { resolveWslMoveFence } from '../../moving-wsl-projects/wsl-move-fence' +} from '../../moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' +import { resolveWslMoveFence } from '../../moving-wsl-projects/quiescence/wsl-move-fence' import { listWslMoveOwedHostAborts, settleWslMoveOwedHostAborts -} from '../../moving-wsl-projects/wsl-move-owed-host-aborts' +} from '../../moving-wsl-projects/cutover-recovery/wsl-move-owed-host-aborts' import { recoverInterruptedWslMoves, resetWslMoveToZero -} from '../../moving-wsl-projects/wsl-move-reset' -import { runWslMoveRetentionPass } from '../../moving-wsl-projects/wsl-move-retention' +} from '../../moving-wsl-projects/cutover-recovery/wsl-move-reset' +import { runWslMoveRetentionPass } from '../../moving-wsl-projects/cutover-recovery/wsl-move-retention' import { createWslMoveWorld, type WslMoveWorld } from './wsl-move-driver-world' import { createWslMoveKillSwitch, diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-round-trip-normalization.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-round-trip-normalization.ts index 7b2ce35ad0b..8113e4bd356 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-round-trip-normalization.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-round-trip-normalization.ts @@ -3,7 +3,7 @@ * schema defaults the host's load fills in, ids it derives, and representation changes the move * makes on purpose. Each known gap is a real loss, named here so a fix has to remove it. */ -import { isRecord } from '../../moving-wsl-projects/wsl-move-canonical-form' +import { isRecord } from '../../moving-wsl-projects/manifest-scope/wsl-move-canonical-form' /** Session fields the real pipeline does not carry yet, with why; each still differs today. */ export const WSL_MOVE_ROUND_TRIP_KNOWN_GAPS: Readonly> = { diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-store-host.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-store-host.ts index faa7562005a..2422a9e7e35 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-move-store-host.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-move-store-host.ts @@ -14,7 +14,7 @@ import { ORCAD_MIGRATION_LOCAL_WSL_SOURCE_RUNTIME_CAPABILITY } from '../../../../shared/orcad-runtime-capabilities' import type { Store } from '../../loading-store/store' -import type { WslMoveHost } from '../../moving-wsl-projects/wsl-move-driver-ports' +import type { WslMoveHost } from '../../moving-wsl-projects/execution/wsl-move-driver-ports' export class WslMoveKilled extends Error {} diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-folders-profile.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-folders-profile.ts index aaca2d482d1..beb806bdafc 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-folders-profile.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-folders-profile.ts @@ -4,7 +4,7 @@ import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folde import type { ProjectGroup } from '../../../../shared/project-group-types' import type { WorkspaceLineage } from '../../../../shared/worktree/lineage-types' import { folderWorkspaceKey, worktreeWorkspaceKey } from '../../../../shared/workspace-scope' -import type { WslMoveProjectionInput } from '../../moving-wsl-projects/wsl-move-state-projection' +import type { WslMoveProjectionInput } from '../../moving-wsl-projects/manifest-scope/wsl-move-state-projection' import { project, repo, diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-heavy-profile.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-heavy-profile.ts index 9fb28f16796..15df12f333e 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-heavy-profile.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-heavy-profile.ts @@ -1,5 +1,5 @@ import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' -import type { WslMoveProjectionInput } from '../../moving-wsl-projects/wsl-move-state-projection' +import type { WslMoveProjectionInput } from '../../moving-wsl-projects/manifest-scope/wsl-move-state-projection' import { project, repo, diff --git a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-profiles.ts b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-profiles.ts index 06f95f44b73..23b047ff43a 100644 --- a/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-profiles.ts +++ b/src/main/persistence/__fixtures__/wsl-mover/wsl-mover-profiles.ts @@ -2,7 +2,7 @@ import type { WslMoveProjectionInput, WslMoveProjectionScope -} from '../../moving-wsl-projects/wsl-move-state-projection' +} from '../../moving-wsl-projects/manifest-scope/wsl-move-state-projection' import { foldersAndAutomationsWslMoverProfile } from './wsl-mover-folders-profile' import { heavyWslMoverProfile } from './wsl-mover-heavy-profile' import { diff --git a/src/main/persistence/loading-store/project-catalog/project-collection-operations.ts b/src/main/persistence/loading-store/project-catalog/project-collection-operations.ts index 6819c218677..5a811252866 100644 --- a/src/main/persistence/loading-store/project-catalog/project-collection-operations.ts +++ b/src/main/persistence/loading-store/project-catalog/project-collection-operations.ts @@ -32,12 +32,12 @@ import { removeWorkspaceLineageForRemovedFolder } from '../workspace-lineage/metadata-lineage-operations' import { bumpLocalWorktreeScanGeneration } from '../../../workspaces/catalog/local-worktree-scan-generation' -import { dropOrcadTerminalRestoreHintsForWorktrees } from '../../migrating-orcad-catalog/orcad-terminal-restore-hint-store' +import { dropOrcadTerminalRestoreHintsForWorktrees } from '../../migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store' import { folderWorkspaceKey } from '../../../../shared/workspace-scope' import { applyWslMoveRetainedMarks, type WslMoveRetainedMark -} from '../../moving-wsl-projects/wsl-move-retained-marks' +} from '../../moving-wsl-projects/cutover-recovery/wsl-move-retained-marks' type ProjectCollectionOperationsRuntime = Pick< StoreRuntimeState, diff --git a/src/main/persistence/loading-store/project-catalog/repo-lifecycle-operations.ts b/src/main/persistence/loading-store/project-catalog/repo-lifecycle-operations.ts index e4f6829af8f..6e4ba7b17cc 100644 --- a/src/main/persistence/loading-store/project-catalog/repo-lifecycle-operations.ts +++ b/src/main/persistence/loading-store/project-catalog/repo-lifecycle-operations.ts @@ -31,8 +31,8 @@ import type { StoreRuntimeState } from '../store-runtime-state' import { type WriteSchedulingOperations, scheduleSave } from '../profile-writing/write-scheduling' import { pruneDeregisteredRepoUiResidue } from './repo-lifecycle-ui-residue' -import { isWslMoveProjectSessionFrozen } from '../../moving-wsl-projects/wsl-move-scope-guard' -import { dropOrcadTerminalRestoreHintsForWorktrees } from '../../migrating-orcad-catalog/orcad-terminal-restore-hint-store' +import { isWslMoveProjectSessionFrozen } from '../../moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { dropOrcadTerminalRestoreHintsForWorktrees } from '../../migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store' import { getRepoIdFromWorktreeId } from '../../../../shared/worktree/id' import { applyNewWindowsDriveProjectDefault } from '../../../wsl/filesystem/wsl-drive-project-new-default' diff --git a/src/main/persistence/loading-store/store-domain-composition.ts b/src/main/persistence/loading-store/store-domain-composition.ts index b30b7d5658d..74014a47f27 100644 --- a/src/main/persistence/loading-store/store-domain-composition.ts +++ b/src/main/persistence/loading-store/store-domain-composition.ts @@ -28,9 +28,9 @@ import { LayoutCommandPersistence } from '../terminal-topology/layout-command-pe import { SshProfileOperations } from './ssh-state/ssh-profile-operations' import { RetiredWorktreeNamePersistence } from './project-catalog/retired-worktree-name-persistence' import { SshLeaseRecoveryOperations } from './ssh-state/ssh-lease-recovery-operations' -import { OrcadSourceExportPersistence } from '../migrating-orcad-catalog/orcad-source-export' +import { OrcadSourceExportPersistence } from '../migrating-orcad-catalog/source/catalog/orcad-source-export' import { OrcadCatalogImportPersistence } from '../migrating-orcad-catalog/orcad-catalog-import' -import { OrcadMigrationBlobInstallPersistence } from '../migrating-orcad-catalog/orcad-migration-blob-install-persistence' +import { OrcadMigrationBlobInstallPersistence } from '../migrating-orcad-catalog/blob-transfer/orcad-migration-blob-install-persistence' export type StoreDomainOperations = WriteSchedulingOperations & PrimaryStateWriteOperations & diff --git a/src/main/persistence/loading-store/store-runtime-state.ts b/src/main/persistence/loading-store/store-runtime-state.ts index 9b183dca79d..867330af29b 100644 --- a/src/main/persistence/loading-store/store-runtime-state.ts +++ b/src/main/persistence/loading-store/store-runtime-state.ts @@ -33,8 +33,8 @@ import type { } from '../scheduling-automations/automation-owner-projection' import type { ProfileStatePersistenceAuthority } from './profile-writing/profile-state-authority' import type { AutomationRun } from '../../../shared/automations/history/automation-run' -import { resolveNewPaneShellPath } from '../migrating-orcad-catalog/orcad-shell-history-installer' -import { OrcadTerminalRestoreHintStore } from '../migrating-orcad-catalog/orcad-terminal-restore-hint-store' +import { resolveNewPaneShellPath } from '../migrating-orcad-catalog/terminal-history/orcad-shell-history-installer' +import { OrcadTerminalRestoreHintStore } from '../migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store' export type DurableProfileStateMutation = { value: T diff --git a/src/main/persistence/loading-store/workspace-sessions/session-host-partitions.ts b/src/main/persistence/loading-store/workspace-sessions/session-host-partitions.ts index e45a555a52f..88c3453f5f7 100644 --- a/src/main/persistence/loading-store/workspace-sessions/session-host-partitions.ts +++ b/src/main/persistence/loading-store/workspace-sessions/session-host-partitions.ts @@ -23,7 +23,7 @@ import { preserveRuntimeAuthoredWorkspaceSessionFields } from '../../runtime-aut import { dropClosedTerminalTabs } from '../../closed-terminal-tab-write-fence' import { findWorktreeIdForTab } from '../../restoring-sessions/pane-identity-migration' import { invalidateLocalWorktreeMetadataPruneInputs } from '../../../workspaces/catalog/local-worktree-metadata-prune-gate' -import { isWslMoveWorkspaceSessionFrozen } from '../../moving-wsl-projects/wsl-move-scope-guard' +import { isWslMoveWorkspaceSessionFrozen } from '../../moving-wsl-projects/quiescence/wsl-move-scope-guard' import { removeWorkspaceSessionOwner, workspaceSessionPartitionIdsForHost diff --git a/src/main/persistence/loading-store/workspace-sessions/session-snapshot-operations.ts b/src/main/persistence/loading-store/workspace-sessions/session-snapshot-operations.ts index bd54671330e..f3ddd05bd70 100644 --- a/src/main/persistence/loading-store/workspace-sessions/session-snapshot-operations.ts +++ b/src/main/persistence/loading-store/workspace-sessions/session-snapshot-operations.ts @@ -23,7 +23,7 @@ import { withRequiredWorkspaceSessionMaps } from './session-host-partitions' import { dropClosedTerminalTabs } from '../../closed-terminal-tab-write-fence' -import { keepWslMoveFrozenSessionsForStore } from '../../moving-wsl-projects/wsl-move-session-freeze' +import { keepWslMoveFrozenSessionsForStore } from '../../moving-wsl-projects/terminal-state/wsl-move-session-freeze' import { type WriteSchedulingOperations, scheduleSave } from '../profile-writing/write-scheduling' import { orderTerminalRowsByTabGroups } from '../../../../shared/workspace-layout/terminal-row-order' diff --git a/src/main/persistence/loading-store/workspace-sessions/workspace-session-snapshot-publication.ts b/src/main/persistence/loading-store/workspace-sessions/workspace-session-snapshot-publication.ts index c6ef18ff328..23e801471b1 100644 --- a/src/main/persistence/loading-store/workspace-sessions/workspace-session-snapshot-publication.ts +++ b/src/main/persistence/loading-store/workspace-sessions/workspace-session-snapshot-publication.ts @@ -13,7 +13,7 @@ import { } from '../../../pty/scrollback/terminal-scrollback-snapshot-async-migration' import { preserveRuntimeAuthoredWorkspaceSessionFields } from '../../runtime-authored-workspace-session-fields' import { dropClosedTerminalTabs } from '../../closed-terminal-tab-write-fence' -import { keepWslMoveFrozenSessionsForStore } from '../../moving-wsl-projects/wsl-move-session-freeze' +import { keepWslMoveFrozenSessionsForStore } from '../../moving-wsl-projects/terminal-state/wsl-move-session-freeze' import { registerPersistedPaneKeyAlias } from '../../restoring-sessions/pane-alias-normalization' import { normalizeWorkspaceSessionPaneIdentities, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-install-persistence.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-install-persistence.ts similarity index 89% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-install-persistence.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-install-persistence.ts index 7bd3bacabc3..563d0262e68 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-install-persistence.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-install-persistence.ts @@ -1,14 +1,14 @@ -import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { parsePaneKey } from '../../../shared/workspace-layout/stable-pane-id' -import { getDaemonHistoryDir } from '../../daemon/launch/daemon-launch-paths' -import { getHistoryRoot } from '../../pty/history/terminal-history-paths' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import { getDaemonHistoryDir } from '../../../daemon/launch/daemon-launch-paths' +import { getHistoryRoot } from '../../../pty/history/terminal-history-paths' +import type { StoreRuntimeState } from '../../loading-store/store-runtime-state' import { findOrcadMigrationImportReceipt, isOrcadMigrationCommitDurable -} from './orcad-catalog-receipt-ledger' +} from '../catalog-commit/orcad-catalog-receipt-ledger' import { installOrcadMigrationReceivedBlobs } from './orcad-migration-blob-installers' import { listOrcadMigrationReceivedBlobNames } from './orcad-migration-blob-staging' import type { OrcadMigrationRequestIdentity } from './orcad-migration-staged-file' diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-installers.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-installers.ts similarity index 91% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-installers.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-installers.ts index 70f7eb558fa..6cf08858025 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-installers.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-installers.ts @@ -1,15 +1,15 @@ // Validate blob contents before commit; install only advertised kinds after durable commit. -import { servesWslMovedPaneHistory } from '../../orcad/orcad-migration-wsl-destination' +import { servesWslMovedPaneHistory } from '../../../orcad/orcad-migration-wsl-destination' import { readFileSync, rmSync } from 'node:fs' import { dirname } from 'node:path' -import type { OrcadMigrationBlobKind } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationBlobKind } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { ORCAD_MIGRATION_TERMINAL_RESTORE_HINTS_KEY, parseOrcadMigrationTerminalRestoreHintsText, type OrcadMigrationTerminalRestoreHint -} from '../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +} from '../../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' import { getOrcadMigrationReceivedBlobPath, stagedOrcadMigrationBlobFiles @@ -21,15 +21,15 @@ import { import { assertOrcadMigrationShellHistoryValid, installOrcadMigrationShellHistory -} from './orcad-shell-history-installer' +} from '../terminal-history/orcad-shell-history-installer' import { assertOrcadMigrationTerminalHistoryValid, installOrcadMigrationTerminalHistory -} from './orcad-terminal-history-installer' +} from '../terminal-history/orcad-terminal-history-installer' import type { OrcadTerminalRestoreHintPlacement, OrcadTerminalRestoreHintStore -} from './orcad-terminal-restore-hint-store' +} from '../terminal-history/orcad-terminal-restore-hint-store' type OrcadMigrationStagedBlobFile = { key: string diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.test.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.test.ts similarity index 93% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.test.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.test.ts index fca560f785b..d8776b1eedd 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.test.ts @@ -3,9 +3,9 @@ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync, mkdirSync import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { assertOrcadMigrationBlobsReady, commitOrcadMigrationBlobs, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.ts similarity index 97% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.ts index 6cd03efdeb2..57f127505f6 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging.ts @@ -13,9 +13,9 @@ import { type OrcadMigrationBlobDescriptor, type OrcadMigrationBlobKind, type OrcadMigrationBlobUploadState -} from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +} from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' import { appendOrcadMigrationStagedChunk, ensureOrcadMigrationDirectory, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-staged-file.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-staged-file.ts similarity index 96% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-staged-file.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-staged-file.ts index 5b1370e5468..c7a273c3b47 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-staged-file.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-staged-file.ts @@ -15,8 +15,8 @@ import { writeSync } from 'node:fs' import { join } from 'node:path' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' export const ORCAD_MIGRATION_STAGING_DIRECTORY = '.orcad-migration-staging' diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-blobs.test.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-blobs.test.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-blobs.test.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-blobs.test.ts index 8c02c810261..36725c95af2 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-blobs.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-blobs.test.ts @@ -3,10 +3,10 @@ import { createHash } from 'node:crypto' import { mkdtempSync, readFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' import { getOrcadMigrationReceivedBlobPath } from './orcad-migration-blob-staging' -import { manifest } from './persistence-orcad-migration-catalog-fixture' -import { createStore, testState } from '../persistence-test-harness' +import { manifest } from '../catalog-commit/persistence-orcad-migration-catalog-fixture' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -17,7 +17,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) // Use a blob kind without an installer to isolate channel behavior. const bytes = Buffer.from('session record one\nsession record two\n') diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-received-blob-durability.test.ts b/src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-received-blob-durability.test.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-received-blob-durability.test.ts rename to src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-received-blob-durability.test.ts index b30b1417eb9..62cf85dc19a 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-received-blob-durability.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/blob-transfer/persistence-orcad-migration-received-blob-durability.test.ts @@ -6,20 +6,20 @@ import { join } from 'node:path' import { ORCAD_MIGRATION_BLOB_CHUNK_BYTES, type OrcadMigrationBlobDescriptor -} from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { getOrcadMigrationReceivedBlobPath } from './orcad-migration-blob-staging' import { commitStagedOrcadMigrationCatalogDurably, getOrcadMigrationCatalogState -} from '../../runtime/hosts/migration/orcad-migration-catalog-import' +} from '../../../runtime/hosts/migration/orcad-migration-catalog-import' import { DORMANT_LEAF_ID, DORMANT_WORKTREE_ID, dormantState, manifest -} from './persistence-orcad-migration-catalog-fixture' -import { createStore, readDataFile, testState, writeDataFile } from '../persistence-test-harness' +} from '../catalog-commit/persistence-orcad-migration-catalog-fixture' +import { createStore, readDataFile, testState, writeDataFile } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -30,7 +30,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) type Store = ReturnType diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-automation-runs.test.ts similarity index 80% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-automation-runs.test.ts index b16669d10b4..592b3b70da2 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-automation-runs.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-automation-runs.test.ts @@ -2,20 +2,20 @@ import { describe, it, expect, vi } from 'vitest' import { createWorkerMaintenanceFixture, maintenanceBarrier -} from '../loading-store/profile-writing/profile-state-maintenance-fixture' -import { ProfileStateWriterError } from '../profile-state/writer/profile-state-writer-errors' -import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' +} from '../../loading-store/profile-writing/profile-state-maintenance-fixture' +import { ProfileStateWriterError } from '../../profile-state/writer/profile-state-writer-errors' +import { hostWorktreeTarget } from '../../../../shared/worktree/host-qualified-identity' import { DORMANT_AUTOMATION_RUN, dormantState, manifest } from './persistence-orcad-migration-catalog-fixture' -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: () => ({ nth_repo_added: 1 }) })) -vi.mock('../../ssh/config/ssh-config-parser', () => ({ +vi.mock('../../../ssh/config/ssh-config-parser', () => ({ loadUserSshConfig: () => ({ hosts: [] }), sshConfigHostsToTargets: () => [] })) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-domains.ts similarity index 82% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-domains.ts index 2abbc3f8b71..ec492f530bd 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-commit-domains.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-commit-domains.ts @@ -1,5 +1,5 @@ -import { WORKTREE_METADATA_DOMAINS } from '../profile-save-domains' -import { WORKSPACE_SESSION_DOMAINS } from '../workspace-session-domains' +import { WORKTREE_METADATA_DOMAINS } from '../../profile-save-domains' +import { WORKSPACE_SESSION_DOMAINS } from '../../workspace-session-domains' /** An imported catalog adds repos, workspaces and their dormant state, and records its receipts. */ export const ORCAD_CATALOG_COMMIT_DOMAINS = [ diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-receipt-ledger.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-receipt-ledger.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-receipt-ledger.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-receipt-ledger.ts index 7a9370fff73..1a09730f356 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-receipt-ledger.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-receipt-ledger.ts @@ -1,16 +1,16 @@ // Commit receipts remain authoritative indefinitely; abandoned stages expire. -import { MAX_ORCAD_MIGRATION_IMPORT_RECEIPTS } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' +import { MAX_ORCAD_MIGRATION_IMPORT_RECEIPTS } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' import type { OrcadMigrationImportReceipt, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import { MAX_ORCAD_MIGRATION_EVICTED_RECEIPTS } from '../../../shared/orcad-migration/orcad-migration-evicted-receipts' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { MAX_ORCAD_MIGRATION_EVICTED_RECEIPTS } from '../../../../shared/orcad-migration/orcad-migration-evicted-receipts' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { StoreRuntimeState } from '../../loading-store/store-runtime-state' import { orcadMigrationStagingKey, type OrcadMigrationRequestIdentity -} from './orcad-migration-staged-file' +} from '../blob-transfer/orcad-migration-staged-file' // Allow a week for clients that went offline mid-move. export const ORCAD_MIGRATION_STAGE_TTL_MS = 7 * 24 * 60 * 60 * 1000 diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-records.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-records.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-records.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-records.ts index 6c32868050c..0036098957e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-records.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-records.ts @@ -1,29 +1,29 @@ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' import { serializeOrcadMigrationValue, type OrcadMigrationImportReceipt, type OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import { normalizeRuntimePathForComparison } from '../../../shared/cross-platform-path' -import { isRepoOnCatalogHost } from '../../../shared/execution-host' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' +import { normalizeRuntimePathForComparison } from '../../../../shared/cross-platform-path' +import { isRepoOnCatalogHost } from '../../../../shared/execution-host' import { assertOrcadMigrationStagedCatalogClaims } from './orcad-staged-catalog-claims' import { toOrcadDestinationFolderWorkspace, toOrcadDestinationProjectGroup, toOrcadDestinationRepository -} from './orcad-destination-catalog-projection' +} from '../destination/orcad-destination-catalog-projection' import { syncProjectHostSetupCompatibilityState, type RepoLifecycleOperations -} from '../loading-store/project-catalog/repo-lifecycle-operations' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +} from '../../loading-store/project-catalog/repo-lifecycle-operations' +import type { StoreRuntimeState } from '../../loading-store/store-runtime-state' import { applyPreparedOrcadMigrationDormantState, prepareOrcadMigrationDormantState, type PreparedOrcadMigrationDormantState -} from './orcad-dormant-state-records' +} from '../destination/orcad-dormant-state-records' import { sameOrcadRepositoryConfiguration, selectNewRows } from './orcad-catalog-row-identity' export type PreparedOrcadMigrationCatalog = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-reference-abort.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-reference-abort.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-reference-abort.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-reference-abort.ts index 7189df0bc87..2527a13ab4d 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-reference-abort.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-reference-abort.ts @@ -3,8 +3,8 @@ import type { OrcadMigrationCatalogReference, OrcadMigrationCatalogReferenceAbortResult, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { StoreRuntimeState } from '../../loading-store/store-runtime-state' export function stagedManifests(state: StoreRuntimeState['state']): OrcadMigrationManifest[] { return (state.orcadMigrationStagedCatalogs ?? []).map((entry) => entry.manifest) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-row-identity.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-row-identity.ts similarity index 90% rename from src/main/persistence/migrating-orcad-catalog/orcad-catalog-row-identity.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-row-identity.ts index c71533c4a59..44c32f6eee4 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-row-identity.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-catalog-row-identity.ts @@ -1,5 +1,5 @@ -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { Repo } from '../../../shared/repo-types' +import { serializeOrcadMigrationValue } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { Repo } from '../../../../shared/repo-types' export function selectNewRows( incoming: T[], diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-automation-run-history.test.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-migration-automation-run-history.test.ts similarity index 61% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-automation-run-history.test.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-migration-automation-run-history.test.ts index 506b1c90465..96418570ca9 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-automation-run-history.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-migration-automation-run-history.test.ts @@ -2,20 +2,16 @@ import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import type { SshTarget } from '../../../shared/ssh-types' -import { - MAX_ORCAD_MIGRATION_MANIFEST_BYTES, - parseOrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest-validation' -import { closeTestStores, createSqliteTestStore } from '../persistence-test-harness' -import { Store } from '../loading-store/store' -import { commitOrcadMigrationDestination } from '../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' -import { storeBackedOrcadMigrationDestination } from '../../managed-server/migration/cutover/testing/orcad-migration-destination-fake' -import './orcad-migration-cutover-journal' -import './orcad-migration-manifest-export' -import '../../ssh/migration-source/orcad-migration-source-assertions' -import { fenceOrcadMigrationSource } from '../../ssh/migration-source/orcad-migration-source-fence' -import { SshTargetOrcadClaims } from '../../ssh/targets/ssh-target-orcad-claims' +import type { SshTarget } from '../../../../shared/ssh-types' +import { parseOrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' +import { closeTestStores, createSqliteTestStore } from '../../persistence-test-harness' +import { Store } from '../../loading-store/store' + +import '../cutover-journals/orcad-migration-cutover-journal' +import '../source/catalog/orcad-migration-manifest-export' +import '../../../ssh/migration-source/orcad-migration-source-assertions' +import { fenceOrcadMigrationSource } from '../../../ssh/migration-source/orcad-migration-source-fence' +import { SshTargetOrcadClaims } from '../../../ssh/targets/ssh-target-orcad-claims' const TARGET: SshTarget = { id: 'ssh-prod', @@ -94,29 +90,6 @@ async function hostWithRunHistory(outputChars = 30_000) { } describe('moving automation run history to a host server', () => { - it('moves history larger than the manifest limit, every run intact', async () => { - const h = await hostWithRunHistory() - const history = h.store.listAutomationRuns(h.automation.id) - expect(JSON.stringify(history).length).toBeGreaterThan(MAX_ORCAD_MIGRATION_MANIFEST_BYTES) - expect(JSON.stringify(h.cutover.manifest).length).toBeLessThan(64 * 1024) - - const committed = await commitOrcadMigrationDestination( - { - userDataPath: h.userDataPath, - store: h.store, - claims: h.claims, - destination: storeBackedOrcadMigrationDestination(h.server) - }, - h.cutover.migrationId - ) - - expect(committed.phase).toBe('destination-committed') - const moved = h.server.listAutomationRuns(h.automation.id) - expect(moved.map((run) => [run.id, run.runNumber, run.outputSnapshot?.content])).toEqual( - history.map((run) => [run.id, run.runNumber, run.outputSnapshot?.content]) - ) - }) - it('refuses a commit whose history never arrived, importing nothing', async () => { const h = await hostWithRunHistory() const manifest = parseOrcadMigrationManifest(JSON.parse(JSON.stringify(h.cutover.manifest))) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-staged-automation-run-history.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-automation-run-history.ts similarity index 69% rename from src/main/persistence/migrating-orcad-catalog/orcad-staged-automation-run-history.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-automation-run-history.ts index b5cea5d5751..4b4847f8337 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-staged-automation-run-history.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-automation-run-history.ts @@ -1,9 +1,9 @@ import { orcadMigrationAutomationRunHistoryBlob, withOrcadMigrationAutomationRunHistory -} from '../../../shared/orcad-migration/orcad-migration-automation-run-history' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { readOrcadMigrationBlob } from './orcad-migration-blob-staging' +} from '../../../../shared/orcad-migration/orcad-migration-automation-run-history' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { readOrcadMigrationBlob } from '../blob-transfer/orcad-migration-blob-staging' /** The manifest signs the history's digest, so its rows import with the catalog or not at all. */ export function withStagedAutomationRunHistory( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-staged-catalog-claims.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-catalog-claims.ts similarity index 89% rename from src/main/persistence/migrating-orcad-catalog/orcad-staged-catalog-claims.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-catalog-claims.ts index 7c0c92b555b..ba838850634 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-staged-catalog-claims.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/orcad-staged-catalog-claims.ts @@ -1,9 +1,9 @@ -import { normalizeRuntimePathForComparison } from '../../../shared/cross-platform-path' +import { normalizeRuntimePathForComparison } from '../../../../shared/cross-platform-path' import type { OrcadMigrationManifest, OrcadMigrationStagedCatalog -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import { collectOrcadMigrationSessionEntityOwners } from './orcad-destination-workspace-session' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { collectOrcadMigrationSessionEntityOwners } from '../destination/orcad-destination-workspace-session' export function assertOrcadMigrationStagedCatalogClaims( manifest: OrcadMigrationManifest, diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog-fixture.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog-fixture.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog-fixture.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog-fixture.ts index 57799934cc8..23659cc7b2d 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog-fixture.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog-fixture.ts @@ -1,16 +1,16 @@ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { Automation } from '../../../shared/automations/automation-definition' -import type { AutomationRun } from '../../../shared/automations/history/automation-run' -import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { Automation } from '../../../../shared/automations/automation-definition' +import type { AutomationRun } from '../../../../shared/automations/history/automation-run' +import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' import type { OrcadMigrationDormantStatePayload, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import { worktreeWorkspaceKey } from '../../../shared/workspace-scope' -import { computeOrcadMigrationManifestSha256 } from '../../orcad/orcad-migration-manifest-digest' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' +import { worktreeWorkspaceKey } from '../../../../shared/workspace-scope' +import { computeOrcadMigrationManifestSha256 } from '../../../orcad/orcad-migration-manifest-digest' export const PROJECT_GROUP: ProjectGroup = { id: 'group-1', diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog.test.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog.test.ts similarity index 81% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog.test.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog.test.ts index e829a0424a3..c191b249a11 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-catalog.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog.test.ts @@ -9,8 +9,8 @@ import { dormantState, manifest } from './persistence-orcad-migration-catalog-fixture' -import { createStore, readDataFile, testState, writeDataFile } from '../persistence-test-harness' -import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' +import { createStore, readDataFile, testState, writeDataFile } from '../../persistence-test-harness' +import { hostWorktreeTarget } from '../../../../shared/worktree/host-qualified-identity' const { trackMock, getCohortAtEmitMock } = vi.hoisted(() => ({ trackMock: vi.fn(), @@ -26,8 +26,8 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: trackMock })) -vi.mock('../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: getCohortAtEmitMock })) +vi.mock('../../../telemetry/client', () => ({ track: trackMock })) +vi.mock('../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: getCohortAtEmitMock })) function commitCatalog( store: ReturnType, @@ -49,41 +49,6 @@ describe('orcad migration catalog persistence', () => { // Two desktops on one host each carry their own focus; the second must not be refused for it. - it('stages durably without publishing rows, then commits catalog and receipt together', async () => { - const store = createStore() - const input = manifest() - - expect( - store.stageOrcadMigrationCatalog(input, { - now: () => new Date('2026-08-30T12:03:00.000Z') - }) - ).toEqual({ - state: 'staged', - migrationId: input.migrationId, - manifestSha256: input.manifestSha256, - stagedAt: '2026-08-30T12:03:00.000Z' - }) - expect(store.getRepos()).toEqual([]) - await store.flushPendingOrThrowAsync() - - const restored = createStore() - expect(restored.getOrcadMigrationCatalogState(input)).toMatchObject({ state: 'staged' }) - expect( - restored.commitStagedOrcadMigrationCatalog(input, { - now: () => new Date('2026-08-30T12:05:00.000Z') - }) - ).toMatchObject({ state: 'committed', receipt: { importedAt: '2026-08-30T12:05:00.000Z' } }) - expect(restored.getRepos()).toHaveLength(1) - await restored.flushPendingOrThrowAsync() - - const committed = createStore() - expect(committed.getOrcadMigrationCatalogState(input)).toMatchObject({ - state: 'committed', - receipt: { repositoryIds: ['repo-1'] } - }) - expect(readDataFile()).not.toHaveProperty('orcadMigrationStagedCatalogs.0') - }) - it('recovers a dormant commit lost before flush from the durable stage', async () => { const store = createStore() const base = manifest() diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-lineage.test.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-lineage.test.ts similarity index 76% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-lineage.test.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-lineage.test.ts index 93315bf1bcc..70045c7ef78 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-lineage.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-lineage.test.ts @@ -2,26 +2,26 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { getDefaultPersistedState } from '../../../shared/constants' + import type { OrcadMigrationDormantStatePayload, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' import type { CrossStoreWorkspaceLineage, WorkspaceLineage, WorktreeLineage -} from '../../../shared/worktree/lineage-types' -import { parseOrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' +} from '../../../../shared/worktree/lineage-types' +import { parseOrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' import { manifest } from './persistence-orcad-migration-catalog-fixture' -import { createStore, testState, writeDataFile } from '../persistence-test-harness' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, safeStorage: { isEncryptionAvailable: () => false } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn(() => ({})) })) @@ -103,29 +103,6 @@ describe('orcad migration lineage', () => { rmSync(testState.dir, { recursive: true, force: true }) }) - it.each(['saved here', 'saved here and repeated', 'only in the import'] as const)( - 'keeps a folder parent over an inferred worktree parent %s', - (inferredParent) => { - if (inferredParent !== 'only in the import') { - writeDataFile({ - ...getDefaultPersistedState(testState.dir), - worktreeLineageById: { [CHILD]: worktreeParent('inferred') } - }) - } - const store = createStore() - - commit( - store, - withLineage(inferredParent === 'saved here' ? [] : [worktreeParent('inferred')], [ - folderParent - ]) - ) - - expect(store.getWorktreeLineage(CHILD)).toBeUndefined() - expect(store.getWorkspaceLineage(CHILD_KEY)?.parentWorkspaceKey).toBe('folder:folder-1') - } - ) - it('refuses a payload whose worktree has two explicit parents, changing nothing', () => { const store = createStore() diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-wsl-generation-reuse.test.ts b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-wsl-generation-reuse.test.ts similarity index 57% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-wsl-generation-reuse.test.ts rename to src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-wsl-generation-reuse.test.ts index f6f32002228..f53e392d910 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-wsl-generation-reuse.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-wsl-generation-reuse.test.ts @@ -7,10 +7,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { Repo } from '../../../shared/repo-types' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { Repo } from '../../../../shared/repo-types' import { manifest } from './persistence-orcad-migration-catalog-fixture' -import { createStore, testState } from '../persistence-test-harness' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -20,8 +20,8 @@ vi.mock('electron', () => ({ decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').slice('encrypted:'.length) } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn(() => ({ nth_repo_added: 1 })) })) @@ -57,42 +57,6 @@ describe('two WSL moves that share a generation number', () => { rmSync(testState.dir, { recursive: true, force: true }) }) - it('stage and commit independently, each under its own receipt', async () => { - const store = createStore() - const earlier = wslMove('move-earlier', 'repo-a') - const later = wslMove('move-later', 'repo-b') - expect(earlier.manifestSha256).not.toBe(later.manifestSha256) - - expect(store.stageOrcadMigrationCatalog(earlier).state).toBe('staged') - expect(store.stageOrcadMigrationCatalog(later).state).toBe('staged') - expect(store.commitStagedOrcadMigrationCatalog(earlier)).toMatchObject({ - state: 'committed', - receipt: { migrationId: 'move-earlier', repositoryIds: ['repo-a'] } - }) - // The earlier commit neither committed nor dropped the later stage. - expect(store.getOrcadMigrationCatalogState(later).state).toBe('staged') - expect(store.commitStagedOrcadMigrationCatalog(later)).toMatchObject({ - state: 'committed', - receipt: { migrationId: 'move-later', repositoryIds: ['repo-b'] } - }) - await store.flushPendingOrThrowAsync() - - const restored = createStore() - for (const move of [earlier, later]) { - expect(restored.getOrcadMigrationCatalogState(move)).toMatchObject({ - state: 'committed', - migrationId: move.migrationId, - manifestSha256: move.manifestSha256 - }) - } - expect( - restored - .getRepos() - .map((repo) => repo.id) - .sort() - ).toEqual(['repo-a', 'repo-b']) - }) - it('abort one without touching the other', () => { const store = createStore() const earlier = wslMove('move-earlier', 'repo-a') diff --git a/src/main/persistence/migrating-orcad-catalog/migration-journal-directory.test.ts b/src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.test.ts similarity index 100% rename from src/main/persistence/migrating-orcad-catalog/migration-journal-directory.test.ts rename to src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.test.ts diff --git a/src/main/persistence/migrating-orcad-catalog/migration-journal-directory.ts b/src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/migration-journal-directory.ts rename to src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.ts index 91e59e93a38..0a8beab005c 100644 --- a/src/main/persistence/migrating-orcad-catalog/migration-journal-directory.ts +++ b/src/main/persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory.ts @@ -1,10 +1,10 @@ // Unreadable journals fail closed; source-specific directories preserve older-build compatibility. import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from 'node:fs' import { join } from 'node:path' -import { writeSecureJsonFileWithinLimit } from '../../../shared/secure-storage/bounded-secure-json-file' -import { errorMessage } from '../../../shared/error-message' -import { readNodeFileSyncWithinLimit } from '../../../shared/file-content/node-bounded-file-reader' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +import { writeSecureJsonFileWithinLimit } from '../../../../shared/secure-storage/bounded-secure-json-file' +import { errorMessage } from '../../../../shared/error-message' +import { readNodeFileSyncWithinLimit } from '../../../../shared/file-content/node-bounded-file-reader' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' const JOURNAL_FILE = /^[A-Za-z0-9_-]{1,128}\.json$/ // `.json....tmp`: a durable write that died before its rename. diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.test.ts b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.test.ts similarity index 66% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.test.ts rename to src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.test.ts index 2110dca23d0..b91d2222586 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.test.ts @@ -1,13 +1,12 @@ -import { mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync } from 'node:fs' +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { orcadMigrationCutoverFixture as cutover } from '../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' +import { orcadMigrationCutoverFixture as cutover } from '../../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' import { findOrcadMigrationSourceCutoverForTarget, listOrcadMigrationSourceCutovers, orcadMigrationCutoverJournalDirectory, - removeOrcadMigrationSourceCutover, writeOrcadMigrationSourceCutover } from './orcad-migration-cutover-journal' @@ -21,16 +20,6 @@ const journalPath = (id: string) => join(orcadMigrationCutoverJournalDirectory(userDataPath), `${id}.json`) describe('migration cutover journal sidecar', () => { - it('round-trips a cutover in an owner-only file', () => { - writeOrcadMigrationSourceCutover(userDataPath, cutover()) - expect(findOrcadMigrationSourceCutoverForTarget(userDataPath, 'ssh-1')).toEqual(cutover()) - if (process.platform !== 'win32') { - expect(statSync(journalPath('migration-1')).mode & 0o077).toBe(0) - } - removeOrcadMigrationSourceCutover(userDataPath, 'migration-1') - expect(listOrcadMigrationSourceCutovers(userDataPath)).toEqual([]) - }) - it.each([ ['corrupt JSON', '{not json'], ['a manifest bound to another target', JSON.stringify({ ...cutover(), sshTargetId: 'ssh-2' })], @@ -42,12 +31,6 @@ describe('migration cutover journal sidecar', () => { expect(() => listOrcadMigrationSourceCutovers(userDataPath)).toThrow('stays fenced') }) - it("reads a newer build's journal that adds an optional field", () => { - mkdirSync(orcadMigrationCutoverJournalDirectory(userDataPath), { recursive: true }) - writeFileSync(journalPath('migration-1'), JSON.stringify({ ...cutover(), addedLater: true })) - expect(listOrcadMigrationSourceCutovers(userDataPath)).toEqual([cutover()]) - }) - it('fails closed on a file whose name disagrees with its migration', () => { mkdirSync(orcadMigrationCutoverJournalDirectory(userDataPath), { recursive: true }) writeFileSync(journalPath('other'), JSON.stringify(cutover())) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.ts b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.ts similarity index 98% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.ts rename to src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.ts index 898b609bcb8..b2ef692cf11 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal.ts +++ b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal.ts @@ -4,7 +4,7 @@ import { isRetainedOrcadMigrationSourceCutover, parseOrcadMigrationSourceCutover, type OrcadMigrationSourceCutover -} from '../../../shared/orcad-migration/orcad-migration-source-cutover' +} from '../../../../shared/orcad-migration/orcad-migration-source-cutover' import { createMigrationJournalDirectory, orderMigrationJournalChain diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-rollback-mark.ts b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-rollback-mark.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-rollback-mark.ts rename to src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-rollback-mark.ts index d2fe9e6535a..8775f840364 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-rollback-mark.ts +++ b/src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-rollback-mark.ts @@ -1,4 +1,4 @@ -import type { KnownRuntimeEnvironment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' +import type { KnownRuntimeEnvironment } from '../../../../shared/remote-runtime/host-catalog/runtime-environments' import { listOrcadMigrationSourceCutovers } from './orcad-migration-cutover-journal' /** Use the durable migration mark or older delta journal time; unreadable journals conservatively return now to block destructive rollback. */ diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-automation-state.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-automation-state.ts similarity index 85% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-automation-state.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-automation-state.ts index 70630d58e9e..0d83e901e27 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-automation-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-automation-state.ts @@ -1,12 +1,12 @@ -import { automationCanonicalDefinition } from '../../../shared/automations/launch/automation-launch-setup' -import { MAX_AUTOMATION_RUNS_PER_AUTOMATION } from '../../../shared/automations/history/automation-run-retention' +import { automationCanonicalDefinition } from '../../../../shared/automations/launch/automation-launch-setup' +import { MAX_AUTOMATION_RUNS_PER_AUTOMATION } from '../../../../shared/automations/history/automation-run-retention' import { isFinalAutomationRunStatus, type AutomationRun -} from '../../../shared/automations/history/automation-run' -import type { Automation } from '../../../shared/automations/automation-definition' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { selectNewRows } from './orcad-catalog-row-identity' +} from '../../../../shared/automations/history/automation-run' +import type { Automation } from '../../../../shared/automations/automation-definition' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import { selectNewRows } from '../catalog-commit/orcad-catalog-row-identity' export type PreparedOrcadMigrationAutomationState = { incomingAutomations: Automation[] diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-catalog-projection.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-catalog-projection.ts similarity index 75% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-catalog-projection.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-catalog-projection.ts index 233b8637a42..760e6be9a43 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-catalog-projection.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-catalog-projection.ts @@ -1,6 +1,6 @@ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' export function toOrcadDestinationRepository(source: Repo): Repo { const destination = structuredClone(source) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-client-state.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-client-state.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-client-state.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-client-state.ts index 1620fbe95f8..cc55a613224 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-client-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-client-state.ts @@ -1,9 +1,9 @@ -import type { PersistedState } from '../../../shared/persisted-state-types' +import type { PersistedState } from '../../../../shared/persisted-state-types' import type { OrcadMigrationClientStatePayload, OrcadMigrationUiRoutingState -} from '../../../shared/orcad-migration/orcad-migration-client-state' -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../shared/orcad-migration/orcad-migration-client-state' +import { serializeOrcadMigrationValue } from '../../../../shared/orcad-migration/orcad-migration-manifest' export type PreparedOrcadMigrationClientState = { incoming: OrcadMigrationClientStatePayload | undefined diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.test.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.test.ts similarity index 58% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.test.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.test.ts index 68f50e2c23f..678bd40c474 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.test.ts @@ -1,12 +1,12 @@ import { describe, expect, it } from 'vitest' -import { getDefaultPersistedState, getDefaultWorkspaceSession } from '../../../shared/constants' +import { getDefaultPersistedState, getDefaultWorkspaceSession } from '../../../../shared/constants' import { CLIENT_HOSTED_BROWSER_PAGE_RECORD_VERSION, type PersistedClientHostedBrowserPage -} from '../../../shared/workspace-session/client-hosted-browser-page-record' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { TerminalLayoutSnapshot } from '../../../shared/workspace-layout/terminal-tab-types' +} from '../../../../shared/workspace-session/client-hosted-browser-page-record' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import type { TerminalLayoutSnapshot } from '../../../../shared/workspace-layout/terminal-tab-types' import { prepareOrcadMigrationWorkspaceSession } from './orcad-destination-workspace-session' const OWNER = 'repo-1::/srv/worktree' @@ -48,22 +48,6 @@ describe('destination workspace-session merge validation', () => { ).toThrow('orcad_migration_dormant_id_conflict:workspace_session:client-browser-page:page-1') }) - it.each(['existing', 'incoming'] as const)( - 'rejects a pane identity already claimed by another %s tab without mutation', - (location) => { - const current = state() - const next = incoming([]) - next.terminalLayoutsByTabId['incoming-tab'] = layout() - const competing = location === 'existing' ? current.workspaceSession : next - competing.terminalLayoutsByTabId['other-tab'] = layout() - const before = structuredClone({ current, next }) - expect(() => prepareOrcadMigrationWorkspaceSession(next, current)).toThrow( - `orcad_migration_dormant_id_conflict:workspace_session:terminal-leaf:${LEAF}` - ) - expect({ current, next }).toEqual(before) - } - ) - it('rejects duplicate leaves within an incoming split', () => { const next = incoming([]) next.terminalLayoutsByTabId.tab = { @@ -99,27 +83,4 @@ describe('destination workspace-session merge validation', () => { ) expect(current).toEqual(before) }) - - it('preserves a unique split and accepts an exact retry with per-pane records', () => { - const next = incoming([]) - next.terminalLayoutsByTabId.tab = { - ...layout(), - root: { - type: 'split', - direction: 'vertical', - ratio: 0.3, - first: { type: 'leaf', leafId: LEAF }, - second: { type: 'leaf', leafId: OTHER_LEAF } - }, - buffersByLeafId: { [LEAF]: 'first output', [OTHER_LEAF]: 'second output' }, - titlesByLeafId: { [LEAF]: 'first', [OTHER_LEAF]: 'second' } - } - const current = state() - const prepared = prepareOrcadMigrationWorkspaceSession(next, current) - expect(prepared.merged?.terminalLayoutsByTabId).toEqual(next.terminalLayoutsByTabId) - current.workspaceSession = prepared.merged! - expect(prepareOrcadMigrationWorkspaceSession(next, current).merged).toEqual( - current.workspaceSession - ) - }) }) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.ts index 4e2ebaed427..655f06c7338 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-workspace-session.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-workspace-session.ts @@ -1,10 +1,10 @@ -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { isRecord } from '../../../shared/orcad-migration/orcad-migration-manifest-fields' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { SESSION_FOCUS_FIELDS } from '../../../shared/workspace-session/workspace-session-host-field-ownership' -import { mergeWorkspaceSessions } from '../../orca-profiles/project-transfer/profile-project-session-state' -import { collectLayoutLeafIdsInOrder } from '../restoring-sessions/terminal-layout-normalization' +import { serializeOrcadMigrationValue } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { isRecord } from '../../../../shared/orcad-migration/orcad-migration-manifest-fields' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import { SESSION_FOCUS_FIELDS } from '../../../../shared/workspace-session/workspace-session-host-field-ownership' +import { mergeWorkspaceSessions } from '../../../orca-profiles/project-transfer/profile-project-session-state' +import { collectLayoutLeafIdsInOrder } from '../../../../shared/workspace-layout/terminal-pane-tree' const MERGED_SESSION_RECORD_FIELDS = [ 'tabsByWorktree', diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-destination-worktree-metadata.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-worktree-metadata.ts similarity index 67% rename from src/main/persistence/migrating-orcad-catalog/orcad-destination-worktree-metadata.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-worktree-metadata.ts index 105f043d1da..39c9f87c7ea 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-destination-worktree-metadata.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-destination-worktree-metadata.ts @@ -1,9 +1,12 @@ -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { OrcadMigrationDormantStatePayload } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { canonicalWorktreeIdentity } from '../../../shared/worktree/identity' -import { composeWorktreeHostIdentity } from '../../../shared/worktree/host-qualified-identity' -import { omitDefaultWorktreeMetaFields } from '../../../shared/worktree/meta-persisted-defaults' +import type { PersistedState } from '../../../../shared/persisted-state-types' + +import { + type OrcadMigrationDormantStatePayload, + serializeOrcadMigrationValue +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { canonicalWorktreeIdentity } from '../../../../shared/worktree/identity' +import { composeWorktreeHostIdentity } from '../../../../shared/worktree/host-qualified-identity' +import { omitDefaultWorktreeMetaFields } from '../../../../shared/worktree/meta-persisted-defaults' export function assertOrcadDestinationCanonicalMetadata( state: PersistedState, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-dormant-lineage-reconciliation.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-lineage-reconciliation.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-dormant-lineage-reconciliation.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-lineage-reconciliation.ts index c4f00aff3d0..38b04d57627 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-dormant-lineage-reconciliation.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-lineage-reconciliation.ts @@ -1,16 +1,16 @@ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' -import type { WorkspaceLineage, WorktreeLineage } from '../../../shared/worktree/lineage-types' -import { toWorkspaceLineageRow } from '../../../shared/worktree/worktree-lineage-workspace-row' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import { hostWorktreeTarget } from '../../../../shared/worktree/host-qualified-identity' +import type { WorkspaceLineage, WorktreeLineage } from '../../../../shared/worktree/lineage-types' +import { toWorkspaceLineageRow } from '../../../../shared/worktree/worktree-lineage-workspace-row' import { folderWorkspaceKey, parseWorkspaceKey, worktreeWorkspaceKey, type WorkspaceKey -} from '../../../shared/workspace-scope' -import { folderParentDefeatsInferredParent } from '../loading-store/workspace-lineage/folder-parent-lineage-persistence' -import { ownsRawIdBucket } from '../loading-store/workspace-lineage/metadata-lineage-operations' +} from '../../../../shared/workspace-scope' +import { folderParentDefeatsInferredParent } from '../../loading-store/workspace-lineage/folder-parent-lineage-persistence' +import { ownsRawIdBucket } from '../../loading-store/workspace-lineage/metadata-lineage-operations' /** One imported child's parent records; `legacy: null` deletes a destination worktree row. */ export type PreparedChildLineage = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-dormant-state-records.ts b/src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-state-records.ts similarity index 90% rename from src/main/persistence/migrating-orcad-catalog/orcad-dormant-state-records.ts rename to src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-state-records.ts index a9fa62729b9..c9044f16690 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-dormant-state-records.ts +++ b/src/main/persistence/migrating-orcad-catalog/destination/orcad-dormant-state-records.ts @@ -1,19 +1,19 @@ import type { OrcadMigrationDormantStatePayload, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { SparsePreset } from '../../../shared/worktree/create-types' -import type { WorkspaceLineage, WorktreeLineage } from '../../../shared/worktree/lineage-types' -import type { WorktreeMeta } from '../../../shared/worktree/meta-types' -import { omitDefaultWorktreeMetaFields } from '../../../shared/worktree/meta-persisted-defaults' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { SparsePreset } from '../../../../shared/worktree/create-types' +import type { WorkspaceLineage, WorktreeLineage } from '../../../../shared/worktree/lineage-types' +import type { WorktreeMeta } from '../../../../shared/worktree/meta-types' +import { omitDefaultWorktreeMetaFields } from '../../../../shared/worktree/meta-persisted-defaults' import { assertOrcadDestinationCanonicalMetadata } from './orcad-destination-worktree-metadata' -import { assertSameValue } from './orcad-catalog-row-identity' +import { assertSameValue } from '../catalog-commit/orcad-catalog-row-identity' import { mergeRetiredNameRegistries, type RetiredNameRegistry -} from '../../../shared/worktree/retired-name-registry' -import { recordRetirementNamespaceRegistry } from '../../workspaces/removal/retirement/worktree-retirement-namespace' +} from '../../../../shared/worktree/retired-name-registry' +import { recordRetirementNamespaceRegistry } from '../../../workspaces/removal/retirement/worktree-retirement-namespace' import { applyPreparedOrcadMigrationWorkspaceSession, prepareOrcadMigrationWorkspaceSession, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts index 3247fdcfaef..4fd5aed0d10 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts +++ b/src/main/persistence/migrating-orcad-catalog/orcad-catalog-import.ts @@ -1,5 +1,5 @@ import { MAX_ORCAD_MIGRATION_STAGED_CATALOGS } from '../../../shared/orcad-migration/orcad-migration-staged-catalog-validation' -import { ORCAD_CATALOG_COMMIT_DOMAINS } from './orcad-catalog-commit-domains' +import { ORCAD_CATALOG_COMMIT_DOMAINS } from './catalog-commit/orcad-catalog-commit-domains' import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' import type { OrcadMigrationCatalogAbortResult, @@ -20,15 +20,16 @@ import type { } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' import type { RepoLifecycleOperations } from '../loading-store/project-catalog/repo-lifecycle-operations' import type { StoreRuntimeState } from '../loading-store/store-runtime-state' -import type { WriteSchedulingOperations } from '../loading-store/profile-writing/write-scheduling' + import { scheduleSave } from '../loading-store/profile-writing/write-scheduling' +import type { WriteSchedulingOperations } from '../loading-store/profile-writing/write-scheduling' import { applyPreparedOrcadMigrationCatalog, assertOrcadMigrationReceiptMatchesManifest, assertSameOrcadMigrationManifest, prepareOrcadMigrationCatalog, type PreparedOrcadMigrationCatalog -} from './orcad-catalog-records' +} from './catalog-commit/orcad-catalog-records' import { expireOrcadMigrationStages, findOrcadMigrationImportReceipt, @@ -36,7 +37,7 @@ import { recordOrcadMigrationCommitWriteGeneration, recordOrcadMigrationImportReceipt, type OrcadMigrationCommitGenerationRuntime -} from './orcad-catalog-receipt-ledger' +} from './catalog-commit/orcad-catalog-receipt-ledger' import { abortOrcadMigrationSnapshots, assertOrcadMigrationSnapshotsReady, @@ -44,7 +45,7 @@ import { inspectOrcadMigrationSnapshotUploads, pruneOrcadMigrationSnapshotStaging, stageOrcadMigrationSnapshotChunk -} from './orcad-scrollback-snapshot-transfer' +} from './terminal-history/orcad-scrollback-snapshot-transfer' import { abortOrcadMigrationBlobs, assertOrcadMigrationBlobSetMatches, @@ -53,14 +54,14 @@ import { inspectOrcadMigrationBlobUploads, pruneOrcadMigrationBlobStaging, stageOrcadMigrationBlobChunk -} from './orcad-migration-blob-staging' -import { withStagedAutomationRunHistory } from './orcad-staged-automation-run-history' -import { assertOrcadMigrationBlobContentsValid } from './orcad-migration-blob-installers' +} from './blob-transfer/orcad-migration-blob-staging' +import { withStagedAutomationRunHistory } from './catalog-commit/orcad-staged-automation-run-history' +import { assertOrcadMigrationBlobContentsValid } from './blob-transfer/orcad-migration-blob-installers' import { abortOrcadMigrationCatalogByReference, committedMigrations, stagedManifests -} from './orcad-catalog-reference-abort' +} from './catalog-commit/orcad-catalog-reference-abort' type OrcadCatalogImportRuntime = OrcadMigrationCommitGenerationRuntime & Pick diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-export-holds.test.ts b/src/main/persistence/migrating-orcad-catalog/orcad-migration-export-holds.test.ts deleted file mode 100644 index 9d79bf37f81..00000000000 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-export-holds.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { mkdtempSync, rmSync, statSync, readFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { - getTerminalScrollbackSnapshotPath, - writeTerminalScrollbackSnapshotSync -} from '../../pty/scrollback/terminal-scrollback-snapshots' -import { deleteRemovedTerminalScrollbackSnapshots } from '../loading-store/workspace-sessions/terminal-session-cleanup' -import { deleteRemovedTerminalScrollbackSnapshotsAsync } from '../../pty/scrollback/terminal-scrollback-snapshot-async-migration' - -const roots: string[] = [] -afterEach(() => { - for (const root of roots.splice(0)) { - rmSync(root, { recursive: true, force: true }) - } -}) - -function storage() { - const root = mkdtempSync(join(tmpdir(), 'orcad-export-holds-')) - roots.push(root) - return { root, storage: { snapshotRoot: join(root, 'terminal-scrollback') } } -} - -function sessionWithRef(ref: string | null): WorkspaceSessionState { - return { - ...getDefaultWorkspaceSession(), - terminalLayoutsByTabId: ref - ? { - 'tab-1': { - root: null, - activeLeafId: null, - expandedLeafId: null, - scrollbackRefsByLeafId: { 'leaf-1': ref } - } - } - : {} - } -} - -describe('scrollback store reads and retention for migration export', () => { - it.each(['sync', 'async'] as const)( - 'keeps a %s-removed snapshot a pending export still reads', - async (mode) => { - const { storage: store } = storage() - const ref = - writeTerminalScrollbackSnapshotSync({ - tabId: 'tab-1', - leafId: 'leaf-1', - buffer: 'retained', - storage: store - }) ?? '' - const path = getTerminalScrollbackSnapshotPath(ref, store) ?? '' - const retained = new Set([ref]) - if (mode === 'sync') { - deleteRemovedTerminalScrollbackSnapshots( - sessionWithRef(ref), - sessionWithRef(null), - store, - retained - ) - } else { - await deleteRemovedTerminalScrollbackSnapshotsAsync( - sessionWithRef(ref), - sessionWithRef(null), - store, - retained - ) - } - expect(readFileSync(path, 'utf8')).toBe('retained') - deleteRemovedTerminalScrollbackSnapshots(sessionWithRef(ref), sessionWithRef(null), store) - expect(() => statSync(path)).toThrow() - } - ) -}) diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-local-only-worktree-meta.test.ts b/src/main/persistence/migrating-orcad-catalog/persistence-local-only-worktree-meta.test.ts deleted file mode 100644 index 4044ee1e5e5..00000000000 --- a/src/main/persistence/migrating-orcad-catalog/persistence-local-only-worktree-meta.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - closeTestStores, - createStore, - readPersistedStateJson, - testState -} from '../persistence-test-harness' -// Repo-less floating/setup terminals belong to this machine and must not project onto SSH hosts (#31498). -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' -import { join } from 'node:path' -import { tmpdir } from 'node:os' -import { FLOATING_TERMINAL_WORKTREE_ID, getDefaultPersistedState } from '../../../shared/constants' -import { composeWorktreeHostIdentity } from '../../../shared/worktree/host-qualified-identity' -import { canonicalWorktreeIdentity } from '../../../shared/worktree/identity' -import { hydrateWorktreeMetaAliasProjection } from '../loading-store/worktree-metadata/worktree-meta-alias-projection' -import { normalizeWorktreeLinkedItemMetadata } from '../tracking-repos/worktree-metadata-normalization' - -vi.mock('electron', () => ({ - app: { getPath: () => testState.dir }, - safeStorage: { isEncryptionAvailable: () => false } -})) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn() })) - -const SSH_HOST = 'ssh:ssh-1' - -const INSTANCE_ID = '11111111-1111-4111-8111-111111111111' -const floatingRow = { - instanceId: INSTANCE_ID, - displayName: '', - comment: '', - isUnread: false, - sortOrder: 1, - lastActivityAt: 1, - workspaceStatus: 'in-progress' -} - -function createUpgradedStore(metadata: Record = {}) { - mkdirSync(testState.dir, { recursive: true }) - writeFileSync( - join(testState.dir, 'orca-data.json'), - JSON.stringify({ - ...getDefaultPersistedState(testState.dir), - worktreeMeta: { [FLOATING_TERMINAL_WORKTREE_ID]: floatingRow }, - ...metadata - }), - 'utf-8' - ) - return createStore() -} - -beforeEach(() => { - testState.dir = mkdtempSync(join(tmpdir(), 'orca-local-only-worktree-meta-')) -}) - -afterEach(async () => { - await closeTestStores() - rmSync(testState.dir, { recursive: true, force: true }) -}) - -describe('local-only workspace metadata', () => { - it('keeps a local floating terminal row over a staler remote copy, and settles in one load', async () => { - const remoteKey = canonicalWorktreeIdentity({ - worktreeId: FLOATING_TERMINAL_WORKTREE_ID, - executionHostId: SSH_HOST, - instanceId: INSTANCE_ID - }) - const localRow = { ...floatingRow, hostId: 'local', lastActivityAt: 5, workspaceStatus: 'done' } - createUpgradedStore({ - worktreeMeta: { [FLOATING_TERMINAL_WORKTREE_ID]: localRow }, - worktreeMetaByIdentity: { [remoteKey]: { ...floatingRow, hostId: SSH_HOST } }, - worktreeIdentityAliases: { - [composeWorktreeHostIdentity(SSH_HOST, FLOATING_TERMINAL_WORKTREE_ID)]: [remoteKey] - } - }).flush() - await closeTestStores() - const saved = JSON.parse(readPersistedStateJson()) - hydrateWorktreeMetaAliasProjection(saved) - expect(normalizeWorktreeLinkedItemMetadata(saved)).toBe(false) - - const reloaded = createStore() - expect( - reloaded.getAllWorktreeMetaForHost('local')[FLOATING_TERMINAL_WORKTREE_ID] - ).toMatchObject({ hostId: 'local', lastActivityAt: 5, workspaceStatus: 'done' }) - expect(reloaded.getAllWorktreeMetaForHost(SSH_HOST)).toEqual({}) - }) -}) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-moved-automations.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-moved-automations.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations.ts index 47670d5999e..0d2eb5dae8a 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-moved-automations.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-moved-automations.ts @@ -1,18 +1,18 @@ /** Moves carry automations disabled, which every server version accepts; re-enable those that ran here once the move commits. */ import { z } from 'zod' -import type { Automation } from '../../../shared/automations/automation-definition' -import { isRetainedOrcadMigrationSourceCutover } from '../../../shared/orcad-migration/orcad-migration-source-cutover' -import { parsePairingCode } from '../../../shared/remote-runtime/pairing/pairing' +import type { Automation } from '../../../../shared/automations/automation-definition' +import { isRetainedOrcadMigrationSourceCutover } from '../../../../shared/orcad-migration/orcad-migration-source-cutover' +import { parsePairingCode } from '../../../../shared/remote-runtime/pairing/pairing' import { ORCAD_MIGRATION_DESTINATION_UNSUPPORTED, sendSupportedMigrationRequest, type CatalogRequestOptions -} from '../../managed-server/migration/catalog/orcad-migration-request' +} from '../../../managed-server/migration/catalog/orcad-migration-request' import { listOrcadMigrationCutoverChainForTarget, listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from './orcad-migration-cutover-journal' +} from '../cutover-journals/orcad-migration-cutover-journal' /** Resolves false when the server answers that it can't; throws when it can't be reached. */ export type EnableServerAutomation = (automation: Automation) => Promise diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.test.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.test.ts similarity index 66% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.test.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.test.ts index 77876d701da..ececfb2c1dc 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.test.ts @@ -1,24 +1,22 @@ import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import type { Repo } from '../../../shared/repo-types' -import type { PersistedOpenFile } from '../../../shared/workspace-session/workspace-session-state-types' -import { closeTestStores, createSqliteTestStore } from '../persistence-test-harness' -import { Store } from '../loading-store/store' +import type { Repo } from '../../../../shared/repo-types' +import type { PersistedOpenFile } from '../../../../shared/workspace-session/workspace-session-state-types' +import { closeTestStores, createSqliteTestStore } from '../../persistence-test-harness' +import { Store } from '../../loading-store/store' import { listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from './orcad-migration-cutover-journal' -import { orcadMigrationCutoverFixture } from '../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' -import { listPendingManagedOrcadMigrations } from '../../managed-server/lifecycle/orcad-managed-migration-status' +} from '../cutover-journals/orcad-migration-cutover-journal' +import { orcadMigrationCutoverFixture } from '../../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' +import { listPendingManagedOrcadMigrations } from '../../../managed-server/lifecycle/orcad-managed-migration-status' import { retainUnretainedOrcadMigrationSources, retainOrcadMigrationSource } from './orcad-migration-source-retention' -import { enableMovedOrcadAutomations } from './orcad-migration-moved-automations' -import { createOrcadMigrationManifest } from './orcad-migration-manifest-export' const TARGET_ID = 'ssh-1' const SOURCE_HOST = `ssh:${TARGET_ID}` @@ -123,29 +121,6 @@ describe('renaming unsaved drafts to the server on commit', () => { store.addRepo(REPO) }) - it('moves the host and desktop drafts, with their baseline, and leaves the source as it was', async () => { - saveFiles(SOURCE_HOST, [draftedFile('/srv/app/host.md', 'host draft')]) - saveFiles('local', [draftedFile('/srv/app/desktop.md', 'desktop draft')]) - const source = JSON.stringify(store.getWorkspaceSession(SOURCE_HOST)) - writeOrcadMigrationSourceCutover(userDataPath, committed()) - - await retainOrcadMigrationSource(userDataPath, 'm-1', store) - - expect(serverFiles()).toEqual([ - { ...draftedFile('/srv/app/host.md', 'host draft'), runtimeEnvironmentId: 'env-1' }, - { ...draftedFile('/srv/app/desktop.md', 'desktop draft'), runtimeEnvironmentId: 'env-1' } - ]) - expect(listOrcadMigrationSourceCutovers(userDataPath)[0]?.sourceRetainedAt).toBeDefined() - expect(JSON.stringify(store.getWorkspaceSession(SOURCE_HOST))).toBe(source) - await store.flushPendingOrThrowAsync() - await closeTestStores() - store = createSqliteTestStore(Store, { dataFile: join(userDataPath, 'orca-data.json') }) - expect(serverFiles()?.map((file) => file.dirtyDraftContent)).toEqual([ - 'host draft', - 'desktop draft' - ]) - }) - it('keeps what the server partition already holds, and never revives a discarded draft', async () => { saveFiles(SOURCE_HOST, [ draftedFile('/srv/app/a.md', 'source A'), @@ -228,49 +203,3 @@ describe('renaming unsaved drafts to the server on commit', () => { }) // #29083: a moved automation must run on the server, never again from this desktop. -describe('moving automations that ran on this desktop', () => { - const TARGET = { id: TARGET_ID, label: 'Prod', host: 'h', port: 22, username: 'u', generation: 2 } - - function committedWithAutomation() { - store.addSshTarget(TARGET) - store.addRepo(REPO) - const automation = store.createAutomation({ - name: 'Nightly check', - prompt: 'Check the repo', - agentId: 'claude', - projectId: REPO.id, - workspaceMode: 'new_per_run', - timezone: 'UTC', - rrule: 'FREQ=DAILY', - dtstart: 1 - }) - const manifest = createOrcadMigrationManifest(store, TARGET, { - migrationId: 'm-1', - destinationEnvironmentId: 'env-1' - }) - writeOrcadMigrationSourceCutover(userDataPath, { - ...orcadMigrationCutoverFixture('m-1', TARGET_ID), - phase: 'destination-committed', - manifestSha256: manifest.manifestSha256, - manifest - }) - return automation - } - - it('disables the retained copy at commit and re-enables it on the server once', async () => { - const automation = committedWithAutomation() - - await retainOrcadMigrationSource(userDataPath, 'm-1', store) - expect(store.listAutomations()[0]?.enabled).toBe(false) - await restart() - expect(store.listAutomations()[0]?.enabled).toBe(false) - - const enable = vi.fn(async () => true) - await expect(enableMovedOrcadAutomations(userDataPath, 'm-1', enable)).resolves.toBe(0) - await enableMovedOrcadAutomations(userDataPath, 'm-1', enable) - expect(enable).toHaveBeenCalledOnce() - expect(enable).toHaveBeenCalledWith( - expect.objectContaining({ id: automation.id, dtstart: automation.dtstart }) - ) - }) -}) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.ts similarity index 91% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.ts index 1d30b6851c6..48b5d847a1e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-source-retention.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-migration-source-retention.ts @@ -1,13 +1,13 @@ /** Keep source rows for downgraded clients using their old relays; new clients hide them and serve managed state. Never delete retained rows automatically. */ -import { toRuntimeExecutionHostId } from '../../../shared/execution-host' -import type { OrcadMigrationSourceCutover } from '../../../shared/orcad-migration/orcad-migration-source-cutover' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { Store } from '../loading-store/store' -import { withRenamedOrcadMigrationDrafts } from './orcad-source-draft-rename' +import { toRuntimeExecutionHostId } from '../../../../shared/execution-host' +import type { OrcadMigrationSourceCutover } from '../../../../shared/orcad-migration/orcad-migration-source-cutover' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import type { Store } from '../../loading-store/store' +import { withRenamedOrcadMigrationDrafts } from '../source/worktrees/orcad-source-draft-rename' import { listOrcadMigrationSourceCutovers, writeOrcadMigrationSourceCutover -} from './orcad-migration-cutover-journal' +} from '../cutover-journals/orcad-migration-cutover-journal' type OrcadMigrationDraftRenameStore = Pick< Store, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source-changes.test.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-changes.test.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-retained-source-changes.test.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-changes.test.ts index ae2a22eb826..8aba00e2213 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source-changes.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-changes.test.ts @@ -2,23 +2,23 @@ import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import type { Repo } from '../../../shared/repo-types' -import type { SshTarget } from '../../../shared/ssh-types' -import { closeTestStores, createSqliteTestStore } from '../persistence-test-harness' -import { Store } from '../loading-store/store' -import { SshConnectionStore } from '../../ssh/targets/ssh-connection-store' -import { orcadMigrationCutoverFixture } from '../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' +import type { Repo } from '../../../../shared/repo-types' +import type { SshTarget } from '../../../../shared/ssh-types' +import { closeTestStores, createSqliteTestStore } from '../../persistence-test-harness' +import { Store } from '../../loading-store/store' +import { SshConnectionStore } from '../../../ssh/targets/ssh-connection-store' +import { orcadMigrationCutoverFixture } from '../../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' import { findOrcadMigrationSourceCutoverForTarget, writeOrcadMigrationSourceCutover -} from './orcad-migration-cutover-journal' -import { keepOrcadServerVersion } from '../../managed-server/migration/cutover/orcad-migration-delta-move' -import { createOrcadMigrationManifest } from './orcad-migration-manifest-export' +} from '../cutover-journals/orcad-migration-cutover-journal' +import { keepOrcadServerVersion } from '../../../managed-server/migration/cutover/orcad-migration-delta-move' +import { createOrcadMigrationManifest } from '../source/catalog/orcad-migration-manifest-export' import { currentOrcadSourceFingerprint, reconcileManagedOrcadSshTargets } from './orcad-retained-source' -import { visibleRepos } from './orcad-source-visibility' +import { visibleRepos } from '../source/catalog/orcad-source-visibility' const TARGET: SshTarget = { id: 'ssh-prod', diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source-session.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-session.ts similarity index 75% rename from src/main/persistence/migrating-orcad-catalog/orcad-retained-source-session.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-session.ts index 4db77c86690..df5d753281c 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source-session.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source-session.ts @@ -1,6 +1,9 @@ -import { parseExecutionHostId, type ExecutionHostId } from '../../../shared/execution-host' -import type { Store } from '../loading-store/store' -import { appUserDataPath, hiddenRetainedSourceTargetIds } from './orcad-source-visibility' +import { parseExecutionHostId, type ExecutionHostId } from '../../../../shared/execution-host' +import type { Store } from '../../loading-store/store' +import { + appUserDataPath, + hiddenRetainedSourceTargetIds +} from '../source/catalog/orcad-source-visibility' /** A hidden source's session goes with its repos: a window adopting it at startup brings closed tabs back (#33539). */ export function visibleSessionHostIds( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source.ts b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-retained-source.ts rename to src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source.ts index 60eae83fba7..3e797dfa825 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-retained-source.ts +++ b/src/main/persistence/migrating-orcad-catalog/retained-source/orcad-retained-source.ts @@ -1,24 +1,27 @@ import { createHash } from 'node:crypto' -import type { OrcadMigrationCatalogPayload } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationCatalogPayload } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { MAX_ORCAD_MIGRATION_FOLDER_WORKSPACES, MAX_ORCAD_MIGRATION_REPOSITORIES -} from '../../../shared/orcad-migration/orcad-migration-manifest-fields' +} from '../../../../shared/orcad-migration/orcad-migration-manifest-fields' -import { isRetainedOrcadMigrationSourceCutover } from '../../../shared/orcad-migration/orcad-migration-source-cutover' -import type { OrcadMigrationSourceCutover } from '../../../shared/orcad-migration/orcad-migration-source-cutover' -import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' -import { getOrcadSshDeployment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' -import type { SshTarget } from '../../../shared/ssh-types' -import type { Store } from '../loading-store/store' -import { collectOrcadMigrationSourceCatalog } from './orcad-source-catalog' +import { + isRetainedOrcadMigrationSourceCutover, + type OrcadMigrationSourceCutover +} from '../../../../shared/orcad-migration/orcad-migration-source-cutover' + +import { listEnvironments } from '../../../../shared/remote-runtime/host-store/runtime-environment-store' +import { getOrcadSshDeployment } from '../../../../shared/remote-runtime/host-catalog/runtime-environments' +import type { SshTarget } from '../../../../shared/ssh-types' +import type { Store } from '../../loading-store/store' +import { collectOrcadMigrationSourceCatalog } from '../source/catalog/orcad-source-catalog' import { listOrcadMigrationCutoverChainForTarget, writeOrcadMigrationSourceCutover -} from './orcad-migration-cutover-journal' +} from '../cutover-journals/orcad-migration-cutover-journal' -import { orcadMigrationCatalogIds } from './orcad-migration-manifest-export' -import type { CatalogStore } from './orcad-source-visibility' +import { orcadMigrationCatalogIds } from '../source/catalog/orcad-migration-manifest-export' +import type { CatalogStore } from '../source/catalog/orcad-source-visibility' type TargetStore = Pick diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-automation-state.ts b/src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-state.ts similarity index 91% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-automation-state.ts rename to src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-state.ts index 9b888936258..f6902172d3d 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-automation-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-state.ts @@ -1,20 +1,20 @@ -import { automationCanonicalDefinition } from '../../../shared/automations/launch/automation-launch-setup' +import { automationCanonicalDefinition } from '../../../../../shared/automations/launch/automation-launch-setup' import { isFinalAutomationRunStatus, type AutomationRun -} from '../../../shared/automations/history/automation-run' -import type { Automation } from '../../../shared/automations/automation-definition' -import { getAutomationRunRepoId } from '../../../shared/automations/history/automation-run-identity' -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' +} from '../../../../../shared/automations/history/automation-run' +import type { Automation } from '../../../../../shared/automations/automation-definition' +import { getAutomationRunRepoId } from '../../../../../shared/automations/history/automation-run-identity' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' import type { OrcadMigrationCatalogPayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' import type { TaskSourceContext, WorkspaceRunContext -} from '../../../shared/work-items/task-source-context' +} from '../../../../../shared/work-items/task-source-context' import { createOrcadMigrationExportScope, orcadMigrationScopeOwnsWholeHost, @@ -22,8 +22,8 @@ import { orcadMigrationOwnsRepoId, type OrcadMigrationSourceScope, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' -import { compareKeys } from './orcad-source-key-order' +} from '../catalog/orcad-source-scope' +import { compareKeys } from '../catalog/orcad-source-key-order' export type OrcadMigrationSourceAutomationInspection = { automations: Automation[] diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-automation-subtraction.ts b/src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-subtraction.ts similarity index 71% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-automation-subtraction.ts rename to src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-subtraction.ts index 38de61887da..13210bdc396 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-automation-subtraction.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/automations/orcad-source-automation-subtraction.ts @@ -1,7 +1,10 @@ -import { getAutomationRunRepoId } from '../../../shared/automations/history/automation-run-identity' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { createOrcadMigrationSourceScope, orcadMigrationOwnsRepoId } from './orcad-source-scope' +import { getAutomationRunRepoId } from '../../../../../shared/automations/history/automation-run-identity' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { + createOrcadMigrationSourceScope, + orcadMigrationOwnsRepoId +} from '../catalog/orcad-source-scope' /** Include rows a downgraded build added to moved projects. */ export function subtractOrcadMigrationSourceAutomationState( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-manifest-export.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-manifest-export.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export.ts index 7757f62fbbe..99b85207721 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-manifest-export.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export.ts @@ -3,38 +3,41 @@ import { createHash, randomUUID } from 'node:crypto' import { ORCAD_MIGRATION_MANIFEST_VERSION, parseOrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest-validation' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest-validation' import type { OrcadMigrationCatalogPayload, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' + +import { + ORCAD_MIGRATION_BLOB_KIND_CONTRACTS, + type OrcadMigrationBlobDescriptor +} from '../../../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' import { orcadMigrationAutomationRunHistoryBlob, serializeOrcadMigrationAutomationRunHistory, withOrcadMigrationAutomationRunHistory -} from '../../../shared/orcad-migration/orcad-migration-automation-run-history' +} from '../../../../../shared/orcad-migration/orcad-migration-automation-run-history' -import type { SshTarget } from '../../../shared/ssh-types' -import type { Store } from '../loading-store/store' +import type { SshTarget } from '../../../../../shared/ssh-types' +import type { Store } from '../../../loading-store/store' import { collectOrcadMigrationSourceCatalog } from './orcad-source-catalog' -import { computeOrcadMigrationManifestSha256 } from '../../orcad/orcad-migration-manifest-digest' +import { computeOrcadMigrationManifestSha256 } from '../../../../orcad/orcad-migration-manifest-digest' import { IDENTITY_ORCAD_MIGRATION_PATH_REWRITER, - rewriteOrcadMigrationPayloadPaths -} from './path-rewrite/orcad-migration-path-rewrite' + rewriteOrcadMigrationPayloadPaths, + type OrcadMigrationPathRewriter +} from '../../path-rewrite/orcad-migration-path-rewrite' -import type { OrcadMigrationPathRewriter } from './path-rewrite/orcad-migration-path-rewrite' import { ORCAD_MIGRATION_MANIFEST_TOO_LARGE, describeOversizedOrcadMigrationPayload, formatKib -} from '../../managed-server/migration/catalog/orcad-migration-payload-capacity' +} from '../../../../managed-server/migration/catalog/orcad-migration-payload-capacity' -import { hasDormantState } from './orcad-migration-dormant-state' +import { hasDormantState } from '../dormancy/orcad-migration-dormant-state' export type OrcadMigrationExportStore = Pick< Store, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-catalog-subtraction.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog-subtraction.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-catalog-subtraction.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog-subtraction.ts index 3a207824e6b..5967bfb4fe8 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-catalog-subtraction.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog-subtraction.ts @@ -1,7 +1,7 @@ // Delta-view copies only: remove still-owned manifest rows; retain groups referenced elsewhere. -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { requireOrcadMigrationSshSource } from '../../../shared/orcad-migration/orcad-migration-source-kind' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import { requireOrcadMigrationSshSource } from '../../../../../shared/orcad-migration/orcad-migration-source-kind' import { orcadSourceFolderWorkspaceIds, repoBelongsToOrcadSource } from './orcad-source-ownership' export function subtractOrcadSourceCatalogState( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-catalog.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog.ts similarity index 83% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-catalog.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog.ts index dcf0d2fb093..3d51bdc14ea 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-catalog.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog.ts @@ -1,8 +1,8 @@ -import type { OrcadMigrationCatalogPayload } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { withoutOrcadRetainedMarker } from '../../../shared/orcad-retained-marker' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { SshTarget } from '../../../shared/ssh-types' -import type { Store } from '../loading-store/store' +import type { OrcadMigrationCatalogPayload } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import { withoutOrcadRetainedMarker } from '../../../../../shared/orcad-retained-marker' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { SshTarget } from '../../../../../shared/ssh-types' +import type { Store } from '../../../loading-store/store' import { orcadSourceFolderWorkspaceIds, repoBelongsToOrcadSource } from './orcad-source-ownership' type OrcadSourceCatalogStore = Pick diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-delta-view.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-delta-view.ts similarity index 73% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-delta-view.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-delta-view.ts index e19688d19f7..dce91067b12 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-delta-view.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-delta-view.ts @@ -4,19 +4,19 @@ import type { OrcadMigrationDormantStatePayload, OrcadMigrationManifest, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { FolderWorkspace } from '../../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { Repo } from '../../../../../shared/repo-types' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' import { subtractOrcadSourceCatalogState } from './orcad-source-catalog-subtraction' import { collectOrcadMigrationUntransferredDependencyCensus, type OrcadMigrationSourceDependencyCensus -} from './orcad-source-dependency-census' -import { subtractOrcadMigrationSourceDormantState } from './orcad-source-dormant-subtraction' -import { collectOrcadMigrationSourceDormantState } from './orcad-source-dormant-state' -import { subtractOrcadMigrationScopeWorkspaceSession } from './orcad-source-workspace-session-subtraction' +} from '../sessions/orcad-source-dependency-census' +import { subtractOrcadMigrationSourceDormantState } from '../dormancy/orcad-source-dormant-subtraction' +import { collectOrcadMigrationSourceDormantState } from '../dormancy/orcad-source-dormant-state' +import { subtractOrcadMigrationScopeWorkspaceSession } from '../sessions/orcad-source-workspace-session-subtraction' export type OrcadMigrationDeltaView = { getRepos: () => Repo[] diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-export.test.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.test.ts similarity index 56% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-export.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.test.ts index db604d6e714..3d10095b0ed 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-export.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.test.ts @@ -2,18 +2,17 @@ import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import { toSshExecutionHostId } from '../../../shared/execution-host' -import type { SshTarget } from '../../../shared/ssh-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { closeTestStores, createSqliteTestStore } from '../persistence-test-harness' -import { Store } from '../loading-store/store' +import { getDefaultWorkspaceSession } from '../../../../../shared/constants' +import { toSshExecutionHostId } from '../../../../../shared/execution-host' +import type { SshTarget } from '../../../../../shared/ssh-types' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { closeTestStores, createSqliteTestStore } from '../../../persistence-test-harness' +import { Store } from '../../../loading-store/store' import { createOrcadMigrationManifest } from './orcad-migration-manifest-export' import { getProfileTerminalScrollbackSnapshotRoot, - readTerminalScrollbackStoredBytesSync, - writeTerminalScrollbackSnapshotSync -} from '../../pty/scrollback/terminal-scrollback-snapshots' + readTerminalScrollbackStoredBytesSync +} from '../../../../pty/scrollback/terminal-scrollback-snapshots' const TARGET: SshTarget = { id: 'ssh-prod', @@ -93,35 +92,6 @@ describe('exporting a relay-hosted SSH target from the profile store', () => { ) }) - it('finishes a retained transfer after the tab closes, then deletes the orphaned file', () => { - const store = sourceStore() - const hostId = toSshExecutionHostId(TARGET.id) - const storage = { snapshotRoot: getProfileTerminalScrollbackSnapshotRoot(dataFiles.at(-1)!) } - const stored = writeTerminalScrollbackSnapshotSync({ - tabId: 'tab-1', - leafId: 'leaf-1', - buffer: 'dormant output\r\n', - storage - })! - const session = dormantSession('') - session.terminalLayoutsByTabId['tab-1'] = { - ...session.terminalLayoutsByTabId['tab-1']!, - buffersByLeafId: {}, - scrollbackRefsByLeafId: { 'leaf-1': stored } - } - store.setWorkspaceSession(session, hostId) - const manifest = createOrcadMigrationManifest(store, TARGET) - const ref = manifest.payload.dormantState?.terminalScrollbackSnapshots?.[0]?.ref ?? '' - expect(ref).toBe(stored) - store.syncOrcadMigrationScrollbackRetention([manifest]) - store.setWorkspaceSession(getDefaultWorkspaceSession(), hostId) - - const chunk = store.readOrcadMigrationSourceSnapshotChunk(manifest, ref, 0) - expect(Buffer.from(chunk.bytesBase64, 'base64').toString('utf8')).toBe('dormant output\r\n') - store.syncOrcadMigrationScrollbackRetention([]) - expect(readTerminalScrollbackStoredBytesSync(ref, storage)).toBeNull() - }) - it('serves an inline dormant buffer after its tab closes, across retries, until released', () => { const store = sourceStore() const hostId = toSshExecutionHostId(TARGET.id) @@ -152,34 +122,4 @@ describe('exporting a relay-hosted SSH target from the profile store', () => { // #29083: an enabled automation refused every Connect and left the host unconnectable. // #30126: three parked shells' local-only scrollback, inlined, overflowed the 768 KB manifest. - - it('retains the newer local-only bytes over an older file saved under the same ref', () => { - const store = sourceStore() - const hostId = toSshExecutionHostId(TARGET.id) - const storage = { snapshotRoot: getProfileTerminalScrollbackSnapshotRoot(dataFiles.at(-1)!) } - const stored = writeTerminalScrollbackSnapshotSync({ - tabId: 'tab-1', - leafId: 'leaf-1', - buffer: 'older shared output\r\n', - storage - })! - const session = dormantSession('') - session.terminalLayoutsByTabId['tab-1'] = { - ...session.terminalLayoutsByTabId['tab-1']!, - buffersByLeafId: {}, - scrollbackRefsByLeafId: { 'leaf-1': stored } - } - session.localOnlyScrollbackByTabId = { 'tab-1': { 'leaf-1': 'newer parked output\r\n' } } - store.setWorkspaceSession(session, hostId) - const manifest = createOrcadMigrationManifest(store, TARGET) - const ref = manifest.payload.dormantState?.terminalScrollbackSnapshots?.[0]?.ref ?? '' - expect(ref).toBe(stored) - store.syncOrcadMigrationScrollbackRetention([manifest]) - store.setWorkspaceSession(getDefaultWorkspaceSession(), hostId) - - const chunk = store.readOrcadMigrationSourceSnapshotChunk(manifest, ref, 0) - expect(Buffer.from(chunk.bytesBase64, 'base64').toString('utf8')).toBe( - 'newer parked output\r\n' - ) - }) }) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-export.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-export.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.ts index 95c728fedb5..d0631ca7efa 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-export.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-export.ts @@ -2,34 +2,34 @@ import { ORCAD_MIGRATION_SCROLLBACK_CHUNK_BYTES, type OrcadMigrationTerminalScrollbackSnapshot -} from '../../../shared/orcad-migration/orcad-migration-scrollback' +} from '../../../../../shared/orcad-migration/orcad-migration-scrollback' import type { OrcadMigrationCatalogPayload, OrcadMigrationDormantStatePayload, OrcadMigrationManifest, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import { assertOrcadMigrationManifestDigest } from '../../orcad/orcad-migration-manifest-digest' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import { assertOrcadMigrationManifestDigest } from '../../../../orcad/orcad-migration-manifest-digest' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' import { collectOrcadMigrationUntransferredDependencyCensus, type OrcadMigrationSourceDependencyCensus -} from './orcad-source-dependency-census' +} from '../sessions/orcad-source-dependency-census' import { collectOrcadMigrationSourceDormantState, type OrcadMigrationSourceDormantInspection -} from './orcad-source-dormant-state' -import { readOrcadMigrationSourceScrollbackChunk } from './orcad-source-scrollback-state' +} from '../dormancy/orcad-source-dormant-state' +import { readOrcadMigrationSourceScrollbackChunk } from '../scrollback/orcad-source-scrollback-state' import { createOrcadMigrationDeltaView, type OrcadMigrationDeltaView } from './orcad-source-delta-view' -import { syncOrcadMigrationScrollbackRetention } from './orcad-source-scrollback-retention' +import { syncOrcadMigrationScrollbackRetention } from '../scrollback/orcad-source-scrollback-retention' import { createOrcadMigrationLeaveBehindView } from './orcad-source-leave-behind-view' import { collectOrcadMigrationSourceDrafts, type OrcadMigrationSourceDrafts -} from './orcad-source-draft-rename' +} from '../worktrees/orcad-source-draft-rename' type OrcadSourceExportRuntime = Pick< StoreRuntimeState, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-key-order.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-key-order.ts similarity index 100% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-key-order.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-key-order.ts diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-leave-behind-view.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-leave-behind-view.ts similarity index 85% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-leave-behind-view.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-leave-behind-view.ts index d6ffce04a16..1cad52af8c1 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-leave-behind-view.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-leave-behind-view.ts @@ -1,7 +1,7 @@ // Offer "Move anyway" only when a consent-free preview shows it clears the blockers. -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' -import { collectOrcadMigrationUntransferredDependencyCensus } from './orcad-source-dependency-census' -import { collectOrcadMigrationSourceDormantState } from './orcad-source-dormant-state' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' +import { collectOrcadMigrationUntransferredDependencyCensus } from '../sessions/orcad-source-dependency-census' +import { collectOrcadMigrationSourceDormantState } from '../dormancy/orcad-source-dormant-state' import type { OrcadMigrationDeltaView } from './orcad-source-delta-view' export function createOrcadMigrationLeaveBehindView( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.test.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.test.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.test.ts index 8b779a9acb0..3c1d60ab133 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from 'vitest' -import { getDefaultPersistedState } from '../../../shared/constants' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import { orcadMigrationCutoverFixture } from '../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' +import { getDefaultPersistedState } from '../../../../../shared/constants' +import type { FolderWorkspace } from '../../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { Repo } from '../../../../../shared/repo-types' +import { orcadMigrationCutoverFixture } from '../../../../managed-server/migration/cutover/testing/orcad-migration-cutover-fixture' import { subtractOrcadSourceCatalogState } from './orcad-source-catalog-subtraction' import { orcadSourceFolderWorkspaceIds, repoBelongsToOrcadSource } from './orcad-source-ownership' diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.ts similarity index 81% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.ts index d820d05431f..801d79c71f3 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-ownership.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-ownership.ts @@ -1,12 +1,12 @@ // Export and subtraction must share repo/folder host attribution or migrated rows can remain behind. -import { getRepoExecutionHostId, parseExecutionHostId } from '../../../shared/execution-host' +import { getRepoExecutionHostId, parseExecutionHostId } from '../../../../../shared/execution-host' import { resolveFolderWorkspaceHost, type FolderWorkspaceHostState -} from '../../../shared/folder-workspaces/folder-workspace-execution-host' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' +} from '../../../../../shared/folder-workspaces/folder-workspace-execution-host' +import type { FolderWorkspace } from '../../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { Repo } from '../../../../../shared/repo-types' export function repoBelongsToOrcadSource(repo: Repo, targetId: string): boolean { if (repo.connectionId === targetId) { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-partial-partition.test.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-partial-partition.test.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-partial-partition.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-partial-partition.test.ts index bfbb2d185ed..d5663748672 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-partial-partition.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-partial-partition.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from 'vitest' -import { getDefaultPersistedState } from '../../../shared/constants' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { Repo } from '../../../shared/repo-types' -import { collectOrcadMigrationSourceDormantState } from './orcad-source-dormant-state' +import { getDefaultPersistedState } from '../../../../../shared/constants' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import type { Repo } from '../../../../../shared/repo-types' +import { collectOrcadMigrationSourceDormantState } from '../dormancy/orcad-source-dormant-state' const TARGET_ID = 'ssh-b4' const WORKTREE = 'repo-1::/root/repo' diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-scope.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-scope.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-scope.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-scope.ts index 761fe7255c9..e6aa9f458a4 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-scope.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-scope.ts @@ -1,28 +1,28 @@ import { isOrcadMigrationLocalWslSource, requireOrcadMigrationSshSource -} from '../../../shared/orcad-migration/orcad-migration-source-kind' +} from '../../../../../shared/orcad-migration/orcad-migration-source-kind' import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID, toSshExecutionHostId -} from '../../../shared/execution-host' +} from '../../../../../shared/execution-host' import type { OrcadMigrationCatalogPayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' import { normalizeWorkspaceSessionKeyToWorkspaceId, parseWorkspaceKey -} from '../../../shared/workspace-scope' -import type { PersistedState } from '../../../shared/persisted-state-types' +} from '../../../../../shared/workspace-scope' +import type { PersistedState } from '../../../../../shared/persisted-state-types' import { getExecutionHostIdFromWorktreeHostIdentity, getWorktreeIdFromHostIdentity, isWorktreeHostIdentity -} from '../../../shared/worktree/host-qualified-identity' -import type { Repo } from '../../../shared/repo-types' -import { ownerKeyBelongsToRepo } from '../../orca-profiles/project-transfer/profile-project-worktree-identity' +} from '../../../../../shared/worktree/host-qualified-identity' +import type { Repo } from '../../../../../shared/repo-types' +import { ownerKeyBelongsToRepo } from '../../../../orca-profiles/project-transfer/profile-project-worktree-identity' import { repoBelongsToOrcadSource } from './orcad-source-ownership' type OrcadMigrationScopeRows = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-visibility.ts b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility.ts similarity index 85% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-visibility.ts rename to src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility.ts index 02477471d99..232e8bfa10f 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-visibility.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility.ts @@ -1,24 +1,24 @@ -import { getAppEnvironment } from '../../../shared/app-environment' -import { getRepoExecutionHostId, parseExecutionHostId } from '../../../shared/execution-host' +import { getAppEnvironment } from '../../../../../shared/app-environment' +import { getRepoExecutionHostId, parseExecutionHostId } from '../../../../../shared/execution-host' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { ProjectHostSetup } from '../../../shared/project-types' -import type { OrcadMigrationSourceCutover } from '../../../shared/orcad-migration/orcad-migration-source-cutover' -import type { Repo } from '../../../shared/repo-types' -import type { SshTarget } from '../../../shared/ssh-types' -import type { Store } from '../loading-store/store' +import type { FolderWorkspace } from '../../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../../shared/project-group-types' +import type { ProjectHostSetup } from '../../../../../shared/project-types' +import type { OrcadMigrationSourceCutover } from '../../../../../shared/orcad-migration/orcad-migration-source-cutover' +import type { Repo } from '../../../../../shared/repo-types' +import type { SshTarget } from '../../../../../shared/ssh-types' +import type { Store } from '../../../loading-store/store' import { orcadSourceFolderWorkspaceIds, projectGroupBelongsToOrcadSource, repoBelongsToOrcadSource } from './orcad-source-ownership' -import { findOrcadMigrationSourceCutoverForTarget } from './orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../cutover-journals/orcad-migration-cutover-journal' import { withoutWslMovedFolderWorkspaces, withoutWslMovedRepos -} from '../moving-wsl-projects/wsl-move-scope-guard' +} from '../../../moving-wsl-projects/quiescence/wsl-move-scope-guard' export const appUserDataPath = (): string => getAppEnvironment().getPath('userData') diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-browser-intents.ts b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-browser-intents.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-client-browser-intents.ts rename to src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-browser-intents.ts index 43fd7e5aa32..7556e799327 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-browser-intents.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-browser-intents.ts @@ -1,11 +1,11 @@ -import type { OrcadMigrationClientHostedBrowserCloseIntent } from '../../../shared/orcad-migration/orcad-migration-client-state' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import type { OrcadMigrationClientHostedBrowserCloseIntent } from '../../../../../shared/orcad-migration/orcad-migration-client-state' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' import { orcadMigrationOwnerMatchesScope, unqualifyOrcadMigrationOwnerKey, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' export function collectCloseIntents( state: PersistedState, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.test.ts b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.test.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.test.ts index 7baaf0ec40b..365373275e1 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.test.ts @@ -1,13 +1,16 @@ import { describe, expect, it } from 'vitest' -import type { OrcadMigrationCatalogPayload } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { getDefaultPersistedState, getDefaultWorkspaceSession } from '../../../shared/constants' -import type { BrowserWorkspace } from '../../../shared/browser-workspace-types' +import type { OrcadMigrationCatalogPayload } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { + getDefaultPersistedState, + getDefaultWorkspaceSession +} from '../../../../../shared/constants' +import type { BrowserWorkspace } from '../../../../../shared/browser-workspace-types' import { CLIENT_HOSTED_BROWSER_PAGE_RECORD_VERSION, type PersistedClientHostedBrowserPage -} from '../../../shared/workspace-session/client-hosted-browser-page-record' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../../shared/workspace-session/client-hosted-browser-page-record' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' import { collectOrcadMigrationSourceClientState } from './orcad-source-client-state' const source = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.ts b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.ts rename to src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.ts index 5ef8f4cd485..7c8e9f655db 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-state.ts @@ -1,17 +1,17 @@ import type { OrcadMigrationClientStatePayload, OrcadMigrationUiRoutingState -} from '../../../shared/orcad-migration/orcad-migration-client-state' +} from '../../../../../shared/orcad-migration/orcad-migration-client-state' import type { OrcadMigrationCatalogPayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' import type { PersistedMobileClientTabSelection, PersistedState -} from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { sessionPartitions } from './orcad-source-workspace-session-fragments' +} from '../../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { sessionPartitions } from '../sessions/orcad-source-workspace-session-fragments' import { collectCloseIntents } from './orcad-source-client-browser-intents' import { createOrcadMigrationExportScope, @@ -19,8 +19,8 @@ import { orcadMigrationOwnerMatchesScope, orcadMigrationOwnsRepoId, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' -import { paneBelongsToTabs } from '../../../shared/workspace-session/workspace-session-pane-ownership' +} from '../catalog/orcad-source-scope' +import { paneBelongsToTabs } from '../../../../../shared/workspace-session/workspace-session-pane-ownership' export type OrcadMigrationSourceClientStateInspection = { payload: OrcadMigrationClientStatePayload | undefined diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-subtraction.ts b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-subtraction.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-client-subtraction.ts rename to src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-subtraction.ts index d9b201cb6ef..560422a75b2 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-client-subtraction.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/clients/orcad-source-client-subtraction.ts @@ -1,23 +1,23 @@ import { type OrcadMigrationManifest, serializeOrcadMigrationValue -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import { requireOrcadMigrationSshSource } from '../../../shared/orcad-migration/orcad-migration-source-kind' -import { parsePersistedAutomationHostFilter } from '../../../shared/automations/ownership/automation-host-filter' -import { hostStableKey } from '../../../shared/automations/ownership/automation-owner-key' -import { toRuntimeExecutionHostId } from '../../../shared/execution-host' -import { composeWorktreeHostIdentity } from '../../../shared/worktree/host-qualified-identity' -import type { OrcadMigrationClientStatePayload } from '../../../shared/orcad-migration/orcad-migration-client-state' -import type { PersistedState } from '../../../shared/persisted-state-types' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import { requireOrcadMigrationSshSource } from '../../../../../shared/orcad-migration/orcad-migration-source-kind' +import { parsePersistedAutomationHostFilter } from '../../../../../shared/automations/ownership/automation-host-filter' +import { hostStableKey } from '../../../../../shared/automations/ownership/automation-owner-key' +import { toRuntimeExecutionHostId } from '../../../../../shared/execution-host' +import { composeWorktreeHostIdentity } from '../../../../../shared/worktree/host-qualified-identity' +import type { OrcadMigrationClientStatePayload } from '../../../../../shared/orcad-migration/orcad-migration-client-state' +import type { PersistedState } from '../../../../../shared/persisted-state-types' import { MAX_CLIENT_HOSTED_BROWSER_CLOSE_INTENTS, type ClientHostedBrowserCloseIntent -} from '../../../shared/workspace-session/client-hosted-browser-close-intent' +} from '../../../../../shared/workspace-session/client-hosted-browser-close-intent' import { createOrcadMigrationSourceScope, orcadMigrationOwnerMatchesScope, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' /** Mutate a delta-view copy only. */ export function subtractOrcadMigrationClientState( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-dormant-state.ts b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-migration-dormant-state.ts similarity index 93% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-dormant-state.ts rename to src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-migration-dormant-state.ts index ee210bc44b5..93bcedbccd2 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-dormant-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-migration-dormant-state.ts @@ -1,4 +1,4 @@ -import type { OrcadMigrationDormantStatePayload } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationDormantStatePayload } from '../../../../../shared/orcad-migration/orcad-migration-manifest' export function hasDormantState(state: OrcadMigrationDormantStatePayload): boolean { return ( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-state.ts b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-state.ts rename to src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state.ts index 09105198584..cad7eb5f8d3 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state.ts @@ -2,27 +2,27 @@ import type { OrcadMigrationCatalogPayload, OrcadMigrationDormantStatePayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { OrcadMigrationDependencyKind } from '../../../shared/orcad-migration/orcad-migration-preflight' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { TerminalScrollbackSnapshotStorage } from '../../pty/scrollback/terminal-scrollback-snapshots' -import { projectHostSetupProjectionFromRepos } from '../../../shared/project-host-setup-projection' -import { isEmptyRetiredNameRegistry } from '../../../shared/worktree/retired-name-registry' -import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id' -import { toOrcadDestinationRepository } from './orcad-destination-catalog-projection' -import { collectOrcadMigrationRetiredWorktreeNamespaces } from './orcad-source-retired-worktree-names' -import { collectOrcadMigrationSourceAutomationState } from './orcad-source-automation-state' -import { collectOrcadMigrationSourceWorkspaceSession } from './orcad-source-workspace-session' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationDependencyKind } from '../../../../../shared/orcad-migration/orcad-migration-preflight' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { TerminalScrollbackSnapshotStorage } from '../../../../pty/scrollback/terminal-scrollback-snapshots' +import { projectHostSetupProjectionFromRepos } from '../../../../../shared/project-host-setup-projection' +import { isEmptyRetiredNameRegistry } from '../../../../../shared/worktree/retired-name-registry' +import { getRepoIdFromWorktreeId } from '../../../../../shared/worktree/id' +import { toOrcadDestinationRepository } from '../../destination/orcad-destination-catalog-projection' +import { collectOrcadMigrationRetiredWorktreeNamespaces } from '../worktrees/orcad-source-retired-worktree-names' +import { collectOrcadMigrationSourceAutomationState } from '../automations/orcad-source-automation-state' +import { collectOrcadMigrationSourceWorkspaceSession } from '../sessions/orcad-source-workspace-session' import { createOrcadMigrationExportScope, orcadMigrationMayMoveChild, orcadMigrationOwnerMatchesScope, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' -import { collectOrcadMigrationSourceClientState } from './orcad-source-client-state' -import { inspectOrcadSourceWorktreeMetadata } from './orcad-source-worktree-metadata' -import { compareKeys } from './orcad-source-key-order' -import { assertNoCrossStoreLinkedWorkspaceInMove } from '../../../shared/worktree/cross-store-lineage-move-refusal' +} from '../catalog/orcad-source-scope' +import { collectOrcadMigrationSourceClientState } from '../clients/orcad-source-client-state' +import { inspectOrcadSourceWorktreeMetadata } from '../worktrees/orcad-source-worktree-metadata' +import { compareKeys } from '../catalog/orcad-source-key-order' +import { assertNoCrossStoreLinkedWorkspaceInMove } from '../../../../../shared/worktree/cross-store-lineage-move-refusal' export const ORCAD_MIGRATION_TRANSFERRED_DORMANT_KINDS = [ 'worktree-metadata', diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-subtraction.ts b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-subtraction.ts similarity index 68% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-subtraction.ts rename to src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-subtraction.ts index 53513ee9324..52dc889e99e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-dormant-subtraction.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/dormancy/orcad-source-dormant-subtraction.ts @@ -1,9 +1,9 @@ -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { subtractOrcadSourceWorktreeMetadata } from './orcad-source-worktree-metadata' -import { subtractOrcadMigrationSourceAutomationState } from './orcad-source-automation-subtraction' -import { subtractOrcadMigrationSourceWorkspaceSession } from './orcad-source-workspace-session-subtraction' -import { subtractOrcadMigrationClientState } from './orcad-source-client-subtraction' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { subtractOrcadSourceWorktreeMetadata } from '../worktrees/orcad-source-worktree-metadata' +import { subtractOrcadMigrationSourceAutomationState } from '../automations/orcad-source-automation-subtraction' +import { subtractOrcadMigrationSourceWorkspaceSession } from '../sessions/orcad-source-workspace-session-subtraction' +import { subtractOrcadMigrationClientState } from '../clients/orcad-source-client-subtraction' /** Mutate a delta-view copy only. */ export function subtractOrcadMigrationSourceDormantState( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-cleanup.ts b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-cleanup.ts similarity index 74% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-cleanup.ts rename to src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-cleanup.ts index e714d880307..15b343bec5b 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-cleanup.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-cleanup.ts @@ -1,10 +1,10 @@ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' import { collectTerminalScrollbackSnapshotRefs, deleteTerminalScrollbackSnapshotSync -} from '../../pty/scrollback/terminal-scrollback-snapshots' -import { sessionPartitions } from './orcad-source-workspace-session-fragments' +} from '../../../../pty/scrollback/terminal-scrollback-snapshots' +import { sessionPartitions } from '../sessions/orcad-source-workspace-session-fragments' /** Retain files still referenced by sessions or pending exports. */ export function deleteUnreferencedOrcadMigrationScrollback( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-retention.ts b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-retention.ts similarity index 89% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-retention.ts rename to src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-retention.ts index ee75202a135..e8f2a28a4e6 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-retention.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-retention.ts @@ -1,9 +1,9 @@ -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { StoreRuntimeState } from '../loading-store/store-runtime-state' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { StoreRuntimeState } from '../../../loading-store/store-runtime-state' import { readTerminalScrollbackStoredBytesSync, writeTerminalScrollbackSnapshotSync -} from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../../pty/scrollback/terminal-scrollback-snapshots' import { deleteUnreferencedOrcadMigrationScrollback } from './orcad-source-scrollback-cleanup' import { findSnapshotBytes, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.test.ts b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.test.ts similarity index 82% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.test.ts index 04397ebaf67..9ef83a82b6e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.test.ts @@ -2,14 +2,14 @@ import { mkdirSync, mkdtempSync, rmSync, truncateSync, writeFileSync } from 'nod import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../shared/orcad-migration/orcad-migration-scrollback' -import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../shared/terminal/replay/terminal-scrollback-limits' -import type { TerminalLayoutSnapshot } from '../../../shared/workspace-layout/terminal-tab-types' +import { getDefaultWorkspaceSession } from '../../../../../shared/constants' +import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../../../shared/orcad-migration/orcad-migration-scrollback' + +import type { TerminalLayoutSnapshot } from '../../../../../shared/workspace-layout/terminal-tab-types' import { makeTerminalScrollbackSnapshotRef, type TerminalScrollbackSnapshotStorage -} from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../../pty/scrollback/terminal-scrollback-snapshots' import { hasDuplicateOrcadMigrationScrollbackDescriptors, projectOrcadMigrationSessionScrollback @@ -88,18 +88,6 @@ describe('orcad source scrollback projection', () => { ]) }) - it('still blocks the move on saved history it cannot read', () => { - const projected = project({ - scrollbackRefsByLeafId: { - 'leaf-big': storeSnapshot('leaf-big', TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT + 1) - } - }) - - expect(projected.blockedItems).toEqual([ - 'saved terminal history Orca could not read for tab tab-1' - ]) - }) - it('refuses duplicate refs or tab/leaf identities across merged fragments', () => { expect( hasDuplicateOrcadMigrationScrollbackDescriptors([ diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.ts b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.ts similarity index 93% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.ts rename to src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.ts index d2debf4d09f..69ddc09a033 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-scrollback-state.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/scrollback/orcad-source-scrollback-state.ts @@ -4,17 +4,17 @@ import { type OrcadMigrationTerminalScrollbackSnapshot, MAX_ORCAD_MIGRATION_SCROLLBACK_SNAPSHOTS, MAX_ORCAD_MIGRATION_SCROLLBACK_TOTAL_BYTES -} from '../../../shared/orcad-migration/orcad-migration-scrollback' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../shared/terminal/replay/terminal-scrollback-limits' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../../shared/orcad-migration/orcad-migration-scrollback' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../../../shared/terminal/replay/terminal-scrollback-limits' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' import { makeTerminalScrollbackSnapshotRef, readTerminalScrollbackStoredBytesSync, readTerminalScrollbackStoredSnapshotSync, type TerminalScrollbackSnapshotStorage -} from '../../pty/scrollback/terminal-scrollback-snapshots' -import { compareKeys } from './orcad-source-key-order' +} from '../../../../pty/scrollback/terminal-scrollback-snapshots' +import { compareKeys } from '../catalog/orcad-source-key-order' export type ProjectedOrcadMigrationScrollback = { session: WorkspaceSessionState diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-dependency-census.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-dependency-census.ts similarity index 83% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-dependency-census.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-dependency-census.ts index 65b9e4ff4db..37cf38d925a 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-dependency-census.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-dependency-census.ts @@ -1,10 +1,10 @@ -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' import { ORCAD_MIGRATION_DEPENDENCY_KINDS, type OrcadMigrationDependencyKind -} from '../../../shared/orcad-migration/orcad-migration-preflight' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { TerminalScrollbackSnapshotStorage } from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../../../shared/orcad-migration/orcad-migration-preflight' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { TerminalScrollbackSnapshotStorage } from '../../../../pty/scrollback/terminal-scrollback-snapshots' import { inspectOrcadMigrationSourceSessions, type OrcadMigrationSourceSessionInspection @@ -12,14 +12,14 @@ import { import { collectOrcadMigrationSourceDormantState, orcadMigrationLeavesBehind -} from './orcad-source-dormant-state' +} from '../dormancy/orcad-source-dormant-state' import { createOrcadMigrationSourceScope, orcadMigrationOwnerMatchesScope, orcadMigrationPartitionScope, type OrcadMigrationSourceScope -} from './orcad-source-scope' -import { paneBelongsToTabs } from '../../../shared/workspace-session/workspace-session-pane-ownership' +} from '../catalog/orcad-source-scope' +import { paneBelongsToTabs } from '../../../../../shared/workspace-session/workspace-session-pane-ownership' export type OrcadMigrationSourceDependencyCensus = { totalCount: number diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-duplicate-session-identities.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-duplicate-session-identities.ts similarity index 90% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-duplicate-session-identities.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-duplicate-session-identities.ts index b5035981277..ae40b75192f 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-duplicate-session-identities.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-duplicate-session-identities.ts @@ -1,5 +1,5 @@ -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { visitOrcadMigrationSessionEntities } from './orcad-destination-workspace-session' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { visitOrcadMigrationSessionEntities } from '../../destination/orcad-destination-workspace-session' import { worktreeLabel } from './orcad-source-workspace-session-eligibility' const KIND_LABELS: Record = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-left-behind-session-rows.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-left-behind-session-rows.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-left-behind-session-rows.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-left-behind-session-rows.ts index 40f365b7988..ebd32700b8b 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-left-behind-session-rows.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-left-behind-session-rows.ts @@ -1,14 +1,14 @@ -import type { BrowserWorkspace } from '../../../shared/browser-workspace-types' -import type { TabGroup } from '../../../shared/tab-types' -import '../../../shared/constants' -import { ORCA_BROWSER_PARTITION } from '../../../shared/browser/browser-session-partition' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { ownedEditorFileId } from '../../../shared/workspace-session/workspace-session-pane-ownership' +import type { BrowserWorkspace } from '../../../../../shared/browser-workspace-types' +import type { TabGroup } from '../../../../../shared/tab-types' +import '../../../../../shared/constants' +import { ORCA_BROWSER_PARTITION } from '../../../../../shared/browser/browser-session-partition' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { ownedEditorFileId } from '../../../../../shared/workspace-session/workspace-session-pane-ownership' import { isOrcadSourceTabHost } from './orcad-source-workspace-session-eligibility' import { orcadMigrationOwnerMatchesScope, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' /** Filter an export copy; retain unsupported rows in the source profile for downgrade. */ export function withoutLeftBehindSessionRows( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-copy-resolution.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-copy-resolution.ts similarity index 83% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-session-copy-resolution.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-copy-resolution.ts index 7ba902a8a83..e662876fc4b 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-copy-resolution.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-copy-resolution.ts @@ -1,21 +1,21 @@ import type { OrcadMigrationCatalogPayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../shared/orcad-migration/orcad-migration-scrollback' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { keepUnsavedDrafts } from '../../../shared/workspace-session/workspace-session-draft-retention' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../../../shared/orcad-migration/orcad-migration-scrollback' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' +import { keepUnsavedDrafts } from '../../../../../shared/workspace-session/workspace-session-draft-retention' import { filterWorkspaceRows, withoutWorkspaces -} from '../../../shared/workspace-session/workspace-session-stranded-partition-adoption' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../../shared/workspace-session/workspace-session-stranded-partition-adoption' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' import { createOrcadMigrationExportScope, orcadMigrationOwnerMatchesScope, orcadMigrationPartitionScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' import { unsavedDraftItems, worktreeLabel } from './orcad-source-workspace-session-eligibility' export type SessionFragment = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-dependencies.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-dependencies.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-session-dependencies.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-dependencies.ts index 06ce2a9de6d..d49297241e4 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-dependencies.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-dependencies.ts @@ -1,6 +1,6 @@ -import type { ExecutionHostId } from '../../../shared/execution-host' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import type { ExecutionHostId } from '../../../../../shared/execution-host' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' import { sessionPartitions } from './orcad-source-workspace-session-fragments' export type OrcadMigrationSourceSessionInspection = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-partitions.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-partitions.ts similarity index 80% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-session-partitions.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-partitions.ts index 24fdd668641..de85886068d 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-session-partitions.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-session-partitions.ts @@ -1,21 +1,21 @@ -import { hasClosedTerminalTabRecord } from '../../../shared/workspace-layout/closed-terminal-tab-tombstones' -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { PersistedState } from '../../../shared/persisted-state-types' -import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../shared/workspace-scope' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { keepUnsavedDrafts } from '../../../shared/workspace-session/workspace-session-draft-retention' +import { hasClosedTerminalTabRecord } from '../../../../../shared/workspace-layout/closed-terminal-tab-tombstones' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../../../shared/workspace-scope' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { keepUnsavedDrafts } from '../../../../../shared/workspace-session/workspace-session-draft-retention' import { withoutWorkspaces, workspaceIdsNamedByPartition, workspacesTheHostSupersedes -} from '../../../shared/workspace-session/workspace-session-stranded-partition-adoption' +} from '../../../../../shared/workspace-session/workspace-session-stranded-partition-adoption' import { sessionPartitions } from './orcad-source-workspace-session-fragments' import { orcadMigrationOwnerMatchesScope, orcadMigrationPartitionScope, orcadMigrationScopeOwnsWholeHost, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' /** Match app adoption (#12723); other duplicate partition copies must agree before export. */ export function orcadMigrationSessionPartitions( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-ambiguity.test.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-ambiguity.test.ts similarity index 81% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-ambiguity.test.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-ambiguity.test.ts index 99938fae9ec..2918d1dcbc6 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-ambiguity.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-ambiguity.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import { LOCAL_EXECUTION_HOST_ID, toSshExecutionHostId } from '../../../shared/execution-host' +import { getDefaultWorkspaceSession } from '../../../../../shared/constants' +import { LOCAL_EXECUTION_HOST_ID, toSshExecutionHostId } from '../../../../../shared/execution-host' import { collectUnsupportedSessionItems } from './orcad-source-workspace-session-eligibility' -import type { OrcadMigrationSourceScope } from './orcad-source-scope' -import type { SleepingAgentSessionRecord } from '../../../shared/agent-session/lifecycle/agent-session-resume' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import type { OrcadMigrationSourceScope } from '../catalog/orcad-source-scope' +import type { SleepingAgentSessionRecord } from '../../../../../shared/agent-session/lifecycle/agent-session-resume' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' // `repo-1` is selected but another host registers it too, so its unqualified keys are ambiguous. const ROWS = { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-eligibility.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-eligibility.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-eligibility.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-eligibility.ts index 5cda605794f..76150a9fc15 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-eligibility.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-eligibility.ts @@ -1,10 +1,10 @@ -import { isWorkspaceKey } from '../../../shared/workspace-scope' -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { SleepingAgentSessionRecord } from '../../../shared/agent-session/lifecycle/agent-session-resume' +import { isWorkspaceKey } from '../../../../../shared/workspace-scope' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' +import type { SleepingAgentSessionRecord } from '../../../../../shared/agent-session/lifecycle/agent-session-resume' import type { PersistedOpenFile, WorkspaceSessionState -} from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../../shared/workspace-session/workspace-session-state-types' import { orcadMigrationOwnerKeyIsAmbiguous, orcadMigrationOwnerMatchesScope, @@ -12,11 +12,11 @@ import { orcadMigrationScopeOwnsWholeHost, unqualifyOrcadMigrationOwnerKey, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' import { paneBelongsToTabs, paneBelongsToTerminalLayout -} from '../../../shared/workspace-session/workspace-session-pane-ownership' +} from '../../../../../shared/workspace-session/workspace-session-pane-ownership' /** Name unsupported live work and remedies; stale/unowned rows stay in the retained profile. */ export function collectUnsupportedSessionItems( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-fragments.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-fragments.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-fragments.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-fragments.ts index 91bd7a03268..9a64de0cd6b 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-fragments.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-fragments.ts @@ -1,8 +1,8 @@ -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { mergeWorkspaceSessions } from '../../orca-profiles/project-transfer/profile-project-session-state' -import { SESSION_FIELDS_PRUNED_BY_OWNER_KEY } from '../../orca-profiles/project-transfer/profile-project-session-field-disposition' -import { withRequiredWorkspaceSessionMaps } from '../loading-store/workspace-sessions/session-host-partitions' +import { serializeOrcadMigrationValue } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { mergeWorkspaceSessions } from '../../../../orca-profiles/project-transfer/profile-project-session-state' +import { SESSION_FIELDS_PRUNED_BY_OWNER_KEY } from '../../../../orca-profiles/project-transfer/profile-project-session-field-disposition' +import { withRequiredWorkspaceSessionMaps } from '../../../loading-store/workspace-sessions/session-host-partitions' export function sessionPartitions( state: { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-layout.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-layout.ts similarity index 87% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-layout.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-layout.ts index ca9c53a343c..20375cba2aa 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-layout.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-layout.ts @@ -1,9 +1,9 @@ -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { parseWorkspaceKey } from '../../../shared/workspace-scope' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { parseWorkspaceKey } from '../../../../../shared/workspace-scope' import { orcadMigrationOwnerMatchesScope, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' export function collectOwnedTerminalTabIds( session: WorkspaceSessionState, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-subtraction.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-subtraction.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-subtraction.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-subtraction.ts index 307e5860f5c..a6185fc9bb7 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session-subtraction.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session-subtraction.ts @@ -1,17 +1,17 @@ -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { markdownFileIdCandidates } from '../../orca-profiles/project-transfer/profile-session-markdown-transfer' -import { removeWorkspaceSessionOwners } from '../restoring-sessions/session-owner-removal' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import { markdownFileIdCandidates } from '../../../../orca-profiles/project-transfer/profile-session-markdown-transfer' +import { removeWorkspaceSessionOwners } from '../../../restoring-sessions/session-owner-removal' import { createOrcadMigrationSourceScope, orcadMigrationOwnerMatchesScope, orcadMigrationOwnsRepoId, orcadMigrationPartitionScope, type OrcadMigrationSourceScope -} from './orcad-source-scope' -import { LOCAL_EXECUTION_HOST_ID, parseExecutionHostId } from '../../../shared/execution-host' +} from '../catalog/orcad-source-scope' +import { LOCAL_EXECUTION_HOST_ID, parseExecutionHostId } from '../../../../../shared/execution-host' import { collectSessionOwnerKeys } from './orcad-source-workspace-session-fragments' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' /** Mutate a delta-view copy only. */ export function subtractOrcadMigrationSourceWorkspaceSession( diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session.ts b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session.ts similarity index 90% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session.ts rename to src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session.ts index 474b50d1943..1341973eae4 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-workspace-session.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/sessions/orcad-source-workspace-session.ts @@ -1,21 +1,21 @@ import type { OrcadMigrationCatalogPayload, OrcadMigrationManifestSource -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../shared/orcad-migration/orcad-migration-scrollback' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { WorkspaceSessionState } from '../../../../../shared/workspace-session/workspace-session-state-types' +import type { OrcadMigrationTerminalScrollbackSnapshot } from '../../../../../shared/orcad-migration/orcad-migration-scrollback' import { extractSessionOwnersForTransfer, hasTransferredSessionState -} from '../../orca-profiles/project-transfer/profile-session-owner-transfer' -import type { TerminalScrollbackSnapshotStorage } from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../../orca-profiles/project-transfer/profile-session-owner-transfer' +import type { TerminalScrollbackSnapshotStorage } from '../../../../pty/scrollback/terminal-scrollback-snapshots' import { createOrcadMigrationExportScope, orcadMigrationOwnerMatchesScope, orcadMigrationPartitionScope, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' import { collectUnsupportedSessionItems, projectDormantSessionFocus, @@ -35,16 +35,16 @@ import { resolveCopiesForHost, type SessionFragment } from './orcad-source-session-copy-resolution' -import { withoutOrcadMigrationDrafts } from './orcad-source-draft-rename' -import { hasClosedTerminalTabRecord } from '../../../shared/workspace-layout/closed-terminal-tab-tombstones' -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../shared/workspace-scope' +import { withoutOrcadMigrationDrafts } from '../worktrees/orcad-source-draft-rename' +import { hasClosedTerminalTabRecord } from '../../../../../shared/workspace-layout/closed-terminal-tab-tombstones' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' +import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../../../shared/workspace-scope' import { orcadMigrationSessionPartitions } from './orcad-source-session-partitions' import { collectDuplicateOrcadMigrationSessionIdentities } from './orcad-source-duplicate-session-identities' import { hasDuplicateOrcadMigrationScrollbackDescriptors, projectOrcadMigrationSessionScrollback -} from './orcad-source-scrollback-state' +} from '../scrollback/orcad-source-scrollback-state' export type OrcadMigrationSourceWorkspaceSessionInspection = { payload: WorkspaceSessionState | undefined diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-draft-rename.ts b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-draft-rename.ts similarity index 89% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-draft-rename.ts rename to src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-draft-rename.ts index b927195c499..1a7e177536e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-draft-rename.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-draft-rename.ts @@ -1,17 +1,17 @@ // Drafts stay on this desktop; commit retargets their host records and restore checks disk baselines. -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' +import type { OrcadMigrationManifest } from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' import type { PersistedOpenFile, WorkspaceSessionState -} from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../../shared/workspace-session/workspace-session-state-types' import { createOrcadMigrationSourceScope, orcadMigrationOwnerMatchesScope, orcadMigrationPartitionScope, unqualifyOrcadMigrationOwnerKey -} from './orcad-source-scope' -import { orcadMigrationSessionPartitions } from './orcad-source-session-partitions' +} from '../catalog/orcad-source-scope' +import { orcadMigrationSessionPartitions } from '../sessions/orcad-source-session-partitions' export type OrcadMigrationSourceDrafts = Record diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-retired-worktree-names.ts b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-retired-worktree-names.ts similarity index 80% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-retired-worktree-names.ts rename to src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-retired-worktree-names.ts index ed0c7421fe3..3efd2494813 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-retired-worktree-names.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-retired-worktree-names.ts @@ -1,21 +1,21 @@ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../../shared/execution-host' import type { OrcadMigrationCatalogPayload, OrcadMigrationDormantStatePayload -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { PersistedState } from '../../../shared/persisted-state-types' +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import type { PersistedState } from '../../../../../shared/persisted-state-types' import { isEmptyRetiredNameRegistry, mergeRetiredNameRegistries, type RetiredNameRegistry -} from '../../../shared/worktree/retired-name-registry' -import { getRemoteRetirementNamespaceKey } from '../../workspaces/removal/retirement/worktree-name-retirement' +} from '../../../../../shared/worktree/retired-name-registry' +import { getRemoteRetirementNamespaceKey } from '../../../../workspaces/removal/retirement/worktree-name-retirement' import { swapRetirementNamespaceHost, retirementHostIdentity, retirementNamespaceKeysToRead -} from '../../workspaces/removal/retirement/worktree-retirement-namespace' -import { compareKeys } from './orcad-source-key-order' +} from '../../../../workspaces/removal/retirement/worktree-retirement-namespace' +import { compareKeys } from '../catalog/orcad-source-key-order' const EMPTY_REGISTRY: RetiredNameRegistry = { exhaustedTiers: 0, names: [] } diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-source-worktree-metadata.ts b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-worktree-metadata.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-source-worktree-metadata.ts rename to src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-worktree-metadata.ts index c182138de15..d0d8115cf7e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-source-worktree-metadata.ts +++ b/src/main/persistence/migrating-orcad-catalog/source/worktrees/orcad-source-worktree-metadata.ts @@ -1,20 +1,23 @@ -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { WorktreeMeta } from '../../../shared/worktree/meta-types' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { serializeOrcadMigrationValue } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { canonicalWorktreeIdentity } from '../../../shared/worktree/identity' +import type { PersistedState } from '../../../../../shared/persisted-state-types' +import type { WorktreeMeta } from '../../../../../shared/worktree/meta-types' + +import { + type OrcadMigrationManifest, + serializeOrcadMigrationValue +} from '../../../../../shared/orcad-migration/orcad-migration-manifest' +import { canonicalWorktreeIdentity } from '../../../../../shared/worktree/identity' import { getExecutionHostIdFromWorktreeHostIdentity, isWorktreeHostIdentity -} from '../../../shared/worktree/host-qualified-identity' -import { pruneUnreferencedWorktreeIdentityMeta } from '../loading-store/worktree-metadata/worktree-identity-metadata' +} from '../../../../../shared/worktree/host-qualified-identity' +import { pruneUnreferencedWorktreeIdentityMeta } from '../../../loading-store/worktree-metadata/worktree-identity-metadata' import { createOrcadMigrationSourceScope, orcadMigrationOwnerMatchesScope, orcadMigrationScopeOwnsWholeHost, unqualifyOrcadMigrationOwnerKey, type OrcadMigrationSourceScope -} from './orcad-source-scope' +} from '../catalog/orcad-source-scope' export function inspectOrcadSourceWorktreeMetadata( state: PersistedState, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-scrollback-retention-wiring.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-scrollback-retention-wiring.ts similarity index 88% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-scrollback-retention-wiring.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-scrollback-retention-wiring.ts index f6306da30f9..b8cb7c6f525 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-scrollback-retention-wiring.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-scrollback-retention-wiring.ts @@ -1,8 +1,8 @@ -import type { Store } from '../loading-store/store' +import type { Store } from '../../loading-store/store' import { listOrcadMigrationSourceCutovers, setOrcadMigrationJournalChangeListener -} from './orcad-migration-cutover-journal' +} from '../cutover-journals/orcad-migration-cutover-journal' export function installOrcadMigrationScrollbackRetention( userDataPath: string, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-migration-shell-history-format.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-shell-history-format.ts similarity index 95% rename from src/main/persistence/migrating-orcad-catalog/orcad-migration-shell-history-format.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-shell-history-format.ts index ca78af863e8..6993906e1f6 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-migration-shell-history-format.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-migration-shell-history-format.ts @@ -1,7 +1,7 @@ // The JSON header carries the unhashed worktree ID needed for history GC; raw history follows. import { z } from 'zod' -import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { hashWorktreeId } from '../../pty/history/terminal-history-id' +import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import { hashWorktreeId } from '../../../pty/history/terminal-history-id' // fish history lives outside Orca's store and cannot migrate. export const ORCAD_MIGRATION_SHELL_HISTORY_SHELLS = ['zsh', 'bash'] as const diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.test.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.test.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.test.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.test.ts index 1fd0bd906bc..02e5fb15336 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.test.ts @@ -3,17 +3,17 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' +import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import type { OrcadMigrationSnapshotChunkRequest, OrcadMigrationTerminalScrollbackSnapshot -} from '../../../shared/orcad-migration/orcad-migration-scrollback' +} from '../../../../shared/orcad-migration/orcad-migration-scrollback' import { getTerminalScrollbackSnapshotPath, type TerminalScrollbackSnapshotStorage -} from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../pty/scrollback/terminal-scrollback-snapshots' import { abortOrcadMigrationSnapshots, assertOrcadMigrationSnapshotsReady, diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.ts similarity index 94% rename from src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.ts index 4d356b04415..3dfdd3edd2e 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-scrollback-snapshot-transfer.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-scrollback-snapshot-transfer.ts @@ -1,19 +1,19 @@ import { mkdirSync } from 'node:fs' import { join } from 'node:path' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { decodeOrcadMigrationSnapshotChunk, type OrcadMigrationSnapshotChunkRequest, type OrcadMigrationSnapshotChunkResult, type OrcadMigrationSnapshotUploadState, type OrcadMigrationTerminalScrollbackSnapshot -} from '../../../shared/orcad-migration/orcad-migration-scrollback' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +} from '../../../../shared/orcad-migration/orcad-migration-scrollback' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' import { getTerminalScrollbackSnapshotPath, getTerminalScrollbackSnapshotRoot, type TerminalScrollbackSnapshotStorage -} from '../../pty/scrollback/terminal-scrollback-snapshots' +} from '../../../pty/scrollback/terminal-scrollback-snapshots' import { appendOrcadMigrationStagedChunk, ensureOrcadMigrationDirectory, @@ -25,7 +25,7 @@ import { pruneOrcadMigrationStagingDirectories, removeOrcadMigrationStagingDirectory, requireStagedOrcadMigrationManifest -} from './orcad-migration-staged-file' +} from '../blob-transfer/orcad-migration-staged-file' /** Only the staged manifest's snapshots may receive chunks; retried ranges must match. */ export function stageOrcadMigrationSnapshotChunk(args: { diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-shell-history-installer.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-shell-history-installer.ts similarity index 89% rename from src/main/persistence/migrating-orcad-catalog/orcad-shell-history-installer.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-shell-history-installer.ts index 685d04d1c8d..7182da99a65 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-shell-history-installer.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-shell-history-installer.ts @@ -13,23 +13,23 @@ import { statSync } from 'node:fs' import { dirname, join, resolve } from 'node:path' -import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { projectGroupIdFromRepoId } from '../../../shared/folder-workspaces/folder-workspace-worktree' -import { folderWorkspaceKey } from '../../../shared/workspace-scope' -import { splitWorktreeId } from '../../../shared/worktree/id' +import { ORCAD_MIGRATION_BLOB_KIND_CONTRACTS } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { projectGroupIdFromRepoId } from '../../../../shared/folder-workspaces/folder-workspace-worktree' +import { folderWorkspaceKey } from '../../../../shared/workspace-scope' +import { splitWorktreeId } from '../../../../shared/worktree/id' import { durableWriteTempPath, syncDirectoryDurablySync, writeFileDurableSync -} from '../../filesystem/durable-file-write' -import { resolveUnixPaneShellPath } from '../../daemon/shell-readiness/shell-ready' -import { resolveUnixShellPath } from '../../providers/local-pty/local-pty-executable-spawn' -import { readHistoryMeta, resolveShellKind } from '../../pty/history/terminal-history' +} from '../../../filesystem/durable-file-write' +import { resolveUnixPaneShellPath } from '../../../daemon/shell-readiness/shell-ready' +import { resolveUnixShellPath } from '../../../providers/local-pty/local-pty-executable-spawn' +import { readHistoryMeta, resolveShellKind } from '../../../pty/history/terminal-history' import { getOrcadMigrationReceivedBlobPath, listOrcadMigrationReceivedBlobNames -} from './orcad-migration-blob-staging' +} from '../blob-transfer/orcad-migration-blob-staging' import { ORCAD_MIGRATION_SHELL_HISTORY_HEADER_SCAN_BYTES, parseOrcadMigrationShellHistoryHeader, @@ -37,7 +37,7 @@ import { shellHistoryFileName, type OrcadMigrationShellHistoryShell } from './orcad-migration-shell-history-format' -import type { OrcadMigrationRequestIdentity } from './orcad-migration-staged-file' +import type { OrcadMigrationRequestIdentity } from '../blob-transfer/orcad-migration-staged-file' type ShellHistoryCatalog = Pick< OrcadMigrationManifest['payload'], diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-terminal-history-installer.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer.ts similarity index 86% rename from src/main/persistence/migrating-orcad-catalog/orcad-terminal-history-installer.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer.ts index 9f773bdab4d..2db9f5d91ac 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-terminal-history-installer.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer.ts @@ -6,23 +6,23 @@ import { createHash } from 'node:crypto' import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs' import { dirname, join } from 'node:path' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' import { MOVED_PANE_HISTORY_SESSION_TAG, parseOrcadMigrationTerminalHistoryText, type OrcadMigrationTerminalHistoryDocument -} from '../../../shared/orcad-migration/orcad-migration-terminal-history' -import { PTY_SESSION_ID_SEPARATOR } from '../../../shared/terminal/pty/lifecycle/pty-session-id-format' -import { parsePaneKey } from '../../../shared/workspace-layout/stable-pane-id' -import { getHistorySessionDirName } from '../../daemon/history/storage/history-paths' -import { isTerminalCheckpointFile } from '../../daemon/history/restoration/terminal-history-checkpoint-reader' -import type { SessionMeta } from '../../daemon/history/storage/terminal-history-metadata' -import { syncDirectoryDurablySync } from '../../filesystem/durable-file-write' +} from '../../../../shared/orcad-migration/orcad-migration-terminal-history' +import { PTY_SESSION_ID_SEPARATOR } from '../../../../shared/terminal/pty/lifecycle/pty-session-id-format' +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import { getHistorySessionDirName } from '../../../daemon/history/storage/history-paths' +import { isTerminalCheckpointFile } from '../../../daemon/history/restoration/terminal-history-checkpoint-reader' +import type { SessionMeta } from '../../../daemon/history/storage/terminal-history-metadata' +import { syncDirectoryDurablySync } from '../../../filesystem/durable-file-write' import { getOrcadMigrationReceivedBlobPath, listOrcadMigrationReceivedBlobNames -} from './orcad-migration-blob-staging' -import type { OrcadMigrationRequestIdentity } from './orcad-migration-staged-file' +} from '../blob-transfer/orcad-migration-blob-staging' +import type { OrcadMigrationRequestIdentity } from '../blob-transfer/orcad-migration-staged-file' const UTF8 = new TextDecoder('utf-8', { fatal: true }) diff --git a/src/main/persistence/migrating-orcad-catalog/orcad-terminal-restore-hint-store.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store.ts similarity index 96% rename from src/main/persistence/migrating-orcad-catalog/orcad-terminal-restore-hint-store.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store.ts index 16b821009c4..901d22d8bd7 100644 --- a/src/main/persistence/migrating-orcad-catalog/orcad-terminal-restore-hint-store.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-restore-hint-store.ts @@ -2,14 +2,14 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' import { z } from 'zod' -import { durableWriteTempPath, writeFileDurableSync } from '../../filesystem/durable-file-write' +import { durableWriteTempPath, writeFileDurableSync } from '../../../filesystem/durable-file-write' import { MAX_ORCAD_MIGRATION_TERMINAL_RESTORE_HINTS, isOrcadMigrationTerminalRestoreHintCwd, isOrcadMigrationTerminalRestoreHintPaneKey, type OrcadMigrationTerminalRestoreHint -} from '../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' -import { ensureOrcadMigrationDirectory } from './orcad-migration-staged-file' +} from '../../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' +import { ensureOrcadMigrationDirectory } from '../blob-transfer/orcad-migration-staged-file' const STORE_VERSION = 2 const INSTALLED_DIRECTORY = 'installed' diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-fixture.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-fixture.ts similarity index 76% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-fixture.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-fixture.ts index 11e5a73310d..5aecad69878 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-fixture.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-fixture.ts @@ -1,16 +1,16 @@ import { createHash } from 'node:crypto' import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' import { join } from 'node:path' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { folderWorkspaceKey } from '../../../shared/workspace-scope' -import { getOrcadMigrationReceivedBlobPath } from './orcad-migration-blob-staging' -import { buildWslMoveShellHistoryBlobs } from '../moving-wsl-projects/wsl-move-shell-history-blobs' -import { commitStagedOrcadMigrationCatalogDurably } from '../../runtime/hosts/migration/orcad-migration-catalog-import' -import { getHistoryRoot } from '../../pty/history/terminal-history-paths' -import { hashWorktreeId } from '../../pty/history/terminal-history-id' -import { FOLDER_WORKSPACE } from './persistence-orcad-migration-catalog-fixture' -import { testState, type createStore } from '../persistence-test-harness' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { folderWorkspaceKey } from '../../../../shared/workspace-scope' +import { getOrcadMigrationReceivedBlobPath } from '../blob-transfer/orcad-migration-blob-staging' +import { buildWslMoveShellHistoryBlobs } from '../../moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs' +import { commitStagedOrcadMigrationCatalogDurably } from '../../../runtime/hosts/migration/orcad-migration-catalog-import' +import { getHistoryRoot } from '../../../pty/history/terminal-history-paths' +import { hashWorktreeId } from '../../../pty/history/terminal-history-id' +import { FOLDER_WORKSPACE } from '../catalog-commit/persistence-orcad-migration-catalog-fixture' +import { testState, type createStore } from '../../persistence-test-harness' type Store = ReturnType export type EncodedBlob = { descriptor: OrcadMigrationBlobDescriptor; bytes: Buffer } diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-install-safety.test.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-install-safety.test.ts similarity index 90% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-install-safety.test.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-install-safety.test.ts index 56351ac8f77..2970833e325 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-install-safety.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-install-safety.test.ts @@ -11,9 +11,12 @@ import { } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { readHistoryMeta } from '../../pty/history/terminal-history' -import { getHistoryRoot } from '../../pty/history/terminal-history-paths' -import { DORMANT_WORKTREE_ID, manifest } from './persistence-orcad-migration-catalog-fixture' +import { readHistoryMeta } from '../../../pty/history/terminal-history' +import { getHistoryRoot } from '../../../pty/history/terminal-history-paths' +import { + DORMANT_WORKTREE_ID, + manifest +} from '../catalog-commit/persistence-orcad-migration-catalog-fixture' import { ZSH, encodedHistories, @@ -23,7 +26,7 @@ import { receivedPath, stage } from './persistence-orcad-migration-shell-history-fixture' -import { createStore, testState } from '../persistence-test-harness' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -34,7 +37,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) let desktopHistory: string diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-login-shell.test.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-login-shell.test.ts similarity index 76% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-login-shell.test.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-login-shell.test.ts index 8c1b7726470..bf96284dcff 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history-login-shell.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history-login-shell.test.ts @@ -3,18 +3,20 @@ import type * as NodeFs from 'node:fs' import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { injectHistoryEnv } from '../../pty/history/terminal-history' -import { getHistoryRoot } from '../../pty/history/terminal-history-paths' -import { DORMANT_WORKTREE_ID, manifest } from './persistence-orcad-migration-catalog-fixture' + +import { getHistoryRoot } from '../../../pty/history/terminal-history-paths' +import { + DORMANT_WORKTREE_ID, + manifest +} from '../catalog-commit/persistence-orcad-migration-catalog-fixture' import { ZSH, commitDurably, encodedHistories, hostHistory, - hostHistoryDirectory, stage } from './persistence-orcad-migration-shell-history-fixture' -import { createStore, testState } from '../persistence-test-harness' +import { createStore, testState } from '../../persistence-test-harness' const { missingShells, presentShells } = vi.hoisted(() => ({ missingShells: new Set(), @@ -46,7 +48,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) let desktopHistory: string @@ -86,16 +88,6 @@ describe('moved WSL history lands under the shell a host pane runs', () => { vi.unstubAllEnvs() }) - it('a zsh pane gets zsh_history, the HISTFILE a new zsh pane reads', async () => { - await moveLoneBridgeHistory(ZSH, () => '/usr/bin/zsh') - - expect(hostHistory(DORMANT_WORKTREE_ID, 'zsh_history')).toBe(ZSH) - expect(hostHistory(DORMANT_WORKTREE_ID, 'bash_history')).toBeNull() - const env: Record = {} - const injected = injectHistoryEnv(env, DORMANT_WORKTREE_ID, '/usr/bin/zsh', '/srv/x') - expect(injected.histFile).toBe(join(hostHistoryDirectory(DORMANT_WORKTREE_ID), 'zsh_history')) - }) - it.skipIf(process.platform === 'win32')( "the host's default-shell setting wins over SHELL, as it does for a new pane", async () => { diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history.test.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history.test.ts similarity index 92% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history.test.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history.test.ts index 5a3d1a587f5..733776ecc99 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-shell-history.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-shell-history.test.ts @@ -2,9 +2,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { mkdirSync, mkdtempSync, rmSync, writeFileSync, existsSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { readHistoryMeta } from '../../pty/history/terminal-history' -import { getHistoryRoot } from '../../pty/history/terminal-history-paths' -import { DORMANT_WORKTREE_ID, manifest } from './persistence-orcad-migration-catalog-fixture' +import { readHistoryMeta } from '../../../pty/history/terminal-history' +import { getHistoryRoot } from '../../../pty/history/terminal-history-paths' +import { + DORMANT_WORKTREE_ID, + manifest +} from '../catalog-commit/persistence-orcad-migration-catalog-fixture' import { BASH, ZSH, @@ -17,7 +20,7 @@ import { stage, type EncodedBlob } from './persistence-orcad-migration-shell-history-fixture' -import { createStore, testState } from '../persistence-test-harness' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -28,7 +31,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) let desktopHistory: string diff --git a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-terminal-restore-hints.test.ts b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-terminal-restore-hints.test.ts similarity index 80% rename from src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-terminal-restore-hints.test.ts rename to src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-terminal-restore-hints.test.ts index 6c8d27b55ad..25ea3a05582 100644 --- a/src/main/persistence/migrating-orcad-catalog/persistence-orcad-migration-terminal-restore-hints.test.ts +++ b/src/main/persistence/migrating-orcad-catalog/terminal-history/persistence-orcad-migration-terminal-restore-hints.test.ts @@ -3,19 +3,19 @@ import { createHash } from 'node:crypto' import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { getOrcadMigrationReceivedBlobPath } from './orcad-migration-blob-staging' -import { commitStagedOrcadMigrationCatalogDurably } from '../../runtime/hosts/migration/orcad-migration-catalog-import' -import { folderWorkspaceKey } from '../../../shared/workspace-scope' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { getOrcadMigrationReceivedBlobPath } from '../blob-transfer/orcad-migration-blob-staging' +import { commitStagedOrcadMigrationCatalogDurably } from '../../../runtime/hosts/migration/orcad-migration-catalog-import' +import { folderWorkspaceKey } from '../../../../shared/workspace-scope' import { DORMANT_LEAF_ID, DORMANT_WORKTREE_ID, FOLDER_WORKSPACE, dormantState, manifest as baseManifest -} from './persistence-orcad-migration-catalog-fixture' -import { createStore, testState } from '../persistence-test-harness' +} from '../catalog-commit/persistence-orcad-migration-catalog-fixture' +import { createStore, testState } from '../../persistence-test-harness' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, @@ -26,7 +26,7 @@ vi.mock('electron', () => ({ } })) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) +vi.mock('../../../telemetry/client', () => ({ track: vi.fn() })) const FOLDER_LEAF_ID = '22222222-2222-4222-8222-222222222222' const PANE = `tab-dormant:${DORMANT_LEAF_ID}` @@ -185,23 +185,4 @@ describe('orcad migration terminal restore hints through the store', () => { expect(peek(restarted, PANE, DORMANT_WORKTREE_ID)).toBeNull() expect(peek(restarted, OTHER_PANE, FOLDER_KEY)).toBe('/srv/app') }) - - it('drops a received file damaged after commit without failing the committed catalog', async () => { - const input = manifest() - const store = createStore() - stageBlob(store, input, encodedHints()) - store.commitStagedOrcadMigrationCatalog(input) - await store.flushPendingOrThrowAsync() - writeFileSync(receivedPath(input), 'not json') - const error = vi.spyOn(console, 'error').mockImplementation(() => {}) - - expect(await commitDurably(createStore(), input)).toBe('committed') - expect(error).toHaveBeenCalledWith( - expect.stringContaining('dropped unreadable terminal restore hints'), - expect.any(Error) - ) - expect(existsSync(receivedPath(input))).toBe(false) - expect(peek(createStore(), PANE, DORMANT_WORKTREE_ID)).toBeNull() - error.mockRestore() - }) }) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.test.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.test.ts similarity index 66% rename from src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.test.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.test.ts index 213865f9e39..c797445dca6 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.test.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.test.ts @@ -2,16 +2,15 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { wslMoveCutoverFixture as cutover } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' +import { wslMoveCutoverFixture as cutover } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { seedWslMoveCutover } from '../../__fixtures__/wsl-mover/wsl-move-journal-seeding' import { - listWslMoveCutoverChain, listWslMoveCutovers, removeWslMoveCutover, writeWslMoveCutover, wslMoveJournalDirectory } from './wsl-move-cutover-journal' -import { resetWslMoveDesktopRewriteStoresForTests } from './wsl-move-desktop-rewrite-stores' +import { resetWslMoveDesktopRewriteStoresForTests } from '../desktop-state/wsl-move-desktop-rewrite-stores' let userDataPath: string beforeEach(() => { @@ -80,28 +79,4 @@ describe('WSL move journal', () => { writeFileSync(journalPath('move-1'), JSON.stringify(edited)) expect(() => listWslMoveCutovers(userDataPath)).toThrow('stay fenced') }) - - it('refuses to remove a move a later move of its distro supersedes, so the chain stays readable', () => { - seedWslMoveCutover(userDataPath, cutover('move-1', 'retained')) - seedWslMoveCutover( - userDataPath, - cutover('move-2', 'retained', { supersedesMigrationId: 'move-1' }, { repoIds: ['repo-2'] }) - ) - seedWslMoveCutover( - userDataPath, - cutover('move-3', 'retained', { supersedesMigrationId: 'move-2' }, { repoIds: ['repo-3'] }) - ) - - expect(() => removeWslMoveCutover(userDataPath, 'move-2')).toThrow('wsl_move_superseded') - expect(() => removeWslMoveCutover(userDataPath, 'move-1')).toThrow('wsl_move_superseded') - expect( - listWslMoveCutoverChain(userDataPath, 'local-wsl:ubuntu').map((c) => c.migrationId) - ).toEqual(['move-1', 'move-2', 'move-3']) - // Newest first, one at a time, and the chain reads after every step. - removeWslMoveCutover(userDataPath, 'move-3') - expect(listWslMoveCutoverChain(userDataPath, 'local-wsl:ubuntu')).toHaveLength(2) - removeWslMoveCutover(userDataPath, 'move-2') - removeWslMoveCutover(userDataPath, 'move-1') - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - }) }) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.ts index 22e98ab85f6..f2fe0a7ecc5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal.ts @@ -4,18 +4,18 @@ import { isWslMoveCutoverFinished, parseWslMoveCutover, type WslMoveCutover -} from '../../../shared/wsl-move/wsl-move-cutover' -import { isRecord } from '../../../shared/orcad-migration/orcad-migration-manifest-fields' -import { assertOrcadMigrationManifestDigest } from '../../orcad/orcad-migration-manifest-digest' +} from '../../../../shared/wsl-move/wsl-move-cutover' +import { isRecord } from '../../../../shared/orcad-migration/orcad-migration-manifest-fields' +import { assertOrcadMigrationManifestDigest } from '../../../orcad/orcad-migration-manifest-digest' import { createMigrationJournalDirectory, orderMigrationJournalChain -} from '../migrating-orcad-catalog/migration-journal-directory' -import { assertWslMoveManifestFits } from './wsl-move-manifest-budget' +} from '../../migrating-orcad-catalog/cutover-journals/migration-journal-directory' +import { assertWslMoveManifestFits } from '../manifest-scope/wsl-move-manifest-budget' import { isWslMoveDesktopRewriteRegistryComplete, pendingWslMoveDesktopRewriteStores -} from './wsl-move-desktop-rewrite-stores' +} from '../desktop-state/wsl-move-desktop-rewrite-stores' export class WslMoveJournalUnreadableError extends Error { constructor(detail: string) { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-owed-host-aborts.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-owed-host-aborts.ts similarity index 86% rename from src/main/persistence/moving-wsl-projects/wsl-move-owed-host-aborts.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-owed-host-aborts.ts index 1c0c9161a3c..e33b2196249 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-owed-host-aborts.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-owed-host-aborts.ts @@ -4,11 +4,11 @@ * keeps its claims on those projects for the stage's 7-day lifetime and refuses every retry. The * reset leaves this record; the next move into the distro aborts that stage by identity first. */ -import type { OrcadMigrationCatalogReferenceAbortResult } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { isRecord } from '../../../shared/orcad-migration/orcad-migration-manifest-fields' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import { createMigrationJournalDirectory } from '../migrating-orcad-catalog/migration-journal-directory' -import type { OrcadMigrationDestinationCatalog } from '../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' +import type { OrcadMigrationCatalogReferenceAbortResult } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { isRecord } from '../../../../shared/orcad-migration/orcad-migration-manifest-fields' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' +import { createMigrationJournalDirectory } from '../../migrating-orcad-catalog/cutover-journals/migration-journal-directory' +import type { OrcadMigrationDestinationCatalog } from '../../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' export type WslMoveOwedHostAbort = { migrationId: string diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-reset.test.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.test.ts similarity index 61% rename from src/main/persistence/moving-wsl-projects/wsl-move-reset.test.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.test.ts index 88f1902aae1..5f128230278 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-reset.test.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.test.ts @@ -1,4 +1,4 @@ -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' @@ -6,20 +6,17 @@ import type { OrcadMigrationCatalogAbortResult, OrcadMigrationCatalogState, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import type { WslMoveCutoverPhase } from '../../../shared/wsl-move/wsl-move-cutover' -import type { OrcadMigrationDestinationCatalog } from '../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' -import { MAX_ORCAD_MIGRATION_MANIFEST_BYTES } from '../../../shared/orcad-migration/orcad-migration-manifest-validation' -import { - ORCAD_MIGRATION_REQUEST_PARAMS_BUDGET_BYTES, - orcadMigrationRequestFits -} from '../../managed-server/migration/catalog/orcad-migration-request-budget' -import { computeOrcadMigrationManifestSha256 } from '../../orcad/orcad-migration-manifest-digest' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { listWslMoveCutovers, wslMoveJournalDirectory } from './wsl-move-cutover-journal' -import { resolveWslMoveFence } from './wsl-move-fence' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../../shared/wsl-host-internal-gate' +import type { WslMoveCutoverPhase } from '../../../../shared/wsl-move/wsl-move-cutover' +import type { OrcadMigrationDestinationCatalog } from '../../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' + +import { orcadMigrationRequestFits } from '../../../managed-server/migration/catalog/orcad-migration-request-budget' + +import { wslMoveCutoverFixture } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { seedWslMoveCutover } from '../../__fixtures__/wsl-mover/wsl-move-journal-seeding' + +import { resolveWslMoveFence } from '../quiescence/wsl-move-fence' import { resetWslMoveToZero } from './wsl-move-reset' let userDataPath: string @@ -131,37 +128,6 @@ function assertCarried(manifest: OrcadMigrationManifest, refuse = false): void { * The widest gap the validators allow: under the manifest cap, so the journal still reads it, yet * over what one request can carry. New moves are refused this size; older records may hold it. */ -function seedOversized(phase: WslMoveCutoverPhase): void { - const base = wslMoveCutoverFixture('move-1', phase) - const sized = (padding: number) => { - const { manifestSha256: _digest, ...unsigned } = base.manifest - const payload = { - ...unsigned.payload, - repositories: unsigned.payload.repositories.map((repo) => ({ - ...repo, - displayName: 'x'.repeat(padding) - })) - } - const signed = { ...unsigned, payload } - return { ...signed, manifestSha256: computeOrcadMigrationManifestSha256(signed) } - } - const overhead = JSON.stringify(sized(0)).length - const manifest = sized(MAX_ORCAD_MIGRATION_MANIFEST_BYTES - overhead - 16) - expect(JSON.stringify(manifest).length).toBeLessThanOrEqual(MAX_ORCAD_MIGRATION_MANIFEST_BYTES) - expect(JSON.stringify({ manifest }).length).toBeGreaterThan( - ORCAD_MIGRATION_REQUEST_PARAMS_BUDGET_BYTES - ) - // Written past the journal's size cap on purpose: a record from before the cap must still reset. - seedWslMoveCutover(userDataPath, base) - writeFileSync( - join(wslMoveJournalDirectory(userDataPath), `${base.migrationId}.json`), - JSON.stringify({ - ...base, - manifestSha256: manifest.manifestSha256, - manifest: { ...manifest, source: base.manifest.source } - }) - ) -} const fenced = (): boolean => resolveWslMoveFence(userDataPath).fenced.repoIds.has('repo-1') @@ -184,15 +150,4 @@ describe('resetWslMoveToZero', () => { }) expect(fenced()).toBe(true) }) - - it('never moves forward on a committed answer the host did not flush first', async () => { - seedOversized('blobs-transferred') - const { destination } = host({ current: 'committed' }, { durableCommitted: false }) - expect(await resetWslMoveToZero({ userDataPath, destination }, 'move-1')).toEqual({ - outcome: 'unverifiable', - reason: 'commit_not_proven_durable' - }) - expect(fenced()).toBe(true) - expect(listWslMoveCutovers(userDataPath)[0]?.phase).toBe('blobs-transferred') - }) }) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-reset.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-reset.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.ts index 7509d861e2e..b63df1e0454 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-reset.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-reset.ts @@ -10,19 +10,19 @@ import type { OrcadMigrationCatalogReferenceAbortResult, OrcadMigrationCatalogState -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' import { WSL_MOVE_CUTOVER_PHASES, type WslMoveCutover, type WslMoveCutoverPhase -} from '../../../shared/wsl-move/wsl-move-cutover' +} from '../../../../shared/wsl-move/wsl-move-cutover' import { abortWithRecovery, confirmDurableCommit, type OrcadMigrationDestinationCatalog -} from '../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' -import { orcadMigrationRequestFits } from '../../managed-server/migration/catalog/orcad-migration-request-budget' -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' +} from '../../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' +import { orcadMigrationRequestFits } from '../../../managed-server/migration/catalog/orcad-migration-request-budget' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' import { listWslMoveCutovers, removeUncommittedWslMoveCutover, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-retained-marks.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-marks.ts similarity index 76% rename from src/main/persistence/moving-wsl-projects/wsl-move-retained-marks.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-marks.ts index 8414214c8a8..695eac67910 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-retained-marks.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-marks.ts @@ -2,14 +2,14 @@ * Writes the `orcadRetained` mark on local project rows (mover design, section 4.5). Only this * machine's rows: the WSL host's own row carries the same id and is never marked. */ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' import { sameOrcadRetainedMarker, type OrcadRetainedMarker -} from '../../../shared/orcad-retained-marker' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { Repo } from '../../../shared/repo-types' -import { isLocalWslMoveRow } from './wsl-move-scope-guard' +} from '../../../../shared/orcad-retained-marker' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { Repo } from '../../../../shared/repo-types' +import { isLocalWslMoveRow } from '../quiescence/wsl-move-scope-guard' /** `marker: null` removes the mark. */ export type WslMoveRetainedMark = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-retained-source.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-source.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-retained-source.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-source.ts index 2c27b5d2058..060bf2015a8 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-retained-source.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retained-source.ts @@ -4,16 +4,16 @@ * whether an older build changed it since. Only identity counts as a change, as for SSH: an older * build's tabs and edits inside a moved project stay in the retained rows. */ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { OrcadRetainedMarker } from '../../../shared/orcad-retained-marker' -import type { Repo } from '../../../shared/repo-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { OrcadRetainedMarker } from '../../../../shared/orcad-retained-marker' +import type { Repo } from '../../../../shared/repo-types' import { WSL_MOVE_CUTOVER_PHASES, type WslMoveCutover -} from '../../../shared/wsl-move/wsl-move-cutover' -import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' +} from '../../../../shared/wsl-move/wsl-move-cutover' +import { createUncToLinuxPathRewriter } from '../manifest-scope/wsl-move-path-rewriter' import type { WslMoveRetainedMark } from './wsl-move-retained-marks' -import { isLocalWslMoveRow } from './wsl-move-scope-guard' +import { isLocalWslMoveRow } from '../quiescence/wsl-move-scope-guard' export type WslMoveRowKind = 'repo' | 'folder' export type WslMoveRowRef = { kind: WslMoveRowKind; id: string } diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-retention.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-retention.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention.ts index 3514a586da7..48c7e99438e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-retention.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention.ts @@ -7,8 +7,8 @@ * flag rows whose identity it changed (a later move offers them; none runs on its own), and drop * marks no committed move explains, such as after "Use on this computer again". */ -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' -import type { Store } from '../loading-store/store' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' +import type { Store } from '../../loading-store/store' import { listWslMoveCutoverChain, onWslMoveJournalChange, @@ -16,7 +16,7 @@ import { writeWslMoveCutover } from './wsl-move-cutover-journal' import { planWslMoveRetainedMarks, type WslMoveRowRef } from './wsl-move-retained-source' -import { userDataKey } from './wsl-move-scope-guard' +import { userDataKey } from '../quiescence/wsl-move-scope-guard' // Bounded like a desktop rewrite store: a busy profile must not hold every later pass. export const WSL_MOVE_RETENTION_FLUSH_TIMEOUT_MS = 30_000 diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-ledger.test.ts similarity index 60% rename from src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-ledger.test.ts index 3c1f8dff716..f71dc8e71cd 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-ledger.test.ts @@ -2,14 +2,10 @@ import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { wslMoveCutoverFixture as cutover } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' +import { wslMoveCutoverFixture as cutover } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { seedWslMoveCutover } from '../../__fixtures__/wsl-mover/wsl-move-journal-seeding' import { listWslMoveCutovers, writeWslMoveCutover } from './wsl-move-cutover-journal' -import { - registerWslMoveDesktopRewriteStore, - resetWslMoveDesktopRewriteStoresForTests, - setWslMoveDesktopRewriteRegistryCompleteForTests -} from './wsl-move-desktop-rewrite-stores' +import { resetWslMoveDesktopRewriteStoresForTests } from '../desktop-state/wsl-move-desktop-rewrite-stores' let userDataPath: string beforeEach(() => { @@ -70,34 +66,4 @@ describe('WSL move rewrite ledger', () => { 'wsl_move_ledger_changed' ) }) - - it('advances to client-rewritten only once every registered store is recorded', () => { - setWslMoveDesktopRewriteRegistryCompleteForTests(true) - registerWslMoveDesktopRewriteStore({ id: 'a', side: 'main', run: () => {}, flush: () => {} }) - registerWslMoveDesktopRewriteStore({ id: 'b', side: 'renderer' }) - seedWslMoveCutover(userDataPath, committed(['a'])) - expect(() => - writeWslMoveCutover( - userDataPath, - cutover('move-1', 'client-rewritten', { rewrittenStores: ['a'] }) - ) - ).toThrow('wsl_move_rewrite_incomplete') - writeWslMoveCutover(userDataPath, committed(['a', 'b'])) - writeWslMoveCutover( - userDataPath, - cutover('move-1', 'client-rewritten', { rewrittenStores: ['a', 'b'] }) - ) - expect(listWslMoveCutovers(userDataPath)[0]?.phase).toBe('client-rewritten') - }) - - it('refuses client-rewritten while the store registry is incomplete', () => { - setWslMoveDesktopRewriteRegistryCompleteForTests(false) - seedWslMoveCutover(userDataPath, committed([])) - expect(() => writeWslMoveCutover(userDataPath, cutover('move-1', 'client-rewritten'))).toThrow( - 'wsl_move_rewrite_incomplete' - ) - setWslMoveDesktopRewriteRegistryCompleteForTests(true) - writeWslMoveCutover(userDataPath, cutover('move-1', 'client-rewritten')) - expect(listWslMoveCutovers(userDataPath)[0]?.phase).toBe('client-rewritten') - }) }) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-retry.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-retry.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-rewrite-retry.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-retry.ts index dd74088040e..c4c69f749e2 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-retry.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-rewrite-retry.ts @@ -3,10 +3,10 @@ * the host could not turn back on yet. A pass runs at startup and after each move; this covers the * host coming back later in the same run. Backs off, and stops once nothing is left. */ -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' import { listWslMoveCutovers } from './wsl-move-cutover-journal' -import { runWslMoveDesktopRewritePass } from './wsl-move-desktop-rewrite' -import { pendingWslMoveDesktopRewriteStores } from './wsl-move-desktop-rewrite-stores' +import { runWslMoveDesktopRewritePass } from '../desktop-state/wsl-move-desktop-rewrite' +import { pendingWslMoveDesktopRewriteStores } from '../desktop-state/wsl-move-desktop-rewrite-stores' import { retryWslMoveHostAutomationsLeftOff, type WslMoveHostAutomationRetryHost diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-host-automations.ts similarity index 98% rename from src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-host-automations.ts index 88a96273877..0518f53508b 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-host-automations.ts @@ -6,8 +6,8 @@ * refused undo turns back on what it turned off and changes nothing here; one it cannot turn back * on is recorded, shown and retried. */ -import type { Automation } from '../../../shared/automations/automation-definition' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' +import type { Automation } from '../../../../shared/automations/automation-definition' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' import { listWslMoveCutovers, writeWslMoveCutover } from './wsl-move-cutover-journal' export type WslMoveHostAutomationStop = diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-undo-spawn-fence.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-undo-spawn-fence.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence.ts index c07fd234bd0..f1779952e56 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-undo-spawn-fence.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-undo-spawn-fence.ts @@ -1,4 +1,4 @@ -import type { RuntimeRpcFailure } from '../../../shared/runtime-rpc-envelope' +import type { RuntimeRpcFailure } from '../../../../shared/runtime-rpc-envelope' /** * While "Use on this computer again" stops a project's terminals on its WSL host, this window's diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-use-locally.ts b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-use-locally.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-use-locally.ts rename to src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-use-locally.ts index a1d71307a33..15ca1c60cec 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-use-locally.ts +++ b/src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-use-locally.ts @@ -7,16 +7,19 @@ import { WSL_MOVE_CUTOVER_PHASES, type WslMoveCutover -} from '../../../shared/wsl-move/wsl-move-cutover' -import type { WslMoveUseLocallyResult } from '../../../shared/wsl-move/wsl-moved-project' -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' -import { isWslMoveRunning } from './wsl-move-running-moves' +} from '../../../../shared/wsl-move/wsl-move-cutover' +import type { WslMoveUseLocallyResult } from '../../../../shared/wsl-move/wsl-moved-project' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' +import { isWslMoveRunning } from '../orchestration/wsl-move-running-moves' import { listWslMoveCutoverChain, listWslMoveCutovers, removeCommittedWslMoveCutover } from './wsl-move-cutover-journal' -import { type WslMoveProjectRef, wslMoveProjectRefForWorkspace } from './wsl-move-scope-guard' +import { + type WslMoveProjectRef, + wslMoveProjectRefForWorkspace +} from '../quiescence/wsl-move-scope-guard' const COMMITTED_FROM = WSL_MOVE_CUTOVER_PHASES.indexOf('destination-committed') diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-automation-filter-rewrite.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-automation-filter-rewrite.ts similarity index 79% rename from src/main/persistence/moving-wsl-projects/wsl-move-automation-filter-rewrite.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-automation-filter-rewrite.ts index 971f245a2d4..fdfba3b77c9 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-automation-filter-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-automation-filter-rewrite.ts @@ -4,8 +4,8 @@ * carried. Only then does it widen to All hosts, once: the ledgered run never repeats, so a * later choice of this desktop stays. */ -import type { PersistedAutomationHostFilter } from '../../../shared/automations/ownership/automation-host-filter' -import { hostStableKey } from '../../../shared/automations/ownership/automation-owner-key' +import type { PersistedAutomationHostFilter } from '../../../../shared/automations/ownership/automation-host-filter' +import { hostStableKey } from '../../../../shared/automations/ownership/automation-owner-key' const DESKTOP_SELF_HOST_KEY = hostStableKey({ authority: { kind: 'desktop' }, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-copy.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-copy.ts similarity index 94% rename from src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-copy.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-copy.ts index 2471ca15db3..e959868201e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-copy.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-copy.ts @@ -4,7 +4,7 @@ * host starts on a fresh partition instead. Browser profiles are global, not per project, so each * profile's whole jar is copied, once per host partition, by the first move into that host. */ -import type { KnownRuntimeEnvironment } from '../../../shared/remote-runtime/host-catalog/runtime-environments' +import type { KnownRuntimeEnvironment } from '../../../../shared/remote-runtime/host-catalog/runtime-environments' import { emptyWslMoveBrowserCookieCopyCounts, WSL_MOVE_BROWSER_COOKIE_COPY_MAX_PROFILES, @@ -12,13 +12,16 @@ import { type WslMoveBrowserCookieCopy, type WslMoveBrowserCookieCopyCounts, type WslMoveBrowserCookieFreshPartitionReason -} from '../../../shared/wsl-move/wsl-move-browser-cookie-copy' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' +} from '../../../../shared/wsl-move/wsl-move-browser-cookie-copy' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' import type { WslHostBrowserRouteStorage, WslHostBrowserRouteStorageResult -} from '../../browser/routing/local-host-partitions/wsl-host-browser-route-partition' -import { listWslMoveCutovers, writeWslMoveCutover } from './wsl-move-cutover-journal' +} from '../../../browser/routing/local-host-partitions/wsl-host-browser-route-partition' +import { + listWslMoveCutovers, + writeWslMoveCutover +} from '../cutover-recovery/wsl-move-cutover-journal' import type { WslMoveDesktopRewriteContext } from './wsl-move-desktop-rewrite-stores' export type WslMoveBrowserCookieCopyDependencies = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-store.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-store.ts similarity index 76% rename from src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-store.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-store.ts index 6432123eba8..f58d15fb620 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-browser-cookie-store.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-browser-cookie-store.ts @@ -1,18 +1,18 @@ /** Registers the `browser-cookies` rewrite store against the app's real browser sessions. */ import { BrowserWindow } from 'electron' -import { listEnvironments } from '../../../shared/remote-runtime/host-store/runtime-environment-store' -import { WSL_MOVE_BROWSER_COOKIES_STORE_ID } from '../../../shared/wsl-move/wsl-move-browser-cookie-copy' +import { listEnvironments } from '../../../../shared/remote-runtime/host-store/runtime-environment-store' +import { WSL_MOVE_BROWSER_COOKIES_STORE_ID } from '../../../../shared/wsl-move/wsl-move-browser-cookie-copy' import { copyBrowserPartitionCookies, flushBrowserPartitionCookies -} from '../../browser/cookies/browser-partition-cookie-copy' -import { activeBrowserRoutePartitionOrcaProfileId } from '../../browser/routing/partitions/browser-route-partition-binding-runtime' -import { browserSessionRegistry } from '../../browser/sessions/profiles/browser-session-registry' -import { browserSessionsInitialized } from '../../browser/sessions/browser-session-startup' +} from '../../../browser/cookies/browser-partition-cookie-copy' +import { activeBrowserRoutePartitionOrcaProfileId } from '../../../browser/routing/partitions/browser-route-partition-binding-runtime' +import { browserSessionRegistry } from '../../../browser/sessions/profiles/browser-session-registry' +import { browserSessionsInitialized } from '../../../browser/sessions/browser-session-startup' import { bindWslHostBrowserRoutePartition, wslHostBrowserRouteStorage -} from '../../browser/routing/local-host-partitions/wsl-host-browser-route-partition' +} from '../../../browser/routing/local-host-partitions/wsl-host-browser-route-partition' import { runWslMoveBrowserCookieCopy, type WslMoveBrowserCookieCopyDependencies diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-registry.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-registry.ts similarity index 100% rename from src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-registry.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-registry.ts diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores.ts index 19120ba8f3f..dd3c753aa56 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores.ts @@ -1,7 +1,7 @@ // Record each store only after durable rewrite so crashes retry the unfinished stores. -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import { WSL_MOVE_RENDERER_REWRITE_STORE_IDS } from '../../../shared/wsl-move/wsl-move-renderer-rewrite-types' -import type { OrcadMigrationPathRewriter } from '../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' +import { WSL_MOVE_RENDERER_REWRITE_STORE_IDS } from '../../../../shared/wsl-move/wsl-move-renderer-rewrite-types' +import type { OrcadMigrationPathRewriter } from '../../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' export type WslMoveDesktopRewriteContext = { cutover: Readonly diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite.ts index 3fbb7f1f9f6..39ef224649c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite.ts @@ -1,25 +1,28 @@ // Persist each store before its ledger entry; restart retries only unrecorded rewrites. -import { toRuntimeExecutionHostId } from '../../../shared/execution-host' +import { toRuntimeExecutionHostId } from '../../../../shared/execution-host' import { WSL_MOVE_CUTOVER_PHASES, type WslMoveCutover -} from '../../../shared/wsl-move/wsl-move-cutover' +} from '../../../../shared/wsl-move/wsl-move-cutover' import type { WslMovePendingRendererRewrite, WslMoveRecordStoreRewrittenRequest, WslMoveRecordStoreRewrittenResult -} from '../../../shared/wsl-move/wsl-move-renderer-rewrite-types' -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' -import { listWslMoveCutovers, writeWslMoveCutover } from './wsl-move-cutover-journal' +} from '../../../../shared/wsl-move/wsl-move-renderer-rewrite-types' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' +import { + listWslMoveCutovers, + writeWslMoveCutover +} from '../cutover-recovery/wsl-move-cutover-journal' import { isWslMoveDesktopRewriteRegistryComplete, listWslMoveDesktopRewriteStores, pendingWslMoveDesktopRewriteStores, type WslMoveDesktopRewriteContext } from './wsl-move-desktop-rewrite-stores' -import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' -import { wslMoveScopeRootPaths } from './wsl-move-scope-roots' -import { reloadWslMoveWindowWithWritesHeld } from './wsl-move-window-write-hold' +import { createUncToLinuxPathRewriter } from '../manifest-scope/wsl-move-path-rewriter' +import { wslMoveScopeRootPaths } from '../manifest-scope/wsl-move-scope-roots' +import { reloadWslMoveWindowWithWritesHeld } from '../quiescence/wsl-move-window-write-hold' // One hung store would stall every serialized pass. export const WSL_MOVE_REWRITE_STORE_TIMEOUT_MS = 30_000 diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-host-automations-rewrite.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-automations-rewrite.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-host-automations-rewrite.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-automations-rewrite.ts index 8cf128f5fcd..c49278f6ac5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-host-automations-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-automations-rewrite.ts @@ -3,9 +3,9 @@ * manifest can only carry them disabled. Ledgered like a desktop store, so a crash or an unreachable * host retries on the next pass, and the move never finishes with them left off. */ -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import type { WslMoveUnfinished } from '../../../shared/wsl-move/wsl-move-driver-types' -import { listWslMoveCutovers } from './wsl-move-cutover-journal' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' +import type { WslMoveUnfinished } from '../../../../shared/wsl-move/wsl-move-driver-types' +import { listWslMoveCutovers } from '../cutover-recovery/wsl-move-cutover-journal' import { registerWslMoveDesktopRewriteStore } from './wsl-move-desktop-rewrite-stores' export const WSL_MOVE_HOST_AUTOMATIONS_STORE_ID = 'host-automations' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-host-owned-chat-tabs.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-owned-chat-tabs.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-host-owned-chat-tabs.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-owned-chat-tabs.ts index 9a10906ab4b..049a9b5485f 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-host-owned-chat-tabs.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-host-owned-chat-tabs.ts @@ -4,8 +4,8 @@ * row of the workspace stays exactly as the quiesce left it: that slept state is what a downgrade * restores, and its terminals and editors now live on the host. */ -import type { Tab, TabGroup } from '../../../shared/tab-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import type { Tab, TabGroup } from '../../../../shared/tab-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' function isChatTab(tab: Pick): boolean { return tab.contentType === 'agent-session' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-main-rewrite-stores.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-main-rewrite-stores.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores.ts index 4fabcc42814..7f20cd19f24 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-main-rewrite-stores.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-main-rewrite-stores.ts @@ -3,20 +3,23 @@ * routing, the local session's focus, then the host partition's seed. Each re-reads the profile, * so a run after a crash before its ledger entry finds its own earlier write and changes nothing. */ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' import type { WorkspaceSessionPatch, WorkspaceSessionState -} from '../../../shared/workspace-session/workspace-session-state-types' -import type { Store } from '../loading-store/store' +} from '../../../../shared/workspace-session/workspace-session-state-types' +import type { Store } from '../../loading-store/store' import { wslMoveAutomationHostFilterUpdate } from './wsl-move-automation-filter-rewrite' import { registerWslMoveDesktopRewriteStore } from './wsl-move-desktop-rewrite-stores' import { wslMoveRewriteScope, type WslMoveRewriteScope } from './wsl-move-rewrite-scope' import { withWslMoveSeededViewState } from './wsl-move-seeded-view-state' -import { wslMoveHostSessionSeed, wslMoveSessionGlobalsPatch } from './wsl-move-session-rewrite' +import { + wslMoveHostSessionSeed, + wslMoveSessionGlobalsPatch +} from '../terminal-state/wsl-move-session-rewrite' import { rewriteWslMoveUiRouting } from './wsl-move-ui-routing-rewrite' -import { holdWslMoveWindowWrites } from './wsl-move-window-write-hold' +import { holdWslMoveWindowWrites } from '../quiescence/wsl-move-window-write-hold' export type WslMoveMainRewriteProfile = Pick< Store, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite.ts index 2eb2e3cb307..142ee96bc8c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite.ts @@ -5,10 +5,10 @@ * stays as written; `SQLITE_TABLE_DISPOSITIONS` gives each table's reason. */ import { existsSync } from 'node:fs' -import { isStructuredWorkerHandle } from '../../../shared/orchestration/workers/structured-worker-handle' -import { hardenOrchestrationDatabaseFiles } from '../../runtime/orchestration/db/database-file-permissions' -import Database from '../../sqlite/sync-database' -import type { SqliteRow } from '../../sqlite/sqlite-statement' +import { isStructuredWorkerHandle } from '../../../../shared/orchestration/workers/structured-worker-handle' +import { hardenOrchestrationDatabaseFiles } from '../../../runtime/orchestration/db/database-file-permissions' +import Database from '../../../sqlite/sync-database' +import type { SqliteRow } from '../../../sqlite/sqlite-statement' import { registerWslMoveDesktopRewriteStore } from './wsl-move-desktop-rewrite-stores' import { wslMoveRewriteScope, type WslMoveRewriteScope } from './wsl-move-rewrite-scope' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-scope.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-rewrite-scope.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-rewrite-scope.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-rewrite-scope.ts index 9acb4dfa2b1..3ba7dec43ff 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-rewrite-scope.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-rewrite-scope.ts @@ -3,12 +3,12 @@ * projects, and what are its id and path on the host. Ids keep their repo; only a UNC path of the * moved distro changes, through the same rewrite the manifest was built with. */ -import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id' +import { getRepoIdFromWorktreeId } from '../../../../shared/worktree/id' import { normalizeWorkspaceSessionKeyToWorkspaceId, parseWorkspaceKey -} from '../../../shared/workspace-scope' -import { rewriteOrcadMigrationWorktreeId } from '../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' +} from '../../../../shared/workspace-scope' +import { rewriteOrcadMigrationWorktreeId } from '../../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' import type { WslMoveDesktopRewriteContext } from './wsl-move-desktop-rewrite-stores' export type WslMoveRewriteScope = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.test.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.test.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.test.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.test.ts index 34349637539..1da74a58a1e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.test.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' import type { PersistedOpenFile, WorkspaceSessionState -} from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../shared/workspace-session/workspace-session-state-types' import { withWslMoveSeededViewState } from './wsl-move-seeded-view-state' const UNC_ROOT = '\\\\wsl.localhost\\Ubuntu\\home\\dev\\app' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.ts index 0b016ae2ed3..ddd44442fb8 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-seeded-view-state.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-seeded-view-state.ts @@ -5,10 +5,10 @@ * cannot rewrite) and closed-terminal-tab tombstones. Only for workspaces seeded in this run, so * anything the user since changed on the host stays as it is. */ -import type { ClosedTerminalTabTombstone } from '../../../shared/workspace-layout/closed-terminal-tab-tombstones' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { ownedEditorFileId } from '../../../shared/workspace-session/workspace-session-pane-ownership' -import { isHostBoundOpenFile } from '../migrating-orcad-catalog/orcad-source-draft-rename' +import type { ClosedTerminalTabTombstone } from '../../../../shared/workspace-layout/closed-terminal-tab-tombstones' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import { ownedEditorFileId } from '../../../../shared/workspace-session/workspace-session-pane-ownership' +import { isHostBoundOpenFile } from '../../migrating-orcad-catalog/source/worktrees/orcad-source-draft-rename' import type { WslMoveRewriteScope } from './wsl-move-rewrite-scope' type ViewStateScope = Pick & { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.test.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.test.ts similarity index 94% rename from src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.test.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.test.ts index fd79603eda8..febc1656df2 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.test.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from 'vitest' -import { toRuntimeExecutionHostId, type ExecutionHostId } from '../../../shared/execution-host' -import type { WorkspaceCleanupDismissal } from '../../../shared/workspace-cleanup/workspace-cleanup' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { wslMoverProfile } from '../__fixtures__/wsl-mover/wsl-mover-profiles' -import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' +import { toRuntimeExecutionHostId, type ExecutionHostId } from '../../../../shared/execution-host' +import type { WorkspaceCleanupDismissal } from '../../../../shared/workspace-cleanup/workspace-cleanup' +import { wslMoveCutoverFixture } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { wslMoverProfile } from '../../__fixtures__/wsl-mover/wsl-mover-profiles' +import { createUncToLinuxPathRewriter } from '../manifest-scope/wsl-move-path-rewriter' import { wslMoveRewriteScope } from './wsl-move-rewrite-scope' import { rewriteWslMoveUiRouting, type WslMoveUiRoutingState } from './wsl-move-ui-routing-rewrite' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.ts index 0ac38bf50d0..ff3a1ed8f93 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-ui-routing-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-ui-routing-rewrite.ts @@ -5,23 +5,23 @@ * stay for a lossless downgrade; only the last-active worktree, a single value, moves. A second * run finds every copy present and changes nothing. */ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { PersistedUIState } from '../../../shared/persisted-ui-state-types' -import { getRepoHostIdentityForParts } from '../../../shared/repo-host-identity' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import type { PersistedUIState } from '../../../../shared/persisted-ui-state-types' +import { getRepoHostIdentityForParts } from '../../../../shared/repo-host-identity' import type { ManualRepoOrderEntry, VisibleWorkspaceHostIds, WorkspaceHostOrder -} from '../../../shared/ui-chrome-types' -import type { WorkspaceCleanupDismissal } from '../../../shared/workspace-cleanup/workspace-cleanup' -import { getWorkspaceCleanupHostIdentity } from '../../../shared/workspace-cleanup/workspace-cleanup-host-identity' -import { resolveVisibleWorkspaceHostIds } from '../../../shared/workspace-view/workspace-host-visibility' +} from '../../../../shared/ui-chrome-types' +import type { WorkspaceCleanupDismissal } from '../../../../shared/workspace-cleanup/workspace-cleanup' +import { getWorkspaceCleanupHostIdentity } from '../../../../shared/workspace-cleanup/workspace-cleanup-host-identity' +import { resolveVisibleWorkspaceHostIds } from '../../../../shared/workspace-view/workspace-host-visibility' import { composeWorktreeHostIdentity, getExecutionHostIdFromWorktreeHostIdentity, getWorktreeIdFromHostIdentity, isWorktreeHostIdentity -} from '../../../shared/worktree/host-qualified-identity' +} from '../../../../shared/worktree/host-qualified-identity' import type { WslMoveRewriteScope } from './wsl-move-rewrite-scope' export type WslMoveUiRoutingState = Pick< diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-windows-shell-choices.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-windows-shell-choices.ts similarity index 85% rename from src/main/persistence/moving-wsl-projects/wsl-move-windows-shell-choices.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-windows-shell-choices.ts index 1a1f6f1c375..963ccd7f05b 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-windows-shell-choices.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-move-windows-shell-choices.ts @@ -1,4 +1,4 @@ -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' /** * A tab's Windows launch choices, dropped on purpose: `shellOverride` names a Windows shell diff --git a/src/main/persistence/moving-wsl-projects/wsl-moved-projects.ts b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-moved-projects.ts similarity index 79% rename from src/main/persistence/moving-wsl-projects/wsl-moved-projects.ts rename to src/main/persistence/moving-wsl-projects/desktop-state/wsl-moved-projects.ts index 86b9ca4b8f1..dc5b19dbacb 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-moved-projects.ts +++ b/src/main/persistence/moving-wsl-projects/desktop-state/wsl-moved-projects.ts @@ -3,10 +3,10 @@ * existing chats stay on this computer (owner decision, option C). Separate from the repo and * folder lists so no caller can mistake one for a normal, editable project. */ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { Repo } from '../../../shared/repo-types' -import type { WslMovedProject } from '../../../shared/wsl-move/wsl-moved-project' -import { isLocalWslMoveRow, wslMoveHostDistro } from './wsl-move-scope-guard' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { Repo } from '../../../../shared/repo-types' +import type { WslMovedProject } from '../../../../shared/wsl-move/wsl-moved-project' +import { isLocalWslMoveRow, wslMoveHostDistro } from '../quiescence/wsl-move-scope-guard' type MovedRepoRow = Pick type MovedFolderRow = Pick< diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-finish.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-finish.ts similarity index 80% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-finish.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-finish.ts index 28be87f3abf..9ac2f669049 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-finish.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-finish.ts @@ -1,8 +1,8 @@ -import type { WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' -import { listWslMoveCutovers } from './wsl-move-cutover-journal' +import type { WslMoveResult } from '../../../../shared/wsl-move/wsl-move-driver-types' +import { listWslMoveCutovers } from '../cutover-recovery/wsl-move-cutover-journal' import type { WslMoveDriverDeps } from './wsl-move-driver-ports' -import { wslMoveAutomationsPending } from './wsl-move-host-automations-rewrite' -import { settleWslMoveWindowWriteHoldForCommit } from './wsl-move-window-write-hold' +import { wslMoveAutomationsPending } from '../desktop-state/wsl-move-host-automations-rewrite' +import { settleWslMoveWindowWriteHoldForCommit } from '../quiescence/wsl-move-window-write-hold' /** A committed move's last step on this desktop, from the driver or a reset that found the commit. */ export async function finishWslMove( diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-journal.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-journal.ts similarity index 84% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-journal.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-journal.ts index ba3b2dca2b7..514b829e384 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-journal.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-journal.ts @@ -2,9 +2,9 @@ * The driver's first durable step: export the slept scope and journal it as `prepared`. Nothing has * reached the host yet, so every failure here is a refusal with its reason, never a put-back. */ -import type { WslMoveRefusal } from '../../../shared/wsl-move/wsl-move-driver-types' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import { journalWslMove } from './wsl-move-delta-plan' +import type { WslMoveRefusal } from '../../../../shared/wsl-move/wsl-move-driver-types' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' +import { journalWslMove } from '../manifest-scope/wsl-move-delta-plan' import type { WslMoveDriverDeps } from './wsl-move-driver-ports' import { exportRequestOf, @@ -13,8 +13,11 @@ import { refusal, type WslMovePrepared } from './wsl-move-driver-plan' -import { resetWslMoveToZero } from './wsl-move-reset' -import { daemonHistoryLeafOf, type WslMoveSleptScrollback } from './wsl-move-slept-scrollback' +import { resetWslMoveToZero } from '../cutover-recovery/wsl-move-reset' +import { + daemonHistoryLeafOf, + type WslMoveSleptScrollback +} from '../terminal-state/wsl-move-slept-scrollback' export async function journalSleptWslMove( deps: Pick, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-pause.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-pause.ts similarity index 86% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-pause.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-pause.ts index 18e11c84a78..04229bfba60 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-pause.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-pause.ts @@ -3,13 +3,13 @@ * again right before it, and the panes it pauses are exactly the ones the gate just passed. A * terminal opened in between refuses the move rather than being slept without its folder. */ -import type { WslMoveRefusal } from '../../../shared/wsl-move/wsl-move-driver-types' +import type { WslMoveRefusal } from '../../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveDriverDeps, WslMoveTerminalScope } from './wsl-move-driver-ports' import { refusal } from './wsl-move-driver-plan' -import type { WslMoveRestoreHintPane } from './wsl-move-restore-hints' -import { assessWslMoveTerminals } from './wsl-move-terminal-gate' -import { withSleptSessionPanes } from './wsl-move-slept-scrollback' -import { sleepUntilPaused } from './wsl-move-quiesce' +import type { WslMoveRestoreHintPane } from '../terminal-state/wsl-move-restore-hints' +import { assessWslMoveTerminals } from '../quiescence/wsl-move-terminal-gate' +import { withSleptSessionPanes } from '../terminal-state/wsl-move-slept-scrollback' +import { sleepUntilPaused } from '../quiescence/wsl-move-quiesce' const sessionsOf = (panes: readonly WslMoveRestoreHintPane[]): string => JSON.stringify(panes.map((pane) => pane.sessionId).sort()) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-plan.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-plan.ts similarity index 89% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-plan.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-plan.ts index 9b4f2c62fd2..d200945fae8 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-plan.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-plan.ts @@ -7,28 +7,30 @@ import { WSL_MOVE_FINISH_PENDING_DETAIL, type WslMoveRefusal, type WslMoveRequest -} from '../../../shared/wsl-move/wsl-move-driver-types' +} from '../../../../shared/wsl-move/wsl-move-driver-types' import { WSL_MOVE_CUTOVER_PHASES, wslMoveJournalKey -} from '../../../shared/wsl-move/wsl-move-cutover' -import { wslHostsAcceptNewWork } from '../../wsl/host-lifecycle/wsl-host-gate' -import { listWslMoveCutoverChain } from './wsl-move-cutover-journal' -import type { WslMovePlan } from './wsl-move-delta-plan' -import { planWslMove } from './wsl-move-delta-plan' -import type { - WslMoveDriverDeps, - WslMoveHost, - WslMoveManifestExport, - WslMoveManifestExportRequest, - WslMoveTerminalScope -} from './wsl-move-driver-ports' -import { assertWslMoveManifestFits } from './wsl-move-manifest-budget' -import { WslMoveScopeChangedError } from './wsl-move-manifest-export' -import { wslMoveHostReadiness } from './wsl-move-preflight' -import { settleWslMoveOwedHostAborts } from './wsl-move-owed-host-aborts' -import { resetWslMoveToZero } from './wsl-move-reset' -import { assessWslMoveTerminals, type WslMoveGateBlocker } from './wsl-move-terminal-gate' +} from '../../../../shared/wsl-move/wsl-move-cutover' +import { wslHostsAcceptNewWork } from '../../../wsl/host-lifecycle/wsl-host-gate' +import { listWslMoveCutoverChain } from '../cutover-recovery/wsl-move-cutover-journal' + +import { type WslMovePlan, planWslMove } from '../manifest-scope/wsl-move-delta-plan' +import type { WslMoveDriverDeps, WslMoveHost, WslMoveTerminalScope } from './wsl-move-driver-ports' + +import { assertWslMoveManifestFits } from '../manifest-scope/wsl-move-manifest-budget' +import { + type WslMoveManifestExport, + type WslMoveManifestExportRequest, + WslMoveScopeChangedError +} from '../manifest-scope/wsl-move-manifest-export' +import { wslMoveHostReadiness } from '../quiescence/wsl-move-preflight' +import { settleWslMoveOwedHostAborts } from '../cutover-recovery/wsl-move-owed-host-aborts' +import { resetWslMoveToZero } from '../cutover-recovery/wsl-move-reset' +import { + assessWslMoveTerminals, + type WslMoveGateBlocker +} from '../quiescence/wsl-move-terminal-gate' export const WSL_MOVE_MANIFEST_TOO_LARGE_PREFIX = 'wsl_move_manifest_too_large:' // Thrown by manifest parsing past the absolute cap, before the journal's own budget can explain. diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-ports.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-ports.ts similarity index 76% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-ports.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-ports.ts index c34b7a4fbfd..75f2be3f07a 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-ports.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-ports.ts @@ -2,36 +2,31 @@ * What the WSL move driver needs from the rest of the app, as ports, so the whole run is testable * with fakes and the production wiring stays in one place (wsl-move-driver-wiring). */ -import type { WslMoveBrowserCookieFreshPartitionReason } from '../../../shared/wsl-move/wsl-move-browser-cookie-copy' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { WslMoveBrowserCookieFreshPartitionReason } from '../../../../shared/wsl-move/wsl-move-browser-cookie-copy' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' import type { OrcadMigrationCatalogState, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import type { WslMoveProgressEvent } from '../../../shared/wsl-move/wsl-move-driver-types' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' +import type { WslMoveProgressEvent } from '../../../../shared/wsl-move/wsl-move-driver-types' import type { OrcadMigrationBlobDestination, OrcadMigrationBlobSource -} from '../../managed-server/migration/transfers/orcad-migration-blob-coordinator' -import type { OrcadMigrationDestinationCatalog } from '../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' -import type { OrcadMigrationSnapshotSource } from '../../managed-server/migration/transfers/orcad-migration-snapshot-coordinator' -import type { WslMoveHostHolding } from './wsl-move-delta-plan' -import type { WslMoveQuiesceDeps } from './wsl-move-quiesce' -import type { WslMoveSleptScrollback } from './wsl-move-slept-scrollback' -import type { WslMoveRestoreHintPane } from './wsl-move-restore-hints' +} from '../../../managed-server/migration/transfers/orcad-migration-blob-coordinator' +import type { OrcadMigrationDestinationCatalog } from '../../../managed-server/migration/cutover/orcad-migration-cutover-coordinator' +import type { OrcadMigrationSnapshotSource } from '../../../managed-server/migration/transfers/orcad-migration-snapshot-coordinator' +import type { WslMoveHostHolding } from '../manifest-scope/wsl-move-delta-plan' +import type { WslMoveQuiesceDeps } from '../quiescence/wsl-move-quiesce' +import type { WslMoveSleptScrollback } from '../terminal-state/wsl-move-slept-scrollback' +import type { WslMoveRestoreHintPane } from '../terminal-state/wsl-move-restore-hints' import type { WslMoveManifestExport, WslMoveManifestExportRequest -} from './wsl-move-manifest-export' -import type { WslMoveGateInputs } from './wsl-move-terminal-gate' - -export type { - WslMoveManifestExport, - WslMoveManifestExportRequest -} from './wsl-move-manifest-export' +} from '../manifest-scope/wsl-move-manifest-export' +import type { WslMoveGateInputs } from '../quiescence/wsl-move-terminal-gate' /** Throws `WslMoveScopeChangedError` when a planned row is gone: plan again. */ export type WslMoveManifestExporter = ( diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-preview.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-preview.ts similarity index 86% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-preview.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-preview.ts index f7c6b3c8045..e375a751c43 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-preview.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-preview.ts @@ -1,9 +1,16 @@ /** What a move of the distro would take, before anything is journaled. */ -import type { WslMovePreview, WslMoveRequest } from '../../../shared/wsl-move/wsl-move-driver-types' +import type { + WslMovePreview, + WslMoveRequest +} from '../../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveDriverDeps } from './wsl-move-driver-ports' import { prepareWslMove, refusal, type WslMoveInterruptedSettle } from './wsl-move-driver-plan' -import { claimWslMoveRun, releaseWslMoveRun, wslMoveClaimRefusal } from './wsl-move-running-moves' -import { unreadableSleptHistory } from './wsl-move-slept-scrollback' +import { + claimWslMoveRun, + releaseWslMoveRun, + wslMoveClaimRefusal +} from '../orchestration/wsl-move-running-moves' +import { unreadableSleptHistory } from '../terminal-state/wsl-move-slept-scrollback' export async function previewWslMove( deps: WslMoveDriverDeps, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-run-end.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-run-end.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-run-end.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-run-end.ts index 821bd3fcee5..1311ba99ee5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-run-end.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-run-end.ts @@ -6,7 +6,7 @@ import type { WslMoveProgressStep, WslMoveResult -} from '../../../shared/wsl-move/wsl-move-driver-types' +} from '../../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveDriverDeps } from './wsl-move-driver-ports' export async function reportWslMoveRunEnd( diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-transfer.ts b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-transfer.ts similarity index 82% rename from src/main/persistence/moving-wsl-projects/wsl-move-driver-transfer.ts rename to src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-transfer.ts index 28de35a3b9a..b00846db9bb 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-transfer.ts +++ b/src/main/persistence/moving-wsl-projects/execution/wsl-move-driver-transfer.ts @@ -3,22 +3,26 @@ * the scrollback snapshots and blobs, then ask for the commit. Each step is journaled before the * next starts, and the commit is requested only from `blobs-transferred` (#29825's contract). */ -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationCatalogState } from '../../../shared/orcad-migration/orcad-migration-manifest' -import type { WslMoveCutover, WslMoveCutoverPhase } from '../../../shared/wsl-move/wsl-move-cutover' +import type { OrcadMigrationBlobDescriptor } from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationCatalogState } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import type { + WslMoveCutover, + WslMoveCutoverPhase +} from '../../../../shared/wsl-move/wsl-move-cutover' import { transferOrcadMigrationBlobs, type OrcadMigrationBlobSource -} from '../../managed-server/migration/transfers/orcad-migration-blob-coordinator' -import { resolveDurableOrcadCatalogMutation } from '../../managed-server/migration/cutover/orcad-catalog-durable-mutation' -import { transferOrcadMigrationSnapshots } from '../../managed-server/migration/transfers/orcad-migration-snapshot-coordinator' -import { writeWslMoveCutover } from './wsl-move-cutover-journal' -import type { WslMoveDriverDeps, WslMoveHost, WslMoveManifestExport } from './wsl-move-driver-ports' -import { assertWslMoveCommitRequestAllowed } from './wsl-move-reset' +} from '../../../managed-server/migration/transfers/orcad-migration-blob-coordinator' +import { resolveDurableOrcadCatalogMutation } from '../../../managed-server/migration/cutover/orcad-catalog-durable-mutation' +import { transferOrcadMigrationSnapshots } from '../../../managed-server/migration/transfers/orcad-migration-snapshot-coordinator' +import { writeWslMoveCutover } from '../cutover-recovery/wsl-move-cutover-journal' +import type { WslMoveDriverDeps, WslMoveHost } from './wsl-move-driver-ports' +import type { WslMoveManifestExport } from '../manifest-scope/wsl-move-manifest-export' +import { assertWslMoveCommitRequestAllowed } from '../cutover-recovery/wsl-move-reset' import { wslMoveTerminalHistoryBlobs, type WslMoveSleptScrollback -} from './wsl-move-slept-scrollback' +} from '../terminal-state/wsl-move-slept-scrollback' type TransferDeps = Pick diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-canonical-form.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-canonical-form.ts similarity index 100% rename from src/main/persistence/moving-wsl-projects/wsl-move-canonical-form.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-canonical-form.ts diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-comparable-path.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-comparable-path.ts similarity index 87% rename from src/main/persistence/moving-wsl-projects/wsl-move-comparable-path.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-comparable-path.ts index 9fa52062133..3c3fca1fd0f 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-comparable-path.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-comparable-path.ts @@ -2,7 +2,10 @@ * One spelling for a WSL folder across UNC aliases (`wsl$`, `wsl.localhost`), distro case, Linux * spelling and trailing separators, so the exit proof and the spawn fence agree on what is in scope. */ -import { foldWslUncPathCaseInsensitiveParts, toWindowsWslUncPath } from '../../../shared/wsl-paths' +import { + foldWslUncPathCaseInsensitiveParts, + toWindowsWslUncPath +} from '../../../../shared/wsl-paths' /** Null for a path that is not in a WSL distro (a Windows drive path, say). */ export function comparableWslPath(path: string, distro: string): string | null { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-compatibility-aliases.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-compatibility-aliases.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-compatibility-aliases.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-compatibility-aliases.ts index 9e8333bcbf9..521fb0b14e2 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-compatibility-aliases.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-compatibility-aliases.ts @@ -1,4 +1,4 @@ -import type { WorktreeMeta } from '../../../shared/worktree/meta-types' +import type { WorktreeMeta } from '../../../../shared/worktree/meta-types' import { createWslMoveStringNormalizer } from './wsl-move-canonical-form' import type { WslMoveProjectionScope } from './wsl-move-state-projection' diff --git a/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.test.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.test.ts new file mode 100644 index 00000000000..1f9c06ee60a --- /dev/null +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.test.ts @@ -0,0 +1,68 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { Repo } from '../../../../shared/repo-types' +import { computeOrcadMigrationManifestSha256 } from '../../../orcad/orcad-migration-manifest-digest' +import { wslMoveCutoverFixture } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' + +import { journalWslMove, planWslMove, type WslMovePlan } from './wsl-move-delta-plan' + +const UNC = '\\\\wsl.localhost\\Ubuntu' +const repo = (id: string, extra: Partial = {}): Repo => ({ + id, + path: `${UNC}\\home\\dev\\${id}`, + displayName: id, + badgeColor: '#000', + addedAt: 0, + ...extra +}) + +const NO_HOST = { repoIds: [], folderWorkspaceIds: [], highestGeneration: 0 } + +let dir: string +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), 'wsl-move-delta-plan-')) +}) +afterEach(() => { + rmSync(dir, { recursive: true, force: true }) +}) + +function state(repos: Repo[], folderWorkspaces: FolderWorkspace[] = []) { + return { repos, folderWorkspaces, projectGroups: [] } +} + +/** The fixture's manifest for a scope and generation, re-signed. */ +function moveFor(migrationId: string, plan: Pick) { + const base = wslMoveCutoverFixture(migrationId, 'prepared', {}, { repoIds: plan.repoIds }) + const { manifestSha256: _unsigned, ...unsigned } = base.manifest + const resigned = { + ...unsigned, + source: { ...unsigned.source, generation: plan.generation } + } + return { ...resigned, manifestSha256: computeOrcadMigrationManifestSha256(resigned) } +} + +/** A finished move of `repoIds`, as a journal record. */ + +function ready(result: ReturnType): WslMovePlan { + if (result.outcome !== 'ready') { + throw new Error(result.code) + } + return result.plan +} + +describe('planWslMove', () => { + it('refuses a manifest whose scope doubles an id', () => { + const plan = ready(planWslMove(dir, state([repo('repo-a'), repo('repo-b')]), 'Ubuntu', NO_HOST)) + expect(() => + journalWslMove({ + userDataPath: dir, + plan: { ...plan, repoIds: ['repo-a', 'repo-a'] }, + manifest: moveFor('move-1', plan), + destinationName: 'Ubuntu' + }) + ).toThrow('wsl_move_manifest_not_planned') + }) +}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.ts index a758a5d874e..0e267347ff2 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-delta-plan.ts @@ -9,32 +9,32 @@ * retained row (as SSH's delta does; see `planOrcadDeltaMove`). The same goes for a project the * host still holds after its move was dropped from the journal. */ -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { isOrcadMigrationLocalWslSource } from '../../../shared/orcad-migration/orcad-migration-source-kind' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { isOrcadMigrationLocalWslSource } from '../../../../shared/orcad-migration/orcad-migration-source-kind' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' import { WSL_MOVE_CUTOVER_PHASES, WSL_MOVE_CUTOVER_VERSION, isWslMoveCutoverFinished, wslMoveJournalKey, type WslMoveCutover -} from '../../../shared/wsl-move/wsl-move-cutover' +} from '../../../../shared/wsl-move/wsl-move-cutover' import { listWslMoveCutoverChain, scanWslMoveCutovers, writeWslMoveCutover -} from './wsl-move-cutover-journal' +} from '../cutover-recovery/wsl-move-cutover-journal' import { wslMoveLocalRowIdentity, wslMoveRowKey, wslMoveScopeRefs, wslMoveTakenRowIdentity, type WslMoveRowRef -} from './wsl-move-retained-source' +} from '../cutover-recovery/wsl-move-retained-source' import { collectWslMoveScope, type WslMoveScope } from './wsl-move-scope' -import { isLocalWslMoveRow } from './wsl-move-scope-guard' +import { isLocalWslMoveRow } from '../quiescence/wsl-move-scope-guard' type WslMovePlanState = { repos: readonly Repo[] diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-budget.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-budget.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-manifest-budget.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-budget.ts index 422a6501737..a04235f3e43 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-budget.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-budget.ts @@ -3,8 +3,8 @@ * abort carries it whole, and a reset that cannot carry it can only ask the host by identity. * Capping it when the move is recorded keeps new moves out of that gap entirely. */ -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { ORCAD_MIGRATION_REQUEST_PARAMS_BUDGET_BYTES } from '../../managed-server/migration/catalog/orcad-migration-request-budget' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { ORCAD_MIGRATION_REQUEST_PARAMS_BUDGET_BYTES } from '../../../managed-server/migration/catalog/orcad-migration-request-budget' // Headroom for a host whose request limit is a little lower than this build's. const WSL_MOVE_MANIFEST_MARGIN_BYTES = 16 * 1024 diff --git a/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.test.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.test.ts new file mode 100644 index 00000000000..f53e0fc1c62 --- /dev/null +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.test.ts @@ -0,0 +1,165 @@ +import { describe, expect, it } from 'vitest' +import { getDefaultPersistedState, getDefaultWorkspaceSession } from '../../../../shared/constants' + +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { Repo } from '../../../../shared/repo-types' +import type { TerminalTab } from '../../../../shared/workspace-layout/terminal-tab-types' + +import { + DORMANT_AUTOMATION, + DORMANT_AUTOMATION_RUN +} from '../../migrating-orcad-catalog/catalog-commit/persistence-orcad-migration-catalog-fixture' + +import { collectOrcadMigrationSourceDormantState } from '../../migrating-orcad-catalog/source/dormancy/orcad-source-dormant-state' +import { + exportWslMoveManifest, + WslMoveScopeChangedError, + type WslMoveManifestExportRequest, + type WslMoveManifestExportStore +} from './wsl-move-manifest-export' + +const DISTRO = 'Ubuntu' +const UNC_REPO = '\\\\wsl.localhost\\Ubuntu\\home\\me\\app' +const UNC_WORKTREE = '\\\\wsl.localhost\\Ubuntu\\home\\me\\app-feature' +const WORKTREE = `app::${UNC_WORKTREE}` +const OTHER_WORKTREE = 'win::C:\\code\\win' + +function repo(id: string, path: string, extra: Partial = {}): Repo { + return { id, path, displayName: id, badgeColor: '#737373', addedAt: 1, ...extra } +} + +function tab(id: string, worktreeId: string): TerminalTab { + return { + id, + ptyId: null, + worktreeId, + title: id, + customTitle: null, + color: null, + sortOrder: 0, + createdAt: 1, + startupCwd: worktreeId.split('::')[1] + } +} + +function sourceState(): PersistedState { + const state = getDefaultPersistedState('C:\\Users\\me') + state.repos = [ + repo('app', UNC_REPO), + repo('win', 'C:\\code\\win'), + repo('elsewhere', '\\\\wsl.localhost\\Debian\\home\\me\\other') + ] + state.worktreeMeta[WORKTREE] = { + displayName: 'Feature', + comment: 'keep', + isUnread: false, + linkedIssue: null, + linkedPR: null, + linkedLinearIssue: null, + isArchived: false, + isPinned: true, + sortOrder: 1, + lastActivityAt: 2 + } + state.worktreeMeta[OTHER_WORKTREE] = { ...state.worktreeMeta[WORKTREE], displayName: 'Windows' } + state.automations = [ + { + ...DORMANT_AUTOMATION, + id: 'automation-app', + enabled: true, + projectId: 'app', + runContext: { + ...DORMANT_AUTOMATION.runContext!, + repoId: 'app', + projectHostSetupId: 'app', + path: UNC_REPO + }, + executionTargetType: 'local', + executionTargetId: 'local', + schedulerOwner: 'local_host_service' + }, + { + ...DORMANT_AUTOMATION, + id: 'automation-win', + enabled: true, + projectId: 'win', + runContext: { + ...DORMANT_AUTOMATION.runContext!, + repoId: 'win', + projectHostSetupId: 'win', + path: 'C:\\code\\win' + }, + executionTargetType: 'local', + executionTargetId: 'local', + schedulerOwner: 'local_host_service' + } + ] + state.automationRuns = [ + { + ...DORMANT_AUTOMATION_RUN, + automationId: 'automation-app', + runContext: state.automations[0]!.runContext + } + ] + state.workspaceSession = { + ...getDefaultWorkspaceSession(), + tabsByWorktree: { + [WORKTREE]: [tab('feature-shell', WORKTREE)], + [OTHER_WORKTREE]: [tab('windows-shell', OTHER_WORKTREE)] + } + } + return state +} + +function storeFor(state: PersistedState): WslMoveManifestExportStore { + return { + getRepos: () => state.repos, + getFolderWorkspaces: () => state.folderWorkspaces, + getProjectGroups: () => state.projectGroups, + inspectOrcadMigrationSourceDormantState: (source, catalog, destination) => + collectOrcadMigrationSourceDormantState(state, source, catalog, undefined, destination) + } +} + +const REQUEST: WslMoveManifestExportRequest = { + migrationId: 'move-1', + now: () => new Date('2026-10-20T00:00:00.000Z'), + distro: DISTRO, + distroGuid: '{guid}', + destinationEnvironmentId: 'wsl:Ubuntu', + generation: 2, + repoIds: ['app'], + folderWorkspaceIds: [] +} + +describe('exportWslMoveManifest', () => { + it('carries no desktop PTY binding, so the moved pane reads its history from the host', () => { + // The host's session kept the desktop's PTY ids, so the client took each pane + // for a live terminal, skipped the scrollback read, and opened a fresh prompt. + const state = sourceState() + const leaf = '11111111-1111-4111-8111-111111111111' + const tab = state.workspaceSession.tabsByWorktree[WORKTREE]![0]! + state.workspaceSession.tabsByWorktree[WORKTREE] = [{ ...tab, ptyId: `${WORKTREE}@@81c7100a` }] + state.workspaceSession.terminalLayoutsByTabId = { + [tab.id]: { + root: { type: 'leaf', leafId: leaf }, + activeLeafId: leaf, + expandedLeafId: null, + ptyIdsByLeafId: { [leaf]: `${WORKTREE}@@81c7100a` }, + buffersByLeafId: { [leaf]: 'history' } + } + } + const { manifest } = exportWslMoveManifest(storeFor(state), REQUEST) + const session = manifest.payload.dormantState?.workspaceSession + const layout = Object.values(session?.terminalLayoutsByTabId ?? {})[0] + expect(layout?.scrollbackRefsByLeafId?.[leaf]).toBeTruthy() + expect(layout).not.toHaveProperty('ptyIdsByLeafId') + expect(Object.values(session?.tabsByWorktree ?? {}).flat()[0]?.ptyId).toBeNull() + }) + + it('refuses to sign a scope naming a project that is no longer here', () => { + expect(() => + exportWslMoveManifest(storeFor(sourceState()), { ...REQUEST, repoIds: ['app', 'gone'] }) + ).toThrow(WslMoveScopeChangedError) + }) +}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.ts index e281aca3eff..f8a96420334 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-manifest-export.ts @@ -6,35 +6,35 @@ * refuses instead of dropping a row. Deterministic for one store state and request, so the driver can * re-export under the fence and compare digests. */ -import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { resolveFolderWorkspaceHost } from '../../../shared/folder-workspaces/folder-workspace-execution-host' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' +import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import { resolveFolderWorkspaceHost } from '../../../../shared/folder-workspaces/folder-workspace-execution-host' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' import type { OrcadMigrationCatalogPayload, OrcadMigrationLocalWslManifestSource, OrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest' +} from '../../../../shared/orcad-migration/orcad-migration-manifest' import { ORCAD_MIGRATION_MANIFEST_VERSION, parseOrcadMigrationManifest -} from '../../../shared/orcad-migration/orcad-migration-manifest-validation' -import { withoutOrcadRetainedMarker } from '../../../shared/orcad-retained-marker' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' -import { parseWorkspaceKey } from '../../../shared/workspace-scope' -import { getRepoIdFromWorktreeId, getRepoMainWorktreeId } from '../../../shared/worktree/id' -import { computeOrcadMigrationManifestSha256 } from '../../orcad/orcad-migration-manifest-digest' -import { hasDormantState } from '../migrating-orcad-catalog/orcad-migration-dormant-state' +} from '../../../../shared/orcad-migration/orcad-migration-manifest-validation' +import { withoutOrcadRetainedMarker } from '../../../../shared/orcad-retained-marker' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' +import { parseWorkspaceKey } from '../../../../shared/workspace-scope' +import { getRepoIdFromWorktreeId, getRepoMainWorktreeId } from '../../../../shared/worktree/id' +import { computeOrcadMigrationManifestSha256 } from '../../../orcad/orcad-migration-manifest-digest' +import { hasDormantState } from '../../migrating-orcad-catalog/source/dormancy/orcad-migration-dormant-state' import { rewriteOrcadMigrationPayloadPaths, rewriteOrcadMigrationWorktreeId -} from '../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' -import type { Store } from '../loading-store/store' -import { compareKeys } from '../migrating-orcad-catalog/orcad-source-key-order' -import { wslUncPathToLinux } from '../../../shared/wsl-paths' +} from '../../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' +import type { Store } from '../../loading-store/store' +import { compareKeys } from '../../migrating-orcad-catalog/source/catalog/orcad-source-key-order' +import { wslUncPathToLinux } from '../../../../shared/wsl-paths' import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' -import { withoutWindowsShellChoices } from './wsl-move-windows-shell-choices' -import { withoutDesktopFocus, withoutPtyBindings } from './wsl-move-session-rewrite' +import { withoutWindowsShellChoices } from '../desktop-state/wsl-move-windows-shell-choices' +import { withoutDesktopFocus, withoutPtyBindings } from '../terminal-state/wsl-move-session-rewrite' export type WslMoveManifestExportRequest = { migrationId: string diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-path-rewriter.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-path-rewriter.ts similarity index 87% rename from src/main/persistence/moving-wsl-projects/wsl-move-path-rewriter.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-path-rewriter.ts index b069283ba1f..9ab4d91e819 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-path-rewriter.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-path-rewriter.ts @@ -1,6 +1,6 @@ // Convert only the moved distro's UNC paths; unrelated paths remain unchanged. -import { wslUncPathToLinux } from '../../../shared/wsl-paths' -import type { OrcadMigrationPathRewriter } from '../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' +import { wslUncPathToLinux } from '../../../../shared/wsl-paths' +import type { OrcadMigrationPathRewriter } from '../../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' export function createUncToLinuxPathRewriter(distro: string): OrcadMigrationPathRewriter { const fileUrl = new RegExp(`^file://(?:wsl\\.localhost|wsl\\$)/([^/]+)(/.*)?$`, 'i') diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-scope-roots.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope-roots.ts similarity index 85% rename from src/main/persistence/moving-wsl-projects/wsl-move-scope-roots.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope-roots.ts index aecbb39979d..9d28dea2e2e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-scope-roots.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope-roots.ts @@ -3,9 +3,9 @@ * repo and folder, and every worktree the move carried meta, lineage or a session for. A store * keyed by a bare file path uses them to tell a moved project's file from another in the distro. */ -import type { OrcadMigrationManifest } from '../../../shared/orcad-migration/orcad-migration-manifest' -import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../shared/workspace-scope' -import { splitWorktreeIdForFilesystem } from '../../../shared/worktree/id' +import type { OrcadMigrationManifest } from '../../../../shared/orcad-migration/orcad-migration-manifest' +import { normalizeWorkspaceSessionKeyToWorkspaceId } from '../../../../shared/workspace-scope' +import { splitWorktreeIdForFilesystem } from '../../../../shared/worktree/id' export function wslMoveScopeRootPaths(manifest: Pick): string[] { const { payload } = manifest diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-scope.test.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.test.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-scope.test.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.test.ts index 00bb62212b8..7e97fa7acfa 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-scope.test.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { Repo } from '../../../shared/repo-types' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { Repo } from '../../../../shared/repo-types' import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' import { collectWslMoveScope } from './wsl-move-scope' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-scope.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-scope.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.ts index 492b52f45ad..921a6928537 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-scope.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-scope.ts @@ -1,15 +1,15 @@ // Move local repos/folders only when every path stays in one distro outside Windows drive mounts. import { posix } from 'node:path' -import { getRepoExecutionHostId } from '../../../shared/execution-host' -import { resolveFolderWorkspaceHost } from '../../../shared/folder-workspaces/folder-workspace-execution-host' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import type { Repo } from '../../../shared/repo-types' +import { getRepoExecutionHostId } from '../../../../shared/execution-host' +import { resolveFolderWorkspaceHost } from '../../../../shared/folder-workspaces/folder-workspace-execution-host' +import type { FolderWorkspace } from '../../../../shared/folder-workspaces/folder-workspace-types' +import type { ProjectGroup } from '../../../../shared/project-group-types' +import type { Repo } from '../../../../shared/repo-types' import { isDrvfsLinuxPath, resolveWslRepoWorktreeBasePath, wslUncPathToLinux -} from '../../../shared/wsl-paths' +} from '../../../../shared/wsl-paths' export type WslMoveScopeRefusal = /** Distro access does not make Windows-drive projects Linux-owned. */ diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-state-projection.ts b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-state-projection.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-state-projection.ts rename to src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-state-projection.ts index 7c0c9fea3c4..38f4eb2825f 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-state-projection.ts +++ b/src/main/persistence/moving-wsl-projects/manifest-scope/wsl-move-state-projection.ts @@ -1,33 +1,33 @@ // Compare stores independently of mover export so omitted rows remain visible after host/path normalization. -import { getAutomationRunRepoId } from '../../../shared/automations/history/automation-run-identity' -import { getRepoExecutionHostId, type ExecutionHostId } from '../../../shared/execution-host' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { PersistedUIState } from '../../../shared/persisted-ui-state-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +import { getAutomationRunRepoId } from '../../../../shared/automations/history/automation-run-identity' +import { getRepoExecutionHostId, type ExecutionHostId } from '../../../../shared/execution-host' +import type { PersistedState } from '../../../../shared/persisted-state-types' +import type { PersistedUIState } from '../../../../shared/persisted-ui-state-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' import { normalizeWorkspaceSessionKeyToWorkspaceId, parseWorkspaceKey -} from '../../../shared/workspace-scope' +} from '../../../../shared/workspace-scope' import { getExecutionHostIdFromWorktreeHostIdentity, isWorktreeHostIdentity -} from '../../../shared/worktree/host-qualified-identity' -import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id' -import { getAllWorktreeMetaForHost } from '../loading-store/worktree-metadata/worktree-identity-metadata' -import { collectProjectGroups } from '../migrating-orcad-catalog/orcad-source-catalog' +} from '../../../../shared/worktree/host-qualified-identity' +import { getRepoIdFromWorktreeId } from '../../../../shared/worktree/id' +import { getAllWorktreeMetaForHost } from '../../loading-store/worktree-metadata/worktree-identity-metadata' +import { collectProjectGroups } from '../../migrating-orcad-catalog/source/catalog/orcad-source-catalog' import { canonicalizeWslMoveValue, createWslMoveStringNormalizer, isRecord } from './wsl-move-canonical-form' -import { WSL_MOVE_DROPPED_PTY_BINDING_KEYS } from '../../../shared/wsl-move/wsl-move-dispositions' +import { WSL_MOVE_DROPPED_PTY_BINDING_KEYS } from '../../../../shared/wsl-move/wsl-move-dispositions' import { fieldOf, pickKeys, projectWslMoveSession, projectWslMoveUi, type WslMoveOwnerInScope -} from './wsl-move-session-projection' +} from '../terminal-state/wsl-move-session-projection' export type WslMoveProjectionScope = { distro: string diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-background-backoff.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-background-backoff.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff.ts index 7d9f1f9cdab..fb3609a1763 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-background-backoff.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff.ts @@ -1,13 +1,13 @@ // Background writers retry naturally; quietly defer moving/moved local rows using host and path evidence. -import { getRepoExecutionHostId } from '../../../shared/execution-host' -import { splitWorktreeIdForFilesystem } from '../../../shared/worktree/id' +import { getRepoExecutionHostId } from '../../../../shared/execution-host' +import { splitWorktreeIdForFilesystem } from '../../../../shared/worktree/id' import { isLocalWslMoveRow, isWslMoveProjectBlocked, isWslMoveProjectFenced, isWslMoveSourceHost, wslMoveProjectRefForWorkspace -} from './wsl-move-scope-guard' +} from '../quiescence/wsl-move-scope-guard' type HostedRow = { connectionId?: string | null; executionHostId?: string | null } diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-external-transitions.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-external-transitions.ts similarity index 98% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-external-transitions.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-external-transitions.ts index ab1ef686571..f340dbb21a7 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-external-transitions.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-external-transitions.ts @@ -6,7 +6,7 @@ import type { WslMoveOrchestratorDeclineCause, WslMoveOrchestratorRecord, WslMoveOrchestratorUserAction -} from '../../../shared/wsl-move/wsl-move-orchestrator-types' +} from '../../../../shared/wsl-move/wsl-move-orchestrator-types' import { WSL_MOVE_ORCHESTRATOR_NOT_NOW_MS, withWslMoveOrchestratorState diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-park.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-park.ts similarity index 86% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-park.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-park.ts index b912d8f66f5..2543906f213 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-park.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-park.ts @@ -1,5 +1,5 @@ /** Which parked distros a trigger other than the user's may move again. */ -import type { WslMoveOrchestratorState } from '../../../shared/wsl-move/wsl-move-orchestrator-types' +import type { WslMoveOrchestratorState } from '../../../../shared/wsl-move/wsl-move-orchestrator-types' export function parkedMayStart( state: Extract, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-ports.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-ports.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-ports.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-ports.ts index e5a9a45faf2..cfcd3e6f3ba 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-ports.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-ports.ts @@ -1,10 +1,13 @@ /** What the move orchestrator (D3a) reads and drives, so tests and production share one shape. */ -import type { WslMovePreview, WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' -import type { WslMoveUseLocallyResult } from '../../../shared/wsl-move/wsl-moved-project' +import type { + WslMovePreview, + WslMoveResult +} from '../../../../shared/wsl-move/wsl-move-driver-types' +import type { WslMoveUseLocallyResult } from '../../../../shared/wsl-move/wsl-moved-project' import type { WslMoveOrchestratorRecord, WslMoveOrchestratorTrigger -} from '../../../shared/wsl-move/wsl-move-orchestrator-types' +} from '../../../../shared/wsl-move/wsl-move-orchestrator-types' import type { WslMovedDistroVerdict } from './wsl-move-orchestrator-external-transitions' export type WslMoveHostReadiness = 'ready' | 'not-running' | 'unverifiable' | 'failed' diff --git a/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-stage1.test.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-stage1.test.ts new file mode 100644 index 00000000000..292d937d38a --- /dev/null +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-stage1.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'vitest' + +import { wslMoveAutoMovesBridgeProjects } from '../../../../shared/wsl-move/wsl-move-rollout-stage' +import { WslMoveOrchestrator } from '../wsl-move-orchestrator' +import { fakePorts } from './wsl-move-orchestrator.test-support' + +// Stage 1 (B3): the WSL hosts setting governs new projects; the user's bridge projects never move on their own. +describe('the move orchestrator in Stage 1', () => { + const stage1 = () => fakePorts({ autoMovesBridgeProjects: wslMoveAutoMovesBridgeProjects }) + + it('still moves when the user asks (their own Retry)', async () => { + const ports = stage1() + const orchestrator = new WslMoveOrchestrator(ports) + await orchestrator.trigger('Ubuntu', 'user') + expect(ports.start).toHaveBeenCalledOnce() + }) +}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-step.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-step.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-step.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-step.ts index 4e6808fba4d..c0808d90b7c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-step.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-step.ts @@ -3,11 +3,14 @@ * preview and, when it is clear, the move. Every wait re-reads the record, so a choice the user * made meanwhile (a release, Not now) wins over the step's stale view. */ -import type { WslMovePreview, WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' +import type { + WslMovePreview, + WslMoveResult +} from '../../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveOrchestratorRecord, WslMoveOrchestratorTrigger -} from '../../../shared/wsl-move/wsl-move-orchestrator-types' +} from '../../../../shared/wsl-move/wsl-move-orchestrator-types' import { applyWslMovedDistroVerdict, applyWslMoveHostRemovalPending, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-store.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-store.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-store.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-store.ts index 5931a5580d2..79058ea5262 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-store.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-store.ts @@ -6,9 +6,9 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' import { z } from 'zod' -import { writeDurableSecureJsonFile } from '../../../shared/secure-storage/secure-file' -import { wslMoveJournalKey } from '../../../shared/wsl-move/wsl-move-cutover' -import type { WslMoveOrchestratorRecord } from '../../../shared/wsl-move/wsl-move-orchestrator-types' +import { writeDurableSecureJsonFile } from '../../../../shared/secure-storage/secure-file' +import { wslMoveJournalKey } from '../../../../shared/wsl-move/wsl-move-cutover' +import type { WslMoveOrchestratorRecord } from '../../../../shared/wsl-move/wsl-move-orchestrator-types' const FILE_NAME = 'wsl-move-orchestrator.json' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-transitions.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-transitions.ts similarity index 98% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-transitions.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-transitions.ts index 3ec2f991ea2..38e7206f77b 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-transitions.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-transitions.ts @@ -7,13 +7,13 @@ import { type WslMovePreview, type WslMoveRefusalCode, type WslMoveResult -} from '../../../shared/wsl-move/wsl-move-driver-types' +} from '../../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveOrchestratorParkReason, WslMoveOrchestratorRecord, WslMoveOrchestratorState, WslMoveOrchestratorTrigger -} from '../../../shared/wsl-move/wsl-move-orchestrator-types' +} from '../../../../shared/wsl-move/wsl-move-orchestrator-types' import { parkedMayStart } from './wsl-move-orchestrator-park' /** Delay after failed automatic attempt n; the attempt after the last delay parks if it fails. */ diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-user-choices.test.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-user-choices.test.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-user-choices.test.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-user-choices.test.ts index 71aa71d8495..8760eae6d5c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-user-choices.test.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator-user-choices.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest' -import type { WslMovePreview } from '../../../shared/wsl-move/wsl-move-driver-types' -import { WslMoveOrchestrator } from './wsl-move-orchestrator' +import type { WslMovePreview } from '../../../../shared/wsl-move/wsl-move-driver-types' +import { WslMoveOrchestrator } from '../wsl-move-orchestrator' import { fakePorts, ready, stateOf } from './wsl-move-orchestrator.test-support' // The orchestrator under the user's own choices and the reviews' race and failure cases. diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test-support.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator.test-support.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test-support.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator.test-support.ts index 450649dd4e7..6d84c78b0a5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test-support.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-orchestrator.test-support.ts @@ -4,9 +4,9 @@ import type { WslMoveBlocker, WslMovePreview, WslMoveResult -} from '../../../shared/wsl-move/wsl-move-driver-types' -import type { WslMoveOrchestratorRecord } from '../../../shared/wsl-move/wsl-move-orchestrator-types' -import type { WslMoveOrchestrator } from './wsl-move-orchestrator' +} from '../../../../shared/wsl-move/wsl-move-driver-types' +import type { WslMoveOrchestratorRecord } from '../../../../shared/wsl-move/wsl-move-orchestrator-types' +import type { WslMoveOrchestrator } from '../wsl-move-orchestrator' import type { WslMoveOrchestratorPorts } from './wsl-move-orchestrator-ports' export const blocker: WslMoveBlocker = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-running-moves.ts b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-running-moves.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-running-moves.ts rename to src/main/persistence/moving-wsl-projects/orchestration/wsl-move-running-moves.ts index 7b34da33c78..e682af790be 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-running-moves.ts +++ b/src/main/persistence/moving-wsl-projects/orchestration/wsl-move-running-moves.ts @@ -5,8 +5,8 @@ import { isWslMoveCutoverFinished, wslMoveJournalKey -} from '../../../shared/wsl-move/wsl-move-cutover' -import { scanWslMoveCutovers } from './wsl-move-cutover-journal' +} from '../../../../shared/wsl-move/wsl-move-cutover' +import { scanWslMoveCutovers } from '../cutover-recovery/wsl-move-cutover-journal' export type RunningWslMove = { controller: AbortController diff --git a/src/main/persistence/moving-wsl-projects/wsl-approved-root-race.wsl.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-approved-root-race.wsl.test.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-approved-root-race.wsl.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-approved-root-race.wsl.test.ts index 26c9a567a5f..2c863b8a4ad 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-approved-root-race.wsl.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-approved-root-race.wsl.test.ts @@ -1,8 +1,8 @@ import { execFile } from 'node:child_process' import { promisify } from 'node:util' import { afterAll, beforeAll, describe, expect, it } from 'vitest' -import { containedDeleteCommand } from '../../wsl/filesystem/wsl-contained-delete' -import { parseWslPath } from '../../wsl/filesystem/unc-path-access' +import { containedDeleteCommand } from '../../../wsl/filesystem/wsl-contained-delete' +import { parseWslPath } from '../../../wsl/filesystem/unc-path-access' const execFileAsync = promisify(execFile) const DISTRO = process.env.ORCA_WSL_TEST_DISTRO ?? 'Ubuntu-24.04' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-distro-in-use.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-distro-in-use.ts similarity index 79% rename from src/main/persistence/moving-wsl-projects/wsl-move-distro-in-use.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-distro-in-use.ts index 3abd178bb1e..eb2f39d941a 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-distro-in-use.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-distro-in-use.ts @@ -1,10 +1,10 @@ /** Whether the move orchestrator still has a reason to keep a distro's record (D3a-2 pruning). */ -import { readWslHostDeployments } from '../../../shared/remote-runtime/host-store/wsl-host-deployment-store' -import { wslMoveJournalKey } from '../../../shared/wsl-move/wsl-move-cutover' -import { parseWslUncPath } from '../../../shared/wsl-paths' -import type { Store } from '../loading-store/store' +import { readWslHostDeployments } from '../../../../shared/remote-runtime/host-store/wsl-host-deployment-store' +import { wslMoveJournalKey } from '../../../../shared/wsl-move/wsl-move-cutover' +import { parseWslUncPath } from '../../../../shared/wsl-paths' +import type { Store } from '../../loading-store/store' import { isLocalWslMoveRow, wslMoveHostDistro } from './wsl-move-scope-guard' -import { defaultWslOrcadEnvironmentId } from '../../wsl/orcad/wsl-orcad-deploy' +import { defaultWslOrcadEnvironmentId } from '../../../wsl/orcad/wsl-orcad-deploy' /** * A bridge project of the distro (local, on its UNC path, not moved) or its WSL host record. A diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.test.ts similarity index 98% rename from src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.test.ts index 2b887b98b02..f8039ea0b0a 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi } from 'vitest' -import type { SessionInfo } from '../../daemon/protocol/daemon-session-info' +import type { SessionInfo } from '../../../daemon/protocol/daemon-session-info' import { proveWslMoveTerminalsExited } from './wsl-move-exit-proof' type CensusSession = Pick & diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.ts index a2233745559..201b7914ac1 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-exit-proof.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-exit-proof.ts @@ -2,9 +2,13 @@ import { parsePtySessionId, WORKTREE_ID_SEPARATOR -} from '../../../shared/terminal/pty/lifecycle/pty-session-id-format' -import { comparableWslPath, isAtOrUnder, isLinuxSpelled } from './wsl-move-comparable-path' -import type { SessionInfo } from '../../daemon/protocol/daemon-session-info' +} from '../../../../shared/terminal/pty/lifecycle/pty-session-id-format' +import { + comparableWslPath, + isAtOrUnder, + isLinuxSpelled +} from '../manifest-scope/wsl-move-comparable-path' +import type { SessionInfo } from '../../../daemon/protocol/daemon-session-info' export type WslMoveExitProof = | { verdict: 'exited' } diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-fence.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-fence.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-fence.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-fence.ts index b95f86de45d..fcb77333e37 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-fence.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-fence.ts @@ -1,13 +1,17 @@ // Journal-backed fences survive older builds rewriting the profile; freeze quiesced sessions for downgrade. -import type { WslMoveCutover, WslMoveCutoverPhase } from '../../../shared/wsl-move/wsl-move-cutover' -import { WSL_MOVE_CUTOVER_PHASES } from '../../../shared/wsl-move/wsl-move-cutover' -import { scanWslMoveCutovers } from './wsl-move-cutover-journal' -import { comparableWslPath } from './wsl-move-comparable-path' -import { wslMoveScopeRootPaths } from './wsl-move-scope-roots' + +import { + type WslMoveCutover, + type WslMoveCutoverPhase, + WSL_MOVE_CUTOVER_PHASES +} from '../../../../shared/wsl-move/wsl-move-cutover' +import { scanWslMoveCutovers } from '../cutover-recovery/wsl-move-cutover-journal' +import { comparableWslPath } from '../manifest-scope/wsl-move-comparable-path' +import { wslMoveScopeRootPaths } from '../manifest-scope/wsl-move-scope-roots' import { listWslDriveUncConversions, type WslDriveUncConversion -} from '../../wsl/filesystem/wsl-drive-unc-conversion-journal' +} from '../../../wsl/filesystem/wsl-drive-unc-conversion-journal' export type WslMoveScopeIds = { repoIds: ReadonlySet diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.test.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.test.ts index 68a5b1067c9..c042118d730 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import type { AutomationRun } from '../../../shared/automations/history/automation-run' +import type { AutomationRun } from '../../../../shared/automations/history/automation-run' import { collectWslMoveGateInputs, type WslMoveGateFactSources } from './wsl-move-gate-facts' const WT = 'repo-1::\\\\wsl.localhost\\Ubuntu\\home\\dev\\app' diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.ts index ec899136b74..e3b68d56386 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-gate-facts.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts.ts @@ -4,20 +4,20 @@ * Status), foreground work from the same process probe the close-tab warning uses, and running * automation runs and live orchestration dispatches from their own stores. This only reads. */ -import type { AgentStatusIpcPayload } from '../../../shared/agent-status/contracts/agent-status-ipc-payload' -import { getAgentResumeArgv } from '../../../shared/agent-launch/startup/agent-resume-argv' -import { isResumableTuiAgent } from '../../../shared/agent-session/lifecycle/agent-session-resume' +import type { AgentStatusIpcPayload } from '../../../../shared/agent-status/contracts/agent-status-ipc-payload' +import { getAgentResumeArgv } from '../../../../shared/agent-launch/startup/agent-resume-argv' +import { isResumableTuiAgent } from '../../../../shared/agent-session/lifecycle/agent-session-resume' import { isFinalAutomationRunStatus, type AutomationRun -} from '../../../shared/automations/history/automation-run' -import { probePtyRunningWorkWithInspection } from '../../../shared/terminal/pty/lifecycle/pty-running-work-probe' -import { parsePaneKey } from '../../../shared/workspace-layout/stable-pane-id' -import type { TerminalProcessInspection } from '../../../shared/terminal/pty/lifecycle/terminal-process-inspection' -import type { WslMoveTerminalScope } from './wsl-move-driver-ports' +} from '../../../../shared/automations/history/automation-run' +import { probePtyRunningWorkWithInspection } from '../../../../shared/terminal/pty/lifecycle/pty-running-work-probe' +import { parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' +import type { TerminalProcessInspection } from '../../../../shared/terminal/pty/lifecycle/terminal-process-inspection' +import type { WslMoveTerminalScope } from '../execution/wsl-move-driver-ports' import type { WslGuestPaneForeground } from './wsl-move-guest-foreground' -import { WSL_MOVE_LIVE_WORKER_STATES } from './wsl-move-orchestration-history-rewrite' -import type { WslMoveRestoreHintPane } from './wsl-move-restore-hints' +import { WSL_MOVE_LIVE_WORKER_STATES } from '../desktop-state/wsl-move-orchestration-history-rewrite' +import type { WslMoveRestoreHintPane } from '../terminal-state/wsl-move-restore-hints' import type { WslMoveGateInputs, WslMovePaneFacts } from './wsl-move-terminal-gate' export type WslMoveLiveTerminal = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.test.ts similarity index 100% rename from src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.test.ts diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.ts similarity index 97% rename from src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.ts index 112fa7fd43d..35ad0d43feb 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-guest-foreground.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground.ts @@ -7,8 +7,8 @@ * `nohup`, `disown`), no daemon it started (`setsid` keeps the key), and no script it runs (a waiting * `read` is still a script). The move's Sleep ends all of those, so any of them blocks. */ -import { recognizeAgentProcess } from '../../../shared/agent-status/process/agent-process-recognition' -import { isShellProcess } from '../../../shared/agent-status/process/shell-process-detection' +import { recognizeAgentProcess } from '../../../../shared/agent-status/process/agent-process-recognition' +import { isShellProcess } from '../../../../shared/agent-status/process/shell-process-detection' /** * `agent`: the shell's one foreground job is an agent CLI and everything else running is its own diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-host-copy-stop.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-host-copy-stop.ts similarity index 100% rename from src/main/persistence/moving-wsl-projects/wsl-move-host-copy-stop.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-host-copy-stop.ts diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-host-readiness.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-host-readiness.ts similarity index 85% rename from src/main/persistence/moving-wsl-projects/wsl-move-host-readiness.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-host-readiness.ts index 8f2fd5721dd..1d760251d71 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-host-readiness.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-host-readiness.ts @@ -3,10 +3,10 @@ * only a distro the running-distro read confirms gets its host connected, or added for a bridge * user who never added one. A failed read proves nothing, so it never counts as stopped. */ -import type { WslRunningDistrosRead } from '../../wsl/discovery/wsl-background-distro-gate' -import { wslMoveJournalKey } from '../../../shared/wsl-move/wsl-move-cutover' -import type { WslHostAddResult } from '../../../shared/wsl-host-types' -import type { WslMoveHostReadiness } from './wsl-move-orchestrator-ports' +import type { WslRunningDistrosRead } from '../../../wsl/discovery/wsl-background-distro-gate' +import { wslMoveJournalKey } from '../../../../shared/wsl-move/wsl-move-cutover' +import type { WslHostAddResult } from '../../../../shared/wsl-host-types' +import type { WslMoveHostReadiness } from '../orchestration/wsl-move-orchestrator-ports' export type WslMoveHostReadinessDeps = { readRunningDistros: () => Promise diff --git a/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-incidental-writes.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-incidental-writes.test.ts new file mode 100644 index 00000000000..ed04bcd650d --- /dev/null +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-incidental-writes.test.ts @@ -0,0 +1,86 @@ +import { mkdtempSync, rmSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { GitPushTarget } from '../../../../shared/worktree/types' +import type { ExecutionHostId } from '../../../../shared/execution-host' +import { mergeWorktreeMetaForWrite } from '../../loading-store/worktree-metadata/worktree-meta-write-normalization' +import { wslMoveCutoverFixture as cutover } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { seedWslMoveCutover } from '../../__fixtures__/wsl-mover/wsl-move-journal-seeding' +import { loadWslMoveFence, resetWslMoveFenceForTests } from './wsl-move-scope-guard' +import type * as LinearCurrentIssueContext from '../../../linear/issues/context/worktree-current-issue' + +const { gitExecFileAsyncMock } = vi.hoisted(() => ({ gitExecFileAsyncMock: vi.fn() })) +vi.mock('../../../git/command-runner/git-exec-file', async (importOriginal) => ({ + ...(await importOriginal>()), + gitExecFileAsync: gitExecFileAsyncMock +})) +vi.mock('../../../linear/issues/context/worktree-current-issue', async (importOriginal) => ({ + ...(await importOriginal()), + resolveLegacyLinearLinkWorkspace: () => ({ workspaceId: 'ws-1', organizationUrlKey: 'acme' }) +})) + +import { materializeWorktreePushTargetRemote } from '../../../ipc/worktree-remote' + +import { hostWorktreeTarget } from '../../../../shared/worktree/host-qualified-identity' + +const MOVING_WT = 'repo-1::/ws/repo-1/wt' + +let userDataPath: string +beforeEach(() => { + userDataPath = mkdtempSync(join(tmpdir(), 'wsl-move-incidental-')) + loadWslMoveFence(userDataPath) + seedWslMoveCutover(userDataPath, cutover('move-1', 'source-fenced')) + gitExecFileAsyncMock.mockReset() + gitExecFileAsyncMock.mockImplementation(async (args: string[]) => { + if (args[0] === 'remote' && args[1] === 'get-url') { + throw new Error('No such remote') + } + return { stdout: '', stderr: '' } + }) +}) +afterEach(() => { + resetWslMoveFenceForTests() + rmSync(userDataPath, { recursive: true, force: true }) +}) + +describe('push-target bookkeeping under a WSL move', () => { + const target: GitPushTarget = { + remoteName: 'pr-contributor-orca', + branchName: 'contributor/fix', + remoteUrl: 'git@github.com:contributor/orca.git' + } + + async function push(worktreeId: string, hostId?: ExecutionHostId) { + const setWorktreeMeta = vi.fn() + const meta = hostId ? { [worktreeId]: mergeWorktreeMetaForWrite(undefined, { hostId }) } : {} + const repos = [ + { id: 'repo-1', path: '/ws/repo-1', displayName: 'r', badgeColor: '#000', addedAt: 0 }, + { + id: 'repo-1', + path: '/ws/repo-1', + displayName: 'r', + badgeColor: '#000', + addedAt: 0, + connectionId: 'target-1' + }, + { id: 'repo-2', path: '/ws/repo-2', displayName: 'r', badgeColor: '#000', addedAt: 0 } + ] + const store = { getAllWorktreeMeta: () => meta, getRepos: () => repos, setWorktreeMeta } + const result = await materializeWorktreePushTargetRemote( + '/ws/repo', + target, + store, + undefined, + {}, + hostWorktreeTarget({ id: worktreeId, hostId: hostId ?? 'local' }) + ) + return { result, setWorktreeMeta } + } + + it('still pushes the moving worktree but skips its metadata write', async () => { + const { result, setWorktreeMeta } = await push(MOVING_WT) + expect(result).toEqual({ ...target, remoteCreated: true }) + expect(setWorktreeMeta).not.toHaveBeenCalled() + }) +}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-moved-distro-check.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-moved-distro-check.ts similarity index 84% rename from src/main/persistence/moving-wsl-projects/wsl-move-moved-distro-check.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-moved-distro-check.ts index bc92ccc3daa..857ef32a818 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-moved-distro-check.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-moved-distro-check.ts @@ -3,8 +3,8 @@ * same distro. A new GUID under the old name is either a reinstall or a re-import of the same * files, which the registry cannot tell apart. */ -import type { WslDistroRegistration } from '../../wsl/discovery/wsl-distro-registry-id' -import type { WslMovedDistroVerdict } from './wsl-move-orchestrator-external-transitions' +import type { WslDistroRegistration } from '../../../wsl/discovery/wsl-distro-registry-id' +import type { WslMovedDistroVerdict } from '../orchestration/wsl-move-orchestrator-external-transitions' export function wslMovedDistroVerdict( registrations: readonly WslDistroRegistration[] | null, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-preflight.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-preflight.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-preflight.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-preflight.ts index b0a1c108590..c7bbe65233d 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-preflight.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-preflight.ts @@ -1,6 +1,6 @@ // No files move: prove rewritten paths identify the same objects before fencing anything. -import { ORCAD_MIGRATION_LOCAL_WSL_SOURCE_RUNTIME_CAPABILITY } from '../../../shared/orcad-runtime-capabilities' -import { isDrvfsLinuxPath, wslUncPathToLinux } from '../../../shared/wsl-paths' +import { ORCAD_MIGRATION_LOCAL_WSL_SOURCE_RUNTIME_CAPABILITY } from '../../../../shared/orcad-runtime-capabilities' +import { isDrvfsLinuxPath, wslUncPathToLinux } from '../../../../shared/wsl-paths' /** Read once through desktop UNC paths and once on the host. */ export type WslMovePathFacts = { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-quiesce.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.test.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-quiesce.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.test.ts index f89931a919e..fb292513e96 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-quiesce.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest' -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import { wslMoveCutoverFixture as cutover } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' +import { wslMoveCutoverFixture as cutover } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' import type { WslMoveExitProof } from './wsl-move-exit-proof' import { quiesceWslMove, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-quiesce.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.ts similarity index 97% rename from src/main/persistence/moving-wsl-projects/wsl-move-quiesce.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.ts index 755a883540a..10e477b10ed 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-quiesce.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-quiesce.ts @@ -1,7 +1,10 @@ // Fence, Sleep, then prove exit; refusal lifts the fence but leaves already-slept workspaces restorable. -import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' +import type { WslMoveCutover } from '../../../../shared/wsl-move/wsl-move-cutover' import type { WslMoveExitProof, WslMoveExitProofScope } from './wsl-move-exit-proof' -import type { WslMoveRestoreHintCapture, WslMoveRestoreHintPane } from './wsl-move-restore-hints' +import type { + WslMoveRestoreHintCapture, + WslMoveRestoreHintPane +} from '../terminal-state/wsl-move-restore-hints' import { assessWslMoveTerminals, type WslMoveGateBlocker, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.test.ts similarity index 96% rename from src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.test.ts index a24069cbc98..78b8437e25e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.test.ts @@ -2,7 +2,7 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { wslMoveJournalDirectory } from './wsl-move-cutover-journal' +import { wslMoveJournalDirectory } from '../cutover-recovery/wsl-move-cutover-journal' import { WslMoveProjectFencedError, assertWslMoveWorkspaceWritable, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.ts similarity index 95% rename from src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.ts index e3482b3362f..5550d2c7dfc 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-scope-guard.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard.ts @@ -1,17 +1,17 @@ // Cache journal fences before handlers run and follow every write; exit proof catches already-admitted spawns. import { resolve } from 'node:path' -import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id' -import { parseWorkspaceKey } from '../../../shared/workspace-scope' -import { isWslUncPath } from '../../../shared/wsl-paths' -import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import { onWslMoveJournalChange } from './wsl-move-cutover-journal' -import { onWslDriveUncConversionJournalChange } from '../../wsl/filesystem/wsl-drive-unc-conversion-journal' +import { getRepoIdFromWorktreeId } from '../../../../shared/worktree/id' +import { parseWorkspaceKey } from '../../../../shared/workspace-scope' +import { isWslUncPath } from '../../../../shared/wsl-paths' +import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import { onWslMoveJournalChange } from '../cutover-recovery/wsl-move-cutover-journal' +import { onWslDriveUncConversionJournalChange } from '../../../wsl/filesystem/wsl-drive-unc-conversion-journal' import { resolveWslMoveFence, type WslMoveFenceState } from './wsl-move-fence' -import { comparableWslPath, isAtOrUnder } from './wsl-move-comparable-path' +import { comparableWslPath, isAtOrUnder } from '../manifest-scope/wsl-move-comparable-path' import { findProjectHostSetup, type ProjectHostSetupTarget -} from '../../../shared/project-host-setup-target' +} from '../../../../shared/project-host-setup-target' export type WslMoveProjectRef = { repoId: string } | { folderWorkspaceId: string } diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.test.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.test.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.test.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.test.ts index 00ba3f92d57..897e666e54e 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.test.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.test.ts @@ -2,8 +2,8 @@ import { describe, expect, it } from 'vitest' import { MAX_ORCAD_MIGRATION_SCROLLBACK_SNAPSHOTS, MAX_ORCAD_MIGRATION_SCROLLBACK_TOTAL_BYTES -} from '../../../shared/orcad-migration/orcad-migration-scrollback' -import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../shared/terminal/replay/terminal-scrollback-limits' +} from '../../../../shared/orcad-migration/orcad-migration-scrollback' +import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../../shared/terminal/replay/terminal-scrollback-limits' import { assessWslMoveTerminals, type WslMovePaneFacts } from './wsl-move-terminal-gate' const pane = (paneKey: string, extra: Partial = {}): WslMovePaneFacts => ({ @@ -104,17 +104,6 @@ describe('assessWslMoveTerminals', () => { expect(gate([pane('t1:a', { agent })])).toEqual({ verdict: 'ready', paneKeys: ['t1:a'] }) }) - it('counts a pane listed twice once, for the caps and the ready list', () => { - const atCount = Array.from({ length: MAX_ORCAD_MIGRATION_SCROLLBACK_SNAPSHOTS }, (_, i) => - pane(`t${i}:a`) - ) - const verdict = gate([...atCount, pane('t0:a')]) - expect(verdict.verdict).toBe('ready') - expect(verdict.verdict === 'ready' && verdict.paneKeys).toHaveLength( - MAX_ORCAD_MIGRATION_SCROLLBACK_SNAPSHOTS - ) - }) - it('blocks on unfinished automation runs and orchestration dispatches in scope', () => { expect(gate([pane('t1:a')], ['run-1'], ['dispatch-1'])).toEqual({ verdict: 'blocked', diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.ts similarity index 93% rename from src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.ts index 0b2d1dae467..2391b7d19f7 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-terminal-gate.ts +++ b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-terminal-gate.ts @@ -1,10 +1,10 @@ // Never end work automatically; missing daemon evidence blocks rather than guessing a pane is restorable. -import type { AgentStatusState } from '../../../shared/agent-status/contracts/agent-status-types' +import type { AgentStatusState } from '../../../../shared/agent-status/contracts/agent-status-types' import { MAX_ORCAD_MIGRATION_SCROLLBACK_SNAPSHOTS, MAX_ORCAD_MIGRATION_SCROLLBACK_TOTAL_BYTES -} from '../../../shared/orcad-migration/orcad-migration-scrollback' -import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../shared/terminal/replay/terminal-scrollback-limits' +} from '../../../../shared/orcad-migration/orcad-migration-scrollback' +import { TERMINAL_SCROLLBACK_STORE_BYTE_LIMIT } from '../../../../shared/terminal/replay/terminal-scrollback-limits' export type WslMovePaneFacts = { paneKey: string diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-window-write-hold.ts b/src/main/persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold.ts similarity index 100% rename from src/main/persistence/moving-wsl-projects/wsl-move-window-write-hold.ts rename to src/main/persistence/moving-wsl-projects/quiescence/wsl-move-window-write-hold.ts diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-startup-rewrite.ts b/src/main/persistence/moving-wsl-projects/startup/wsl-move-startup-rewrite.ts similarity index 92% rename from src/main/persistence/moving-wsl-projects/wsl-move-startup-rewrite.ts rename to src/main/persistence/moving-wsl-projects/startup/wsl-move-startup-rewrite.ts index 238e939d96d..39da3ddc2e3 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-startup-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/startup/wsl-move-startup-rewrite.ts @@ -3,11 +3,11 @@ * see a committed move's rewrite, or the renderer hydrates the old routing and later writes it * back over the rewrite. So startup waits for the pass, but never long. */ -import { wslHostsServing } from '../../wsl/host-lifecycle/wsl-host-gate' +import { wslHostsServing } from '../../../wsl/host-lifecycle/wsl-host-gate' import { runWslMoveDesktopRewritePass, type WslMoveDesktopRewritePassOptions -} from './wsl-move-desktop-rewrite' +} from '../desktop-state/wsl-move-desktop-rewrite' // A pass is a few profile writes and flushes; past this the window opens and the pass finishes // behind it, holding the window's saves and reloading it. diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-startup.ts b/src/main/persistence/moving-wsl-projects/startup/wsl-move-startup.ts similarity index 68% rename from src/main/persistence/moving-wsl-projects/wsl-move-startup.ts rename to src/main/persistence/moving-wsl-projects/startup/wsl-move-startup.ts index 53635da94f6..80bb7aa0b59 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-startup.ts +++ b/src/main/persistence/moving-wsl-projects/startup/wsl-move-startup.ts @@ -2,25 +2,25 @@ * The WSL mover's part of main-process startup: registers the desktop rewrite stores, resets or * finishes interrupted moves, then keeps retained rows marked and retries a failed host step. */ -import type { Store } from '../loading-store/store' -import { recoverInterruptedWslMoves } from './wsl-move-reset' -import { isWslDistroRegistered } from '../../wsl/discovery/wsl-distro-registry-id' +import type { Store } from '../../loading-store/store' +import { recoverInterruptedWslMoves } from '../cutover-recovery/wsl-move-reset' +import { isWslDistroRegistered } from '../../../wsl/discovery/wsl-distro-registry-id' import { runWslMoveStartupRewrite } from './wsl-move-startup-rewrite' -import { installWslMoveRetention } from './wsl-move-retention' -import { registerWslMoveDesktopRewriteRegistry } from './wsl-move-desktop-rewrite-registry' -import { sweepOrphanedWslMoveSleptSpools } from './wsl-move-slept-spool-sweep' -import { settleInterruptedWslMoveUndos } from './wsl-move-undo-host-automations' -import { enableWslHostAutomations } from '../../wsl/host-lifecycle/wsl-host-automation-enable' +import { installWslMoveRetention } from '../cutover-recovery/wsl-move-retention' +import { registerWslMoveDesktopRewriteRegistry } from '../desktop-state/wsl-move-desktop-rewrite-registry' +import { sweepOrphanedWslMoveSleptSpools } from '../terminal-state/wsl-move-slept-spool-sweep' +import { settleInterruptedWslMoveUndos } from '../cutover-recovery/wsl-move-undo-host-automations' +import { enableWslHostAutomations } from '../../../wsl/host-lifecycle/wsl-host-automation-enable' import { scheduleWslMoveRewriteRetry, setWslMoveHostAutomationRestorer -} from './wsl-move-rewrite-retry' +} from '../cutover-recovery/wsl-move-rewrite-retry' import { disableWslHostAutomations, restoreWslHostAutomations -} from '../../wsl/host-lifecycle/wsl-host-automation-disable' -import { orchestrationDbFile } from '../../runtime/orchestration/db/orchestration-db-file' -import { productionWslMoveBrowserCookieCopyDependencies } from './wsl-move-browser-cookie-store' +} from '../../../wsl/host-lifecycle/wsl-host-automation-disable' +import { orchestrationDbFile } from '../../../runtime/orchestration/db/orchestration-db-file' +import { productionWslMoveBrowserCookieCopyDependencies } from '../desktop-state/wsl-move-browser-cookie-store' /** Resolves once interrupted moves are reset or finished; main-process-ready waits on it, bounded. */ export function startWslMoveStartup(userDataPath: string, store: Store): Promise { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-restore-hints-blob.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints-blob.ts similarity index 80% rename from src/main/persistence/moving-wsl-projects/wsl-move-restore-hints-blob.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints-blob.ts index caa88208722..9126f2145fe 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-restore-hints-blob.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints-blob.ts @@ -1,14 +1,17 @@ import { createHash } from 'node:crypto' -import type { OrcadMigrationBlobDescriptor } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { sameOrcadMigrationBlob } from '../../../shared/orcad-migration/orcad-migration-blob-transfer' + +import { + type OrcadMigrationBlobDescriptor, + sameOrcadMigrationBlob +} from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' import { MAX_ORCAD_MIGRATION_TERMINAL_RESTORE_HINTS_BYTES, ORCAD_MIGRATION_TERMINAL_RESTORE_HINTS_KEY, ORCAD_MIGRATION_TERMINAL_RESTORE_HINTS_VERSION, parseOrcadMigrationTerminalRestoreHintsDocument, type OrcadMigrationTerminalRestoreHint -} from '../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' -import type { OrcadMigrationBlobSource } from '../../managed-server/migration/transfers/orcad-migration-blob-coordinator' +} from '../../../../shared/orcad-migration/orcad-migration-terminal-restore-hints' +import type { OrcadMigrationBlobSource } from '../../../managed-server/migration/transfers/orcad-migration-blob-coordinator' export type WslMoveRestoreHintsBlob = { descriptor: OrcadMigrationBlobDescriptor diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-restore-hints.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints.ts similarity index 94% rename from src/main/persistence/moving-wsl-projects/wsl-move-restore-hints.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints.ts index b541d769802..7c8e3da322c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-restore-hints.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-restore-hints.ts @@ -1,6 +1,6 @@ // Restore the last checkpointed cwd after Sleep instead of silently reopening at the worktree root. -import type { ColdRestoreDetection } from '../../daemon/history/restoration/terminal-history-cold-restore-info' -import { wslUncPathToLinux } from '../../../shared/wsl-paths' +import type { ColdRestoreDetection } from '../../../daemon/history/restoration/terminal-history-cold-restore-info' +import { wslUncPathToLinux } from '../../../../shared/wsl-paths' export type WslMoveRestoreHint = { paneKey: string; cwd: string } diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.test.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.test.ts similarity index 88% rename from src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.test.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.test.ts index 0e4747fc00f..7343a6e367a 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.test.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.test.ts @@ -1,18 +1,18 @@ -import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' +import { hostWorktreeTarget } from '../../../../shared/worktree/host-qualified-identity' import { mkdtempSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { Tab, TabGroup } from '../../../shared/tab-types' -import type { Store } from '../loading-store/store' -import { closeTestStores, createStore, testState } from '../persistence-test-harness' -import { makeTerminalTab } from '../persistence-session-fixtures' -import { wslMoveCutoverFixture as cutover } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { ProfileStateSqliteAuthority } from '../profile-state/profile-state-sqlite-authority' -import { loadWslMoveFence, resetWslMoveFenceForTests } from './wsl-move-scope-guard' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import type { Tab, TabGroup } from '../../../../shared/tab-types' +import type { Store } from '../../loading-store/store' +import { closeTestStores, createStore, testState } from '../../persistence-test-harness' +import { makeTerminalTab } from '../../persistence-session-fixtures' +import { wslMoveCutoverFixture as cutover } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { seedWslMoveCutover } from '../../__fixtures__/wsl-mover/wsl-move-journal-seeding' +import { ProfileStateSqliteAuthority } from '../../profile-state/profile-state-sqlite-authority' +import { loadWslMoveFence, resetWslMoveFenceForTests } from '../quiescence/wsl-move-scope-guard' vi.mock('electron', () => ({ app: { getPath: () => testState.dir }, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.ts similarity index 84% rename from src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.ts index ca5d90f9c4d..2014e60ae1a 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-session-freeze.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-freeze.ts @@ -4,23 +4,23 @@ * change nor drop it. Every other workspace's rows, and the global fields, are taken as written. * Once the host owns the project, its native chat tabs are taken as written too. */ -import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../shared/workspace-session/workspace-session-host-field-ownership' +import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../../shared/workspace-session/workspace-session-host-field-ownership' import { mergeWorkspaceSessionArrayField, mergeWorkspaceSessionRecordField -} from '../../../shared/workspace-session/workspace-session-host-records' +} from '../../../../shared/workspace-session/workspace-session-host-records' import { filterWorkspaceRows, withoutWorkspaces, workspaceIdsNamedByPartition -} from '../../../shared/workspace-session/workspace-session-stranded-partition-adoption' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../shared/workspace-session/workspace-session-stranded-partition-adoption' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' import { hasWslMoveFrozenSessions, isWslMoveWorkspaceHostOwned, isWslMoveWorkspaceSessionFrozen -} from './wsl-move-scope-guard' -import { hostOwnedChatTabRows } from './wsl-move-host-owned-chat-tabs' +} from '../quiescence/wsl-move-scope-guard' +import { hostOwnedChatTabRows } from '../desktop-state/wsl-move-host-owned-chat-tabs' const CHAT_TAB_FIELDS = ['unifiedTabs', 'tabGroups', 'tabGroupLayouts'] as const diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-session-projection.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-projection.ts similarity index 87% rename from src/main/persistence/moving-wsl-projects/wsl-move-session-projection.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-projection.ts index 603631d7658..28bb1bee209 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-session-projection.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-projection.ts @@ -1,14 +1,14 @@ -import type { PersistedUIState } from '../../../shared/persisted-ui-state-types' -import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../shared/workspace-session/workspace-session-host-field-ownership' +import type { PersistedUIState } from '../../../../shared/persisted-ui-state-types' +import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../../shared/workspace-session/workspace-session-host-field-ownership' import { buildWorktreeIdByFileId, buildWorktreeIdByTabId, worktreeIdForPaneKey -} from '../../../shared/workspace-session/workspace-session-host-records' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { isRecord, parseEditorFileId } from './wsl-move-canonical-form' -import { WORKSPACE_SESSION_DISPOSITIONS } from '../../../shared/wsl-move/wsl-move-dispositions' -import { UI_STATE_DISPOSITIONS } from '../../../shared/wsl-move/wsl-move-ui-dispositions' +} from '../../../../shared/workspace-session/workspace-session-host-records' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import { isRecord, parseEditorFileId } from '../manifest-scope/wsl-move-canonical-form' +import { WORKSPACE_SESSION_DISPOSITIONS } from '../../../../shared/wsl-move/wsl-move-dispositions' +import { UI_STATE_DISPOSITIONS } from '../../../../shared/wsl-move/wsl-move-ui-dispositions' export type WslMoveOwnerInScope = (owner: string | undefined | null) => boolean type OwnerInScope = WslMoveOwnerInScope diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.test.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.test.ts similarity index 89% rename from src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.test.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.test.ts index 1e56ae94f8e..fa8ea269d33 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.test.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.test.ts @@ -1,13 +1,13 @@ import { describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import { toRuntimeExecutionHostId } from '../../../shared/execution-host' -import type { Tab } from '../../../shared/tab-types' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { wslMoverProfile } from '../__fixtures__/wsl-mover/wsl-mover-profiles' -import { tabGroup, terminalTab } from '../__fixtures__/wsl-mover/wsl-mover-profile-rows' -import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' -import { wslMoveRewriteScope } from './wsl-move-rewrite-scope' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' +import { toRuntimeExecutionHostId } from '../../../../shared/execution-host' +import type { Tab } from '../../../../shared/tab-types' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import { wslMoveCutoverFixture } from '../../__fixtures__/wsl-mover/wsl-move-cutover-fixture' +import { wslMoverProfile } from '../../__fixtures__/wsl-mover/wsl-mover-profiles' +import { tabGroup, terminalTab } from '../../__fixtures__/wsl-mover/wsl-mover-profile-rows' +import { createUncToLinuxPathRewriter } from '../manifest-scope/wsl-move-path-rewriter' +import { wslMoveRewriteScope } from '../desktop-state/wsl-move-rewrite-scope' import { wslMoveHostSessionSeed, wslMoveReleasedSessionFocusPatch diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.ts similarity index 90% rename from src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.ts index 43ab96e6828..4a3742a79f3 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-session-rewrite.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-session-rewrite.ts @@ -4,24 +4,24 @@ * shows the moved tabs before the host publishes. Native chats stay on this computer (owner * decision, option C), and terminals restart on the host, so neither is seeded. */ -import { LOCAL_EXECUTION_HOST_ID } from '../../../shared/execution-host' -import type { Tab } from '../../../shared/tab-types' -import { filterWorkspaceSessionTabs } from '../../../shared/workspace-session/workspace-session-tab-filter' -import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../shared/workspace-session/workspace-session-host-field-ownership' +import { LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host' +import type { Tab } from '../../../../shared/tab-types' +import { filterWorkspaceSessionTabs } from '../../../../shared/workspace-session/workspace-session-tab-filter' +import { WORKSPACE_SESSION_FIELD_OWNERSHIP } from '../../../../shared/workspace-session/workspace-session-host-field-ownership' import { mergeWorkspaceSessionArrayField, mergeWorkspaceSessionRecordField -} from '../../../shared/workspace-session/workspace-session-host-records' +} from '../../../../shared/workspace-session/workspace-session-host-records' import type { WorkspaceSessionPatch, WorkspaceSessionState -} from '../../../shared/workspace-session/workspace-session-state-types' +} from '../../../../shared/workspace-session/workspace-session-state-types' import { filterWorkspaceRows, workspaceIdsNamedByPartition -} from '../../../shared/workspace-session/workspace-session-stranded-partition-adoption' -import { parseWorkspaceKey, worktreeWorkspaceKey } from '../../../shared/workspace-scope' -import type { WslMoveRewriteScope } from './wsl-move-rewrite-scope' +} from '../../../../shared/workspace-session/workspace-session-stranded-partition-adoption' +import { parseWorkspaceKey, worktreeWorkspaceKey } from '../../../../shared/workspace-scope' +import type { WslMoveRewriteScope } from '../desktop-state/wsl-move-rewrite-scope' type SessionGlobals = Pick< WorkspaceSessionState, diff --git a/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.test.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.test.ts new file mode 100644 index 00000000000..a09529fb27b --- /dev/null +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.test.ts @@ -0,0 +1,59 @@ +import { appendFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' + +import { rewriteOrcadMigrationWorktreeId } from '../../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' +import { hashWorktreeId } from '../../../pty/history/terminal-history-id' + +import { createUncToLinuxPathRewriter } from '../manifest-scope/wsl-move-path-rewriter' +import { + buildWslMoveShellHistoryBlobs, + type WslMoveShellHistoryBlobs +} from './wsl-move-shell-history-blobs' + +const SOURCE_ID = 'repo-a::\\\\wsl.localhost\\Ubuntu\\home\\dev\\app' +const DESTINATION_ID = rewriteOrcadMigrationWorktreeId( + SOURCE_ID, + createUncToLinuxPathRewriter('Ubuntu') +) + +let root: string + +function writeHistory(worktreeId: string, file: string, content: string | Buffer): string { + const directory = join(root, hashWorktreeId(worktreeId)) + mkdirSync(directory, { recursive: true }) + const path = join(directory, file) + writeFileSync(path, content) + return path +} + +function build( + worktrees = [{ sourceWorktreeId: SOURCE_ID, destinationWorktreeId: DESTINATION_ID }] +): Promise { + return buildWslMoveShellHistoryBlobs({ distro: 'Ubuntu', worktrees, historyRoot: root }) +} + +describe('WSL move shell history blobs', () => { + beforeEach(() => { + root = mkdtempSync(join(tmpdir(), 'orca-wsl-move-history-')) + }) + + afterEach(() => { + rmSync(root, { recursive: true, force: true }) + }) + + it('refuses a read once the file changed after its digest was taken', async () => { + const path = writeHistory(SOURCE_ID, 'bash_history', 'one\n') + const blobs = await build() + const [descriptor] = blobs.descriptors + appendFileSync(path, 'two\n') + + await expect(blobs.source.readChunk(descriptor, 0, 1024)).rejects.toThrow( + 'orcad_migration_source_blob_changed:shell-history' + ) + await expect( + blobs.source.readChunk({ ...descriptor, sha256: 'f'.repeat(64) }, 0, 1) + ).rejects.toThrow('orcad_migration_source_blob_changed:shell-history') + }) +}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.ts similarity index 94% rename from src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.ts index 7ff6233c745..72b9f2d4f1c 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-shell-history-blobs.ts @@ -8,17 +8,17 @@ import { orcadMigrationBlobIdentity, sameOrcadMigrationBlob, type OrcadMigrationBlobDescriptor -} from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import type { OrcadMigrationBlobSource } from '../../managed-server/migration/transfers/orcad-migration-blob-coordinator' -import { getHistoryRootWsl } from '../../pty/history/terminal-history-paths' -import { hashWorktreeId } from '../../pty/history/terminal-history-id' +} from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' +import type { OrcadMigrationBlobSource } from '../../../managed-server/migration/transfers/orcad-migration-blob-coordinator' +import { getHistoryRootWsl } from '../../../pty/history/terminal-history-paths' +import { hashWorktreeId } from '../../../pty/history/terminal-history-id' import { MAX_ORCAD_MIGRATION_SHELL_HISTORY_BYTES, ORCAD_MIGRATION_SHELL_HISTORY_SHELLS, encodeOrcadMigrationShellHistoryHeader, orcadMigrationShellHistoryKey, shellHistoryFileName -} from '../migrating-orcad-catalog/orcad-migration-shell-history-format' +} from '../../migrating-orcad-catalog/terminal-history/orcad-migration-shell-history-format' export type WslMoveShellHistoryWorktree = { /** UNC identity used by desktop history. */ diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.test.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.test.ts similarity index 94% rename from src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.test.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.test.ts index d4597ad46d4..4529b658ebf 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.test.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.test.ts @@ -2,10 +2,10 @@ import { mkdtempSync, readFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' -import { getDefaultWorkspaceSession } from '../../../shared/constants' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { TerminalModes } from '../../daemon/protocol/terminal-modes' -import { parseOrcadMigrationTerminalHistoryText } from '../../../shared/orcad-migration/orcad-migration-terminal-history' +import { getDefaultWorkspaceSession } from '../../../../shared/constants' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import type { TerminalModes } from '../../../daemon/protocol/terminal-modes' +import { parseOrcadMigrationTerminalHistoryText } from '../../../../shared/orcad-migration/orcad-migration-terminal-history' import { daemonHistoryLeafOf, listWslMoveSleptSessionPanes, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.ts index 2b110a8f25f..55cbd4e35a5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback.ts @@ -10,25 +10,25 @@ import { join } from 'node:path' import { type OrcadMigrationBlobDescriptor, ORCAD_MIGRATION_BLOB_KIND_CONTRACTS -} from '../../../shared/orcad-migration/orcad-migration-blob-transfer' +} from '../../../../shared/orcad-migration/orcad-migration-blob-transfer' import { ORCAD_MIGRATION_TERMINAL_HISTORY_VERSION, type OrcadMigrationTerminalHistoryDocument -} from '../../../shared/orcad-migration/orcad-migration-terminal-history' +} from '../../../../shared/orcad-migration/orcad-migration-terminal-history' import { isTerminalLeafId, makePaneKey, parsePaneKey -} from '../../../shared/workspace-layout/stable-pane-id' -import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' -import type { WslMoveRequest } from '../../../shared/wsl-move/wsl-move-driver-types' -import { parsePtySessionId } from '../../../shared/terminal/pty/lifecycle/pty-session-id-format' -import { collectLeafIds } from '../../../shared/workspace-layout/terminal-pane-layout-tree' -import type { ColdRestoreInfo } from '../../daemon/history/restoration/terminal-history-cold-restore-info' -import type { TerminalCheckpointFile } from '../../daemon/protocol/daemon-checkpoint-file' -import type { OrcadMigrationBlobSource } from '../../managed-server/migration/transfers/orcad-migration-blob-coordinator' -import { orcadMigrationTerminalHistoryKey } from '../migrating-orcad-catalog/orcad-terminal-history-installer' -import type { WslMoveDriverDeps } from './wsl-move-driver-ports' +} from '../../../../shared/workspace-layout/stable-pane-id' +import type { WorkspaceSessionState } from '../../../../shared/workspace-session/workspace-session-state-types' +import type { WslMoveRequest } from '../../../../shared/wsl-move/wsl-move-driver-types' +import { parsePtySessionId } from '../../../../shared/terminal/pty/lifecycle/pty-session-id-format' +import { collectLeafIds } from '../../../../shared/workspace-layout/terminal-pane-layout-tree' +import type { ColdRestoreInfo } from '../../../daemon/history/restoration/terminal-history-cold-restore-info' +import type { TerminalCheckpointFile } from '../../../daemon/protocol/daemon-checkpoint-file' +import type { OrcadMigrationBlobSource } from '../../../managed-server/migration/transfers/orcad-migration-blob-coordinator' +import { orcadMigrationTerminalHistoryKey } from '../../migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer' +import type { WslMoveDriverDeps } from '../execution/wsl-move-driver-ports' import { wslMoveHostLinuxCwd, type ColdRestoreReader, diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-slept-spool-sweep.ts b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-spool-sweep.ts similarity index 91% rename from src/main/persistence/moving-wsl-projects/wsl-move-slept-spool-sweep.ts rename to src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-spool-sweep.ts index 4091a1563e7..fbb4fdb706d 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-slept-spool-sweep.ts +++ b/src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-spool-sweep.ts @@ -1,6 +1,6 @@ import { readdirSync, rmSync } from 'node:fs' import { join } from 'node:path' -import { listWslMoveCutovers } from './wsl-move-cutover-journal' +import { listWslMoveCutovers } from '../cutover-recovery/wsl-move-cutover-journal' import { WSL_MOVE_SLEPT_SPOOL_DIR } from './wsl-move-slept-scrollback' /** diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.test.ts deleted file mode 100644 index ad95f51aa73..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-delta-plan.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { Repo } from '../../../shared/repo-types' -import { computeOrcadMigrationManifestSha256 } from '../../orcad/orcad-migration-manifest-digest' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { removeWslMoveCutover } from './wsl-move-cutover-journal' -import { journalWslMove, planWslMove, type WslMovePlan } from './wsl-move-delta-plan' - -const UNC = '\\\\wsl.localhost\\Ubuntu' -const repo = (id: string, extra: Partial = {}): Repo => ({ - id, - path: `${UNC}\\home\\dev\\${id}`, - displayName: id, - badgeColor: '#000', - addedAt: 0, - ...extra -}) - -const NO_HOST = { repoIds: [], folderWorkspaceIds: [], highestGeneration: 0 } - -let dir: string -beforeEach(() => { - dir = mkdtempSync(join(tmpdir(), 'wsl-move-delta-plan-')) -}) -afterEach(() => { - rmSync(dir, { recursive: true, force: true }) -}) - -function state(repos: Repo[], folderWorkspaces: FolderWorkspace[] = []) { - return { repos, folderWorkspaces, projectGroups: [] } -} - -/** The fixture's manifest for a scope and generation, re-signed. */ -function moveFor(migrationId: string, plan: Pick) { - const base = wslMoveCutoverFixture(migrationId, 'prepared', {}, { repoIds: plan.repoIds }) - const { manifestSha256: _unsigned, ...unsigned } = base.manifest - const resigned = { - ...unsigned, - source: { ...unsigned.source, generation: plan.generation } - } - return { ...resigned, manifestSha256: computeOrcadMigrationManifestSha256(resigned) } -} - -/** A finished move of `repoIds`, as a journal record. */ -function retainedMove( - migrationId: string, - repoIds: string[], - generation: number, - supersedesMigrationId?: string -) { - const manifest = moveFor(migrationId, { repoIds, generation }) - return { - ...wslMoveCutoverFixture( - migrationId, - 'retained', - supersedesMigrationId ? { supersedesMigrationId } : {} - ), - manifest, - manifestSha256: manifest.manifestSha256 - } -} - -function ready(result: ReturnType): WslMovePlan { - if (result.outcome !== 'ready') { - throw new Error(result.code) - } - return result.plan -} - -describe('planWslMove', () => { - it('refuses a delta planned against a head that has since moved on', () => { - seedWslMoveCutover(dir, retainedMove('move-1', ['repo-a'], 1)) - const stale = ready( - planWslMove(dir, state([repo('repo-a'), repo('repo-b')]), 'Ubuntu', NO_HOST) - ) - seedWslMoveCutover(dir, retainedMove('move-2', ['repo-c'], 2, 'move-1')) - - expect(() => - journalWslMove({ - userDataPath: dir, - plan: stale, - manifest: moveFor('move-3', stale), - destinationName: 'Ubuntu' - }) - ).toThrow('wsl_move_must_extend_its_chain') - }) - - it('never takes again what the host still holds after its move was dropped', () => { - seedWslMoveCutover(dir, retainedMove('move-1', ['repo-a'], 1)) - seedWslMoveCutover(dir, retainedMove('move-2', ['repo-b'], 2, 'move-1')) - // What "Use on this computer again" does: the host keeps repo-b and its generation. - removeWslMoveCutover(dir, 'move-2') - - const plan = ready( - planWslMove(dir, state([repo('repo-a'), repo('repo-b'), repo('repo-c')]), 'Ubuntu', { - repoIds: ['repo-a', 'repo-b'], - folderWorkspaceIds: [], - highestGeneration: 2 - }) - ) - expect(plan).toMatchObject({ - repoIds: ['repo-c'], - heldByHost: [{ kind: 'repo', id: 'repo-b' }], - supersedesMigrationId: 'move-1', - generation: 3 - }) - }) - - it('refuses a manifest whose scope doubles an id', () => { - const plan = ready(planWslMove(dir, state([repo('repo-a'), repo('repo-b')]), 'Ubuntu', NO_HOST)) - expect(() => - journalWslMove({ - userDataPath: dir, - plan: { ...plan, repoIds: ['repo-a', 'repo-a'] }, - manifest: moveFor('move-1', plan), - destinationName: 'Ubuntu' - }) - ).toThrow('wsl_move_manifest_not_planned') - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-commit-reproof.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-driver-commit-reproof.test.ts deleted file mode 100644 index 426207c689f..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-commit-reproof.test.ts +++ /dev/null @@ -1,181 +0,0 @@ -/** - * R46: the quiesce proves every terminal in scope exited, but the commit comes later. A terminal - * that started in between must be refused by the fence, or block the commit and reset the move. - */ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import { - createWslMoveWorld, - type WslMoveWorld -} from '../__fixtures__/wsl-mover/wsl-move-driver-world' -import { listWslMoveCutovers } from './wsl-move-cutover-journal' -import { - registerWslMoveDesktopRewriteStore, - resetWslMoveDesktopRewriteStoresForTests, - setWslMoveDesktopRewriteRegistryCompleteForTests -} from './wsl-move-desktop-rewrite-stores' -import { moveProjectsToWslHost } from './wsl-move-driver' -import { - proveWslMoveTerminalsExited, - type WslMoveExitProof, - type WslMoveExitProofScope -} from './wsl-move-exit-proof' -import { - isWslMoveCwdFenced, - loadWslMoveFence, - resetWslMoveFenceForTests -} from './wsl-move-scope-guard' - -let userDataPath: string -let world: WslMoveWorld - -beforeEach(() => { - vi.stubEnv(WSL_HOSTS_INTERNAL_GATE_ENV, '1') - userDataPath = mkdtempSync(join(tmpdir(), 'wsl-move-reproof-')) - world = createWslMoveWorld(userDataPath) - loadWslMoveFence(userDataPath) - setWslMoveDesktopRewriteRegistryCompleteForTests(true) - registerWslMoveDesktopRewriteStore({ - id: 'ui-routing', - side: 'main', - run: () => {}, - flush: () => {} - }) -}) - -afterEach(() => { - vi.unstubAllEnvs() - resetWslMoveFenceForTests() - resetWslMoveDesktopRewriteStoresForTests() - rmSync(userDataPath, { recursive: true, force: true }) -}) - -const request = { distro: 'Ubuntu' } - -/** The quiesce's proof answers `exited`; the next one answers `later`. */ -function proofsThen(later: WslMoveExitProof): WslMoveExitProofScope[] { - const scopes: WslMoveExitProofScope[] = [] - world.deps.quiesce.proveExited = async (scope) => { - scopes.push(scope) - world.points.push('prove-exited') - return scopes.length === 1 ? { verdict: 'exited' } : later - } - return scopes -} - -describe('the exit proof again before the commit', () => { - it('runs after the last blob and right before the commit, with the quiesce scope', async () => { - const scopes = proofsThen({ verdict: 'exited' }) - - expect(await moveProjectsToWslHost(world.deps, request)).toMatchObject({ outcome: 'moved' }) - expect(world.points.filter((point) => point === 'prove-exited')).toHaveLength(2) - expect(world.points.slice(-3, -1)).toEqual(['prove-exited', 'commit:before']) - expect(scopes[1]).toEqual(scopes[0]) - expect([...scopes[1].sessionIds]).toEqual(['session-1']) - }) - - it.each<[string, WslMoveExitProof, string]>([ - ['live', { verdict: 'live', sessionIds: ['bare-session'] }, 'terminals-started-after-pause'], - [ - 'unverifiable', - { verdict: 'unverifiable', reason: 'a daemon generation did not answer' }, - 'exit-unverifiable: a daemon generation did not answer' - ] - ])('blocks the commit and resets when a terminal reads %s', async (_label, proof, detail) => { - proofsThen(proof) - - const result = await moveProjectsToWslHost(world.deps, request) - - expect(result).toEqual({ outcome: 'refused', code: 'wsl_move_pause_failed', detail }) - expect(world.points).not.toContain('commit:before') - // Back to zero on both sides: the journal record is gone and the host's staging aborted. - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - expect([...world.catalog.values()]).toEqual([]) - expect(isWslMoveCwdFenced('/home/dev/app')).toBe(false) - }) - - it('resets without the host, since nothing asked it to commit yet', async () => { - proofsThen({ verdict: 'live', sessionIds: ['bare-session'] }) - const connect = world.deps.connectHost - world.deps.connectHost = async (distro) => { - const host = await connect(distro) - const readState = host?.catalog.readState - if (host && readState) { - // The host goes away once the blobs are sent; the reset must not wait for it. - host.catalog.readState = async (manifest) => { - if (world.points.filter((point) => point === 'prove-exited').length > 1) { - throw new Error('host unreachable') - } - return readState(manifest) - } - } - return host - } - - const result = await moveProjectsToWslHost(world.deps, request) - - expect(result).toMatchObject({ outcome: 'refused', code: 'wsl_move_pause_failed' }) - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - }) -}) - -// Users with several projects in one distro open terminals in the others while a move copies. -describe('the real exit proof, at the quiesce and again before the commit', () => { - type Census = { sessionId: string; cwd: string | null; wslDistro: string | null }[] - - /** The census answers `atQuiesce` first, then `beforeCommit`. */ - function census(atQuiesce: Census, beforeCommit: Census): void { - let calls = 0 - world.deps.quiesce.proveExited = (scope) => { - calls += 1 - const sessions = (calls === 1 ? atQuiesce : beforeCommit).map((session) => ({ - ...session, - isAlive: true - })) - return proveWslMoveTerminalsExited( - { - listSessions: async () => sessions, - countFallbackSessions: () => 0, - isScopeFenced: () => true - }, - scope - ) - } - } - - const otherProject = { sessionId: 'bare-1', cwd: '/home/dev/other', wslDistro: 'Ubuntu' } - - it('moves past terminals in other folders of the distro, open before and during the copy', async () => { - census( - [otherProject], - [otherProject, { ...otherProject, sessionId: 'bare-2', cwd: '/home/dev' }] - ) - - expect(await moveProjectsToWslHost(world.deps, request)).toMatchObject({ outcome: 'moved' }) - }) - - it.each<[string, Census[number], string]>([ - [ - 'in a moving folder', - { sessionId: 'bare-3', cwd: '/home/dev/app/src', wslDistro: 'Ubuntu' }, - 'terminals-started-after-pause' - ], - [ - 'with no folder to place it by', - { sessionId: 'bare-4', cwd: null, wslDistro: 'Ubuntu' }, - 'exit-unverifiable: live terminals with no known workspace: bare-4' - ] - ])('still resets for a terminal that starts %s during the copy', async (_l, session, detail) => { - census([otherProject], [otherProject, session]) - - expect(await moveProjectsToWslHost(world.deps, request)).toEqual({ - outcome: 'refused', - code: 'wsl_move_pause_failed', - detail - }) - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-fault-injection.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-driver-fault-injection.test.ts deleted file mode 100644 index 10e7818b498..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-fault-injection.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Fault injection over the real move driver and a real orcad profile store (an earlier - * pattern): the desktop is killed at every point a clean move passes (each journal write, each - * host call before it lands and after its reply is lost, each pause step, each desktop rewrite - * store), optionally with orcad restarted too. After the restart and the reconnect, the move is - * back at zero or fully moved, never in between; a second restart changes nothing; and a move - * reset to zero can be run again from scratch. - */ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import { testState } from '../persistence-test-harness' -import { - createWslMoveKillRig, - removeWslMoveRigDirs, - restartWslMoveRig, - WSL_MOVE_RIG_REQUEST as request, - wslMoveRigOutcome as outcomeOf, - wslMoveRigRetentionStore as retentionStore, - type WslMoveRig, - type WslMoveRigOutcome as Outcome -} from '../__fixtures__/wsl-mover/wsl-move-kill-rig' -import type * as Journal from './wsl-move-cutover-journal' -import { resetWslMoveDesktopRewriteStoresForTests } from './wsl-move-desktop-rewrite-stores' -import { moveProjectsToWslHost } from './wsl-move-driver' -import { runWslMoveRetentionPass } from './wsl-move-retention' - -vi.mock('electron', () => ({ - app: { getPath: () => testState.dir }, - safeStorage: { - isEncryptionAvailable: () => true, - encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'), - decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').slice('encrypted:'.length) - } -})) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ - getCohortAtEmit: vi.fn(() => ({ nth_repo_added: 1 })) -})) - -// The journal's writes and removals are kill points too; the hook is set per test. -const journalKill = vi.hoisted(() => { - const hook: { at: ((name: string) => void) | null } = { at: null } - return hook -}) -vi.mock('./wsl-move-cutover-journal', async (importOriginal) => { - const actual = await importOriginal() - const around = ( - name: (...args: NoInfer) => string, - run: (...args: A) => void - ) => { - return (...args: A): void => { - journalKill.at?.(`${name(...args)}:before`) - run(...args) - journalKill.at?.(`${name(...args)}:after`) - } - } - return { - ...actual, - writeWslMoveCutover: around( - (_path: string, cutover: Parameters[1]) => - `journal:${cutover.phase}`, - actual.writeWslMoveCutover - ), - removeWslMoveCutover: around(() => 'journal:remove', actual.removeWslMoveCutover), - removeUncommittedWslMoveCutover: around( - () => 'journal:remove-uncommitted', - actual.removeUncommittedWslMoveCutover - ) - } -}) - -let rig: WslMoveRig - -function newRig(): WslMoveRig { - const next = createWslMoveKillRig() - journalKill.at = next.at - return next -} - -beforeEach(() => { - vi.stubEnv(WSL_HOSTS_INTERNAL_GATE_ENV, '1') - // A killed process's catch handlers warn about the calls that now throw. - vi.spyOn(console, 'warn').mockImplementation(() => {}) - rig = newRig() -}) - -afterEach(() => { - journalKill.at = null - vi.restoreAllMocks() - vi.unstubAllEnvs() - resetWslMoveDesktopRewriteStoresForTests() - removeWslMoveRigDirs() -}) - -async function killedMove(r: WslMoveRig, killAt: string): Promise { - r.kill.killAt = killAt - await moveProjectsToWslHost(r.world.deps, request).catch(() => {}) - // Retention runs on the journal change after the move, in the same process. - await runWslMoveRetentionPass({ userDataPath: r.userDataPath, store: retentionStore(r) }).catch( - () => {} - ) - expect(r.kill.dead, `kill point ${killAt} fired`).toBe(true) -} - -/** Every kill point a clean move passes, from a throwaway run. */ -async function killPoints(): Promise { - const probe = newRig() - const result = await moveProjectsToWslHost(probe.world.deps, request) - expect(result).toMatchObject({ outcome: 'moved' }) - await runWslMoveRetentionPass({ userDataPath: probe.userDataPath, store: retentionStore(probe) }) - return [...new Set(probe.kill.points)] -} - -describe('WSL move driver fault injection (real host store)', () => { - it('a clean move ends fully moved on a real host store', async () => { - expect(await moveProjectsToWslHost(rig.world.deps, request)).toMatchObject({ - outcome: 'moved' - }) - await runWslMoveRetentionPass({ userDataPath: rig.userDataPath, store: retentionStore(rig) }) - expect(outcomeOf(rig)).toBe('fully-moved') - }) - - it.each([false, true])( - 'every kill point ends at zero or fully moved, and survives a second restart (orcad restarted: %s)', - { timeout: 120_000 }, - async (orcadRestarted) => { - const points = await killPoints() - expect(points.length).toBeGreaterThan(30) - const matrix: Record = {} - for (const killAt of points) { - const r = newRig() - await killedMove(r, killAt) - await restartWslMoveRig(r, { hostUp: false, orcadRestarted }) - const hostDown = outcomeOf(r) - await restartWslMoveRig(r, { hostUp: true, orcadRestarted }) - const hostUp = outcomeOf(r) - matrix[killAt] = { hostDown, hostUp } - await restartWslMoveRig(r, { hostUp: true, orcadRestarted }) - expect(outcomeOf(r), `${killAt}: a second restart changes nothing`).toBe(hostUp) - if (hostUp === 'back-at-zero') { - const again = await moveProjectsToWslHost(r.world.deps, request) - expect(again, `a fresh move after ${killAt}`).toMatchObject({ outcome: 'moved' }) - } - } - for (const [killAt, result] of Object.entries(matrix)) { - expect(['back-at-zero', 'fully-moved'], `${killAt} with the host up`).toContain( - result.hostUp - ) - // Without the host, only a possible commit waits; everything else resolves locally. - expect( - ['back-at-zero', 'zero-abort-owed', 'fully-moved', 'waiting-for-host'], - killAt - ).toContain(result.hostDown) - } - // The commit point: a kill before the commit lands resets; one after it moves forward. - expect(matrix['commit:before']).toEqual({ - hostDown: 'waiting-for-host', - hostUp: 'back-at-zero' - }) - expect(matrix['commit:lost-reply']).toEqual({ - hostDown: 'waiting-for-host', - hostUp: 'fully-moved' - }) - // A kill after the host staged: the desktop resets alone, and the stage goes on reconnect. - expect(matrix['journal:destination-staged:after']).toEqual({ - hostDown: 'zero-abort-owed', - hostUp: 'back-at-zero' - }) - expect(matrix['store:browser:run']).toEqual({ - hostDown: 'fully-moved', - hostUp: 'fully-moved' - }) - } - ) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver-preview-settle.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-driver-preview-settle.test.ts deleted file mode 100644 index 01bc4606e01..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver-preview-settle.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import { - createWslMoveWorld, - type WslMoveWorld -} from '../__fixtures__/wsl-mover/wsl-move-driver-world' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { listWslMoveCutovers } from './wsl-move-cutover-journal' -import { - registerWslMoveDesktopRewriteStore, - resetWslMoveDesktopRewriteStoresForTests, - setWslMoveDesktopRewriteRegistryCompleteForTests -} from './wsl-move-desktop-rewrite-stores' -import { previewWslMove } from './wsl-move-driver' -import { runWslMoveDesktopRewritePass } from './wsl-move-desktop-rewrite' -import { - isWslMoveWindowWriteHeld, - resetWslMoveWindowWriteHoldForTests, - setWslMoveReloadableWindow -} from './wsl-move-window-write-hold' - -let userDataPath: string -let world: WslMoveWorld - -beforeEach(() => { - vi.stubEnv(WSL_HOSTS_INTERNAL_GATE_ENV, '1') - userDataPath = mkdtempSync(join(tmpdir(), 'wsl-move-preview-settle-')) - world = createWslMoveWorld(userDataPath) - setWslMoveDesktopRewriteRegistryCompleteForTests(true) - registerWslMoveDesktopRewriteStore({ - id: 'ui-routing', - side: 'main', - run: () => {}, - flush: () => {} - }) -}) - -afterEach(() => { - vi.unstubAllEnvs() - resetWslMoveDesktopRewriteStoresForTests() - resetWslMoveWindowWriteHoldForTests() - rmSync(userDataPath, { recursive: true, force: true }) -}) - -const request = { distro: 'Ubuntu' } -const journal = () => listWslMoveCutovers(userDataPath) -const AUTOMATIC = { settleInterrupted: 'finish-at-restart' } as const - -// An app update or crash between sending the copy and the host's commit leaves this record; the -// startup recovery has no host to ask, so the projects stay fenced until a move settles it. -function seedInterruptedCommit(): string { - const stuck = wslMoveCutoverFixture('stuck', 'blobs-transferred', {}, { repoIds: ['repo-9'] }) - seedWslMoveCutover(userDataPath, stuck) - return stuck.migrationId -} - -describe('the automatic mover previewing after an interrupted commit', () => { - it('records a commit the host made, but leaves the window and its reload to the next start', async () => { - const window = { - isDestroyed: () => false, - reload: vi.fn(), - allowUnload: vi.fn(() => () => {}), - onLoadedOrGone: vi.fn(() => () => {}) - } - setWslMoveReloadableWindow(() => window) - world.catalog.set(seedInterruptedCommit(), 'committed') - expect(await previewWslMove(world.deps, request, AUTOMATIC)).toEqual({ - outcome: 'refused', - code: 'wsl_move_finished_earlier_move', - detail: 'finish-pending' - }) - expect(journal().find((cutover) => cutover.migrationId === 'stuck')?.phase).toBe( - 'destination-committed' - ) - // An automatic step never reloads the window past its unload veto, nor drops its saves. - await new Promise((resolve) => setImmediate(resolve)) - expect(window.allowUnload).not.toHaveBeenCalled() - expect(window.reload).not.toHaveBeenCalled() - expect(isWslMoveWindowWriteHeld()).toBe(false) - // The next start's pass, before any window opens, finishes it forward. - setWslMoveReloadableWindow(() => null) - await runWslMoveDesktopRewritePass({ userDataPath, warn: () => {} }) - expect(journal().find((cutover) => cutover.migrationId === 'stuck')?.phase).toBe( - 'client-rewritten' - ) - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-driver.ts b/src/main/persistence/moving-wsl-projects/wsl-move-driver.ts index cd70246491d..b5377ed1ae5 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-driver.ts +++ b/src/main/persistence/moving-wsl-projects/wsl-move-driver.ts @@ -12,22 +12,25 @@ */ import type { WslMoveRequest, WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveCutover } from '../../../shared/wsl-move/wsl-move-cutover' -import { removeWslMoveCutover, writeWslMoveCutover } from './wsl-move-cutover-journal' -import { journalSleptWslMove } from './wsl-move-driver-journal' -import type { WslMoveDriverDeps, WslMoveHost } from './wsl-move-driver-ports' +import { + removeWslMoveCutover, + writeWslMoveCutover +} from './cutover-recovery/wsl-move-cutover-journal' +import { journalSleptWslMove } from './execution/wsl-move-driver-journal' +import type { WslMoveDriverDeps, WslMoveHost } from './execution/wsl-move-driver-ports' import { readSleptScrollback, daemonHistoryLeafOf, type WslMoveSleptScrollback -} from './wsl-move-slept-scrollback' -import { reportWslMoveRunEnd } from './wsl-move-driver-run-end' +} from './terminal-state/wsl-move-slept-scrollback' +import { reportWslMoveRunEnd } from './execution/wsl-move-driver-run-end' import { exportRequestOf, isWslMoveScopeChanged, prepareWslMove, refusal, type WslMovePrepared -} from './wsl-move-driver-plan' +} from './execution/wsl-move-driver-plan' import { advanceWslMove, collectWslMoveBlobs, @@ -35,21 +38,21 @@ import { sendWslMoveBlobs, stageWslMove, wslMoveCopyBytes -} from './wsl-move-driver-transfer' -import { pauseWslMoveScope } from './wsl-move-driver-pause' -import { quiesceWslMove, type WslMoveQuiesceRefusalReason } from './wsl-move-quiesce' -import { finishWslMove as finish } from './wsl-move-driver-finish' -import { resetWslMoveToZero } from './wsl-move-reset' +} from './execution/wsl-move-driver-transfer' +import { pauseWslMoveScope } from './execution/wsl-move-driver-pause' +import { quiesceWslMove, type WslMoveQuiesceRefusalReason } from './quiescence/wsl-move-quiesce' +import { finishWslMove as finish } from './execution/wsl-move-driver-finish' +import { resetWslMoveToZero } from './cutover-recovery/wsl-move-reset' import { claimWslMoveRun, releaseWslMoveRun, wslMoveClaimRefusal, type RunningWslMove -} from './wsl-move-running-moves' +} from './orchestration/wsl-move-running-moves' import { holdWslMoveWindowWritesForCommit, settleWslMoveWindowWriteHoldForCommit -} from './wsl-move-window-write-hold' +} from './quiescence/wsl-move-window-write-hold' class WslMoveStop extends Error {} @@ -58,9 +61,6 @@ const WSL_MOVE_TERMINALS_STARTED = 'terminals-started-after-pause' /** The quiesce's own wording, so both proofs read alike in the result. */ const WSL_MOVE_EXIT_UNVERIFIABLE = 'exit-unverifiable' -export { cancelWslMove, isWslMoveRunning } from './wsl-move-running-moves' -export { previewWslMove } from './wsl-move-driver-preview' - export async function moveProjectsToWslHost( deps: WslMoveDriverDeps, request: WslMoveRequest diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-gate-stub-agent-hooks.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-gate-stub-agent-hooks.test.ts deleted file mode 100644 index 0f95c5a5574..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-gate-stub-agent-hooks.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { AgentHookServer } from '../../agent-hooks/server/agent-hook-server' -import { makePaneKey } from '../../../shared/workspace-layout/stable-pane-id' -import { collectWslMoveGateInputs, type WslMoveGateFactSources } from './wsl-move-gate-facts' -import { assessWslMoveTerminals } from './wsl-move-terminal-gate' - -const WT = 'repo-1::\\\\wsl.localhost\\Ubuntu\\home\\dev\\app' -const PANE = makePaneKey('tab-1', '11111111-1111-4111-8111-111111111111') -const scope = { workspaceIds: [WT], workspaceKeys: new Set([WT]) } - -// The verify stub "codex" posts real hook events from the distro. Its -// Stop must let an idle agent pass the gate; only a turn still running may block. (The stub fires -// SessionStart at launch, which reads as a turn start, so a stub never given a prompt blocks.) -describe('the WSL move gate with the stub agent hook events', () => { - let server: AgentHookServer - let dir: string - - beforeEach(async () => { - dir = mkdtempSync(join(tmpdir(), 'wsl-move-stub-agent-')) - server = new AgentHookServer() - await server.start({ env: 'production' }) - }) - - afterEach(() => { - server.stop() - rmSync(dir, { recursive: true, force: true }) - }) - - async function hook(event: string, prompt = ''): Promise { - const env = server.buildPtyEnv() - const response = await fetch(`http://127.0.0.1:${env.ORCA_AGENT_HOOK_PORT}/hook/codex`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Orca-Agent-Hook-Token': env.ORCA_AGENT_HOOK_TOKEN - }, - body: JSON.stringify({ - paneKey: PANE, - tabId: 'tab-1', - worktreeId: WT, - // The stub's payload: no turn ids, a transcript it writes itself. - payload: { - session_id: '0f0e0d0c-0b0a-4908-8706-050403020100', - transcript_path: join(dir, 'rollout-stub.jsonl'), - cwd: '/home/dev/app', - hook_event_name: event, - model: 'stub', - prompt, - last_assistant_message: event === 'Stop' ? `stub answer to: ${prompt}` : '' - } - }) - }) - expect(response.status).toBe(204) - } - - async function gate(): Promise> { - const sources: WslMoveGateFactSources = { - listTerminals: () => [ - { - ptyId: 'pty-1', - workspaceId: WT, - paneKey: PANE, - wslDistro: 'Ubuntu', - foregroundAgent: null - } - ], - inspect: async () => ({ - foregroundProcess: 'wsl.exe', - hasChildProcesses: true, - childProcessEvidence: 'children' - }), - agentRows: (paneKey) => server.getStatusSnapshotForPane(paneKey), - scrollbackBytes: async () => 10, - automationRuns: () => [], - dispatches: () => [], - // The distro sees the stub as the shell's one foreground job. - guestForegrounds: async () => new Map([[PANE, { agent: 'codex' }]]) - } - return assessWslMoveTerminals(await collectWslMoveGateInputs(sources, scope)) - } - - it('passes an agent whose turn ended with Stop', async () => { - await hook('SessionStart') - await hook('UserPromptSubmit', 'hello p4') - expect(await gate()).toMatchObject({ - verdict: 'blocked', - blockers: [{ kind: 'agent-working' }] - }) - await hook('Stop', 'hello p4') - expect(await gate()).toEqual({ verdict: 'ready', paneKeys: [PANE] }) - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-guest-process-table-cost.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-guest-process-table-cost.test.ts deleted file mode 100644 index 6ed355ed4ce..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-guest-process-table-cost.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { execFileSync } from 'node:child_process' -import { chmodSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, describe, expect, it } from 'vitest' -import { - classifyWslGuestPaneForeground, - parseWslGuestPaneProcesses, - WSL_GUEST_PANE_PROCESS_SCRIPT -} from './wsl-move-guest-foreground' - -const itOnPosix = process.platform === 'win32' ? it.skip : it -const TOOLS = ['cat', 'tr', 'sed', 'head', 'wc', 'readlink', 'grep'] - -let root: string | undefined -afterEach(() => { - if (root) { - rmSync(root, { recursive: true, force: true }) - } - root = undefined -}) - -/** A fake /proc: a pane shell and its untagged job among `others` processes; returns tool calls. */ -function runAgainst(others: number): { calls: number; stdout: string } { - root = mkdtempSync(join(tmpdir(), 'orca-guest-table-')) - const proc = join(root, 'proc') - const entry = (pid: number, comm: string, ppid: number, sid: number, environ: string) => { - const dir = join(proc, String(pid)) - mkdirSync(dir, { recursive: true }) - writeFileSync(join(dir, 'stat'), `${pid} (${comm}) S ${ppid} ${sid} ${sid} 0\n`) - writeFileSync(join(dir, 'environ'), environ) - writeFileSync(join(dir, 'cmdline'), `${comm}\0`) - symlinkSync('/home/a', join(dir, 'cwd')) - } - entry(100, 'bash', 1, 100, 'ORCA_PANE_KEY=tab:leaf\0') - // Started with `env -i`: no pane key, but in the pane shell's session. - entry(200, 'sleep', 100, 100, 'PATH=/bin\0') - for (let pid = 1000; pid < 1000 + others; pid += 1) { - entry(pid, 'other', 1, pid, 'PATH=/bin\0') - } - // Each tool is shimmed to log its call, then run the real one. - const bin = join(root, 'bin') - const log = join(root, 'calls') - mkdirSync(bin) - writeFileSync(log, '') - for (const tool of TOOLS) { - const real = execFileSync('sh', ['-c', `command -v ${tool}`]) - .toString() - .trim() - writeFileSync(join(bin, tool), `#!/bin/sh\necho ${tool} >> '${log}'\nexec '${real}' "$@"\n`) - chmodSync(join(bin, tool), 0o755) - } - const script = WSL_GUEST_PANE_PROCESS_SCRIPT.replaceAll('/proc/', `${proc}/`) - const stdout = execFileSync('sh', ['-c', script], { - env: { PATH: `${bin}:${process.env.PATH ?? ''}` } - }).toString() - const calls = execFileSync('cat', [log]).toString().split('\n').filter(Boolean).length - return { calls, stdout } -} - -describe("the move's guest process table", () => { - // Review of #33398: one fork storm per /proc entry made busy distros hit the read's cap. - itOnPosix( - 'costs the same however many processes the distro runs, and keeps untagged jobs', - () => { - const few = runAgainst(5) - const many = runAgainst(400) - expect(many.calls).toBe(few.calls) - const rows = parseWslGuestPaneProcesses(many.stdout) ?? [] - expect(rows).toHaveLength(402) - expect(classifyWslGuestPaneForeground(rows, 'tab:leaf')).toBe('process-running') - } - ) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-incidental-writes.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-incidental-writes.test.ts deleted file mode 100644 index 5c5fe044285..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-incidental-writes.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { GitPushTarget } from '../../../shared/worktree/types' -import type { ExecutionHostId } from '../../../shared/execution-host' -import { mergeWorktreeMetaForWrite } from '../loading-store/worktree-metadata/worktree-meta-write-normalization' -import { wslMoveCutoverFixture as cutover } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { loadWslMoveFence, resetWslMoveFenceForTests } from './wsl-move-scope-guard' -import type * as LinearCurrentIssueContext from '../../linear/issues/context/worktree-current-issue' -import type { ResolvedWorktree } from '../../runtime/workspaces/catalog/runtime-worktree-path-identity' - -const { gitExecFileAsyncMock } = vi.hoisted(() => ({ gitExecFileAsyncMock: vi.fn() })) -vi.mock('../../git/command-runner/git-exec-file', async (importOriginal) => ({ - ...(await importOriginal>()), - gitExecFileAsync: gitExecFileAsyncMock -})) -vi.mock('../../linear/issues/context/worktree-current-issue', async (importOriginal) => ({ - ...(await importOriginal()), - resolveLegacyLinearLinkWorkspace: () => ({ workspaceId: 'ws-1', organizationUrlKey: 'acme' }) -})) - -import { materializeWorktreePushTargetRemote } from '../../ipc/worktree-remote' -import { RuntimeLinearTeamWriteCommands } from '../../runtime/integrations/linear/runtime-linear-team-write-commands' -import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' - -const MOVING_WT = 'repo-1::/ws/repo-1/wt' - -let userDataPath: string -beforeEach(() => { - userDataPath = mkdtempSync(join(tmpdir(), 'wsl-move-incidental-')) - loadWslMoveFence(userDataPath) - seedWslMoveCutover(userDataPath, cutover('move-1', 'source-fenced')) - gitExecFileAsyncMock.mockReset() - gitExecFileAsyncMock.mockImplementation(async (args: string[]) => { - if (args[0] === 'remote' && args[1] === 'get-url') { - throw new Error('No such remote') - } - return { stdout: '', stderr: '' } - }) -}) -afterEach(() => { - resetWslMoveFenceForTests() - rmSync(userDataPath, { recursive: true, force: true }) -}) - -describe('push-target bookkeeping under a WSL move', () => { - const target: GitPushTarget = { - remoteName: 'pr-contributor-orca', - branchName: 'contributor/fix', - remoteUrl: 'git@github.com:contributor/orca.git' - } - - async function push(worktreeId: string, hostId?: ExecutionHostId) { - const setWorktreeMeta = vi.fn() - const meta = hostId ? { [worktreeId]: mergeWorktreeMetaForWrite(undefined, { hostId }) } : {} - const repos = [ - { id: 'repo-1', path: '/ws/repo-1', displayName: 'r', badgeColor: '#000', addedAt: 0 }, - { - id: 'repo-1', - path: '/ws/repo-1', - displayName: 'r', - badgeColor: '#000', - addedAt: 0, - connectionId: 'target-1' - }, - { id: 'repo-2', path: '/ws/repo-2', displayName: 'r', badgeColor: '#000', addedAt: 0 } - ] - const store = { getAllWorktreeMeta: () => meta, getRepos: () => repos, setWorktreeMeta } - const result = await materializeWorktreePushTargetRemote( - '/ws/repo', - target, - store, - undefined, - {}, - hostWorktreeTarget({ id: worktreeId, hostId: hostId ?? 'local' }) - ) - return { result, setWorktreeMeta } - } - - it('still pushes the moving worktree but skips its metadata write', async () => { - const { result, setWorktreeMeta } = await push(MOVING_WT) - expect(result).toEqual({ ...target, remoteCreated: true }) - expect(setWorktreeMeta).not.toHaveBeenCalled() - }) -}) - -describe('Linear workspace backfill under a WSL move', () => { - function worktree(id: string, hostId: ExecutionHostId): ResolvedWorktree { - const path = id.slice(id.indexOf('::') + 2) - return { - id, - repoId: id.slice(0, id.indexOf('::')), - hostId, - path, - head: 'abc', - branch: 'refs/heads/main', - isBare: false, - isMainWorktree: false, - displayName: 'wt', - comment: '', - linkedIssue: null, - linkedPR: null, - linkedLinearIssue: 'ACME-1', - isArchived: false, - isUnread: false, - isPinned: false, - sortOrder: 0, - lastActivityAt: 0, - parentWorktreeId: null, - childWorktreeIds: [], - lineage: null, - git: { path, head: 'abc', branch: 'refs/heads/main', isBare: false, isMainWorktree: false } - } - } - - async function resolveCurrent(row: ResolvedWorktree) { - const setWorktreeMeta = vi.fn() - const commands = new RuntimeLinearTeamWriteCommands({ - runtimeAvailable: () => true, - showTerminal: async () => { - throw new Error('unused') - }, - resolveWorkspaceSelector: async () => row, - listResolvedWorktrees: async () => [row], - setWorktreeMeta, - emitClientEvent: () => {} - }) - const link = await commands.linearResolveCurrentIssue({ cwd: row.path }) - return { link, setWorktreeMeta } - } - - it('answers for the moving worktree without persisting the backfill', async () => { - const { link, setWorktreeMeta } = await resolveCurrent(worktree(MOVING_WT, 'local')) - expect(link.workspaceId).toBe('ws-1') - expect(setWorktreeMeta).not.toHaveBeenCalled() - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.test.ts deleted file mode 100644 index 28059eae8a0..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-manifest-export.test.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getDefaultPersistedState, getDefaultWorkspaceSession } from '../../../shared/constants' -import type { SleepingAgentSessionRecord } from '../../../shared/agent-session/lifecycle/agent-session-resume' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { Repo } from '../../../shared/repo-types' -import type { TerminalTab } from '../../../shared/workspace-layout/terminal-tab-types' -import { assertOrcadMigrationManifestDigest } from '../../orcad/orcad-migration-manifest-digest' -import { - DORMANT_AUTOMATION, - DORMANT_AUTOMATION_RUN -} from '../migrating-orcad-catalog/persistence-orcad-migration-catalog-fixture' -import { createOrcadMigrationSourceScope } from '../migrating-orcad-catalog/orcad-source-scope' -import { collectOrcadMigrationSourceDormantState } from '../migrating-orcad-catalog/orcad-source-dormant-state' -import { - exportWslMoveManifest, - WslMoveScopeChangedError, - type WslMoveManifestExportRequest, - type WslMoveManifestExportStore -} from './wsl-move-manifest-export' - -const DISTRO = 'Ubuntu' -const UNC_REPO = '\\\\wsl.localhost\\Ubuntu\\home\\me\\app' -const UNC_WORKTREE = '\\\\wsl.localhost\\Ubuntu\\home\\me\\app-feature' -const WORKTREE = `app::${UNC_WORKTREE}` -const OTHER_WORKTREE = 'win::C:\\code\\win' - -function repo(id: string, path: string, extra: Partial = {}): Repo { - return { id, path, displayName: id, badgeColor: '#737373', addedAt: 1, ...extra } -} - -function tab(id: string, worktreeId: string): TerminalTab { - return { - id, - ptyId: null, - worktreeId, - title: id, - customTitle: null, - color: null, - sortOrder: 0, - createdAt: 1, - startupCwd: worktreeId.split('::')[1] - } -} - -function sourceState(): PersistedState { - const state = getDefaultPersistedState('C:\\Users\\me') - state.repos = [ - repo('app', UNC_REPO), - repo('win', 'C:\\code\\win'), - repo('elsewhere', '\\\\wsl.localhost\\Debian\\home\\me\\other') - ] - state.worktreeMeta[WORKTREE] = { - displayName: 'Feature', - comment: 'keep', - isUnread: false, - linkedIssue: null, - linkedPR: null, - linkedLinearIssue: null, - isArchived: false, - isPinned: true, - sortOrder: 1, - lastActivityAt: 2 - } - state.worktreeMeta[OTHER_WORKTREE] = { ...state.worktreeMeta[WORKTREE], displayName: 'Windows' } - state.automations = [ - { - ...DORMANT_AUTOMATION, - id: 'automation-app', - enabled: true, - projectId: 'app', - runContext: { - ...DORMANT_AUTOMATION.runContext!, - repoId: 'app', - projectHostSetupId: 'app', - path: UNC_REPO - }, - executionTargetType: 'local', - executionTargetId: 'local', - schedulerOwner: 'local_host_service' - }, - { - ...DORMANT_AUTOMATION, - id: 'automation-win', - enabled: true, - projectId: 'win', - runContext: { - ...DORMANT_AUTOMATION.runContext!, - repoId: 'win', - projectHostSetupId: 'win', - path: 'C:\\code\\win' - }, - executionTargetType: 'local', - executionTargetId: 'local', - schedulerOwner: 'local_host_service' - } - ] - state.automationRuns = [ - { - ...DORMANT_AUTOMATION_RUN, - automationId: 'automation-app', - runContext: state.automations[0]!.runContext - } - ] - state.workspaceSession = { - ...getDefaultWorkspaceSession(), - tabsByWorktree: { - [WORKTREE]: [tab('feature-shell', WORKTREE)], - [OTHER_WORKTREE]: [tab('windows-shell', OTHER_WORKTREE)] - } - } - return state -} - -function storeFor(state: PersistedState): WslMoveManifestExportStore { - return { - getRepos: () => state.repos, - getFolderWorkspaces: () => state.folderWorkspaces, - getProjectGroups: () => state.projectGroups, - inspectOrcadMigrationSourceDormantState: (source, catalog, destination) => - collectOrcadMigrationSourceDormantState(state, source, catalog, undefined, destination) - } -} - -const REQUEST: WslMoveManifestExportRequest = { - migrationId: 'move-1', - now: () => new Date('2026-10-20T00:00:00.000Z'), - distro: DISTRO, - distroGuid: '{guid}', - destinationEnvironmentId: 'wsl:Ubuntu', - generation: 2, - repoIds: ['app'], - folderWorkspaceIds: [] -} - -describe('exportWslMoveManifest', () => { - it('signs what the host and the journal will read, even with in-memory dates', () => { - // A row added this session can still hold a Date the next load would read back as a string. The - // signature covered "{}" for it while the host hashed the string, so the first move after adding - // a project reset with a digest mismatch until a restart. - const state = sourceState() - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the in-memory shape the load normalizes. - ;(state.repos[0] as unknown as Record).lastSeenAt = new Date( - '2026-10-20T00:00:00.000Z' - ) - const { manifest } = exportWslMoveManifest(storeFor(state), REQUEST) - expect(() => - assertOrcadMigrationManifestDigest(JSON.parse(JSON.stringify(manifest))) - ).not.toThrow() - }) - - it("shares no object with the live state, so a later sleep can't change what was signed", () => { - const state = sourceState() - const { manifest } = exportWslMoveManifest(storeFor(state), REQUEST) - // Sleep and the session freeze mutate the live session after the export signs it. - for (const tabs of Object.values(state.workspaceSession.tabsByWorktree)) { - for (const tab of tabs) { - tab.title = 'renamed by sleep' - } - } - expect(() => - assertOrcadMigrationManifestDigest(JSON.parse(JSON.stringify(manifest))) - ).not.toThrow() - }) - - describe('only the selected projects can refuse it', () => { - const agentIn = ( - worktreeId: string, - tabId: string, - leafId: string - ): SleepingAgentSessionRecord => ({ - paneKey: `${tabId}:${leafId}`, - tabId, - worktreeId, - agent: 'codex', - providerSession: { key: 'session_id', id: `session-${tabId}` }, - prompt: 'Saved prompt', - state: 'done', - capturedAt: 1, - updatedAt: 1, - connectionId: null, - origin: 'live' - }) - const layout = (leafId: string) => ({ - root: { type: 'leaf' as const, leafId }, - activeLeafId: leafId, - expandedLeafId: null - }) - - it('is still refused by the same kinds of state in the selected project', () => { - const state = sourceState() - const own = agentIn(WORKTREE, 'feature-shell', 'feature-leaf') - state.workspaceSession.terminalLayoutsByTabId = { 'feature-shell': layout('elsewhere') } - state.workspaceSession.sleepingAgentSessionsByPaneKey = { [own.paneKey]: own } - state.workspaceSession.openFilesByWorktree = { - [WORKTREE]: [ - { - filePath: '/home/me/app-feature/notes.md', - relativePath: 'notes.md', - worktreeId: WORKTREE, - language: 'markdown', - dirtyDraftContent: 'unsaved', - runtimeEnvironmentId: 'some-other-server' - } - ] - } - const { blockers } = exportWslMoveManifest(storeFor(state), REQUEST) - expect(blockers).toEqual( - expect.arrayContaining([ - expect.stringMatching(/codex session saved in/), - expect.stringMatching(/unsaved changes to/) - ]) - ) - }) - - it('never silently leaves behind an agent whose key may be the selected project', () => { - // `app` is also registered by an SSH host, so an unqualified `app::` key names either. - const state = sourceState() - state.repos.push(repo('app', '/srv/app', { connectionId: 'box' })) - const own = agentIn(WORKTREE, 'feature-shell', 'feature-leaf') - state.workspaceSession.terminalLayoutsByTabId = { 'feature-shell': layout('elsewhere') } - state.workspaceSession.sleepingAgentSessionsByPaneKey = { [own.paneKey]: own } - expect(exportWslMoveManifest(storeFor(state), REQUEST).blockers).toEqual([ - expect.stringMatching(/codex session saved in/) - ]) - }) - }) - - it('signs the session as the host parses it, even with a field the parser drops', () => { - // On a real host, a move right after sleeping terminals reset with a digest mismatch, because the - // signature covered session fields the manifest parser does not keep. - const state = sourceState() - const sleptTab: Record = { - ...state.workspaceSession.tabsByWorktree[WORKTREE]![0] - } - sleptTab.fieldNoParserKeeps = 1 - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: an extra field on a real tab. - state.workspaceSession.tabsByWorktree[WORKTREE] = [sleptTab as unknown as TerminalTab] - const { manifest } = exportWslMoveManifest(storeFor(state), REQUEST) - expect(() => - assertOrcadMigrationManifestDigest(JSON.parse(JSON.stringify(manifest))) - ).not.toThrow() - }) - - it('carries no desktop PTY binding, so the moved pane reads its history from the host', () => { - // The host's session kept the desktop's PTY ids, so the client took each pane - // for a live terminal, skipped the scrollback read, and opened a fresh prompt. - const state = sourceState() - const leaf = '11111111-1111-4111-8111-111111111111' - const tab = state.workspaceSession.tabsByWorktree[WORKTREE]![0]! - state.workspaceSession.tabsByWorktree[WORKTREE] = [{ ...tab, ptyId: `${WORKTREE}@@81c7100a` }] - state.workspaceSession.terminalLayoutsByTabId = { - [tab.id]: { - root: { type: 'leaf', leafId: leaf }, - activeLeafId: leaf, - expandedLeafId: null, - ptyIdsByLeafId: { [leaf]: `${WORKTREE}@@81c7100a` }, - buffersByLeafId: { [leaf]: 'history' } - } - } - const { manifest } = exportWslMoveManifest(storeFor(state), REQUEST) - const session = manifest.payload.dormantState?.workspaceSession - const layout = Object.values(session?.terminalLayoutsByTabId ?? {})[0] - expect(layout?.scrollbackRefsByLeafId?.[leaf]).toBeTruthy() - expect(layout).not.toHaveProperty('ptyIdsByLeafId') - expect(Object.values(session?.tabsByWorktree ?? {}).flat()[0]?.ptyId).toBeNull() - }) - - it('refuses to sign a scope naming a project that is no longer here', () => { - expect(() => - exportWslMoveManifest(storeFor(sourceState()), { ...REQUEST, repoIds: ['app', 'gone'] }) - ).toThrow(WslMoveScopeChangedError) - }) - - it('still keeps the SSH conversion steps from accepting a WSL manifest', () => { - const { manifest } = exportWslMoveManifest(storeFor(sourceState()), REQUEST) - expect(() => - createOrcadMigrationSourceScope({ - source: manifest.source, - catalog: manifest.payload, - repos: [] - }) - ).toThrow('orcad_migration_source_not_ssh') - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-stage1.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-stage1.test.ts deleted file mode 100644 index 4065b69f41d..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator-stage1.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { wslMoveJournalKey } from '../../../shared/wsl-move/wsl-move-cutover' -import type { WslMoveOrchestratorRecord } from '../../../shared/wsl-move/wsl-move-orchestrator-types' -import { wslMoveAutoMovesBridgeProjects } from '../../../shared/wsl-move/wsl-move-rollout-stage' -import { WslMoveOrchestrator } from './wsl-move-orchestrator' -import { fakePorts, stateOf } from './wsl-move-orchestrator.test-support' - -// Stage 1 (B3): the WSL hosts setting governs new projects; the user's bridge projects never move on their own. -describe('the move orchestrator in Stage 1', () => { - const stage1 = () => fakePorts({ autoMovesBridgeProjects: wslMoveAutoMovesBridgeProjects }) - - it.each(['project-opened', 'connect', 'startup', 'timer'] as const)( - 'starts no move on a %s wake, and readies no host for one', - async (trigger) => { - const ports = stage1() - const orchestrator = new WslMoveOrchestrator(ports) - await orchestrator.trigger('Ubuntu', trigger) - expect(ports.prepareHost).not.toHaveBeenCalled() - expect(ports.preview).not.toHaveBeenCalled() - expect(ports.start).not.toHaveBeenCalled() - expect(stateOf(orchestrator, 'Ubuntu')).toBeUndefined() - } - ) - - it('still moves when the user asks (their own Retry)', async () => { - const ports = stage1() - const orchestrator = new WslMoveOrchestrator(ports) - await orchestrator.trigger('Ubuntu', 'user') - expect(ports.start).toHaveBeenCalledOnce() - }) - - it('still checks a finished move for a removed or replaced distro (R38) on a wake', async () => { - const loaded = new Map([ - [ - wslMoveJournalKey('Ubuntu'), - { - distro: 'Ubuntu', - state: { kind: 'done', migrationId: 'm1' }, - attempts: 0, - appVersion: '1.0.0', - updatedAt: 0 - } - ] - ]) - const checkMovedDistro = vi.fn(async () => 'gone' as const) - const ports = fakePorts({ - autoMovesBridgeProjects: wslMoveAutoMovesBridgeProjects, - load: () => loaded, - finishedMove: () => ({ migrationId: 'm1', distroGuid: 'guid' }), - checkMovedDistro - }) - const orchestrator = new WslMoveOrchestrator(ports) - await orchestrator.trigger('Ubuntu', 'startup') - expect(checkMovedDistro).toHaveBeenCalledOnce() - expect(ports.start).not.toHaveBeenCalled() - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test.ts index 42ee58bf4c4..37d083798c8 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test.ts +++ b/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest' import { WslMoveOrchestrator } from './wsl-move-orchestrator' -import { fakePorts } from './wsl-move-orchestrator.test-support' +import { fakePorts } from './orchestration/wsl-move-orchestrator.test-support' describe('WslMoveOrchestrator', () => { it('keeps Restore offered when the release is refused', async () => { diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.ts b/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.ts index 4d3db1605e6..664abd7aa6d 100644 --- a/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.ts +++ b/src/main/persistence/moving-wsl-projects/wsl-move-orchestrator.ts @@ -7,8 +7,11 @@ */ import type { WslMovePreview, WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveUseLocallyResult } from '../../../shared/wsl-move/wsl-moved-project' -import type { WslMoveOrchestratorPorts } from './wsl-move-orchestrator-ports' -import { readWslMoveFinishedMove, runWslMoveOrchestratorStep } from './wsl-move-orchestrator-step' +import type { WslMoveOrchestratorPorts } from './orchestration/wsl-move-orchestrator-ports' +import { + readWslMoveFinishedMove, + runWslMoveOrchestratorStep +} from './orchestration/wsl-move-orchestrator-step' import { wslMoveJournalKey } from '../../../shared/wsl-move/wsl-move-cutover' import type { WslMoveOrchestratorDeclineCause, @@ -20,13 +23,13 @@ import { newWslMoveOrchestratorRecord, sameWslMoveOrchestratorRecord, wslMoveOrchestratorTimerDelay -} from './wsl-move-orchestrator-transitions' +} from './orchestration/wsl-move-orchestrator-transitions' import { applyWslMoveHostAddedByUser, applyWslMoveReleasedByUser, applyWslMoveUserAction, settleWslMoveOrchestratorRecord -} from './wsl-move-orchestrator-external-transitions' +} from './orchestration/wsl-move-orchestrator-external-transitions' /** A project opened again within this window does not read the running distros again. */ export const WSL_MOVE_ORCHESTRATOR_PROJECT_OPENED_THROTTLE_MS = 60_000 diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts deleted file mode 100644 index b8c8ab23b70..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-real-pause.test.ts +++ /dev/null @@ -1,306 +0,0 @@ -/** - * The quiesce step against real terminals: real shells on node-pty, hosted by a real in-process - * daemon. Sleep ends them through the daemon, the daemon's own census proves they exited, its - * final checkpoint names each pane's folder, and a new shell started there prints it. - * - * On Windows it runs only in the real-WSL lane (ORCA_WSL_MOVE_REAL_PAUSE_DISTRO): the shells are - * `wsl.exe` in that distro, opened through its UNC path, exactly as a moving project's are. - */ -import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { DaemonPtyAdapter } from '../../daemon/providers/adapter/daemon-pty-adapter' -import { DaemonServer } from '../../daemon/server/daemon-server' -import { getDaemonSocketPath } from '../../daemon/launch/daemon-spawner' -import { HistoryReader } from '../../daemon/history/restoration/history-reader' -import { createPtySubprocess } from '../../daemon/pty-subprocess/pty-subprocess' -import { runProcessSync } from '@orca/process-host' -import { buildWslExecArgs } from '../../../shared/wsl-login-shell-command' -import { toWindowsWslUncPath } from '../../../shared/wsl-paths' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { - listWslMoveCutovers, - removeWslMoveCutover, - writeWslMoveCutover -} from './wsl-move-cutover-journal' -import { proveWslMoveTerminalsExited } from './wsl-move-exit-proof' -import { quiesceWslMove, type WslMoveQuiesceScope } from './wsl-move-quiesce' -import { captureWslMoveRestoreHints } from './wsl-move-restore-hints' - -const WSL_DISTRO = - process.platform === 'win32' ? process.env.ORCA_WSL_MOVE_REAL_PAUSE_DISTRO : undefined -const DISTRO = WSL_DISTRO ?? 'Ubuntu' -const SHELL = ['/bin/bash', '/bin/sh'].find(existsSync) ?? '/bin/sh' -const WORKTREE = `repo-1::${toWindowsWslUncPath('/home/dev/repo-1', DISTRO)}` -const PANE_A = 'tab-1:11111111-1111-4111-8111-111111111111' -const PANE_B = 'tab-2:22222222-2222-4222-8222-222222222222' -const SESSION_A = `${WORKTREE}@@aaaa1111` -const SESSION_B = `${WORKTREE}@@bbbb2222` -const TIMEOUT_MS = 20_000 - -type Daemon = { - server: DaemonServer - /** This app's client: the PTYs it holds are what `livePtyIds` reports. */ - adapter: DaemonPtyAdapter - /** Another client of the same daemon, e.g. a window this process never adopted. */ - otherAdapter: DaemonPtyAdapter -} - -let root: string -let home: string -let project: string -let userDataPath: string -let historyDir: string -let daemon: Daemon -let started: Daemon | undefined -const daemonDirs: string[] = [] -const output = new Map() -const exited = new Set() -const heldByThisApp = new Set() -const spawned: { adapter: DaemonPtyAdapter; id: string }[] = [] - -async function startDaemon(): Promise { - // Its own short dir keeps the socket path inside sun_path, so the endpoint never relocates to /tmp. - const daemonDir = mkdtempSync(join(tmpdir(), 'wmrp-')) - daemonDirs.push(daemonDir) - const socketPath = getDaemonSocketPath(daemonDir) - const tokenPath = join(daemonDir, 'test.token') - const server = new DaemonServer({ - socketPath, - tokenPath, - spawnSubprocess: (opts) => createPtySubprocess(opts) - }) - await server.start() - const adapter = new DaemonPtyAdapter({ socketPath, tokenPath, historyPath: historyDir }) - const otherAdapter = new DaemonPtyAdapter({ socketPath, tokenPath }) - for (const client of [adapter, otherAdapter]) { - client.onData(({ id, data }) => output.set(id, `${output.get(id) ?? ''}${data}`)) - client.onExit(({ id }) => exited.add(id)) - } - return { server, adapter, otherAdapter } -} - -/** `cwd` is the shell's own (Linux) folder; a WSL shell is opened through its UNC path. */ -async function openShell(adapter: DaemonPtyAdapter, sessionId: string, cwd: string) { - await adapter.spawn({ - cols: 120, - rows: 30, - sessionId, - worktreeId: WORKTREE, - ...(WSL_DISTRO - ? { cwd: toWindowsWslUncPath(cwd, WSL_DISTRO), terminalWindowsWslDistro: WSL_DISTRO } - : { - cwd, - shellOverride: SHELL, - env: { HOME: home, SHELL, TERM: 'xterm-256color' } - }) - }) - spawned.push({ adapter, id: sessionId }) - if (adapter === daemon.adapter) { - heldByThisApp.add(sessionId) - } -} - -/** Types a command and waits for a marker the shell computes, so the echoed input never matches. */ -async function run(adapter: DaemonPtyAdapter, sessionId: string, command: string, tag: string) { - adapter.write(sessionId, `${command}; echo ${tag}_$((40+2))\n`) - await vi.waitFor(() => expect(output.get(sessionId) ?? '').toContain(`${tag}_42`), { - timeout: 10_000, - interval: 25 - }) -} - -// What a shell with cwd reporting prints after `cd`; the daemon's checkpoint tracks OSC 7. -const reportCwd = 'printf \'\\033]7;file://localhost%s\\033\\\\\' "$PWD"' - -/** Worktree Sleep's stopAndWait: end the PTY through the daemon, keep its history, await exit. */ -async function sleepPane(sessionId: string): Promise { - await daemon.adapter.shutdown(sessionId, { keepHistory: true }) - await vi.waitFor(() => expect(exited.has(sessionId)).toBe(true), { - timeout: 10_000, - interval: 25 - }) - heldByThisApp.delete(sessionId) -} - -function quiesceDeps(sleep: () => Promise) { - return { - gateInputs: async () => ({ panes: [], runningAutomationRunIds: [], activeDispatchIds: [] }), - sleepWorkspaces: async () => { - await sleep() - return { failedWorktreeIds: [] } - }, - livePtyIds: () => [...heldByThisApp], - captureRestoreHints: (panes: WslMoveQuiesceScope['panes'], distro: string) => - captureWslMoveRestoreHints(new HistoryReader(historyDir), panes, distro), - proveExited: (proofScope: Parameters[1]) => - proveWslMoveTerminalsExited( - { - listSessions: () => daemon.adapter.listSessions(), - countFallbackSessions: () => 0, - isScopeFenced: () => true - }, - proofScope - ), - writeCutover: (cutover: Parameters[1]) => - writeWslMoveCutover(userDataPath, cutover), - removeCutover: (migrationId: string) => removeWslMoveCutover(userDataPath, migrationId), - now: () => new Date('2026-10-20T00:00:00.000Z') - } -} - -function moveScope(): WslMoveQuiesceScope { - return { - workspaceIds: [WORKTREE], - workspaceKeys: new Set([WORKTREE]), - panes: [ - { paneKey: PANE_A, sessionId: SESSION_A, wslDistro: DISTRO }, - { paneKey: PANE_B, sessionId: SESSION_B, wslDistro: DISTRO } - ] - } -} - -function prepareMove() { - const prepared = wslMoveCutoverFixture('move-1', 'prepared', {}, {}, undefined, DISTRO) - writeWslMoveCutover(userDataPath, prepared) - return prepared -} - -/** A project folder inside the distro, made there, so no Windows path stands in for it. */ -function makeDistroProject(distro: string): string { - const dir = `/tmp/orca-wmrp-${process.pid}-${Date.now()}` - const made = runProcessSync({ - program: 'wsl.exe', - args: buildWslExecArgs(distro, ['mkdir', '-p', `${dir}/sub`]) - }) - if (made.code !== 0) { - throw new Error(`could not create ${dir} in ${distro}: ${made.stderr}`) - } - return dir -} - -describe.skipIf(process.platform === 'win32' && !WSL_DISTRO)( - 'WSL move quiesce on real terminals', - () => { - beforeEach(async () => { - // Real path: macOS tmp is a symlink through /private, and `pwd` prints the resolved one. - root = realpathSync(mkdtempSync(join(tmpdir(), 'wsl-move-real-pause-'))) - home = join(root, 'home') - project = WSL_DISTRO ? makeDistroProject(WSL_DISTRO) : join(root, 'project') - userDataPath = join(root, 'user-data') - historyDir = join(root, 'history') - for (const dir of [home, ...(WSL_DISTRO ? [] : [join(project, 'sub')]), userDataPath]) { - mkdirSync(dir, { recursive: true }) - } - // A quiet prompt and no user rc files, so the user's own shell setup cannot leak in. - for (const rc of ['.bash_profile', '.bashrc', '.profile']) { - writeFileSync(join(home, rc), "PS1='prompt> '\n") - } - vi.stubEnv('HOME', home) - vi.stubEnv('ENV', join(home, '.profile')) - daemon = await startDaemon() - started = daemon - }) - - afterEach(async () => { - for (const { adapter, id } of spawned.splice(0)) { - await adapter.shutdown(id, { immediate: true }).catch(() => {}) - } - heldByThisApp.clear() - output.clear() - exited.clear() - started?.adapter.dispose() - started?.otherAdapter.dispose() - await started?.server.shutdown() - started = undefined - vi.unstubAllEnvs() - if (WSL_DISTRO) { - runProcessSync({ - program: 'wsl.exe', - args: buildWslExecArgs(WSL_DISTRO, ['rm', '-rf', project]) - }) - } - for (const dir of [root, ...daemonDirs.splice(0)]) { - rmSync(dir, { recursive: true, force: true }) - } - }) - - it( - 'pauses two real shells, proves they exited, journals the folder, and reopens a shell there', - async () => { - const sub = `${project}/sub` - await openShell(daemon.adapter, SESSION_A, project) - await openShell(daemon.adapter, SESSION_B, project) - await run(daemon.adapter, SESSION_A, `cd sub && ${reportCwd}`, 'CD') - await run(daemon.adapter, SESSION_B, reportCwd, 'AT') - const census = await daemon.adapter.listSessions() - expect(census.filter((s) => s.isAlive).map((s) => s.sessionId)).toEqual( - expect.arrayContaining([SESSION_A, SESSION_B]) - ) - - const result = await quiesceWslMove( - prepareMove(), - moveScope(), - quiesceDeps(async () => { - await sleepPane(SESSION_A) - await sleepPane(SESSION_B) - }) - ) - - if (result.outcome !== 'quiesced') { - throw new Error(`quiesce refused: ${JSON.stringify(result)}`) - } - // Read from the shell's own reports, not the folder it was spawned in. - expect(result.restoreHints).toMatchObject({ staleCwdPaneKeys: [], noCwdPaneKeys: [] }) - // The daemon's census, not this process's bookkeeping, says both shells are gone. - expect((await daemon.adapter.listSessions()).filter((s) => s.isAlive)).toEqual([]) - const [journaled] = listWslMoveCutovers(userDataPath) - expect(journaled?.phase).toBe('quiesced') - expect(journaled?.provenExitedSessionIds).toEqual([SESSION_A, SESSION_B]) - expect(journaled?.terminalRestoreHints).toEqual([ - { paneKey: PANE_A, cwd: sub }, - { paneKey: PANE_B, cwd: project } - ]) - - const hint = journaled?.terminalRestoreHints?.find((h) => h.paneKey === PANE_A) - const restored = `${WORKTREE}@@cccc3333` - await openShell(daemon.adapter, restored, hint?.cwd ?? project) - await run(daemon.adapter, restored, 'pwd', 'PWD') - // The line `pwd` printed, right before the marker; the echoed command line holds neither. - expect(output.get(restored)).toContain(`${sub}\r\nPWD_42`) - }, - // Real daemon shells start, pause and exit; their startup alone can take seconds. - TIMEOUT_MS - ) - - it( - 'refuses and lifts the fence when the daemon still runs a pane this app does not hold', - async () => { - await openShell(daemon.adapter, SESSION_A, project) - // Started by another client, so this app's own PTY list cannot see it; only the census can. - await openShell(daemon.otherAdapter, SESSION_B, project) - await run(daemon.adapter, SESSION_A, reportCwd, 'A') - await run(daemon.otherAdapter, SESSION_B, reportCwd, 'B') - - const result = await quiesceWslMove( - prepareMove(), - moveScope(), - quiesceDeps(() => sleepPane(SESSION_A)) - ) - - expect(result).toMatchObject({ - outcome: 'refused', - reason: 'terminals-live', - liveSessionIds: [SESSION_B], - fenceLifted: true - }) - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - const alive = (await daemon.adapter.listSessions()).filter((s) => s.isAlive) - expect(alive.map((s) => s.sessionId)).toEqual([SESSION_B]) - }, - // Real daemon shells start, pause and exit; their startup alone can take seconds. - TIMEOUT_MS - ) - } -) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-retention.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-retention.test.ts deleted file mode 100644 index 9682d72414a..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-retention.test.ts +++ /dev/null @@ -1,318 +0,0 @@ -import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { getDefaultPersistedState } from '../../../shared/constants' -import type { FolderWorkspace } from '../../../shared/folder-workspaces/folder-workspace-types' -import type { PersistedState } from '../../../shared/persisted-state-types' -import type { ProjectGroup } from '../../../shared/project-group-types' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import type { Store } from '../loading-store/store' -import { - closeTestStores, - createStore, - makeRepo, - readPersistedStateJson, - testState, - writeDataFile -} from '../persistence-test-harness' -import { - visibleFolderWorkspaces, - visibleRepos -} from '../migrating-orcad-catalog/orcad-source-visibility' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { listWslMoveCutovers, wslMoveJournalDirectory } from './wsl-move-cutover-journal' -import { planWslMove } from './wsl-move-delta-plan' -import { runWslMoveRetentionPass } from './wsl-move-retention' -import { loadWslMoveFence, resetWslMoveFenceForTests } from './wsl-move-scope-guard' -import { bringWslMovedProjectBack } from './wsl-move-use-locally' - -vi.mock('electron', () => ({ - app: { getPath: () => testState.dir }, - safeStorage: { isEncryptionAvailable: () => false } -})) - -const UNC = '\\\\wsl.localhost\\Ubuntu' -const NOW = new Date('2026-10-20T00:00:00.000Z') -const MARK = { migrationId: 'move-1', environmentId: 'wsl:Ubuntu' } - -const group: ProjectGroup = { - id: 'group', - name: 'Ubuntu folders', - parentPath: `${UNC}\\srv`, - connectionId: null, - parentGroupId: null, - createdFrom: 'manual', - tabOrder: 0, - isCollapsed: false, - color: null, - createdAt: 0, - updatedAt: 0 -} - -function folder(id: string, folderPath: string, connectionId: string | null = null) { - return { - id, - projectGroupId: 'group', - name: id, - folderPath, - connectionId, - linkedTask: null, - comment: 'kept', - isArchived: false, - isUnread: false, - isPinned: false, - sortOrder: 0, - lastActivityAt: 0, - createdAt: 0, - updatedAt: 0 - } satisfies FolderWorkspace -} - -const movedRepo = makeRepo({ - id: 'repo-a', - displayName: 'repo-a', - path: `${UNC}\\home\\dev\\repo-a`, - worktreeBaseRef: 'origin/main' -}) -const stayingRepo = makeRepo({ id: 'repo-w', displayName: 'Windows', path: 'C:\\src\\w' }) -const sshRepo = makeRepo({ id: 'repo-a', displayName: 'remote', path: '/r', connectionId: 'ssh-1' }) - -function profile(overrides: Partial = {}): PersistedState { - return { - ...getDefaultPersistedState(testState.dir), - repos: [movedRepo, stayingRepo, sshRepo], - projectGroups: [group], - folderWorkspaces: [folder('notes', `${UNC}\\srv\\notes`), folder('remote', '/srv/r', 'ssh-1')], - ...overrides - } -} - -function persisted(): PersistedState { - return JSON.parse(readPersistedStateJson()) -} - -const retainedMove = (phase: 'client-rewritten' | 'retained' = 'client-rewritten') => - wslMoveCutoverFixture('move-1', phase, {}, { repoIds: ['repo-a'], folderWorkspaceIds: ['notes'] }) - -const localRow = (rows: T[]): T[] => - rows.filter((row) => !row.connectionId) - -let store: Store -function open(state: PersistedState): Store { - writeDataFile(state) - store = createStore() - loadWslMoveFence(testState.dir) - return store -} -const pass = () => - runWslMoveRetentionPass({ userDataPath: testState.dir, store, now: () => NOW, warn: () => {} }) - -beforeEach(() => { - testState.dir = mkdtempSync(join(tmpdir(), 'wsl-move-retention-')) - vi.stubEnv(WSL_HOSTS_INTERNAL_GATE_ENV, '1') -}) -afterEach(async () => { - vi.unstubAllEnvs() - resetWslMoveFenceForTests() - await closeTestStores() - rmSync(testState.dir, { recursive: true, force: true }) -}) - -describe('WSL move retention', () => { - it('marks the source rows durably, then retains the move; nothing is deleted', async () => { - seedWslMoveCutover(testState.dir, retainedMove()) - open(profile()) - - const report = await pass() - - expect(report).toEqual({ retainedMigrationIds: ['move-1'], rewrittenMarks: 2, changed: [] }) - expect(listWslMoveCutovers(testState.dir)[0]?.phase).toBe('retained') - const saved = persisted() - expect(saved.repos).toHaveLength(3) - expect(localRow(saved.repos).find((repo) => repo.id === 'repo-a')).toEqual({ - ...movedRepo, - orcadRetained: MARK - }) - expect(saved.folderWorkspaces?.find((row) => row.id === 'notes')?.orcadRetained).toEqual(MARK) - // The SSH rows sharing an id, and the Windows project, are never marked. - expect(saved.repos.find((repo) => repo.connectionId === 'ssh-1')?.orcadRetained).toBeUndefined() - expect(saved.repos.find((repo) => repo.id === 'repo-w')?.orcadRetained).toBeUndefined() - expect( - saved.folderWorkspaces?.find((row) => row.id === 'remote')?.orcadRetained - ).toBeUndefined() - // Hidden by the same lists SSH uses. - const userData = () => testState.dir - expect( - visibleRepos(store, userData).map((repo) => [repo.id, repo.connectionId ?? null]) - ).toEqual([ - ['repo-w', null], - ['repo-a', 'ssh-1'] - ]) - expect(visibleFolderWorkspaces(store, userData).map((row) => row.id)).toEqual(['remote']) - }) - - it('downgrade then re-upgrade: re-hides, re-marks, flags the edit and loses no row', async () => { - seedWslMoveCutover(testState.dir, retainedMove()) - open(profile()) - await pass() - await closeTestStores() - resetWslMoveFenceForTests() - - // An older build: it never reads the WSL journal, strips the marks it does not know, and the - // user renames the moved project and adds a new one in the same distro. - const downgraded = persisted() - const strip = ({ - orcadRetained: _stripped, - ...row - }: T) => row - const added = makeRepo({ id: 'repo-b', displayName: 'repo-b', path: `${UNC}\\home\\dev\\b` }) - const rows = downgraded.repos - .map(strip) - .map((repo) => - repo.id === 'repo-a' && !repo.connectionId ? { ...repo, displayName: 'renamed' } : repo - ) - open({ - ...downgraded, - repos: [...rows, added], - folderWorkspaces: downgraded.folderWorkspaces?.map(strip) - }) - expect(store.getRepos().some((repo) => repo.orcadRetained)).toBe(false) - - const report = await pass() - - expect(report).toEqual({ - retainedMigrationIds: [], - rewrittenMarks: 2, - changed: [{ kind: 'repo', id: 'repo-a' }] - }) - const saved = persisted() - const local = localRow(saved.repos) - expect(local.find((repo) => repo.id === 'repo-a')).toEqual({ - ...movedRepo, - displayName: 'renamed', - orcadRetained: { ...MARK, sourceChangedAt: NOW.toISOString() } - }) - expect(saved.folderWorkspaces?.find((row) => row.id === 'notes')).toMatchObject({ - comment: 'kept', - orcadRetained: MARK - }) - expect(local.map((repo) => repo.id).sort()).toEqual(['repo-a', 'repo-b', 'repo-w']) - expect( - visibleRepos(store, () => testState.dir) - .filter((repo) => !repo.connectionId) - .map((repo) => repo.id) - .sort() - ).toEqual(['repo-b', 'repo-w']) - // Offered, never run: the edit is listed and only the new project would move. - const planned = planWslMove( - testState.dir, - { - repos: store.getRepos(), - folderWorkspaces: store.getFolderWorkspaces(), - projectGroups: store.getProjectGroups() - }, - 'Ubuntu', - { repoIds: ['repo-a'], folderWorkspaceIds: ['notes'], highestGeneration: 1 } - ) - expect(planned).toMatchObject({ - outcome: 'ready', - plan: { repoIds: ['repo-b'], changed: [{ kind: 'repo', id: 'repo-a' }] } - }) - expect(listWslMoveCutovers(testState.dir).map((entry) => entry.migrationId)).toEqual(['move-1']) - - // A later start keeps the first time it saw the change. - const again = await runWslMoveRetentionPass({ - userDataPath: testState.dir, - store, - now: () => new Date('2026-11-01T00:00:00.000Z') - }) - expect(again?.rewrittenMarks).toBe(0) - }) - - it('drops the marks once the move is dropped, so the rows list again', async () => { - seedWslMoveCutover(testState.dir, retainedMove()) - open(profile()) - await pass() - - expect(bringWslMovedProjectBack(testState.dir, { repoId: 'repo-a' }).released).toBe(true) - const report = await pass() - - expect(report?.rewrittenMarks).toBe(2) - expect(store.getRepos().some((repo) => repo.orcadRetained)).toBe(false) - expect(store.getFolderWorkspaces().some((row) => row.orcadRetained)).toBe(false) - expect(visibleRepos(store, () => testState.dir)).toHaveLength(3) - }) - - it('keeps every mark when the journal cannot be read', async () => { - seedWslMoveCutover(testState.dir, retainedMove()) - open(profile()) - await pass() - const dir = wslMoveJournalDirectory(testState.dir) - mkdirSync(dir, { recursive: true }) - writeFileSync(join(dir, 'broken.json'), '{') - - expect(await pass()).toBeNull() - expect(localRow(store.getRepos()).find((repo) => repo.id === 'repo-a')?.orcadRetained).toEqual( - MARK - ) - }) - - it('marks a delta move with its own id and keeps the earlier move on its rows', async () => { - seedWslMoveCutover(testState.dir, retainedMove('retained')) - open(profile()) - await pass() - seedWslMoveCutover( - testState.dir, - wslMoveCutoverFixture( - 'move-2', - 'client-rewritten', - { supersedesMigrationId: 'move-1' }, - { repoIds: ['repo-z'] } - ) - ) - store.addRepo( - makeRepo({ id: 'repo-z', displayName: 'repo-z', path: `${UNC}\\home\\dev\\repo-z` }) - ) - - expect((await pass())?.retainedMigrationIds).toEqual(['move-2']) - - const marks = localRow(store.getRepos()).map((repo) => [ - repo.id, - repo.orcadRetained?.migrationId - ]) - expect(marks).toEqual( - expect.arrayContaining([ - ['repo-a', 'move-1'], - ['repo-z', 'move-2'] - ]) - ) - }) - - it('leaves the move unretained when its marks cannot be made durable', async () => { - seedWslMoveCutover(testState.dir, retainedMove()) - open(profile()) - const failing = { - getRepos: () => store.getRepos(), - getFolderWorkspaces: () => store.getFolderWorkspaces(), - setWslMoveRetainedMarks: (marks: Parameters[0]) => - store.setWslMoveRetainedMarks(marks), - flushPendingOrThrowAsync: () => Promise.reject(new Error('disk full')) - } - - expect( - await runWslMoveRetentionPass({ userDataPath: testState.dir, store: failing, warn: () => {} }) - ).toBeNull() - expect(listWslMoveCutovers(testState.dir)[0]?.phase).toBe('client-rewritten') - }) - - it('drops a mark naming a move that never took the row', async () => { - seedWslMoveCutover(testState.dir, retainedMove('retained')) - open(profile({ repos: [movedRepo, { ...stayingRepo, orcadRetained: MARK }] })) - - await pass() - - expect(store.getRepos().find((repo) => repo.id === 'repo-w')?.orcadRetained).toBeUndefined() - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.test.ts deleted file mode 100644 index c2e4a320c1c..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-shell-history-blobs.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { createHash } from 'node:crypto' -import { - appendFileSync, - mkdirSync, - mkdtempSync, - rmSync, - truncateSync, - utimesSync, - writeFileSync -} from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it } from 'vitest' -import { - parseOrcadMigrationBlobDescriptor, - type OrcadMigrationBlobDescriptor -} from '../../../shared/orcad-migration/orcad-migration-blob-transfer' -import { rewriteOrcadMigrationWorktreeId } from '../migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' -import { hashWorktreeId } from '../../pty/history/terminal-history-id' -import { parseOrcadMigrationShellHistoryHeader } from '../migrating-orcad-catalog/orcad-migration-shell-history-format' -import { createUncToLinuxPathRewriter } from './wsl-move-path-rewriter' -import { - buildWslMoveShellHistoryBlobs, - type WslMoveShellHistoryBlobs -} from './wsl-move-shell-history-blobs' - -const SOURCE_ID = 'repo-a::\\\\wsl.localhost\\Ubuntu\\home\\dev\\app' -const DESTINATION_ID = rewriteOrcadMigrationWorktreeId( - SOURCE_ID, - createUncToLinuxPathRewriter('Ubuntu') -) -const SOURCE_FOLDER_ID = 'folder:workspace-1' - -let root: string - -function writeHistory(worktreeId: string, file: string, content: string | Buffer): string { - const directory = join(root, hashWorktreeId(worktreeId)) - mkdirSync(directory, { recursive: true }) - const path = join(directory, file) - writeFileSync(path, content) - return path -} - -function build( - worktrees = [{ sourceWorktreeId: SOURCE_ID, destinationWorktreeId: DESTINATION_ID }] -): Promise { - return buildWslMoveShellHistoryBlobs({ distro: 'Ubuntu', worktrees, historyRoot: root }) -} - -async function readAll( - blobs: WslMoveShellHistoryBlobs, - descriptor: OrcadMigrationBlobDescriptor, - chunk: number -): Promise { - const parts: Buffer[] = [] - for (let offset = 0; offset < descriptor.byteLength; offset += chunk) { - parts.push(await blobs.source.readChunk(descriptor, offset, chunk)) - } - return Buffer.concat(parts) -} - -describe('WSL move shell history blobs', () => { - beforeEach(() => { - root = mkdtempSync(join(tmpdir(), 'orca-wsl-move-history-')) - }) - - afterEach(() => { - rmSync(root, { recursive: true, force: true }) - }) - - it('keys each zsh/bash history by the host worktree id and carries that id in the header', async () => { - expect(DESTINATION_ID).toBe('repo-a::/home/dev/app') - writeHistory(SOURCE_ID, 'zsh_history', ': 1700000000:0;ls\n') - writeHistory(SOURCE_ID, 'bash_history', 'git status\n') - - const blobs = await build() - - const keys = blobs.descriptors.map((descriptor) => descriptor.key) - const hash = hashWorktreeId(DESTINATION_ID) - expect(keys).toEqual([`${hash}-zsh`, `${hash}-bash`]) - expect(keys.some((key) => key.startsWith(hashWorktreeId(SOURCE_ID)))).toBe(false) - for (const descriptor of blobs.descriptors) { - expect(parseOrcadMigrationBlobDescriptor(descriptor)).toEqual(descriptor) - // Read in pieces that straddle the header boundary. - const bytes = await readAll(blobs, descriptor, 7) - expect(bytes.length).toBe(descriptor.byteLength) - expect(createHash('sha256').update(bytes).digest('hex')).toBe(descriptor.sha256) - const header = parseOrcadMigrationShellHistoryHeader(descriptor.key, bytes, bytes.length) - expect(header.worktreeId).toBe(DESTINATION_ID) - } - const zsh = await readAll(blobs, blobs.descriptors[0], 1024) - expect(zsh.toString('utf8')).toBe( - `{"version":1,"worktreeId":"repo-a::/home/dev/app"}\n: 1700000000:0;ls\n` - ) - }) - - it('marks a bash history as the login shell only when no zsh history came with it', async () => { - writeHistory(SOURCE_ID, 'zsh_history', ': 1:0;ls\n') - writeHistory(SOURCE_ID, 'bash_history', 'ls\n') - writeHistory(SOURCE_FOLDER_ID, 'bash_history', 'make\n') - - const blobs = await build([ - { sourceWorktreeId: SOURCE_ID, destinationWorktreeId: DESTINATION_ID }, - { sourceWorktreeId: SOURCE_FOLDER_ID, destinationWorktreeId: SOURCE_FOLDER_ID } - ]) - - const loginShell = await Promise.all( - blobs.descriptors.map(async (descriptor) => { - const bytes = await readAll(blobs, descriptor, descriptor.byteLength) - return parseOrcadMigrationShellHistoryHeader(descriptor.key, bytes, bytes.length).loginShell - }) - ) - expect(loginShell).toEqual([false, false, true]) - }) - - it('blocks the move on a history over the per-blob cap instead of truncating it', async () => { - const path = writeHistory(SOURCE_ID, 'bash_history', '') - truncateSync(path, 64 * 1024 * 1024) - - await expect(build()).rejects.toThrow( - `orcad_migration_shell_history_too_large:${hashWorktreeId(DESTINATION_ID)}-bash` - ) - }) - - it('merges the \\\\wsl$ and \\\\wsl.localhost histories of one worktree oldest first', async () => { - const legacyId = SOURCE_ID.replace('wsl.localhost', 'wsl$') - const legacy = writeHistory(legacyId, 'bash_history', 'old one\nold two') - const current = writeHistory(SOURCE_ID, 'bash_history', 'new one\n') - utimesSync(legacy, 1_000, 1_000) - utimesSync(current, 2_000, 2_000) - - // Input order must not outrank history age. - const blobs = await build([ - { sourceWorktreeId: SOURCE_ID, destinationWorktreeId: DESTINATION_ID }, - { sourceWorktreeId: legacyId, destinationWorktreeId: DESTINATION_ID } - ]) - - expect(blobs.descriptors.map((descriptor) => descriptor.key)).toEqual([ - `${hashWorktreeId(DESTINATION_ID)}-bash` - ]) - const [descriptor] = blobs.descriptors - const bytes = await readAll(blobs, descriptor, 5) - expect(createHash('sha256').update(bytes).digest('hex')).toBe(descriptor.sha256) - const header = parseOrcadMigrationShellHistoryHeader(descriptor.key, bytes, bytes.length) - expect(bytes.subarray(header.byteLength).toString('utf8')).toBe('old one\nold two\nnew one\n') - }) - - it('refuses a read once the file changed after its digest was taken', async () => { - const path = writeHistory(SOURCE_ID, 'bash_history', 'one\n') - const blobs = await build() - const [descriptor] = blobs.descriptors - appendFileSync(path, 'two\n') - - await expect(blobs.source.readChunk(descriptor, 0, 1024)).rejects.toThrow( - 'orcad_migration_source_blob_changed:shell-history' - ) - await expect( - blobs.source.readChunk({ ...descriptor, sha256: 'f'.repeat(64) }, 0, 1) - ).rejects.toThrow('orcad_migration_source_blob_changed:shell-history') - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-two-desktops.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-two-desktops.test.ts deleted file mode 100644 index 57f892fcc30..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-two-desktops.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -/** - * R39: two Orca desktops (say a stable and a dev profile) moving into the one orcad of a distro. - * Each desktop is its own process with its own profile and journal, so desktop B runs on a second - * copy of the mover modules. The host's staging claims serialize overlapping moves: one wins, the - * other is refused and back at zero; neither corrupts the other. - */ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { WSL_HOSTS_INTERNAL_GATE_ENV } from '../../../shared/wsl-host-internal-gate' -import { testState } from '../persistence-test-harness' -import type { Store } from '../loading-store/store' -import { - createWslMoveKillRig, - removeWslMoveRigDirs, - WSL_MOVE_RIG_REQUEST as request, - wslMoveRigOutcome, - wslMoveRigRetentionStore, - wslMoveRigTempDir, - type WslMoveRig -} from '../__fixtures__/wsl-mover/wsl-move-kill-rig' -import { resetWslMoveDesktopRewriteStoresForTests } from './wsl-move-desktop-rewrite-stores' -import { moveProjectsToWslHost } from './wsl-move-driver' -import type { WslMoveResult } from '../../../shared/wsl-move/wsl-move-driver-types' -import type { Repo } from '../../../shared/repo-types' -import { runWslMoveRetentionPass } from './wsl-move-retention' - -vi.mock('electron', () => ({ - app: { getPath: () => testState.dir }, - safeStorage: { - isEncryptionAvailable: () => true, - encryptString: (plaintext: string) => Buffer.from(`encrypted:${plaintext}`, 'utf-8'), - decryptString: (ciphertext: Buffer) => ciphertext.toString('utf-8').slice('encrypted:'.length) - } -})) -vi.mock('../../telemetry/client', () => ({ track: vi.fn() })) -vi.mock('../../telemetry/cohort-classifier', () => ({ - getCohortAtEmit: vi.fn(() => ({ nth_repo_added: 1 })) -})) - -type OtherDesktop = { - userDataPath: string - repos: Repo[] - move: () => Promise - retain: () => Promise - journalPhases: () => string[] -} - -/** Desktop B: its own module copies, profile and journal, on desktop A's host store. */ -async function otherDesktop(host: () => Store, repos: Repo[]): Promise { - vi.resetModules() - const driver = await import('./wsl-move-driver') - const stores = await import('./wsl-move-desktop-rewrite-stores') - const journal = await import('./wsl-move-cutover-journal') - const retention = await import('./wsl-move-retention') - const worldModule = await import('../__fixtures__/wsl-mover/wsl-move-driver-world') - const hostModule = await import('../__fixtures__/wsl-mover/wsl-move-store-host') - stores.setWslMoveDesktopRewriteRegistryCompleteForTests(true) - stores.registerWslMoveDesktopRewriteStore({ - id: 'ui-routing', - side: 'main', - run: () => {}, - flush: () => {} - }) - const userDataPath = wslMoveRigTempDir('wsl-move-desktop-b-') - const world = worldModule.createWslMoveWorld(userDataPath) - world.repos.splice(0, world.repos.length, ...repos) - // Its own ids: a second profile never shares this desktop's random move ids. - let moves = 0 - world.deps.newMigrationId = () => `desktop-b-move-${(moves += 1)}` - const port = hostModule.createWslMoveStoreHost({ - store: host, - kill: hostModule.createWslMoveKillSwitch(), - prefix: 'b:' - }) - world.deps.connectHost = async () => port - return { - userDataPath, - repos: world.repos, - move: () => driver.moveProjectsToWslHost(world.deps, request), - retain: async () => { - await retention.runWslMoveRetentionPass({ - userDataPath, - store: { - getRepos: () => world.repos, - getFolderWorkspaces: () => [], - setWslMoveRetainedMarks: () => 1, - flushPendingOrThrowAsync: async () => {} - } - }) - }, - journalPhases: () => journal.listWslMoveCutovers(userDataPath).map((entry) => entry.phase) - } -} - -let rig: WslMoveRig - -beforeEach(() => { - vi.stubEnv(WSL_HOSTS_INTERNAL_GATE_ENV, '1') - vi.spyOn(console, 'warn').mockImplementation(() => {}) - rig = createWslMoveKillRig() -}) - -afterEach(() => { - vi.restoreAllMocks() - vi.unstubAllEnvs() - resetWslMoveDesktopRewriteStoresForTests() - removeWslMoveRigDirs() -}) - -/** Desktop A's move, held just before its commit until `release` runs. */ -function pausedBeforeCommit(): { - paused: Promise - release: () => void - done: Promise -} { - let release = (): void => {} - let onPaused = (): void => {} - const paused = new Promise((resolve) => (onPaused = resolve)) - const gate = new Promise((resolve) => (release = resolve)) - const { proveExited } = rig.world.deps.quiesce - let calls = 0 - rig.world.deps.quiesce.proveExited = async (scope) => { - calls += 1 - // The second proof runs after every blob and right before the commit request. - if (calls === 2) { - onPaused() - await gate - } - return proveExited(scope) - } - return { paused, release, done: moveProjectsToWslHost(rig.world.deps, request) } -} - -describe('R39: two desktops moving into one distro', () => { - it('the same project from both: the later stage is refused and resets; the first finishes', async () => { - const a = pausedBeforeCommit() - await a.paused - const b = await otherDesktop(() => rig.host, [...rig.world.repos]) - - const bResult = await b.move() - expect(bResult).toMatchObject({ outcome: 'reset' }) - expect(JSON.stringify(bResult)).toContain('orcad_migration_staged_claim_conflict') - expect(b.journalPhases()).toEqual([]) - - a.release() - expect(await a.done).toMatchObject({ outcome: 'moved' }) - await runWslMoveRetentionPass({ - userDataPath: rig.userDataPath, - store: wslMoveRigRetentionStore(rig) - }) - expect(wslMoveRigOutcome(rig)).toBe('fully-moved') - expect(rig.host.getRepos().filter((repo) => repo.id === 'repo-1')).toHaveLength(1) - }) - - it('different projects from each, overlapping: both move, and the host holds both', async () => { - const a = pausedBeforeCommit() - await a.paused - const b = await otherDesktop( - () => rig.host, - [{ ...rig.world.repos[0], id: 'repo-2', path: '\\\\wsl.localhost\\Ubuntu\\home\\dev\\other' }] - ) - - expect(await b.move()).toMatchObject({ outcome: 'moved' }) - a.release() - expect(await a.done).toMatchObject({ outcome: 'moved' }) - expect( - rig.host - .getRepos() - .map((repo) => repo.id) - .sort() - ).toEqual(['repo-1', 'repo-2']) - }) -}) diff --git a/src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.test.ts b/src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.test.ts deleted file mode 100644 index 353086d1807..00000000000 --- a/src/main/persistence/moving-wsl-projects/wsl-move-undo-host-automations.test.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { mkdtempSync, rmSync } from 'node:fs' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { wslMoveCutoverFixture } from '../__fixtures__/wsl-mover/wsl-move-cutover-fixture' -import { seedWslMoveCutover } from '../__fixtures__/wsl-mover/wsl-move-journal-seeding' -import { - listWslMoveCutovers, - removeCommittedWslMoveCutover, - writeWslMoveCutover -} from './wsl-move-cutover-journal' -import { listUnfinishedWslMoves } from './wsl-move-host-automations-rewrite' -import { resetWslMoveDesktopRewriteStoresForTests } from './wsl-move-desktop-rewrite-stores' -import { - retryWslMoveHostAutomationsLeftOff, - runWslMoveHostAutomationsExclusive, - settleInterruptedWslMoveUndos, - stopWslMoveHostAutomations, - type WslMoveHostAutomationPorts -} from './wsl-move-undo-host-automations' - -const MOVE = 'move-1' - -/** A fake host and the copies here; `host` is each automation's enabled flag there. */ -function world(hostStates: Record, here: Record) { - const host = new Map(Object.entries(hostStates)) - const local = new Map(Object.entries(here)) - const fail: { disableAt: string | null; restore: boolean } = { disableAt: null, restore: false } - const ports: WslMoveHostAutomationPorts = { - read: async (ids) => Object.fromEntries(ids.map((id) => [id, host.get(id) ?? false])), - disable: async (ids) => { - const done: string[] = [] - for (const id of ids) { - if (id === fail.disableAt) { - // The host drops mid-loop: what was turned off stays off. - throw Object.assign(new Error('wsl_move_automation_disable_failed:gone'), { - leftOff: done - }) - } - host.set(id, false) - done.push(id) - } - return done - }, - restore: async (ids) => { - if (fail.restore) { - throw new Error('host gone') - } - for (const id of ids) { - host.set(id, true) - } - }, - listHere: () => [...local].map(([id, enabled]) => ({ id, enabled })), - setHere: (id, enabled) => { - local.set(id, enabled) - } - } - return { host, local, fail, ports } -} - -describe('undo of a move with automations', () => { - let userDataPath: string - beforeEach(() => { - userDataPath = mkdtempSync(join(tmpdir(), 'wsl-move-undo-automations-')) - vi.spyOn(console, 'warn').mockImplementation(() => {}) - seedWslMoveCutover(userDataPath, wslMoveCutoverFixture(MOVE, 'retained')) - }) - afterEach(() => { - vi.restoreAllMocks() - resetWslMoveDesktopRewriteStoresForTests() - rmSync(userDataPath, { recursive: true, force: true }) - }) - const cutover = () => listWslMoveCutovers(userDataPath)[0] - - // d3a: undo kept the pre-move state and dropped what the user chose on the host since. - - it('records what a refusal could not turn back on, and a later undo keeps it on here', async () => { - const w = world({ a: true }, { a: true }) - const first = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - w.fail.restore = true - if (first.outcome !== 'stopped') { - throw new Error('expected stopped') - } - await first.restore() - expect(w.host.get('a')).toBe(false) - expect(listUnfinishedWslMoves(userDataPath)).toEqual([ - { migrationId: MOVE, distro: 'Ubuntu', automationsPending: ['a'] } - ]) - // d3a #1: off on the host only through the failed rollback; the user's choice is still on. - w.fail.restore = false - const second = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (second.outcome !== 'stopped') { - throw new Error('expected stopped') - } - second.applyHere() - expect(w.local.get('a')).toBe(true) - }) - - it('records what the host dropped mid-loop left off, and shows it in the notice', async () => { - const w = world({ a: true, b: true }, { a: true, b: true }) - w.fail.disableAt = 'b' - const stop = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a', 'b'], w.ports) - expect(stop).toEqual({ outcome: 'failed' }) - expect(cutover()?.hostAutomationsLeftOff).toEqual(['a']) - // Only the left-off one keeps its recorded choice for a later undo. - expect(cutover()?.undoHostAutomationIntent).toEqual({ a: true }) - expect(listUnfinishedWslMoves(userDataPath)[0]?.automationsPending).toEqual(['a']) - }) - - // d3-gate-audit / d3a #1: a retry mid-RPC while an undo releases the move. - it('takes turns with an undo, so a released move is neither resurrected nor left on the host', async () => { - const w = world({ a: true }, { a: true }) - w.fail.restore = true - const stop = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (stop.outcome === 'stopped') { - await stop.restore() - } - w.fail.restore = false - const order: string[] = [] - let finishRestore = () => {} - const retry = retryWslMoveHostAutomationsLeftOff(userDataPath, { - restore: async (_env, ids) => { - order.push('retry restore') - await new Promise((resolve) => { - finishRestore = resolve - }) - for (const id of ids) { - w.host.set(id, true) - } - }, - disable: async () => {} - }) - // The undo waits for the retry's turn, then turns the host copy off and releases. - const undo = runWslMoveHostAutomationsExclusive(async () => { - order.push('undo') - const again = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (again.outcome === 'stopped') { - again.applyHere() - } - removeCommittedWslMoveCutover(userDataPath, MOVE) - }) - await vi.waitFor(() => expect(order).toEqual(['retry restore'])) - finishRestore() - await Promise.all([retry, undo]) - expect(order).toEqual(['retry restore', 'undo']) - expect(w.host.get('a')).toBe(false) - expect(w.local.get('a')).toBe(true) - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - }) - - it('a retry finding the move released writes nothing back and turns its host copies off again', async () => { - const w = world({ a: true }, { a: true }) - w.fail.restore = true - const stop = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (stop.outcome === 'stopped') { - await stop.restore() - } - expect(w.host.get('a')).toBe(false) - const disable = vi.fn(async (_env: string, ids: readonly string[]) => { - for (const id of ids) { - w.host.set(id, false) - } - }) - expect( - await retryWslMoveHostAutomationsLeftOff(userDataPath, { - restore: async (_env, ids) => { - for (const id of ids) { - w.host.set(id, true) - } - // The move is released by another route during the host round trip. - removeCommittedWslMoveCutover(userDataPath, MOVE) - }, - disable - }) - ).toBe(false) - expect(listWslMoveCutovers(userDataPath)).toEqual([]) - // The project is local again: the host copy this retry turned on goes back off. - expect(disable).toHaveBeenCalledWith('wsl:Ubuntu', ['a']) - expect(w.host.get('a')).toBe(false) - }) - - // d3a: a restart cleared the record, so a later undo read the left-off one as the user's "off". - it('a later undo after a restart and failed retries still keeps a left-off one on here', async () => { - const w = world({ a: true }, { a: true }) - w.fail.restore = true - const refused = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (refused.outcome === 'stopped') { - await refused.restore() - } - settleInterruptedWslMoveUndos(userDataPath) - const unreachable = { - restore: async () => { - throw new Error('unreachable') - }, - disable: async () => {} - } - expect(await retryWslMoveHostAutomationsLeftOff(userDataPath, unreachable)).toBe(true) - expect(await retryWslMoveHostAutomationsLeftOff(userDataPath, unreachable)).toBe(true) - expect(w.host.get('a')).toBe(false) - w.fail.restore = false - const later = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (later.outcome !== 'stopped') { - throw new Error('expected stopped') - } - later.applyHere() - expect(w.local.get('a')).toBe(true) - }) - - it('treats a left-off one as on even when only the left-off list survives', async () => { - const seeded = cutover() - if (!seeded) { - throw new Error('expected the move') - } - // Only the left-off list survives (an older build dropped the recorded choice). - writeWslMoveCutover(userDataPath, { ...seeded, hostAutomationsLeftOff: ['a'] }) - const w = world({ a: false }, { a: true }) - const stop = await stopWslMoveHostAutomations(userDataPath, MOVE, ['a'], w.ports) - if (stop.outcome !== 'stopped') { - throw new Error('expected stopped') - } - stop.applyHere() - expect(w.local.get('a')).toBe(true) - }) -}) diff --git a/src/main/persistence/restoring-sessions/cross-host-pane-tab-ids.ts b/src/main/persistence/restoring-sessions/cross-host-pane-tab-ids.ts index 7842bd42b87..d3098be6f3a 100644 --- a/src/main/persistence/restoring-sessions/cross-host-pane-tab-ids.ts +++ b/src/main/persistence/restoring-sessions/cross-host-pane-tab-ids.ts @@ -1,6 +1,6 @@ import type { PersistedState } from '../../../shared/persisted-state-types' import { buildWorktreeIdByTabId } from '../../../shared/workspace-session/workspace-session-host-records' -import { isWslMoveWorkspaceHostOwned } from '../moving-wsl-projects/wsl-move-scope-guard' +import { isWslMoveWorkspaceHostOwned } from '../moving-wsl-projects/quiescence/wsl-move-scope-guard' /** * Tab ids owned by more than one host partition. Legacy alias keys (`tabId:1`) and acknowledgement diff --git a/src/main/persistence/restoring-sessions/session-owner-removal.ts b/src/main/persistence/restoring-sessions/session-owner-removal.ts index 59864fe4399..eb4463bbb28 100644 --- a/src/main/persistence/restoring-sessions/session-owner-removal.ts +++ b/src/main/persistence/restoring-sessions/session-owner-removal.ts @@ -6,7 +6,7 @@ import { type ExecutionHostId } from '../../../shared/execution-host' import '../../../shared/workspace-session/workspace-session-partition-owner' -import { isWslMoveWorkspaceSessionFrozen } from '../moving-wsl-projects/wsl-move-scope-guard' +import { isWslMoveWorkspaceSessionFrozen } from '../moving-wsl-projects/quiescence/wsl-move-scope-guard' import { cloneWorkspaceSessionState, deleteOwnerKeyedSessionFields } from './session-owner-fields' /** Frozen WSL sessions must survive pruning for downgrade. */ diff --git a/src/main/persistence/terminal-topology/duplicate-pty-pane-repair.ts b/src/main/persistence/terminal-topology/duplicate-pty-pane-repair.ts index b6d3b2326d5..005b55b574a 100644 --- a/src/main/persistence/terminal-topology/duplicate-pty-pane-repair.ts +++ b/src/main/persistence/terminal-topology/duplicate-pty-pane-repair.ts @@ -7,7 +7,7 @@ import { import type { TerminalLayoutSnapshot } from '../../../shared/workspace-layout/terminal-tab-types' import type { WorkspaceSessionState } from '../../../shared/workspace-session/workspace-session-state-types' import type { DurableProfileStateMutation } from '../loading-store/store-runtime-state' -import { isWslMoveWorkspaceSessionFrozen } from '../moving-wsl-projects/wsl-move-scope-guard' +import { isWslMoveWorkspaceSessionFrozen } from '../moving-wsl-projects/quiescence/wsl-move-scope-guard' import { findWorktreeIdForTab } from '../restoring-sessions/pane-identity-migration' import { writeRestorable } from './restorable-write' import { diff --git a/src/main/persistence/terminal-topology/layout-command-commit.ts b/src/main/persistence/terminal-topology/layout-command-commit.ts index 2eabe9c93ca..f295da221c7 100644 --- a/src/main/persistence/terminal-topology/layout-command-commit.ts +++ b/src/main/persistence/terminal-topology/layout-command-commit.ts @@ -12,7 +12,7 @@ import { keepPartitionEditorViews, partitionEditorViewsOf } from '../loading-store/workspace-sessions/layout-editor-views' -import { keepWslMoveFrozenSessionsForStore } from '../moving-wsl-projects/wsl-move-session-freeze' +import { keepWslMoveFrozenSessionsForStore } from '../moving-wsl-projects/terminal-state/wsl-move-session-freeze' import { applyCommandToSession, type LayoutLiveContext, diff --git a/src/main/runtime/construction/runtime-repository-command-state.ts b/src/main/runtime/construction/runtime-repository-command-state.ts index a270a35225c..59f39b3725f 100644 --- a/src/main/runtime/construction/runtime-repository-command-state.ts +++ b/src/main/runtime/construction/runtime-repository-command-state.ts @@ -14,7 +14,7 @@ import { RuntimeRepositoryIssueCommand } from '../repositories/runtime-repositor import { ClientHostedBrowserRowPublisher } from '../browser/client-pages/client-hosted-browser-row-publication' import { getRuntimeBrowserPageRegistry } from '../browser/client-pages/runtime-browser-page-registry' import { getBrowserHostLeaseRegistry } from '../browser-host/leases/browser-host-lease-registry-instance' -import { isWslMoveWorktreeBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveWorktreeBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { worktreeRowTarget } from '../../persistence/host-qualified-worktree-meta' import { createBranchSwitchHost, diff --git a/src/main/runtime/integrations/git/runtime-branch-switch-host.ts b/src/main/runtime/integrations/git/runtime-branch-switch-host.ts index 65258fc6308..43c3c669597 100644 --- a/src/main/runtime/integrations/git/runtime-branch-switch-host.ts +++ b/src/main/runtime/integrations/git/runtime-branch-switch-host.ts @@ -6,7 +6,7 @@ import { } from '../../../../shared/worktree/hosted-review-links' import { parseWorkspaceKey } from '../../../../shared/workspace-scope' import { splitWorktreeIdForFilesystem } from '../../../../shared/worktree/id' -import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { worktreeRowTarget } from '../../../persistence/host-qualified-worktree-meta' import type { RuntimeStore } from '../../construction/runtime-store-contract' import { findAgentSwitchBlocker, type AgentSwitchRow } from './branch-switch-agent-blocker' diff --git a/src/main/runtime/integrations/linear/runtime-linear-team-write-commands.ts b/src/main/runtime/integrations/linear/runtime-linear-team-write-commands.ts index a21486762d0..b60f8c828fc 100644 --- a/src/main/runtime/integrations/linear/runtime-linear-team-write-commands.ts +++ b/src/main/runtime/integrations/linear/runtime-linear-team-write-commands.ts @@ -17,7 +17,7 @@ import type { import type { LinearAgentWriteTarget } from './linear-agent-write-target' import type { ResolvedWorktree } from '../../workspaces/catalog/runtime-worktree-path-identity' import { RuntimeLinearDedupeCommands } from './runtime-linear-dedupe-commands' -import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveWorktreeBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { parseWorkspaceKey } from '../../../../shared/workspace-scope' export class RuntimeLinearTeamWriteCommands extends RuntimeLinearDedupeCommands { diff --git a/src/main/runtime/repositories/folder-workspace-deletion.ts b/src/main/runtime/repositories/folder-workspace-deletion.ts index 0c1494bfd1d..e81bb5cb500 100644 --- a/src/main/runtime/repositories/folder-workspace-deletion.ts +++ b/src/main/runtime/repositories/folder-workspace-deletion.ts @@ -2,7 +2,7 @@ import { folderWorkspaceKey } from '../../../shared/workspace-scope' import { assertWslMoveProjectWritable, isLocalWslMoveRow -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { assertUniqueIdWhenRequired, type FolderWorkspaceMutationOptions diff --git a/src/main/runtime/repositories/runtime-preserved-branch-cleanup.ts b/src/main/runtime/repositories/runtime-preserved-branch-cleanup.ts index f7170eb665d..23f47b3f3b4 100644 --- a/src/main/runtime/repositories/runtime-preserved-branch-cleanup.ts +++ b/src/main/runtime/repositories/runtime-preserved-branch-cleanup.ts @@ -16,7 +16,7 @@ import { cleanupUnusedWorktreePushTargetRemote } from '../../ipc/worktree-remote import { getLocalProjectWorktreeGitOptions } from '../../workspaces/execution-host/project-runtime-git-options' import { SshHostNotServedError } from '../../providers/ssh-host-not-served-error' import type { RuntimeStore } from '../construction/runtime-store-contract' -import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { resolveWorktreeRemovalRepoOwner } from '../../workspaces/removal/worktree-removal-repo-owner' import { parseExactWorktreeIdSelector } from '../workspaces/catalog/runtime-worktree-selection' diff --git a/src/main/runtime/repositories/runtime-project-group-controller.ts b/src/main/runtime/repositories/runtime-project-group-controller.ts index 175110e036b..1be8e84cb87 100644 --- a/src/main/runtime/repositories/runtime-project-group-controller.ts +++ b/src/main/runtime/repositories/runtime-project-group-controller.ts @@ -34,7 +34,7 @@ import { assertWslMoveRepoWritable, isLocalWslMoveRow, shouldDropWslMoveProjectUpdate -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export type RuntimeProjectGroupDependencies = { getStore: () => RuntimeStore | null diff --git a/src/main/runtime/repositories/runtime-project-host-setup-controller.ts b/src/main/runtime/repositories/runtime-project-host-setup-controller.ts index 5a0cb4ce49a..043f9ef524e 100644 --- a/src/main/runtime/repositories/runtime-project-host-setup-controller.ts +++ b/src/main/runtime/repositories/runtime-project-host-setup-controller.ts @@ -40,7 +40,7 @@ import { assertWslMoveHostSetupIdWritable, assertWslMoveHostSetupWritable, assertWslMoveReposWritable -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { runtimeVisibleProjectHostSetups } from '../workspaces/catalog/runtime-visible-catalog' import { assertNoProjectWorktreeCreate } from '../../workspaces/creation/worktree-create-in-flight' import { releaseWorktreeCreatePreparationsForRepo } from '../../workspaces/creation/preparation/worktree-create-preparation-project-removal' diff --git a/src/main/runtime/repositories/runtime-repository-fork-backfill.ts b/src/main/runtime/repositories/runtime-repository-fork-backfill.ts index c4682c4c489..ed74f846c04 100644 --- a/src/main/runtime/repositories/runtime-repository-fork-backfill.ts +++ b/src/main/runtime/repositories/runtime-repository-fork-backfill.ts @@ -4,7 +4,7 @@ import { githubAvatarIcon, githubAvatarSlug } from '../../../shared/repo-icon' import { probeRepoUpstream } from '../../github/client/fetch/repo-slug-upstream' import { GhExecutableAbsenceBatch } from '../../git/command-runner/gh-executable-absence-batch' import type { RuntimeStore } from '../construction/runtime-store-contract' -import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { blockedWslDistroForPath, wslDistroForPath } from '../../wsl/filesystem/wsl-unc-access-gate' type MetadataJob = { diff --git a/src/main/runtime/repositories/runtime-repository-issue-command.ts b/src/main/runtime/repositories/runtime-repository-issue-command.ts index 35165b4b358..2f65323946c 100644 --- a/src/main/runtime/repositories/runtime-repository-issue-command.ts +++ b/src/main/runtime/repositories/runtime-repository-issue-command.ts @@ -8,7 +8,7 @@ import { import { isFolderRepo } from '../../../shared/repo-kind' import { joinWorktreeRelativePath } from '../files/paths/runtime-relative-paths' import type { RuntimeStore } from '../construction/runtime-store-contract' -import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' type RuntimeRepositoryIssueCommandDeps = { resolveRepo: (selector: string) => Promise diff --git a/src/main/runtime/repositories/runtime-repository-settings-controller.ts b/src/main/runtime/repositories/runtime-repository-settings-controller.ts index e9829d7f8f5..157632613ef 100644 --- a/src/main/runtime/repositories/runtime-repository-settings-controller.ts +++ b/src/main/runtime/repositories/runtime-repository-settings-controller.ts @@ -6,7 +6,7 @@ import type { GhAccountBinding } from '../../../shared/github/account-binding' import { invalidateAuthorizedRootsCache } from '../../ipc/worktrees/removal/registered-worktree-roots-cache' import { prepareLocalWorktreeRootForRepo } from '../../workspaces/creation/worktree-root-preparation' import type { RuntimeStore } from '../construction/runtime-store-contract' -import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { teardownStops } from '../workspaces/removal/owned-session-teardown-policy' import { assertNoProjectWorktreeCreate } from '../../workspaces/creation/worktree-create-in-flight' import { releaseWorktreeCreatePreparationsForRepo } from '../../workspaces/creation/preparation/worktree-create-preparation-project-removal' diff --git a/src/main/runtime/repositories/runtime-repository-sparse-presets.ts b/src/main/runtime/repositories/runtime-repository-sparse-presets.ts index 87f402a9b79..af7b449c5bb 100644 --- a/src/main/runtime/repositories/runtime-repository-sparse-presets.ts +++ b/src/main/runtime/repositories/runtime-repository-sparse-presets.ts @@ -5,7 +5,7 @@ import { normalizeSparsePresetName } from '../../ipc/repos/sparse-preset-validation' import type { RuntimeStore } from '../construction/runtime-store-contract' -import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' type RuntimeRepositorySparsePresetDependencies = { getStore: () => RuntimeStore | null diff --git a/src/main/runtime/rpc/methods/workspace-layout/workspace-layout-apply.test.ts b/src/main/runtime/rpc/methods/workspace-layout/workspace-layout-apply.test.ts index 2dc84aef7e6..09f062a2444 100644 --- a/src/main/runtime/rpc/methods/workspace-layout/workspace-layout-apply.test.ts +++ b/src/main/runtime/rpc/methods/workspace-layout/workspace-layout-apply.test.ts @@ -32,7 +32,7 @@ vi.mock('../../../../../shared/layout-owner-switch', () => ({ ORCA_LAYOUT_OWNER_ const frozen = vi.hoisted(() => ({ workspaces: new Set() })) vi.mock( - '../../../../persistence/moving-wsl-projects/wsl-move-scope-guard', + '../../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard', async (importOriginal) => ({ ...(await importOriginal()), isWslMoveWorkspaceSessionFrozen: (workspace: string) => frozen.workspaces.has(workspace) diff --git a/src/main/runtime/session-lifecycle/projection/restored-pane-materialize.ts b/src/main/runtime/session-lifecycle/projection/restored-pane-materialize.ts index 282a9594848..24b4762a578 100644 --- a/src/main/runtime/session-lifecycle/projection/restored-pane-materialize.ts +++ b/src/main/runtime/session-lifecycle/projection/restored-pane-materialize.ts @@ -30,7 +30,7 @@ import type { WorkspaceLayoutStream } from '../../terminal/surface/workspace-lay import { getDaemonHistoryDir } from '../../../daemon/launch/daemon-launch-paths' import { HistoryReader } from '../../../daemon/history/restoration/history-reader' import { servesWslMovedPaneHistory } from '../../../orcad/orcad-migration-wsl-destination' -import { movedPaneHistorySessionId } from '../../../persistence/migrating-orcad-catalog/orcad-terminal-history-installer' +import { movedPaneHistorySessionId } from '../../../persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer' import { makePaneKey, parsePaneKey } from '../../../../shared/workspace-layout/stable-pane-id' import { agentProviderSessionsEqual } from '../../../../shared/agent-session/lifecycle/agent-session-resume' import { worktreeIdsEqual } from '../../../../shared/worktree/id' diff --git a/src/main/runtime/sidebar-inputs/orca-runtime-sidebar-temporal.ts b/src/main/runtime/sidebar-inputs/orca-runtime-sidebar-temporal.ts index 86fcae7ae67..78c56efe1d5 100644 --- a/src/main/runtime/sidebar-inputs/orca-runtime-sidebar-temporal.ts +++ b/src/main/runtime/sidebar-inputs/orca-runtime-sidebar-temporal.ts @@ -33,7 +33,7 @@ import { WORKSPACE_RECORD_DOMAINS } from '../../persistence/profile-save-domains import { isWslMoveProjectBlocked, wslMoveProjectRefForWorkspace -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' /** * Feeds main's sleeping retention, and owns the host's sort stamps: clients sort by those, so main diff --git a/src/main/runtime/sidebar-inputs/orca-runtime-windowless-terminal-activity.ts b/src/main/runtime/sidebar-inputs/orca-runtime-windowless-terminal-activity.ts index 4eecc2e8cbc..c3da1236aa6 100644 --- a/src/main/runtime/sidebar-inputs/orca-runtime-windowless-terminal-activity.ts +++ b/src/main/runtime/sidebar-inputs/orca-runtime-windowless-terminal-activity.ts @@ -17,7 +17,7 @@ import type { RuntimePtyWorktreeRecord } from '../terminal/records/runtime-termi import { isWslMoveProjectBlocked, wslMoveProjectRefForWorkspace -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' type Runtime = OrcaRuntimeWithWslMoveTerminalFacts diff --git a/src/main/runtime/terminal/layout/runtime-layout-apply.ts b/src/main/runtime/terminal/layout/runtime-layout-apply.ts index ce2bcfca80f..01777cc7ea9 100644 --- a/src/main/runtime/terminal/layout/runtime-layout-apply.ts +++ b/src/main/runtime/terminal/layout/runtime-layout-apply.ts @@ -9,7 +9,7 @@ import type { import type { TerminalLeafMoveRequest } from '../../../../shared/workspace-layout/terminal-leaf-move' import { renameTabCommandsOf } from '../../../../shared/workspace-layout/workspace-layout-commands' import { markAgentLaunchesClosedByUser } from '../../../agent-launch/agent-launch-pane-attachment' -import { isWslMoveWorkspaceSessionFrozen } from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { isWslMoveWorkspaceSessionFrozen } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import type { RuntimeStore } from '../../construction/runtime-store-contract' /** Route tab commands to their holding partitions; group trees and browser records use the workspace partition. */ diff --git a/src/main/runtime/workspaces/catalog/runtime-visible-catalog.ts b/src/main/runtime/workspaces/catalog/runtime-visible-catalog.ts index 2bfa3d4051b..93d585d57a7 100644 --- a/src/main/runtime/workspaces/catalog/runtime-visible-catalog.ts +++ b/src/main/runtime/workspaces/catalog/runtime-visible-catalog.ts @@ -18,7 +18,7 @@ import { visibleProjectGroups, visibleProjectHostSetups, visibleRepos -} from '../../../persistence/migrating-orcad-catalog/orcad-source-visibility' +} from '../../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-visibility' import type { RuntimeStore } from '../../construction/runtime-store-contract' type CatalogSource = Pick< diff --git a/src/main/runtime/workspaces/catalog/runtime-worktree-filesystem.ts b/src/main/runtime/workspaces/catalog/runtime-worktree-filesystem.ts index 3393bdf6328..d1eec9e4a8d 100644 --- a/src/main/runtime/workspaces/catalog/runtime-worktree-filesystem.ts +++ b/src/main/runtime/workspaces/catalog/runtime-worktree-filesystem.ts @@ -18,7 +18,7 @@ import { mergeRuntimeFolderWorkspace } from './runtime-folder-workspace' import type { RuntimeStore } from '../../construction/runtime-store-contract' -import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { hostWorktreeTargetForRepo } from '../../../persistence/host-qualified-worktree-meta' /** Callers hold a local removal route; an `ssh:` or `runtime:` host is refused before this. */ diff --git a/src/main/runtime/workspaces/catalog/wsl-moved-project-chat-runtime.test.ts b/src/main/runtime/workspaces/catalog/wsl-moved-project-chat-runtime.test.ts index bf34ad779d1..01967365dfc 100644 --- a/src/main/runtime/workspaces/catalog/wsl-moved-project-chat-runtime.test.ts +++ b/src/main/runtime/workspaces/catalog/wsl-moved-project-chat-runtime.test.ts @@ -20,7 +20,7 @@ import { seedWslMoveCutover } from '../../../persistence/__fixtures__/wsl-mover/ import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { OrcaRuntimeService } from '../../orca-runtime' import type { ResolvedWorktree } from './runtime-worktree-path-identity' import type { ResolvedWorktreeSnapshot } from './runtime-resolved-worktree-cache' diff --git a/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.test.ts b/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.test.ts index 747cf42fbcc..c65653e05f1 100644 --- a/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.test.ts +++ b/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.test.ts @@ -8,7 +8,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import type { Repo } from '../../../../shared/repo-types' import type { GitWorktreeInfo } from '../../../../shared/worktree/types' import { diff --git a/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.ts b/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.ts index e0ba12251e5..a0f95bcd8d8 100644 --- a/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.ts +++ b/src/main/runtime/workspaces/creation/runtime-provisioned-root-adoption.ts @@ -13,7 +13,7 @@ import { } from '../../../workspaces/catalog/provisioned-root-checkout' import { gitExecFileAsync } from '../../../git/command-runner/git-exec-file' import type { RuntimeStore } from '../../construction/runtime-store-contract' -import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { hostWorktreeTargetForRepo } from '../../../persistence/host-qualified-worktree-meta' export type RuntimeProvisionedRootRequest = ProvisionedRootRequest & { expectedPath: string } diff --git a/src/main/runtime/workspaces/creation/workspace-creation.ts b/src/main/runtime/workspaces/creation/workspace-creation.ts index c921f5bc2f5..05099a66f69 100644 --- a/src/main/runtime/workspaces/creation/workspace-creation.ts +++ b/src/main/runtime/workspaces/creation/workspace-creation.ts @@ -24,17 +24,16 @@ import { prepareRuntimeLocalWorktreeSetup } from './runtime-local-worktree-setup' import { invalidateAuthorizedRootsCacheForRepo } from '../../../ipc/worktrees/removal/registered-worktree-roots-scoped-invalidation' -import { - startRuntimeLocalWorktreeTerminals, - type RuntimeLocalWorktreeTerminalPorts -} from '../startup/runtime-local-worktree-terminal-startup' +import { startRuntimeLocalWorktreeTerminals } from '../startup/runtime-local-worktree-terminal-startup' +import type { RuntimeLocalWorktreeTerminalPorts } from '../startup/runtime-local-worktree-terminal-startup' import { trackRuntimeWorkspaceCreate } from '../../../workspaces/creation/workspace-create-telemetry' import type { RuntimeWorkspaceCreateEvents } from '../../../workspaces/creation/workspace-create-telemetry' + import { createdWorkspaceActivationCallbacks, wslUserAct } from '../startup/workspace-create-activation' -import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveRepoWritable } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { resolveManagedWorktreeCreateStartup } from '../startup/managed-worktree-create-startup' import type { WorkspaceCreationHandle } from '../lifecycle/workspace-lifecycle-creations' import { workspaceLifecycleKey } from '../lifecycle/workspace-lifecycle-commands' diff --git a/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata-wsl-move.test.ts b/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata-wsl-move.test.ts index 2eea7b37654..eac26f34247 100644 --- a/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata-wsl-move.test.ts +++ b/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata-wsl-move.test.ts @@ -15,7 +15,7 @@ import { WslMoveProjectFencedError, loadWslMoveFence, resetWslMoveFenceForTests -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { persistRuntimeManagedWorktreeSortOrder, updateRuntimeManagedWorktreeMetadata diff --git a/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata.ts b/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata.ts index 13acf959498..ffb672c291f 100644 --- a/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata.ts +++ b/src/main/runtime/workspaces/metadata/runtime-managed-worktree-metadata.ts @@ -21,7 +21,7 @@ import { isWslMoveWorkspaceBlocked, shouldDropWslMoveProjectUpdate, wslMoveProjectRefForWorkspace -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { RuntimeLineageError, explicitParentError } from '../lineage/runtime-lineage-error' import type { ResolvedWorkspaceParent } from '../lineage/runtime-worktree-lineage-resolution' import { assertParentInAnotherStore } from '../lineage/cross-store-parent-store-check' diff --git a/src/main/runtime/workspaces/metadata/runtime-wsl-move-terminal-facts.ts b/src/main/runtime/workspaces/metadata/runtime-wsl-move-terminal-facts.ts index 1f463f6da4b..c07c43e6ddf 100644 --- a/src/main/runtime/workspaces/metadata/runtime-wsl-move-terminal-facts.ts +++ b/src/main/runtime/workspaces/metadata/runtime-wsl-move-terminal-facts.ts @@ -1,5 +1,5 @@ import { OrcaRuntimeWithClientTerminalScrollback } from '../../terminal/output/runtime-client-scrollback' -import type { WslMoveLiveTerminal } from '../../../persistence/moving-wsl-projects/wsl-move-gate-facts' +import type { WslMoveLiveTerminal } from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-gate-facts' export abstract class OrcaRuntimeWithWslMoveTerminalFacts extends OrcaRuntimeWithClientTerminalScrollback { /** The pane a live terminal shows, including one the window has not reopened since a relaunch. */ diff --git a/src/main/runtime/workspaces/removal/workspace-removal.ts b/src/main/runtime/workspaces/removal/workspace-removal.ts index f4b8967642b..086bee323a6 100644 --- a/src/main/runtime/workspaces/removal/workspace-removal.ts +++ b/src/main/runtime/workspaces/removal/workspace-removal.ts @@ -36,7 +36,7 @@ import { removeOrphanOrFolderWorktree } from './workspace-registration-removal' import { assertWslMoveWorkspaceWritable, isWslMoveSourceHost -} from '../../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' export abstract class OrcaRuntimeWithRemoveManagedWorktree extends RuntimeWorkspaceMetadata { abstract removeWorktreeMetadataAndHistory( diff --git a/src/main/ssh/migration-source/orcad-migration-source-assertions.ts b/src/main/ssh/migration-source/orcad-migration-source-assertions.ts index c722d0daaef..4ccdaba6b70 100644 --- a/src/main/ssh/migration-source/orcad-migration-source-assertions.ts +++ b/src/main/ssh/migration-source/orcad-migration-source-assertions.ts @@ -7,7 +7,7 @@ import type { OrcadMigrationSourceCutover } from '../../../shared/orcad-migratio import { exportOrcadMigrationManifest, type OrcadMigrationExportedBlob -} from '../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +} from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { resolveOrcadMigrationFence } from './orcad-migration-source-fence' import { confirmOrcadMigrationTerminalsUnderFence } from './orcad-migration-terminal-gate' import { collectUntransferredDependentBlockers } from '../targets/ssh-target-orcad-dependents' diff --git a/src/main/ssh/migration-source/orcad-migration-source-fence.test.ts b/src/main/ssh/migration-source/orcad-migration-source-fence.test.ts index 94b129a5892..cb0f46851f6 100644 --- a/src/main/ssh/migration-source/orcad-migration-source-fence.test.ts +++ b/src/main/ssh/migration-source/orcad-migration-source-fence.test.ts @@ -9,14 +9,14 @@ import { Store } from '../../persistence/loading-store/store' import { listOrcadMigrationSourceCutovers, orcadMigrationCutoverJournalDirectory -} from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { fenceOrcadMigrationSource, resolveOrcadMigrationFence } from './orcad-migration-source-fence' import type { OrcadMigrationTerminalVerdict } from './orcad-migration-terminal-gate' import { SshTargetOrcadClaims } from '../targets/ssh-target-orcad-claims' -import '../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import '../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import '../../../shared/orcad-migration/orcad-migration-manifest-validation' const TARGET: SshTarget = { diff --git a/src/main/ssh/migration-source/orcad-migration-source-fence.ts b/src/main/ssh/migration-source/orcad-migration-source-fence.ts index c8c41da60e4..0d438fb070f 100644 --- a/src/main/ssh/migration-source/orcad-migration-source-fence.ts +++ b/src/main/ssh/migration-source/orcad-migration-source-fence.ts @@ -8,12 +8,12 @@ import { } from '../../../shared/orcad-migration/orcad-migration-source-cutover' import type { SshTarget } from '../../../shared/ssh-types' import { assertOrcadMigrationRequestFits } from '../../managed-server/migration/catalog/orcad-migration-request-budget' -import { createOrcadMigrationManifest } from '../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import { createOrcadMigrationManifest } from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { findOrcadMigrationSourceCutoverForTarget, removeOrcadMigrationSourceCutover, writeOrcadMigrationSourceCutover -} from '../../persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +} from '../../persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { confirmOrcadMigrationTerminalsUnderFence, type OrcadMigrationTerminalVerdict diff --git a/src/main/ssh/migration-source/orcad-migration-ssh-relay-source.ts b/src/main/ssh/migration-source/orcad-migration-ssh-relay-source.ts index 5b2c596323e..5239d147dbd 100644 --- a/src/main/ssh/migration-source/orcad-migration-ssh-relay-source.ts +++ b/src/main/ssh/migration-source/orcad-migration-ssh-relay-source.ts @@ -1,8 +1,8 @@ import { ORCAD_MIGRATION_SSH_RELAY_SOURCE_KIND } from '../../../shared/orcad-migration/orcad-migration-source-kind' import type { SshTarget } from '../../../shared/ssh-types' -import { collectOrcadMigrationSourceCatalog } from '../../persistence/migrating-orcad-catalog/orcad-source-catalog' +import { collectOrcadMigrationSourceCatalog } from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-source-catalog' import type { Store } from '../../persistence/loading-store/store' -import { createOrcadMigrationManifest } from '../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +import { createOrcadMigrationManifest } from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { IDENTITY_ORCAD_MIGRATION_PATH_REWRITER } from '../../persistence/migrating-orcad-catalog/path-rewrite/orcad-migration-path-rewrite' import type { OrcadMigrationSource, diff --git a/src/main/ssh/targets/ssh-target-orcad-preflight.ts b/src/main/ssh/targets/ssh-target-orcad-preflight.ts index 35514ec135a..2e5307f4b89 100644 --- a/src/main/ssh/targets/ssh-target-orcad-preflight.ts +++ b/src/main/ssh/targets/ssh-target-orcad-preflight.ts @@ -8,7 +8,7 @@ import type { import { createOrcadMigrationManifest, type OrcadMigrationExportStore -} from '../../persistence/migrating-orcad-catalog/orcad-migration-manifest-export' +} from '../../persistence/migrating-orcad-catalog/source/catalog/orcad-migration-manifest-export' import { collectTargetCatalogBlockers, resolveOrcadPreflightTarget diff --git a/src/main/startup/main-process-ready-foundation.ts b/src/main/startup/main-process-ready-foundation.ts index 6d94fca06e8..12b535e211c 100644 --- a/src/main/startup/main-process-ready-foundation.ts +++ b/src/main/startup/main-process-ready-foundation.ts @@ -15,8 +15,8 @@ import { browserSiteDisplayController } from '../browser/site-settings/display/b import { ensureActiveOrcaProfile } from '../orca-profiles/profile-index-store' import { getCanonicalUserDataPath } from '../persistence/loading-store/user-data-path' import { getAppEnvironment } from '../../shared/app-environment' -import { loadWslMoveFence } from '../persistence/moving-wsl-projects/wsl-move-scope-guard' -import { startWslMoveStartup } from '../persistence/moving-wsl-projects/wsl-move-startup' +import { loadWslMoveFence } from '../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' +import { startWslMoveStartup } from '../persistence/moving-wsl-projects/startup/wsl-move-startup' import { startWslHostsPolicyLiveUpdates } from '../wsl/host-lifecycle/wsl-hosts-policy-live-update' import { runPendingWslDriveUncConversions } from '../wsl/filesystem/wsl-drive-unc-conversion-startup' import { createProfileStateStoreForStartup } from '../persistence/profile-state/startup/profile-state-startup-authority' diff --git a/src/main/startup/main-process-ready-runtime.ts b/src/main/startup/main-process-ready-runtime.ts index 10889bba800..65aefc3637b 100644 --- a/src/main/startup/main-process-ready-runtime.ts +++ b/src/main/startup/main-process-ready-runtime.ts @@ -40,7 +40,7 @@ import { startSpeechModelWarmup } from '../speech/speech-model-warmup' import { logStartupMilestone } from './startup-diagnostics' import { refreshInstalledOpenCodeStatusPlugins } from '../opencode/opencode-status-plugin-startup-refresh' import { pruneDesktopOrcadArtifactCache } from '../orcad/orcad-artifact-cache-retention' -import { runGatedWslMoveDesktopRewritePass } from '../persistence/moving-wsl-projects/wsl-move-desktop-rewrite' +import { runGatedWslMoveDesktopRewritePass } from '../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite' import { ORCA_LAYOUT_OWNER_IS_MAIN } from '../../shared/layout-owner-switch' import { repairDuplicatePtyPanesOnStart } from '../runtime/terminal/identity/moved-pane-owner-rekey' import { WslUsageReporter } from '../telemetry/wsl-usage-reporter' diff --git a/src/main/telemetry/wsl-move-telemetry.ts b/src/main/telemetry/wsl-move-telemetry.ts index e0db23da55c..f279bc8ff97 100644 --- a/src/main/telemetry/wsl-move-telemetry.ts +++ b/src/main/telemetry/wsl-move-telemetry.ts @@ -10,7 +10,7 @@ import { } from '../../shared/telemetry-wsl-move-event-schemas' import type { WslMoveRefusalCode, WslMoveResult } from '../../shared/wsl-move/wsl-move-driver-types' import type { WslMoveCutoverPhase } from '../../shared/wsl-move/wsl-move-cutover' -import type { WslMoveDriverDeps } from '../persistence/moving-wsl-projects/wsl-move-driver-ports' +import type { WslMoveDriverDeps } from '../persistence/moving-wsl-projects/execution/wsl-move-driver-ports' import { track } from './client' type Props = EventProps<'wsl_move'> diff --git a/src/main/updater/lifecycle/updater-wsl-move-install-hold.test.ts b/src/main/updater/lifecycle/updater-wsl-move-install-hold.test.ts index 0d8b9d0aa85..47f10efbb6e 100644 --- a/src/main/updater/lifecycle/updater-wsl-move-install-hold.test.ts +++ b/src/main/updater/lifecycle/updater-wsl-move-install-hold.test.ts @@ -5,7 +5,7 @@ import { wslMoveClaimRefusal, releaseWslMoveRun, type RunningWslMove -} from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import { wslMoveInstallHold } from './updater-wsl-move-install-hold' const ends: (() => void)[] = [] diff --git a/src/main/updater/lifecycle/updater-wsl-move-install-hold.ts b/src/main/updater/lifecycle/updater-wsl-move-install-hold.ts index 0da3a0c3127..a735ff8fcf7 100644 --- a/src/main/updater/lifecycle/updater-wsl-move-install-hold.ts +++ b/src/main/updater/lifecycle/updater-wsl-move-install-hold.ts @@ -2,7 +2,7 @@ import { translateMain } from '../../i18n/main-i18n' import { isAnyWslMoveRunning, isWslMoveUndoRunning -} from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' /** * Why an install must wait: quitting would interrupt a move (it recovers, but the projects stay diff --git a/src/main/updater/updater.wsl-move-install-hold-driver.test.ts b/src/main/updater/updater.wsl-move-install-hold-driver.test.ts index d6489eeb528..af418752775 100644 --- a/src/main/updater/updater.wsl-move-install-hold-driver.test.ts +++ b/src/main/updater/updater.wsl-move-install-hold-driver.test.ts @@ -15,11 +15,11 @@ import type { WslMoveResult } from '../../shared/wsl-move/wsl-move-driver-types' import { loadUpdaterModule, warmUpdaterModule } from './testing/updater-test-module-loader' import { updaterMainWindow } from './testing/updater-test-main-window' import type * as RigModule from '../persistence/__fixtures__/wsl-mover/wsl-move-kill-rig' -import type * as RewriteStores from '../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' +import type * as RewriteStores from '../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' import type * as Driver from '../persistence/moving-wsl-projects/wsl-move-driver' -import type * as RunningMoves from '../persistence/moving-wsl-projects/wsl-move-running-moves' +import type * as RunningMoves from '../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import type * as ReleaseHere from '../ipc/wsl/wsl-move-release-here' -import type * as Retention from '../persistence/moving-wsl-projects/wsl-move-retention' +import type * as Retention from '../persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention' const { nativeUpdaterMock, @@ -97,11 +97,12 @@ async function loadMover(): Promise { rig: fixture.createWslMoveKillRig(), fixture, driver: await import('../persistence/moving-wsl-projects/wsl-move-driver'), - moves: await import('../persistence/moving-wsl-projects/wsl-move-running-moves'), + moves: await import('../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves'), rewriteStores: - await import('../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores'), + await import('../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores'), releaseHere: await import('../ipc/wsl/wsl-move-release-here'), - retention: await import('../persistence/moving-wsl-projects/wsl-move-retention') + retention: + await import('../persistence/moving-wsl-projects/cutover-recovery/wsl-move-retention') } mover = loaded return loaded diff --git a/src/main/workspaces/catalog/imported-folder-project-link.ts b/src/main/workspaces/catalog/imported-folder-project-link.ts index 022b9f06583..89bf3ea8827 100644 --- a/src/main/workspaces/catalog/imported-folder-project-link.ts +++ b/src/main/workspaces/catalog/imported-folder-project-link.ts @@ -11,7 +11,7 @@ import { import type { ProjectHostSetupExistingFolderArgs } from '../../../shared/project-types' import type { Repo } from '../../../shared/repo-types' import type { RuntimeStore } from '../../runtime/construction/runtime-store-contract' -import { assertWslMoveHostSetupWritable } from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +import { assertWslMoveHostSetupWritable } from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { readCurrentGitRemoteIdentity } from './repo-git-remote-identity' export type RepositoryMetadataOwner = { diff --git a/src/main/workspaces/catalog/repo-backfill-wsl-move.test.ts b/src/main/workspaces/catalog/repo-backfill-wsl-move.test.ts index 97457fb3d2c..2caeb48302a 100644 --- a/src/main/workspaces/catalog/repo-backfill-wsl-move.test.ts +++ b/src/main/workspaces/catalog/repo-backfill-wsl-move.test.ts @@ -11,7 +11,7 @@ import { seedWslMoveCutover } from '../../persistence/__fixtures__/wsl-mover/wsl import { loadWslMoveFence, resetWslMoveFenceForTests -} from '../../persistence/moving-wsl-projects/wsl-move-scope-guard' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-scope-guard' import { probeGitRemoteIdentity } from './repo-git-remote-identity' import { enrichMissingRepoGitRemoteIdentities, diff --git a/src/main/workspaces/catalog/repo-git-remote-identity-enrichment.ts b/src/main/workspaces/catalog/repo-git-remote-identity-enrichment.ts index c1ef9a5f50b..093d4bcb11d 100644 --- a/src/main/workspaces/catalog/repo-git-remote-identity-enrichment.ts +++ b/src/main/workspaces/catalog/repo-git-remote-identity-enrichment.ts @@ -14,7 +14,7 @@ import { probeGitRemoteIdentity } from './repo-git-remote-identity' import { getProjectRuntimeReadGitOptions } from '../execution-host/project-runtime-git-options' import { isLocalGitRuntimeRouterInstalled } from '../../git/command-runner/local-git-runtime-route' import type { ProjectRuntimeResolutionStore } from '../execution-host/local-project-runtime-resolution' -import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { blockedWslDistroForPath, wslDistroForPath } from '../../wsl/filesystem/wsl-unc-access-gate' const NO_IDENTITY_RETRY_TTL_MS = 5 * 60 * 1000 diff --git a/src/main/workspaces/catalog/worktree-lineage-pruning.ts b/src/main/workspaces/catalog/worktree-lineage-pruning.ts index d98125bee12..001c6e6b80b 100644 --- a/src/main/workspaces/catalog/worktree-lineage-pruning.ts +++ b/src/main/workspaces/catalog/worktree-lineage-pruning.ts @@ -7,7 +7,7 @@ import { isWorkspaceKey, parseWorkspaceKey } from '../../../shared/workspace-sco import { splitWorktreeId } from '../../../shared/worktree/id' import { worktreeRetentionPathComparisonKey } from './worktree-retention-path-comparison' import type { Store } from '../../persistence/loading-store/store' -import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/wsl-move-background-backoff' +import { isWslMoveRepoBlocked } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-background-backoff' import { hostWorktreeTarget } from '../../../shared/worktree/host-qualified-identity' type WorktreeLineagePruningStore = Pick & diff --git a/src/main/wsl/execution/wsl-guest-process-table.ts b/src/main/wsl/execution/wsl-guest-process-table.ts index d0c4907ff57..fc0fd88ae78 100644 --- a/src/main/wsl/execution/wsl-guest-process-table.ts +++ b/src/main/wsl/execution/wsl-guest-process-table.ts @@ -6,7 +6,7 @@ import { parseWslGuestPaneProcesses, WSL_GUEST_PANE_PROCESS_SCRIPT, type WslGuestProcessRow -} from '../../persistence/moving-wsl-projects/wsl-move-guest-foreground' +} from '../../persistence/moving-wsl-projects/quiescence/wsl-move-guest-foreground' import { runWslProcess } from './wsl-runner' import { blockedWslDistroForPath } from '../filesystem/wsl-unc-access-gate' diff --git a/src/main/wsl/filesystem/wsl-drive-unc-conversion-journal.ts b/src/main/wsl/filesystem/wsl-drive-unc-conversion-journal.ts index d3b2930c07d..e38353b3c33 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-conversion-journal.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-conversion-journal.ts @@ -8,7 +8,7 @@ * - `profile-rewritten`: the profile names the drive paths; the other stores only go forward. */ import { isRecord } from '../../../shared/orcad-migration/orcad-migration-manifest-fields' -import { createMigrationJournalDirectory } from '../../persistence/migrating-orcad-catalog/migration-journal-directory' +import { createMigrationJournalDirectory } from '../../persistence/migrating-orcad-catalog/cutover-journals/migration-journal-directory' export const WSL_DRIVE_UNC_CONVERSION_PHASES = ['prepared', 'profile-rewritten'] as const export type WslDriveUncConversionPhase = (typeof WSL_DRIVE_UNC_CONVERSION_PHASES)[number] diff --git a/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.test.ts b/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.test.ts index e167e01f64f..8b89d710182 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.test.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.test.ts @@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { getDefaultPersistedState } from '../../../shared/constants' import type { PersistedState } from '../../../shared/persisted-state-types' -import '../../persistence/moving-wsl-projects/wsl-move-fence' +import '../../persistence/moving-wsl-projects/quiescence/wsl-move-fence' import { listWslDriveUncConversions, writeWslDriveUncConversion diff --git a/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.ts b/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.ts index ef3878dfca0..51cb0d031b0 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-conversion-run.ts @@ -12,8 +12,8 @@ import type { WslDriveUncConversionResult } from '../../../shared/wsl-drive-unc-conversion-types' import type { WslMoveRefusal } from '../../../shared/wsl-move/wsl-move-driver-types' -import type { WslMoveTerminalScope } from '../../persistence/moving-wsl-projects/wsl-move-driver-ports' -import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/wsl-move-scope' +import type { WslMoveTerminalScope } from '../../persistence/moving-wsl-projects/execution/wsl-move-driver-ports' +import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-scope' import { listWslDriveUncConversionsForProfile, writeWslDriveUncConversion diff --git a/src/main/wsl/filesystem/wsl-drive-unc-conversion-stores.ts b/src/main/wsl/filesystem/wsl-drive-unc-conversion-stores.ts index 316347fcfa9..2dbdaea8eb5 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-conversion-stores.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-conversion-stores.ts @@ -13,7 +13,7 @@ import { syncDirectoryDurablySync, writeFileDurableSync } from '../../filesystem/durable-file-write' -import { rewriteWslMoveOrchestrationHistoryFile } from '../../persistence/moving-wsl-projects/wsl-move-orchestration-history-rewrite' +import { rewriteWslMoveOrchestrationHistoryFile } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-orchestration-history-rewrite' import Database from '../../sqlite/sync-database' import { hashWorktreeId } from '../../pty/history/terminal-history-id' diff --git a/src/main/wsl/filesystem/wsl-drive-unc-identity-rewrite.ts b/src/main/wsl/filesystem/wsl-drive-unc-identity-rewrite.ts index 7a8ac4fef03..aaed4ddbe61 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-identity-rewrite.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-identity-rewrite.ts @@ -16,7 +16,7 @@ import { getRepoIdFromWorktreeId } from '../../../shared/worktree/id' import { parseEditorFileId, WSL_MOVE_FREE_TEXT_KEYS -} from '../../persistence/moving-wsl-projects/wsl-move-canonical-form' +} from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-canonical-form' import { rewriteOrcadMigrationPathValue, type OrcadMigrationPathRewriter diff --git a/src/main/wsl/filesystem/wsl-drive-unc-project-scope.ts b/src/main/wsl/filesystem/wsl-drive-unc-project-scope.ts index ead13564e00..904ae4cd387 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-project-scope.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-project-scope.ts @@ -12,7 +12,7 @@ import { normalizeRuntimePathForComparison } from '../../../shared/cross-platfor import { rewriteWorktreeIdPath } from '../../../shared/worktree/id' import { wslUncDrivePathToWindows } from '../../../shared/wsl-paths' -import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/wsl-move-scope' +import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-scope' import type { WindowsDriveMount } from './wsl-guest-drive-mountinfo' import { wslUncPathIsWindowsDriveFolder } from './wsl-drive-unc-mounts' diff --git a/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.test.ts b/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.test.ts index 10dbd754cba..b0078d3324b 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.test.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.test.ts @@ -9,7 +9,7 @@ import { WSL_MOVER_DISTRO, type WslMoverPaths } from '../../persistence/__fixtures__/wsl-mover/wsl-mover-profile-rows' -import type { WslMoveProjectionInput } from '../../persistence/moving-wsl-projects/wsl-move-state-projection' +import type { WslMoveProjectionInput } from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-state-projection' import { WslDriveUncKeyCollisionError } from './wsl-drive-unc-identity-rewrite' import { rewriteWslDriveUncState } from './wsl-drive-unc-state-rewrite' diff --git a/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.ts b/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.ts index ba15cf4f68e..2947cd711ff 100644 --- a/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.ts +++ b/src/main/wsl/filesystem/wsl-drive-unc-state-rewrite.ts @@ -18,7 +18,7 @@ import { PTY_SESSION_ID_SEPARATOR } from '../../../shared/terminal/pty/lifecycle import { isWorkspaceKey, parseWorkspaceKey } from '../../../shared/workspace-scope' import { withCrossStoreChildKey } from '../../../shared/worktree/cross-store-lineage-records' import { WSL_DRIVE_UNC_STATE_DISPOSITIONS } from '../../../shared/wsl-drive-unc-state-dispositions' -import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/wsl-move-scope' +import { wslMoveRepoPaths } from '../../persistence/moving-wsl-projects/manifest-scope/wsl-move-scope' import { withoutDiscoveryShadows } from './wsl-drive-unc-discovery-shadows' import { wslUncDrivePathToWindows } from '../../../shared/wsl-paths' import { diff --git a/src/main/wsl/host-lifecycle/wsl-host-automation-enable.ts b/src/main/wsl/host-lifecycle/wsl-host-automation-enable.ts index aef7231ff8f..9a28c2ac5d0 100644 --- a/src/main/wsl/host-lifecycle/wsl-host-automation-enable.ts +++ b/src/main/wsl/host-lifecycle/wsl-host-automation-enable.ts @@ -8,7 +8,7 @@ import { getPreferredPairingOffer } from '../../../shared/remote-runtime/host-ca import { resolveEnvironment } from '../../../shared/remote-runtime/host-store/runtime-environment-store' import { sendSupportedMigrationRequest } from '../../managed-server/migration/catalog/orcad-migration-request' import { getWslHostService } from './wsl-host-service-instance' -import type { WslMoveMovedAutomation } from '../../persistence/moving-wsl-projects/wsl-move-host-automations-rewrite' +import type { WslMoveMovedAutomation } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-host-automations-rewrite' // The host's automation service message for an id it does not hold. export const AUTOMATION_NOT_FOUND = 'Automation not found' diff --git a/src/main/wsl/host-lifecycle/wsl-host-gate-startup.ts b/src/main/wsl/host-lifecycle/wsl-host-gate-startup.ts index 64c689a27a3..afdb8533428 100644 --- a/src/main/wsl/host-lifecycle/wsl-host-gate-startup.ts +++ b/src/main/wsl/host-lifecycle/wsl-host-gate-startup.ts @@ -4,7 +4,7 @@ import { wslHostsPolicyState, type WslHostsPolicy } from '../../../shared/wsl-hosts-policy' -import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/wsl-move-cutover-journal' +import { listWslMoveCutovers } from '../../persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' import { configureWslHostsGate } from './wsl-host-gate' import { readCachedWslHostsPolicy } from './wsl-hosts-policy-live-update' diff --git a/src/main/wsl/orcad/wsl-orcad-deploy.ts b/src/main/wsl/orcad/wsl-orcad-deploy.ts index 5505eb2c432..8901944fd21 100644 --- a/src/main/wsl/orcad/wsl-orcad-deploy.ts +++ b/src/main/wsl/orcad/wsl-orcad-deploy.ts @@ -31,7 +31,7 @@ import { deployOrcad, type OrcadDeployOptions } from '../../managed-server/install/orcad-remote-deploy' -import { isWslMoveUnderwayOnHost } from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +import { isWslMoveUnderwayOnHost } from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import { readLocalFullVersion } from '../../managed-server/install/remote-versioned-install' import { createWslDistroHolder } from '../discovery/wsl-distro-holder' diff --git a/src/main/wsl/orcad/wsl-orcad-update-move-hold-driver.test.ts b/src/main/wsl/orcad/wsl-orcad-update-move-hold-driver.test.ts index 4ced00c4809..ff310707c17 100644 --- a/src/main/wsl/orcad/wsl-orcad-update-move-hold-driver.test.ts +++ b/src/main/wsl/orcad/wsl-orcad-update-move-hold-driver.test.ts @@ -25,13 +25,13 @@ import { wslMoveRigOutcome, type WslMoveRig } from '../../persistence/__fixtures__/wsl-mover/wsl-move-kill-rig' -import { resetWslMoveDesktopRewriteStoresForTests } from '../../persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores' +import { resetWslMoveDesktopRewriteStoresForTests } from '../../persistence/moving-wsl-projects/desktop-state/wsl-move-desktop-rewrite-stores' import { moveProjectsToWslHost } from '../../persistence/moving-wsl-projects/wsl-move-driver' import { cancelWslMove, isWslMoveRunning, isWslMoveUnderwayOnHost -} from '../../persistence/moving-wsl-projects/wsl-move-running-moves' +} from '../../persistence/moving-wsl-projects/orchestration/wsl-move-running-moves' import { getRemoteHostPlatform } from '../../ssh/remote-host/ssh-remote-platform' import type { OrcadHostTransport } from '../../managed-server/install/orcad-host-transport' import type { WslDistroHolder } from '../discovery/wsl-distro-holder-types' diff --git a/tests/e2e/helpers/orcad-convert-flow.ts b/tests/e2e/helpers/orcad-convert-flow.ts index 4510ecb2aed..1df69683b82 100644 --- a/tests/e2e/helpers/orcad-convert-flow.ts +++ b/tests/e2e/helpers/orcad-convert-flow.ts @@ -1,7 +1,7 @@ import type { Page } from '@stablyai/playwright-test' import { expect } from './orca-app' import { readPersistedProfileState } from './persisted-profile-state' -import { findOrcadMigrationSourceCutoverForTarget } from '../../../src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../../src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { RuntimeClient } from '../../../src/cli/runtime/client' const CONVERT_TIMEOUT_MS = 8 * 60_000 diff --git a/tests/e2e/ssh-orcad-auto-convert.spec.ts b/tests/e2e/ssh-orcad-auto-convert.spec.ts index 0e254898969..770387ee214 100644 --- a/tests/e2e/ssh-orcad-auto-convert.spec.ts +++ b/tests/e2e/ssh-orcad-auto-convert.spec.ts @@ -20,7 +20,7 @@ import { readHostOrcadActivation } from './helpers/orcad-template-variant' import { seedRelayEraProfile } from './helpers/orcad-upgrade-profile' -import { findOrcadMigrationSourceCutoverForTarget } from '../../src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { toSshExecutionHostId } from '../../src/shared/execution-host' import { decommissionConvertedHost, diff --git a/tests/e2e/ssh-orcad-shared-login-migration.spec.ts b/tests/e2e/ssh-orcad-shared-login-migration.spec.ts index 74f800a8000..703cb33bbea 100644 --- a/tests/e2e/ssh-orcad-shared-login-migration.spec.ts +++ b/tests/e2e/ssh-orcad-shared-login-migration.spec.ts @@ -12,7 +12,7 @@ import { managedServer, reconnect, serverCall } from './helpers/orcad-convert-fl import { seedRelayEraProfile } from './helpers/orcad-upgrade-profile' import { startOrcadConvertHost, type OrcadConvertHost } from './helpers/orcad-convert-host' import { callEnvironment } from './helpers/paired-host-terminal' -import { findOrcadMigrationSourceCutoverForTarget } from '../../src/main/persistence/migrating-orcad-catalog/orcad-migration-cutover-journal' +import { findOrcadMigrationSourceCutoverForTarget } from '../../src/main/persistence/migrating-orcad-catalog/cutover-journals/orcad-migration-cutover-journal' import { ORCAD_TEMPLATE_MANIFEST_FILENAME } from '../../src/shared/orcad-artifacts' const HOST = process.env.ORCA_E2E_ORCAD_CONVERT_HOST diff --git a/tests/e2e/wsl-move-fence.spec.ts b/tests/e2e/wsl-move-fence.spec.ts index 6ec256b200e..1780bfaf40f 100644 --- a/tests/e2e/wsl-move-fence.spec.ts +++ b/tests/e2e/wsl-move-fence.spec.ts @@ -17,7 +17,7 @@ import { wslMoveCutoverFixture } from '../../src/main/persistence/__fixtures__/w import { listWslMoveCutovers, writeWslMoveCutover -} from '../../src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal' +} from '../../src/main/persistence/moving-wsl-projects/cutover-recovery/wsl-move-cutover-journal' import { WSL_MOVE_CUTOVER_PHASES, type WslMoveCutoverPhase diff --git a/tests/e2e/wsl-move-restore-lifecycle.spec.ts b/tests/e2e/wsl-move-restore-lifecycle.spec.ts index 4780e34c6ac..146896f1b3c 100644 --- a/tests/e2e/wsl-move-restore-lifecycle.spec.ts +++ b/tests/e2e/wsl-move-restore-lifecycle.spec.ts @@ -46,14 +46,14 @@ import { withMovedRows } from './helpers/wsl-moved-host-profile' import { HistoryReader } from '../../src/main/daemon/history/restoration/history-reader' -import { getOrcadMigrationReceivedBlobPath } from '../../src/main/persistence/migrating-orcad-catalog/orcad-migration-blob-staging' +import { getOrcadMigrationReceivedBlobPath } from '../../src/main/persistence/migrating-orcad-catalog/blob-transfer/orcad-migration-blob-staging' import { installOrcadMigrationTerminalHistory, movedPaneHistorySessionId, orcadMigrationTerminalHistoryKey -} from '../../src/main/persistence/migrating-orcad-catalog/orcad-terminal-history-installer' +} from '../../src/main/persistence/migrating-orcad-catalog/terminal-history/orcad-terminal-history-installer' import { getHistorySessionDirName } from '../../src/main/daemon/history/storage/history-paths' -import { readWslMoveSleptScrollbackFromHistory } from '../../src/main/persistence/moving-wsl-projects/wsl-move-slept-scrollback' +import { readWslMoveSleptScrollbackFromHistory } from '../../src/main/persistence/moving-wsl-projects/terminal-state/wsl-move-slept-scrollback' import { wslMoveCutoverFixture } from '../../src/main/persistence/__fixtures__/wsl-mover/wsl-move-cutover-fixture' import { seedWslMoveCutover } from '../../src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding' import { toRuntimeExecutionHostId } from '../../src/shared/execution-host'