Make worktree maintenance visible and responsive - #104
Conversation
Long maintenance commands currently provide no useful feedback, and the TUI blocks safe navigation behind an expensive fleet-wide refresh. The approved design narrows interactive refresh to the active project while keeping the daemon-owned global cache authoritative. Merged pruning will prove pull-request relevance before reporting dirty state. This lets users confirm removal of a dirty, confirmed-merged worktree without weakening the hard stop for a branch that advanced after its pull request. The design also keeps removal responsive through a single background queue and preserves fail-closed generation, endpoint, and ownership checks. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Dry runs, declined prompts, and unattended commands need distinct exit semantics. Assign each case a stable reason and increase the prune report schema version so machine consumers can interpret the result without knowing the invocation mode. Treat ignored files as deletion-sensitive content. Refresh status before a prompt and make the prompt authorize the complete worktree directory. Also separate inventory currency from status collection. A background global refresh must update daemon cache and effective configuration without paying for fleet-wide Git status. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Break the approved ergonomics design into three independently testable delivery sequences: maintenance progress and merged pruning, scoped TUI inventory, and queued worktree removal. Capture the reviewed failure semantics, freshness boundaries, lock ownership, and test-first checkpoints so implementation decisions are not left implicit. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Long maintenance operations need visible feedback without turning redirected output into an unbounded event log. Use one transient terminal line and four milestones for non-terminal streams. Keep progress on stderr so structured stdout remains safe for automation. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Dry runs, declined prompts, and unattended runs need different machine-readable results even when they observe the same dirty merged worktree. Give each path a stable reason with its own summary and exit behavior. Increase the schema version so consumers can recognize the new contract. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Dirty state alone does not identify a merged worktree. Resolve the pull request and verify its exact head first so unrelated dirty worktrees remain normal non-candidates and advanced branches retain their hard stop. The command can now make the final cleanliness decision with current evidence. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
A merged pull request is strong removal evidence, but local files still need a narrow user decision. Recheck dirtiness at prompt time and force only the one worktree that the user accepts. Keep unattended runs fail-closed, make dry runs informative, and group repeated human diagnostics so large fleets remain readable. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Doctor and prune can spend many seconds inspecting a fleet without visible feedback. Report their current phase and bounded candidate counts on stderr so people can tell that work is advancing. Separate expired-candidate validation from removal so each phase reflects the operation that is actually running. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Users and automation need to know where progress is written and how dirty merged worktrees affect reports and exit status. Document the stderr contract, narrow interactive approval, and schema version 2 reasons. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Large inventories paid for several Git processes per worktree before the dashboard could show current state. Read file state, divergence, and branch metadata from one stable porcelain response so each row has a much smaller fixed cost. Keep per-file untracked counts with -uall and preserve the existing no-fetch divergence behavior. Generated with Codex Co-authored-by: Codex <codex@openai.com>
One goroutine per worktree makes large inventories compete for processes and file descriptors. Use a small worker pool so refresh cost stays predictable and one unavailable repository degrades only its own row. Calculate activity from the worktree root, HEAD, and changed paths. Clean checkouts stay recent without scanning every tracked file. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
A current daemon snapshot does not always need expensive Git status collection. Give callers an explicit scope and status choice so the TUI can refresh structural catalog data independently. Run daemon, status, tmux, and fleet I/O outside the backend configuration lock so long refreshes do not freeze unrelated backend reads. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
The lifecycle repository view can fall back to the global catalog when its anchor is missing or is not a repository. Reject empty, unrelated, and main-less results so one scoped refresh cannot mark unrelated cached rows current. Merge accepted rows over the dashboard snapshot and retain catalog-only fields such as the canonical repository URL. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
A cached global catalog is useful for first paint, but it must not force every project through Git status before the active view is usable. Refresh the selected repository first and update the daemon-owned global catalog once in the background without status work. Track currency by scope so mutations wait for the evidence they need. Preserve cached rows and newer project statuses when a background refresh fails or returns structural updates. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Cached rows are enough to enter an existing directory or reconnect to a session that is still live. Let those actions proceed during refresh while keeping every session-creation path behind current inventory. Re-resolve cached tmux state at attach time and fail closed unless exactly one endpoint is live. This prevents stale cache hints from creating or repairing workspaces. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Dashboard users need to know why cached rows appear before current status and which actions remain safe during that window. Describe the project-first refresh, the background global pass, and the live-only navigation rules. Also document the cheaper activity signal so row ordering no longer implies a scan of every tracked file. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
A confirmed deletion can take long enough that an unchanged row looks stuck and invites duplicate actions. Give active and queued removals an explicit state that takes precedence over Git status. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Deletion should be exceptional slow work, not a modal pause for the whole dashboard. Queue confirmed worktrees in order, keep other rows usable, and reconcile each outcome against its repository. Capture removal authority under the backend lock, then release it before daemon, fleet, and tmux I/O. Inventory configuration and navigation can continue while one removal runs. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Users can keep working while deletion runs, but they need a clear contract for queue order and failure recovery. Explain the removing state and which interactions remain available. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Keep scoped refresh fail-closed by separating dashboard launch context from repository requests, validating the anchor, and refusing to carry status across a changed checkout. Avoid hidden global work in the fleet overlay, retain removal and warning state across merges, preserve failed fleet observations, and account for nested deletions in activity. Dry-run merged pruning now checks every hard removal condition before reporting confirmation as the only remaining requirement. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
A terminal error must not share a line with an active spinner, and completed counts must describe finished candidate work. Pause progress before diagnostics and advance merged-prune counts only after each prior candidate has reached an outcome. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
The responsive inventory refactor left obsolete wrappers and an unused test assignment that the repository lint gate rejects. Remove that dead code and apply the required Markdown formatting so the branch passes its publication checks. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
A status-free cache update must not authorize destructive work, and a slow inventory response must not undo newer removal reconciliation. Track freshness per project, reject superseded inventory results, and retain in-flight removal state across every merge. Treat all porcelain v2 worktree changes as dirty so renames, copies, and type changes cannot bypass removal checks. Preserve the finished architecture in maintained docs instead of implementation plans. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Destructive prompts and mutations need current, unambiguous state. Quote merged-prune paths, reject fleet results from before a removal or replacement inventory, and make project freshness stale while a global status refresh runs. Fail the status command when any worktree could not be inspected so structured output cannot look complete when it is not. Keep TUI fleet reads project-scoped; whole-host publication remains on explicit mutations and sync. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Project views without a local repository must use dashboard freshness. This keeps directory workspaces and remote-only fleet rows usable without sending an invalid repository request. Treat forge identity casing consistently when tracking freshness, and bound the activity lookup so one stalled Git process cannot block an inventory worker. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
A structural dashboard refresh can discover a worktree whose status was never collected. Mark its project stale so mutations and session creation remain blocked until a scoped status refresh completes. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
A missing or unreadable launch repository must not strand the TUI on cached rows. Continue with the status-free global refresh after recording the scoped refresh error. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
A completed queued removal must take precedence over inventory that started before it. Supersede those responses immediately so they cannot restore a deleted row while another removal runs. Confirm actions against the current row and use context-matched tmux termination. This prevents a delayed confirmation from acting on a changed workspace or replacement session. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Leaving a project view exposes projects whose status may still be stale. Start the global status refresh immediately so those rows do not remain blocked without active work. A dirty-delete confirmation must authorize one exact checkout. Carry its branch and HEAD into the mutation-locked removal preflight so an external checkout or commit change preserves the worktree. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Forced TUI removal now requires the checkout identity supplied by real inventory rows. Include that identity in the existing forced-removal fixtures so they continue to exercise generation rejection and dirty removal. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
A remote-only worktree must receive current status before the TUI enables mutations. Refresh status after materialization so the new local row does not remain blocked. Repository inspection can be slow. Keep it outside the backend configuration lock so inventory updates remain responsive while a removal is prepared. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Removal preparation now validates against a configuration snapshot. The old backend-bound wrapper has no caller and fails the repository lint gate. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
An older daemon must not accept forced removal without enforcing the confirmed branch and HEAD. Require the new checkout-removal capability while retaining the existing session-removal contract. Inventory can change while a confirmation or branch prompt is open. Reject the action when the checkout identity, project, or freshness no longer matches what the user reviewed. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
kwt is unreleased, so its existing v2 removal contract has no installed compatibility boundary. Extend that contract with branch and HEAD guards instead of adding a permanent v3 layer. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Windows can spell one temporary directory through both short-name and long-name paths. Verify that the diagnostic identifies the failed worktree without requiring one operating-system-specific full path. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
An active creation must remain visible until its command finishes, even when a scoped listing has not discovered it. A rejected removal can mean that the checkout or status changed after confirmation, so refresh the affected project before another action. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
This adds `kwt changes [path]`, a focused command for seeing exactly which files changed in one registered worktree. It reports staged and working-tree changes separately, including untracked files, renames, copies, deletions, and conflicts. Human output is intended for interactive use; `--json` provides deterministic ordering and a stable contract. The same inspection API is available to Go consumers. Kwt checks the worktree’s durable generation before and after reading Git status. If the worktree is removed or replaced during inspection, kwt discards the result instead of returning changes for the wrong checkout. The daemon supplies current inventory and configuration, while Git runs in the foreground client with bounded time and output. Kwt credentials and repository-routing variables are removed from Git’s environment while trusted Git configuration remains available. If an exact change list exceeds the output limit, kwt returns an actionable error instead of partial file records. This does not change the status accounting or TUI presentation introduced in #104. The TUI-related code here only keeps credential filtering current during repository refreshes. This PR also raises kwt’s source-build baseline to Go 1.27.0, matching the other Go projects. The resulting macOS support floor is version 13. Out of scope: patches or file contents, fetching, watching, caching, sibling-worktree discovery, and daemon-owned status polling. Co-authored-by: sarcasticbird <sarcasticbird@users.noreply.github.com>
This makes long-running worktree maintenance visible and keeps the TUI usable while inventory updates and deletions run.
doctorandprunenow show bounded progress, the current phase, and an ETA without mixing status text into structured output.prune --mergedproves that a pull request was merged before dirtiness matters, then asks before removing a dirty merged worktree. Unattended runs still fail closed.A lightweight global refresh keeps the shared cache current without repeating fleet-wide Git status work. Repository scope, session liveness, and removal authority remain fail-closed.