th-fe75ca: close a SmoothFlow session out from anywhere, not just a finished card - #604
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: cd506d4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…inished card
Close-out existed since th-883ce9 but was reachable ONLY from an Inbox card, and
only for a session that had already finished — so the answer to "close this
session" was "finish it first", which is no answer for the ones you actually
want to stop.
Reach: the sidebar row's context menu (Open / Kill / Close Out…) and Session ▸
Close Out… (⌘⌥W) on the focused row, both for LIVE sessions too — the engine
already kills a running session before closing it, and the sheet now says so
before you confirm ("still running — closing kills it first"), with the button
reading "Kill and close".
Detail: the sheet named the pearl and worktree but not what it was about to
destroy. It now shows the branch, the uncommitted-file count and the pearl's
title. Merged state stays uncached on purpose: the engine reveals it by refusing
the close, and a flag here would be a second source of truth that can disagree at
the instant of the close. Force is still post-refusal only. A refusal on a close
started outside the Inbox gets its own sheet rather than vanishing into the rail.
The decision and every line of its copy are SessionClose.decide(session:handoff:),
a pure function unit-tested apart from the AppKit presentation. hasOwnWorktree
also got stricter: a projectless shell row (worktree = $HOME) is no longer offered
"remove this directory".
Tests: 95 unit (13 new in SessionCloseTests) + 12 XCUITests green, including three
new mock-server tests for the sidebar path on a live session, the Session menu
path, and a sidebar-started refusal leaving the row untouched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…hed-only Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
brentrager
force-pushed
the
th-fe75ca-session-closeout
branch
from
September 17, 2026 19:08
bc12d4e to
f4a961b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brent: "i still can't like close sessions when i open smooth flow?" — correct, and this fixes it.
flow.closehas been frame-complete since th-883ce9, but the only way to reach it was an Inbox card, and only for a session that had already finished. So "close this session" meant "finish it first" — no help for the sessions you actually want to stop. No sidebar menu, no menu-bar item, nothing for a running row.Reach
A live row closes the same way — the engine kills it before anything else — and the sheet says so before you confirm: "still running — closing kills it first", with the button reading Kill and close.
Detail
The sheet named the pearl and worktree but not what it was about to destroy. It now shows the branch, the uncommitted-file count, and the pearl's title. App-side only —
Handoff.Packetalready carriedbranch/dirtyand the sheet is loaded before it goes up, so there is no new frame.No precomputed
mergedflag, deliberately: the engine reveals merged state at the only moment it matters, by refusing the close with a reason shown verbatim. Force stays post-refusal — never a checkbox you can arm before the reason exists. A refusal on a close started outside the Inbox (sidebar, menu) now gets its own sheet instead of vanishing into the rail.One safety tightening:
hasOwnWorktreenow also requires a non-empty project, so a projectless shell row sitting in$HOMEis never offered "remove worktree /Users/you".Tests
SessionClose.decide(session:handoff:)is a pure function over session + handoff producing every toggle, default and line of copy — modelled onPaneClose.decide, tested apart from the AppKit presentation.SessionCloseTests)mock/server.mjs: the sidebar path on a live session (asserts the kill warning and dirty count are on screen), the Session-menu path on the focused row, and a sidebar-started refusal where Keep it leaves the row exactly where it was.Docs updated in the same PR:
docs/Architecture/SmoothFlow-macOS.md(close-out section + ⌘⌥W in the keyboard table) anddocs/Engineering/SmoothFlow-Testing-macOS.md(suite row + the new accessibility identifiers). Changeset included.Pearl th-fe75ca. Branched off main; #582 rewrites
Sources/UI/and I'll rebase onto whatever keymap it lands, wiringClose Out…through it rather than reverting.🤖 Generated with Claude Code