Skip to content

feat(terminal): give each worktree its own terminals - #47

Merged
THPubs merged 4 commits into
devfrom
feat/worktree-terminal
Nov 1, 2026
Merged

THPubs merged 4 commits into
devfrom
feat/worktree-terminal

Conversation

@THPubs

@THPubs THPubs commented Nov 1, 2026 •

Copy link
Copy Markdown
Member

What changed

Terminals are now kept per terminal scope: the project's main folder, or one worktree
(added to the glossary in docs/context/terminal.md).

  • The dock shows only the active session's scope. New terminals open in that folder.
  • Switching sessions swaps which scope is visible. Hidden scopes stay mounted, so running
    terminals keep their output.
  • The main folder is keyed by the bare project id, so terminals saved before this change load
    as main-folder terminals. Saved data needs no migration.
  • Parking a project stops the terminals of every scope it has.
  • Removing a worktree closes that worktree's terminals (dropScope). The main folder's stay.
  • The terminal button's count and busy pulse cover the current scope only. The quit confirm
    still checks every terminal.
  • The store field byProject is renamed to byScope, and the workspace prop projectId to
    scope.

Why

Terminals were kept per project. Every session in a project shared one set of terminals, all
opened in the project's main folder. So a terminal opened from a worktree session ran in the
main folder, and main-folder terminals showed up in every worktree.

How I tested it

  • New tests for scope keys, per-scope counts and busy state, the dock showing only the active
    scope, the toggle count, and worktree removal closing its terminals.
  • pnpm check passes.
  • Smoke build launched (pnpm smoke) for a manual check.

Checklist

  • The PR targets dev.
  • I wrote or updated tests, and pnpm check passes.
  • I read and tested every line, and I can explain it in review.
  • AI tools wrote most of this change. (Tick if true. See Using AI tools.)

🤖 Generated with Claude Code

THPubs and others added 4 commits November 1, 2026 13:28
Terminals were keyed by project, so every session in a project shared one
set of terminals, all opened in the project's main folder. A worktree
session's terminal ran in the wrong folder, and main-folder terminals showed
up in every worktree.

Terminals are now keyed by a terminal scope: the project's main folder or
one worktree. The dock shows only the active session's scope, and new
terminals open in that folder. The main folder keeps the bare project id as
its key, so terminals saved before this change stay in the main folder.

- Parking a project stops the terminals of every scope it has.
- Removing a worktree closes that worktree's terminals.
- The terminal button's count and busy pulse cover the current scope only;
  the quit confirm still checks every terminal.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The saved terminals blob is now keyed by terminal scope: the bare project
id for the main folder, or the project id and a folder joined by a NUL.
The orphan sweep still matched each whole key against the parked project
ids, so a worktree scope never matched and a parked project's worktree
panes stayed owned; a leftover daemon serving one was never reaped.

kriyon-core now builds the same scope key as the frontend
(terminal_scope, scope_project_id) and decides which scopes own their
panes (LiveTerminalScopes): none of a parked project's, and a worktree
scope only while a session on the rail works in it, matching the
frontend's dormant scopes. owned_ids reads the project paths to build
each session's scope.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…ree terminals

Two gaps in the terminal scopes:

- A session's scope came from its worktree path alone. A nested session
  runs in its lead's worktree without one of its own, so its terminals
  were filed under the main folder while opening in the worktree. The
  scope now comes from the folder the session works in.
- Archiving or closing the last session in a worktree left that
  worktree's terminals mounted and running, but no session could show
  them any more. Such a scope is now dormant, like a parked project's:
  the dock unmounts it and its panes stop, while its tabs stay, so a
  session back in that folder brings them back with fresh shells.
  installParkedTerminalStops becomes installDormantTerminalStops.

A hidden scope's fallback folder is now its own folder, not the main one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Removing a worktree closes its terminals. A clean removal never showed a
confirm, so a dev server or build running in one of them was killed
without warning, while closing a busy tab, parking and quitting all ask
first.

Removal now checks the worktree's terminals first. When a command is
running, the row asks "Stop it & remove" before anything is removed; the
dirty-tree confirm that may follow does not ask about the terminals again.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@THPubs
THPubs merged commit 3683d96 into dev Nov 1, 2026
@THPubs

THPubs commented Nov 1, 2026

Copy link
Copy Markdown
Member Author

Review and fix — pass 1

Reviewed the whole pull request, fixed what was found, then re-checked the fixes.

4 issues found and fixed in 2 passes. All checks green; CI green.

  • Rust orphan sweep now understands terminal scope keys.
  • Unreachable worktree terminals are stopped (tabs kept), like a parked project's.
  • A session's scope follows the folder it works in (nested sessions).
  • Removing a worktree asks before stopping a running command.

Also added the template checklist to the description.

Notes

The re-check scored three more points below 75: archive/close stopping a busy worktree terminal without a confirm (same as the existing park-by-archive behaviour), a second dirty-tree confirm after a mid-flow busy check, and sessions still on the rail in a removed worktree.

Fixed this pass

  • src/state/terminals.ts:52 — Teach the Rust orphan sweep to split terminal scope keys
  • src/layout/TerminalDock.tsx:72 — Drop or expose terminal scopes no session can reach
  • src/sidebar/useWorktreeRemoval.ts:57 — Confirm before worktree removal kills busy worktree terminals
  • src/layout/TerminalDock.tsx:56 — Keep a main-folder scope's terminals in the main folder

Checked by 3 finders (correctness, processes & lifecycle, contract, tests, public text, step 5 re-check of the fixes, architecture re-check of the fixes) · architecture review · scorer: 8 scored, 4 kept.


Ready to merge, as far as this review can see. Nothing is open from this pass or any pass before it.

THPubs added a commit that referenced this pull request Nov 1, 2026
Brings in the worktree terminals (#47) and the 0.15.0 release (#49). The
one conflict was daemon_rt.rs's imports: it keeps kriyon_core::uds's
UnixStream, which Windows needs, and dev's HashMap.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
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