Skip to content

feat(wsl-mover): a moved project's existing chats stay listed and resumable on this computer (D1b-7a) - #29550

Closed
nwparker wants to merge 4 commits into
nwparker/wsl-mover-d1b-6d1-host-scrollbackfrom
nwparker/wsl-mover-d1b-7a-moved-project-chats
Closed

nwparker wants to merge 4 commits into
nwparker/wsl-mover-d1b-6d1-host-scrollbackfrom
nwparker/wsl-mover-d1b-7a-moved-project-chats

Conversation

@nwparker

@nwparker nwparker commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 9 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​774 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​774
Prod 33 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​653 $\color{#cf222e}{\Huge{\mathbf{−}}}$​39 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​614

This PR is stacked for owner review. The agent will not merge it. Its base is #29526 (D1b-6d-1). Under the owner's merge policy it touches shared user paths, listed below.

Shared paths this PR touches

  • Sidebar:
    • New section: WslMovedProjectsSection sits under the worktree list. It renders only when a WSL move has committed, so nothing changes for anyone today.
    • New IPC: repos:listWslMoved is read-only. The paired web client returns [].
  • Chat tab hydration and the startup purge: a "moved workspace" keeps only its native-chat tabs. A moved workspace is one whose project id matches but which the catalog doesn't list, so a host's own same-id rows are never touched.
  • Session freeze: once the move has committed, chat-tab writes for a moved workspace are accepted. Terminal and editor rows stay frozen.
  • Runtime hidden-repo check (the SSH list path from fix(ssh): the CLI, phone and paired clients no longer list a converted host's retained rows #28754): runtimeHiddenRepoIds becomes runtimeHiddenRepos(...).has(repoId, hostId). It is used by worktree.ps, worktree.list and the hidden-host check. Tests cover the same-id case for both WSL and SSH. The SSH Docker end-to-end shards must run on this PR.
  • Locales: a new key, sidebar.wslMoved.movedToHost, is added to all six locale files.

ELI5

The owner decided that when a WSL project moves to its WSL host, its existing chats stay on this computer. New chats start on the host. Without this PR those chats would vanish after a move, because the moved project is hidden from the sidebar. This PR keeps the moved project in the sidebar as a small read-only entry, "Moved to host", that lists only its existing chats. Each chat opens and resumes on this computer as before. Terminals and edits for that project stay refused, because they now live on the host.

What Changed

This is step D1b-7a of the lossless WSL project mover.

  • Catalog: the moved local rows stay hidden from repos:list and folderWorkspaces:list. A separate read-only repos:listWslMoved returns {kind, id, displayName, path, distro} for local rows the WSL host now owns, taking the distro from the move journal. The renderer keeps these in wslMovedProjects, so a moved project is never treated as an editable one. Phone and CLI lists are unchanged.
  • Tabs that survive: startup hydration and the purge keep a moved workspace's agent-session tabs only. Its terminal, editor and browser tabs are dropped, because those moved to the host.
  • Sidebar entry: the project name, "Moved to host", and one button per chat. It has no menu and no new-terminal, new-chat or edit actions.
  • Opening a chat: clicking a chat, or opening it from Session History, opens it under this entry without starting a terminal.
  • Session freeze: after commit, chat-tab writes for the moved workspace are accepted, while the frozen terminal and editor rows stay exactly as the move left them.
  • Hidden repos by (id, host): after a move the host's row shares the moved project's id. Comparing by id alone would have let the hidden local row leak into runtime worktree.ps and worktree.list.

Why

Why existing chats stay: chats in a WSL project run on Windows. Their transcripts and account homes are in the Windows home, so moving them to the host would strand them (owner decision C, 2026-10-16). Keeping them reachable here is the lossless choice until per-provider transcript moves exist (follow-ups A1–A5).

Why a separate read-only entry: the alternative was to list the chats under the host's project, which has the same repo id. That would mean rewriting each chat's location to a host it never ran on.

Linked Issue

N/A (maintainer; tracked in the WSL-via-orcad implementation tracker, step D1b-7a).

Visual Proof

Taken over CDP from a hidden window (ORCA_BACKGROUND_LAUNCH=1), using a seeded committed move journal and one chat:

moved-project-sidebar.png

moved-project-chat-open.png

For review:

  • Placement: the entry sits at the bottom of the sidebar, under the project list.
  • Blank second screenshot: the chat area is blank because the e2e ran with native chat turned off. The sidebar is the proof.

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • Session freeze: chats are accepted after commit and refused while the move is only quiesced; the slept terminal is kept.

  • listWslMovedProjects: lists only local rows the host owns, never mid-move, and never an SSH row with the same id.

  • Runtime hidden repos by (id, host): covered for both WSL and SSH.

  • Main runtime: a moved chat's folder still resolves to its UNC path through attach, ensure and restart-resume, and its revealed tab is saved alongside the frozen terminal.

  • Renderer:

    • hydration and persistence keep only the chat tab;
    • the purge keeps the chat-only workspace;
    • the sidebar entry renders with no edit or new actions;
    • the host's own listed worktree is never treated as moved.
  • End-to-end:

    • New spec, tests/e2e/wsl-move-moved-project-chats.spec.ts: it seeds a chat and a committed journal and reveals the chat. It then checks the entry and label, that the chat is the only button, and that the terminal is gone. After closing, both the chat and the slept terminal are saved.
    • wsl-move-fence.spec.ts still passes.
  • Checks: pnpm tc:node, pnpm tc:web, both oxlint configs, the changed-code quality gate, the localization checks, dead classes, max lines, and the focus-read ratchet all pass. The touched suites pass (386 files).

Known limitation: a seeded chat tab doesn't come back by itself after a restart unless the host republishes it. The same happens in an unmoved project with this fixture, so the e2e uses the reveal path.

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Nothing writes a move journal yet, so this changes nothing for anyone today. The internal WSL host gate is unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from b2bddf5 to 5f9a900 Compare October 16, 2026 09:13
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from 830d672 to cf7b47a Compare October 16, 2026 09:15
@nwparker

Copy link
Copy Markdown
Contributor Author

SSH coverage for the runtimeHiddenRepos (id, host) change: the PR's own run skipped the SSH Docker lane because its path filter only selects it for tests/e2e/ssh-orcad-* changes. I dispatched the e2e workflow on this head (e9cd5d5): https://github.com/stablyai/orca/actions/runs/38882378661. Both ssh on managed orcad (Docker 1/2, 2/2) shards and changed e2e specs passed.

@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from 5f9a900 to 371a5d0 Compare October 16, 2026 11:24
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from e9cd5d5 to 21de21c Compare October 16, 2026 11:25
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from 371a5d0 to 9b87fc4 Compare October 16, 2026 12:02
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from 21de21c to d9a6f2f Compare October 16, 2026 12:02
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from d9a6f2f to 1a052ad Compare October 16, 2026 12:18
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from b86fcc6 to 2e3663b Compare October 16, 2026 12:41
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from 1a052ad to 5d9dcb2 Compare October 16, 2026 12:41
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from 2e3663b to f24ad83 Compare October 20, 2026 21:05
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from 5d9dcb2 to fa92dab Compare October 20, 2026 21:06
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from f24ad83 to d034364 Compare October 20, 2026 23:15
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from fa92dab to 76f3e02 Compare October 20, 2026 23:16
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from d034364 to b303971 Compare October 21, 2026 00:44
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from 76f3e02 to c035565 Compare October 21, 2026 00:46
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-6d1-host-scrollback branch from b303971 to 4a74631 Compare October 21, 2026 05:16
@nwparker
nwparker force-pushed the nwparker/wsl-mover-d1b-7a-moved-project-chats branch from c035565 to ed9c23a Compare October 21, 2026 05:16
@nwparker

Copy link
Copy Markdown
Contributor Author

Contained in the dark landing PR #34059 (its head commit is an ancestor of the landing branch). Closing in favour of it; branch kept.

@nwparker nwparker closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant