Skip to content

feat(e11): interactive fuzzy switch (TTY selector, preview, script-stable fallback) - #58

Merged
imneov merged 5 commits into
mainfrom
feat/e11-interactive-switch
Jul 7, 2026
Merged

feat(e11): interactive fuzzy switch (TTY selector, preview, script-stable fallback)#58
imneov merged 5 commits into
mainfrom
feat/e11-interactive-switch

Conversation

@imneov

@imneov imneov commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Story map

  • E11-S1: 28f183f feat(e11-s1): gate bare switch on interactive TTY
    • Allows bare claudecm switch only when stdin and stdout are TTYs.
    • Keeps non-TTY bare switch on the existing Cobra usage-error path.
    • Adds injected TTY/capability checks and cancellation-without-writes tests.
  • E11-S2: a0b44e2 feat(e11-s2): add fuzzy profile selector core
    • Adds isolated internal/tui selector core, strict profile loading, active marker, fuzzy filtering over name/notes/provider/base URL/model, and already-active no-op handling.
  • E11-S3: 4e6d0d0 feat(e11-s3): show redacted selector preview
    • Adds redacted selected-profile preview using profile metadata and resolver effective context; --reveal is the only reveal path.
    • Preview errors are scoped into the preview lines.
  • E11-S4: 9588f08 feat(e11-s4): document selector handoff boundary
    • Documents the terminal-only boundary in README and quickstart.
    • Adds a boundary test that internal/tui does not import internal/writepath or internal/commit.

Dependency decision

No new dependency was added. The selector uses the existing golang.org/x/term dependency for TTY detection, terminal size, and raw mode, plus a small local fuzzy matcher/render loop in internal/tui. This keeps the dependency surface smaller than bringing in Bubble Tea while still satisfying the story requirements: type-to-filter, arrow navigation, active marker, preview, clean terminal capability fallback, and testable filtering/detection logic.

Hard requirement compliance

  1. Bare claudecm switch opens the selector only in an interactive TTY where both stdin and stdout are TTYs. The selector supports type-to-filter, Up/Down navigation, active-profile marker, and redacted preview.
  2. Selection hands only the selected profile name back to runSwitch, so the existing named switch pipeline performs diff, confirmation, dry-run, commit, state update, backup reporting, and error handling.
  3. claudecm switch <name>, --yes, --dry-run, and existing flags keep the named path. Bare switch in non-TTY keeps the existing usage error and exit code; sanity run: echo | ./claudecm switch exits 1 with accepts 1 arg(s), received 0.
  4. Capability fallback checks TERM=dumb and terminal size before raw mode. On failure it prints a clear selector-unavailable message and falls back to command usage instead of corrupting the terminal.
  5. Dependency surface is unchanged: existing golang.org/x/term only, with local selector code.
  6. Interactive code is isolated in internal/tui. Fuzzy matching, active-marker item building, preview rendering, terminal capability detection, key parsing, and writepath/commit boundary are unit-tested. The raw terminal loop itself remains thin and is not fully unit-tested.
  7. README and docs/quickstart.md mention interactive switch with the boundary wording: terminal-only optional UX; scripts/non-TTY/named --yes behavior unaffected.

Verification

  • go build ./...
  • go vet ./...
  • go test -race ./internal/tui -count=1 -timeout=120s
  • go test -race ./cmd -run 'TestSwitch(ArgsBareNonTTY|BareTTY|NamedBypasses)' -count=1 -timeout=300s
  • go test ./... -p 1 -timeout=900s
  • go build -o ./claudecm . && echo | ./claudecm switch confirmed non-TTY fallback: exit 1, usage error, no selector.

@imneov
imneov merged commit 61d8334 into main Jul 7, 2026
9 checks passed
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.

1 participant