Skip to content

feat(mecatui): bound worktree picker and move it to a modal surface - #2279

Merged
jbeda merged 3 commits into
mainfrom
impl/2172-worktrees-surface
Oct 16, 2026
Merged

jbeda merged 3 commits into
mainfrom
impl/2172-worktrees-surface

Conversation

@jbeda

@jbeda jbeda commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Convert /worktrees to a bounded modal surface, based on the merged temp-runtime fix (#2278).

  • Budget wrapped chrome before list rows; bound width/height, show overflow, and provide a close-only fallback for unusable geometry.
  • Reuse bounded.List and presentListRow for wrapped selection, stable selector-backed filtering, navigation/resize reveal, and wheel scrolling independent of selection.
  • Move picker/filter/confirmation state, captured dependencies, discovery cancellation, and instance/request-correlated results into the surface. Remove legacy Model state/routes; emit only a narrow root-owned handoff intent.
  • Preserve explicit confirmation and create-first session handoff: send the exact opaque selector/source and retain the original session/transcript until server-confirmed successor binding.
  • Preserve the newer execution-picker routes and selection guards while replaying the saved patch.
  • Trim the keybindings reference across existing features: remove routine picker/mouse instructions, generic navigation walkthroughs, and duplicate editing entries while retaining non-obvious shortcuts and platform prerequisites.
  • Consolidate repeated bounded keyboard/wheel mappings across comparable pickers/readers. Caller-specific move subsets, shortcut precedence, filtering, compact/loading guards, and list-versus-reader behavior remain intact; remove Toolcalls' duplicate wheel classification/map expression.

The picker remains a snapshot fetched once per open, as agreed. It does not add live inventory refresh or a stable-ID API. Selection preservation during filtering/reconciliation applies to unchanged selectors; identity across selector rotation after branch/HEAD changes is deferred. This is unrelated to session reattachment or placement persistence.

No temp-storage, server/protocol, schedule, active conversation scrolling, or prompt-editing changes. Confirmation is moved/fitted without changing its choices.

Closes #2172. Related to #1742 and #2237.

Validation

  • Complete focused UI and bounded suites, including race detection.
  • Scenario tests for many/wrapped rows, narrow/short/zero offers, stable card geometry, exact selection after navigation/filter/reorder/wheel-resize, loading/error/empty/no-match states, unsafe metadata and confirmation, live conversation updates, close/reopen/old-request rejection, captured dependencies/cancellation, and exact source/selector handoff.
  • Navigation-helper and real-caller regressions for remapped/disabled keys, overlapping bindings, Close/Choose/global-default precedence, physical-arrow filtering, Worktrees' no-paging subset, Skills' filter-versus-learned behavior, and routed wheel/geometry ownership.
  • task lint
  • task test and task test:race (system temporary storage)
  • task docs and task site:build
  • go run ./cmd/mecademo — tool call, permission ask/approval, and final result.
  • git diff --check

Full suites initially encountered Unix-socket path-length failures in two newer upstream startup-compatibility fixtures, which explicitly override XDG_RUNTIME_DIR with a nested t.TempDir(). Both complete suites passed with shorter system temporary storage; no tests were skipped and those unrelated fixtures were not changed.

Panel review passed across Spec, Standards, Test adequacy, and Domain (security, architecture, library reuse, duplication). Test findings were fixed and incrementally re-reviewed; the selector-refresh scope finding was resolved by the agreed snapshot-on-open decision. The navigation follow-up received its own incremental panel review and routed regression-test recheck, with no remaining findings; full test/race/lint/demo gates were rerun for the refactor.

Implementation plan

Full plan and agreed scope, archived as a verified PR comment.

@jbeda

jbeda commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Implementation plan

  • Provenance: .scratch/2172-worktrees-surface/plan.md
  • Branch: impl/2172-worktrees-surface
  • Baseline: f0534f85938c27f40133f849ef3ea7b02119c298
  • Updated: 2026-10-15T23:36:18Z
  • Published plan portion SHA-256: adce4ebee814c82e55cfae6ecc3578c0a490911a4ebe2df158e6d323f0cbe125
  • Verification below describes intended checks; actual outcomes are in the PR description.
  • Scope clarification: retain snapshot-on-open behavior; no live refresh or stable-ID API expansion.
  • Documentation amendment: remove routine interaction instructions across existing picker entries; preserve useful shortcuts, consequences, and platform limitations.
  • Navigation amendment: consolidate shared key/wheel mapping and nearby duplication while retaining caller-specific moves, binding precedence, filtering, and wheel behavior. Incremental review base is the docs follow-up commit 425ae9857d7e345a04a7ea8f98f0fab5f00d818d.

/worktrees bounded surface plan

Slug: 2172-worktrees-surface
Branch: impl/2172-worktrees-surface
Base/start: f0534f85938c27f40133f849ef3ea7b02119c298 (merged #2278 on main)
Specification: #2172 plus the operator's explicit request to convert to surface ownership where needed.

Scope and decisions

  • Convert the filterable /worktrees inventory to bounded.List, preserving stable opaque-selector-backed identities, selection and compatible visible anchors during filtering and reconciliation of unchanged selectors.
  • The inventory remains a snapshot fetched once per open, matching the existing modal behavior. The operator explicitly accepted no live refresh when external state changes. Cross-selector identity after branch/HEAD changes is deferred; it does not affect session placement or reattachment. No new stable-ID API is introduced.
  • Surface owns inventory, filter, selection, confirmation state, captured dependencies, rendering, cancellation and instance/request-correlated async results. Model owns modal lifetime and root session effects through a narrow handoff intent.
  • Budget wrapped title/explanation, filter, action hints and overflow before rows; fit width/height and provide close-only compact fallback. Standard selection presentation uses presentListRow; wheel moves the window without selecting or leaking into conversation.
  • Preserve typing-first filtering, up/down/top/bottom navigation, Escape clear-then-close, Enter confirmation, Escape back, and explicit second Enter handoff. Do not add printable navigation aliases that intercept filtering.
  • Preserve create-first handoff: source binding/transcript remain until the server creates the successor; use only the opaque worktree selector and server-reported placement.
  • Confirmation is moved into the owning surface and fitted to its geometry, without adding new choices or changing session semantics. No broader confirmation redesign.
  • Preserve the newer upstream execution picker routes and selection guards while removing only legacy worktree routes.
  • Keep the keybindings reference focused on useful shortcuts and non-obvious behavior. Remove routine picker/mouse instructions, generic navigation walkthroughs, and duplicate editing entries across existing features, not only the worktree row. Retain terminal, approval-scope, remapping, cancellation, and clipboard prerequisites.
  • Reuse shared bounded keyboard/wheel translation across comparable UI callers instead of repeating mapping switches. Preserve each caller's supported moves, overlap precedence, close/action priority, filter typing, geometry/loading guards, and list-versus-viewport behavior. Models keeps paging; Worktrees keeps no paging; legacy non-up wheel fallback remains unchanged where present. Leave native/Bubble viewport and active-conversation/prompt behavior alone.
  • No server/API changes, temp-storage changes, schedule work, active conversation scrolling or prompt editing changes. No new pointer activation or page-navigation semantics.

Tasks

  1. Restore the saved UI patch on the merged base and resolve overlapping parent routes while retaining upstream execution-picker behavior.
  2. Review bounded geometry, identity preservation, surface lifetime/request ownership and explicit handoff; fix concrete defects inside scope.
  3. Verify scenario coverage and focused UI/bounded integration, including execution-picker regressions.
  4. Consolidate repeated bounded keyboard/wheel mappings and nearby same-semantics duplication; add helper and real-caller regressions for overlap precedence, filtering, no-paging subsets, and wheel guards.
  5. Run panel review against the exact start commit and final-tree candidate; resolve concrete blockers and review affected deltas. Follow-up cleanup uses incremental baseline 425ae9857d7e345a04a7ea8f98f0fab5f00d818d while retaining the original whole-change review evidence.
  6. Run local task lint, task test, task test:race, and the offline demo. Update documentation only if the change adds behavior beyond existing UI hints and documented surface conventions; Markdown edits run task docs.
  7. Commit only owned implementation/user-doc paths, push and create/update a PR for human review. Publish this plan as a PR comment. Do not merge.

Acceptance and verification intentions

  • Many items, narrow widths and short heights never overflow the offer; selection/wheel changes at fixed geometry do not destabilize the card.
  • Filtering and inventory reconciliation preserve surviving selector identities and compatible window anchors. Resize/navigation reveal selection and Enter confirms the actual selected worktree. Reconciliation tests exercise the internal result seam; no user-visible refresh action or periodic reload is added.
  • Wrapped selected rows receive standard styling with a single cursor marker; unsafe metadata remains sanitized and valid UTF-8.
  • Loading/error/empty/no-match states show accurate available hints and cannot activate stale inventory.
  • Wheel events never change selection or scroll hidden conversation. Live events continue updating conversation without disturbing the modal.
  • Closing cancels discovery; late results from closed/reopened surfaces or old requests are rejected.
  • Compact/zero geometry prevents activation, including a resize before View, and restores prompt focus on close.
  • Explicit confirmation produces only a Model-owned handoff intent; source mismatch is rejected and source continuity persists through successor creation/failure.

No unresolved design questions. Gate results and review findings belong in the run record and PR description, not this plan.

jbeda and others added 3 commits October 15, 2026 17:11
Preserve snapshot-on-open filtering, explicit confirmation, and create-first handoff while bounding list geometry and owning discovery in the surface.

Co-authored-by: Mecatl <noreply@mecatl.dev>
Remove routine picker, mouse, navigation, and duplicate editing guidance while retaining non-obvious shortcuts and platform caveats.

Co-authored-by: Mecatl <noreply@mecatl.dev>
Preserve each caller’s supported moves, binding precedence, filter typing, and wheel guards while consolidating repeated input translation.

Co-authored-by: Mecatl <noreply@mecatl.dev>
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.

mecatui: bound /worktrees picker

1 participant