The git surfaces leave the glass — tab, trail, branch line, and the remote pair, peeled
Step 3 of strategy/01-git-excision.md: the popover strip is Info/Theme/Sync, the titlebar widget says the name alone, the card window's History section and its slot go, Board ▸ Pull/Push comes out with the RemoteCommands scaffold, and View ▸ History re-tags from the commit trail to the deferred foreign-change journal. The Sync placeholder re-annotates to the future ops-based sync service. Four git test suites leave with the surfaces they pinned (BoardGitSetup, BoardInfoPopover, BranchSwitch, GitUndo). The git engine still compiles underneath, unreferenced by UI. 2,890 tests green. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -718,38 +718,19 @@ struct BoardWindowHost: View {
|
||||
// card windows share that machinery and have no board to describe. It goes in after the
|
||||
// load rather than at attach because it carries the store; the controller installs it once,
|
||||
// whichever of the two arrives second.
|
||||
//
|
||||
// The git state comes from the **session**, which `start()` began a moment ago, rather than
|
||||
// from the entitlement or the disk: a board's popover must describe the board as it opened
|
||||
// (12-editions.md ▸ The entitlement, "an open board finishes with the provider it composed";
|
||||
// 06-history-undo.md ▸ Rules, mode is an open-time fact). A `nil` session cannot happen on
|
||||
// this path — `beginSession` precedes `configureWindow` — and reads as a board with no
|
||||
// repository, which is the harmless direction.
|
||||
//
|
||||
// **The tier is no longer passed down** (12 ▸ PIVOT 2026-08-07): git is tier-independent, so
|
||||
// every one of these surfaces reads the board's mode and nothing else. `BoardSession.tier`
|
||||
// still exists and is still recorded — it just has no git-facing consumer here.
|
||||
//
|
||||
// The settings sheet used to adopt the same fact here, so its two doors could validate on it
|
||||
// (2026-07-31 → 2026-08-07). The sheet is retired and the popover is the one configuration
|
||||
// home, so the git state is handed to exactly one surface again — this widget — and the
|
||||
// mid-session transition 06 sanctions (add-git flipping the mode) re-resolves the Git tab's
|
||||
// postures under it live, with no second reader to disagree.
|
||||
let session = appModel.session(for: ref)
|
||||
windowController.installTitlebarAccessory(
|
||||
boardInfoTitlebarAccessory(
|
||||
store: store,
|
||||
recents: appModel.styleRecents,
|
||||
git: session?.git,
|
||||
presentation: boardInfo
|
||||
)
|
||||
)
|
||||
// The widget above now says the board's name (and, on a git-mode board, its branch)
|
||||
// itself, so the system title display would only repeat it — the card-window seam
|
||||
// (`CardWindowHost.configureWindow`, `HostedWindowController.hideTitle`), applied here for
|
||||
// the same reason. `.navigationTitle(windowTitle)` a few lines up in `body` is untouched —
|
||||
// `window.title` keeps feeding the Window menu, Exposé, VoiceOver and restoration; only the
|
||||
// title bar's own rendering of that string is suppressed.
|
||||
// The widget above now says the board's name itself, so the system title display would only
|
||||
// repeat it — the card-window seam (`CardWindowHost.configureWindow`,
|
||||
// `HostedWindowController.hideTitle`), applied here for the same reason.
|
||||
// `.navigationTitle(windowTitle)` a few lines up in `body` is untouched — `window.title`
|
||||
// keeps feeding the Window menu, Exposé, VoiceOver and restoration; only the title bar's own
|
||||
// rendering of that string is suppressed.
|
||||
//
|
||||
// **After the load, and only after it**, which is why it is not in the loading half above:
|
||||
// this line and the widget it defers to are one exchange, and a loading window that hid its
|
||||
|
||||
@@ -257,7 +257,7 @@ final class CardWindowSession: CardSessionFlushing {
|
||||
///
|
||||
/// This file owns identity, lifecycle, the title and subtitle, and where the window opens. The
|
||||
/// two-column composition inside it is `CardWindowView`'s, and what fills those columns — the title
|
||||
/// field, Preview/Edit, the sidebar's five sections — arrives card by card underneath a composition
|
||||
/// field, Preview/Edit, the sidebar's four sections — arrives card by card underneath a composition
|
||||
/// that does not move. The *window-scoped* state those surfaces need lives here, because a window is
|
||||
/// what it is scoped to: the body column's mode (`CardBodyPresentation`) and the raw-source outlet
|
||||
/// (`CardRawSourceSession`), both published through the focus system so the View menu's rows can
|
||||
@@ -288,9 +288,6 @@ struct CardWindowHost: View {
|
||||
/// snapshot the store applies — a cache that died with the view would regenerate every thumbnail
|
||||
/// on every reload (`AttachmentThumbnailCache`).
|
||||
@State private var thumbnails = AttachmentThumbnailCache()
|
||||
/// This card's commit trail (05-card-window.md ▸ History). Held here for `thumbnails`' reason —
|
||||
/// it must survive every snapshot — and surfaced to the view only in git mode (`cardHistory`).
|
||||
@State private var history = CardHistory()
|
||||
/// Whether a close is waiting on the dirty-buffer modal. Set when `windowShouldClose` could not
|
||||
/// flush; cleared by the resolution that lets the close resume.
|
||||
@State private var isClosePending = false
|
||||
@@ -417,31 +414,6 @@ struct CardWindowHost: View {
|
||||
.onDisappear { finish() }
|
||||
}
|
||||
|
||||
/// **This card's commit trail, or nothing at all** (05-card-window.md ▸ History).
|
||||
///
|
||||
/// `nil` is the section's absence rule, read from the board's own git state rather than from a
|
||||
/// flag: a mode other than `git` means a board the app manages no history for, on any tier. The
|
||||
/// question stopped having a tier half at 12-editions.md ▸ PIVOT 2026-08-07 — every session
|
||||
/// composes a git state now, so what decides the section is whether *this board's* history is
|
||||
/// git-backed. The object is held by this host so it survives every snapshot, `thumbnails`'
|
||||
/// reason exactly.
|
||||
private var cardHistory: CardHistory? {
|
||||
guard appModel.session(for: ref.board)?.gitMode == .git else { return nil }
|
||||
return history
|
||||
}
|
||||
|
||||
/// What a trail re-read depends on: this card, and the number of commits the board has landed.
|
||||
///
|
||||
/// The count is the committer's own (`GitAutoCommitter.commitCount`), which advances for every
|
||||
/// commit the app makes — the debounced ones, the launch catch-up, and a restore's. A foreign
|
||||
/// commit an agent made *itself* moves HEAD without touching it; the trail then refreshes at the
|
||||
/// next commit or the next open, which is the same freshness bound the popover's branch line has
|
||||
/// and a great deal cheaper than polling HEAD from a sidebar.
|
||||
private func historyReloadKey(store: BoardStore) -> String {
|
||||
let commits = appModel.session(for: ref.board)?.git?.committer?.commitCount ?? 0
|
||||
return "\(ref.cardID)#\(commits)"
|
||||
}
|
||||
|
||||
/// **The minimum grows only while the comments pane is beside the body** (05-card-window.md ▸
|
||||
/// Composition) — which is the whole reason the stacked mount exists, so a narrow display keeps
|
||||
/// the minimum it always had.
|
||||
@@ -475,20 +447,11 @@ struct CardWindowHost: View {
|
||||
comments: session.comments,
|
||||
thumbnails: thumbnails,
|
||||
undo: session.undo,
|
||||
history: cardHistory,
|
||||
fileDrop: CardWindowDropDelegate(store: store, cardID: placement.card.id),
|
||||
onToggleTask: { offset, checked in
|
||||
store.toggleTaskMarker(inCard: placement.card.id, bodyOffset: offset, checked: checked)
|
||||
}
|
||||
)
|
||||
// **The trail, re-read when a commit lands** (05 ▸ History). The id is the pair of facts
|
||||
// the answer depends on: which card this is, and how many commits this board has made —
|
||||
// so the section refreshes after the app's own commits, after an agent's that the watcher
|
||||
// committed, and after a ⌘Z's restore, with nothing here knowing what a committer is.
|
||||
.task(id: historyReloadKey(store: store)) {
|
||||
guard let cardHistory else { return }
|
||||
await cardHistory.load(boardRoot: store.rootURL, cardFolderName: ref.cardID)
|
||||
}
|
||||
// **The listing is the snapshot's, republished** — `Card.attachments`, which the loader
|
||||
// fills from `attachments/`'s top-level files in Finder order. Every write in the
|
||||
// section is bracketed, so the reload that refreshes this arrives by itself and the
|
||||
|
||||
@@ -98,10 +98,12 @@ struct FindSteppingCommands: View {
|
||||
/// did not move, the validation and the action filled in — and the pair also carries the clause that
|
||||
/// joins them, "Edit Body disables while Raw Source is active" (05-card-window.md).
|
||||
///
|
||||
// m7-git: History is a plain command that focuses the sidebar's History section, and disables
|
||||
// outright on mode `none` / repo-nested boards once that section exists (05-card-window.md,
|
||||
// 07-sync-collab.md). It remains unconditionally disabled here — the sidebar reserves the section's
|
||||
// place (`CardWindowView.historySlot`) but draws nothing, so there is still no surface to focus.
|
||||
// View ▸ History used to anticipate the sidebar's git commit-trail section (`CardWindowView`),
|
||||
// which left with app-managed git (strategy/01-git-excision.md, 2026-08-08). The row is re-tagged
|
||||
// rather than removed: it now anticipates the foreign-change journal successor (01-git-excision.md
|
||||
// ▸ Successors — deferred, its design and timing not yet ruled). It stays unconditionally disabled
|
||||
// here — there is no journal yet to focus — and the sidebar no longer reserves a place for it; the
|
||||
// row itself is the only surviving reservation of the slot.
|
||||
/// The comments pane's two rows join them (11-command-nexus.md lists Show Comments and Comments
|
||||
/// Beside Body between Edit Body and Raw Source): both are live, both are app-wide persisted bits,
|
||||
/// and both are scoped to the card window (`ShowCommentsCommand`, `CommentsBesideBodyCommand`).
|
||||
@@ -114,19 +116,3 @@ struct CardViewCommands: View {
|
||||
FutureCommand(title: "History")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Board ▸ Pull / Push
|
||||
|
||||
/// Board ▸ Pull / Push — no default chord, remote-backed boards only (11-command-nexus.md;
|
||||
/// 07-sync-collab.md: "also Board-menu items").
|
||||
///
|
||||
// m7-git: menu-bar twins of the board popover's own Pull/Push buttons (07-sync-collab.md).
|
||||
// Validation will be remote-mode plus 06's abnormal-state pause ("disabled during 06's
|
||||
// abnormal-state pause ... and on an unresolvable remote" — 11-command-nexus.md). Unconditionally
|
||||
// disabled here: there is no remote model, no popover twin, and no git mode to validate against yet.
|
||||
struct RemoteCommands: View {
|
||||
var body: some View {
|
||||
FutureCommand(title: "Pull")
|
||||
FutureCommand(title: "Push")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user