Implement undo and redo as forward commits
GitHistoryProvider is the second HistoryProviding implementation: its stack IS HEAD's first-parent ancestry, reseeded on load (redo empty), re-synced to HEAD before every crossing so agents' self-commits become the top and ⌘Z steps back exactly one commit; any arriving commit clears redo (a heal-only window deliberately does not). Restores are forward commits through the ordinary signature path — GitRestoreOperation materializes only the current-vs-target diff as working-tree writes and resolves no reset/checkout symbol at all; heal commits are transparent in-session (pointer passes over, restores exclude heal-owned paths, identity carried on landed windows via PlannedCommit.kind → GitLandedCommit). Subjects "Undo:/Redo: <crossed subject>"; menu labels never nest in-session; the root commit is not a step (crossing it would restore the empty tree). Provider binding flips: makeHistoryProvider(store, tier, git) — free binds native everywhere, Pro binds the git provider on git boards and NOTHING on mode-none/repo-nested (the pair disables through existing validation); add-git mid-session live-binds via HistoryStore.didAddGit → bindHistoryProvider (the flip only ever adds). SessionSettleGate is the reusable Save All / Discard / Cancel step: restores whose diff touches an open Edit session or raw-source buffer gate on it (Save All applies with validation — a refused buffer cancels the whole restore focused on the offender; Discard reverts via CardBodyEditSession.discardBuffer and reconciles against the working tree, deliberately skipping the second flush); untouched sessions ride through undisturbed. Built for the branch-switch card to reuse. BoardStore gains the async performWholesale sibling. CardHistorySection fills the m6 EmptyView slot: read-only, newest first, follows the card across lane moves by folder-component match (the UUID is the identity — no rename detection), absent off git mode and off Pro. 2332 tests / 403 suites green; InertGitTests untouched. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -1248,6 +1248,39 @@ public final class BoardStore: HealHost {
|
||||
}
|
||||
}
|
||||
|
||||
/// The same bracket over work that **awaits** — the undo restore (06-history-undo.md) and, next,
|
||||
/// the branch switch.
|
||||
///
|
||||
/// A sibling rather than a replacement, and the reason is a hard fact about the two callers: the
|
||||
/// synchronous version above exists because `performWrite`-shaped work is synchronous, while a
|
||||
/// git operation is a detached libgit2 task the main actor must not block on
|
||||
/// (`GitRepository`'s isolation rule). Both keep the bracket, the reload floor and the completion
|
||||
/// phrase in one place; the distinct argument label is what keeps overload resolution from having
|
||||
/// to guess which one a trailing closure meant.
|
||||
///
|
||||
/// The refusal, the ordering and the arming are the synchronous version's, unchanged — see its
|
||||
/// doc comment for all three.
|
||||
public func performWholesale(
|
||||
announcing completion: String? = nil,
|
||||
awaiting operation: () async throws -> Void
|
||||
) async throws {
|
||||
if let readOnlyLock {
|
||||
throw BoardStoreWriteRefusal.readOnlyLocked(readOnlyLock)
|
||||
}
|
||||
watcherBrackets?.begin()
|
||||
defer {
|
||||
wholesaleReloadFloor = reloadGeneration + 1
|
||||
wholesaleCompletion = completion
|
||||
watcherBrackets?.end()
|
||||
}
|
||||
do {
|
||||
try await operation()
|
||||
} catch let error as BoardWriteError {
|
||||
banners.post(error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lane width
|
||||
|
||||
/// Writes a lane's width — the one commit point both width mechanisms share (03-board-ui.md §
|
||||
|
||||
Reference in New Issue
Block a user