Skip to content

feat: Telescope-inspired SearchPicker for all search commands#886

Merged
stack72 merged 1 commit intomainfrom
search-picker
Mar 26, 2026
Merged

feat: Telescope-inspired SearchPicker for all search commands#886
stack72 merged 1 commit intomainfrom
search-picker

Conversation

@adamhjk
Copy link
Copy Markdown
Contributor

@adamhjk adamhjk commented Mar 26, 2026

Summary

Closes #866.

Replace the flat fzf-style SearchTUI with a new SearchPicker component inspired by Neovim's Telescope plugin. All 12 search commands now show a split-pane interface with a results list on the left and a live preview of the selected item on the right.

Key features

  • Three-region layout: branding line (matching workflow run tree style), search prompt, and split results/preview panes separated by clean separator lines
  • Async preview loading with 100ms debounce and LRU cache (10 items) — previews show actual content (YAML with syntax highlighting, JSON with syntax highlighting, rendered markdown reports) not just metadata
  • Alternate screen buffer so the picker disappears cleanly on exit, leaving only the selected item's detail in scrollback
  • Graceful degradation across four tiers (bordered-split → stacked → inline → minimal) based on terminal dimensions
  • Ctrl-u/d scrolls the preview pane, stops at end of content
  • Domain-specific action keys (e.g. r to run a workflow, i to install an extension)

Architecture

  • New shared components in renderers/components/: SearchPicker, PickerBorders, ResultsList, PreviewPane, HelpBar
  • New hooks: usePreviewFetch (debounced async + LRU), usePreviewScroll
  • Pure computePickerLayout() function for tier selection (15 unit tests)
  • LruCache with 7 unit tests
  • All search renderers migrated from renderInteractiveSearch to renderInteractivePicker with fetchPreview callbacks
  • Everything in the renderers/ pattern, nothing in legacy output/

Simplifications

  • Extension search: eliminated the two-phase detail view + while-loop back pattern
  • Workflow search: removed action select menu and in-process execution; r key shells out to swamp workflow run instead; preview shows raw YAML with syntax highlighting

Commands migrated

Command Preview content
model search Methods with arg types, data output specs
data search Actual file content (JSON highlighted, markdown rendered)
extension search Full description, platforms, labels, dates
type search Methods, global arguments schema
vault search Vault config as formatted JSON
vault type search Type, name, description
workflow search Raw YAML with syntax highlighting
workflow run search Job/step status tree with icons
workflow history search Job/step status tree with icons
model output search Provenance, artifacts, errors
model method history search Same as model output
report search Rendered markdown report content

Test Plan

  • All 3574 existing tests pass
  • 22 new unit tests (15 for picker layout tiers, 7 for LRU cache)
  • Manual testing of all 12 search commands at various terminal sizes
  • Verified: alternate screen buffer, scrollback output, Ctrl-u/d scroll, action keys, cancel behavior

🤖 Generated with Claude Code

Replace the flat fzf-style SearchTUI with a new SearchPicker component
inspired by Neovim's Telescope plugin. All 12 search commands now show a
split-pane interface with a results list on the left and a live preview
of the selected item on the right.

Key features:
- Three-region layout: branding line, search prompt, and split
  results/preview panes separated by clean horizontal/vertical lines
- Async preview loading with 100ms debounce and LRU cache — previews
  show the actual content (YAML, JSON with syntax highlighting, rendered
  markdown) not just metadata
- Alternate screen buffer so the picker disappears cleanly on exit,
  leaving only the selected item's detail in scrollback
- Graceful degradation across four tiers (bordered-split → stacked →
  inline → minimal) based on terminal dimensions
- Ctrl-u/d scrolls the preview pane, stops at end of content
- Domain-specific action keys (e.g. 'r' to run a workflow, 'i' to
  install an extension)

Architecture:
- New shared components in renderers/components/: SearchPicker,
  PickerBorders, ResultsList, PreviewPane, HelpBar
- New hooks: usePreviewFetch (debounced async + LRU), usePreviewScroll
- Pure computePickerLayout() function for tier selection
- All search renderers migrated from renderInteractiveSearch to
  renderInteractivePicker with fetchPreview callbacks
- Everything in the renderers/ pattern, nothing in legacy output/

Simplifications:
- Extension search: eliminated the two-phase detail view + while-loop
- Workflow search: removed action select menu and in-process execution;
  'r' key shells out to `swamp workflow run` instead
- Action keys skip scrollback printing (just run the action)
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Well-architected PR that introduces a Telescope-inspired SearchPicker with clean separation of concerns. The four-tier degradation strategy is well thought out, the LRU cache + debounce pattern is solid, and the migration of all 12 search commands is thorough and consistent.

Blocking Issues

None.

Suggestions

  1. Duplicated renderMethodArguments functionmodel_search.tsx and type_search.tsx each define an identical renderMethodArguments function. Consider extracting it into a shared utility (e.g., in renderers/components/ or alongside model_get.ts which already exports formatMethodLines).

  2. Duplicated STATUS_COLORS, STATUS_ICONS, and formatDurationSecworkflow_run_search.tsx and workflow_history_search.tsx define identical copies of these constants and helper. A shared module (e.g., renderers/components/workflow_status.ts) would reduce duplication.

  3. SPLIT_BORDER_COLS = 3 comment is misleading — The comment in picker_layout.ts says "1 column for vertical divider + 2 columns for left/right outer borders", but BorderedSplitLayout doesn't render left/right outer borders. The layout still works (flexGrow absorbs the slack), but the constant may be 2 too high, causing the content area to be slightly narrower than the available terminal width.

  4. New YamlWorkflowRunRepository type import in CLI commandsworkflow_history_search.ts and workflow_run_search.ts now import type { YamlWorkflowRunRepository } from the infrastructure layer. This couples CLI commands to a concrete repository implementation. Consider using the abstract WorkflowRunRepository interface from the domain layer, or passing the fetchPreview closure from a higher level that already knows the concrete type.

  5. LruCache.get() returns undefined for cached undefined values — The get method can't distinguish between "key not found" and "key maps to undefined". Since preview fetchers always return defined values this isn't a problem today, but it's worth noting in the class doc. Similarly, usePreviewFetch checks if (cached !== undefined) which means a fetcher that legitimately returns undefined would re-fetch every time. Again, not an issue with current usage.

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI UX Review

Blocking

None.

Suggestions

  1. model method history search missing rich previewsrc/cli/commands/model_method_history_search.ts was not updated to pass a fetchPreview to createModelOutputSearchRenderer. It gets the new picker UI and shows basic metadata (name, type, status, duration), but not the full output detail with provenance and artifacts. The PR description table claims this command has "Same as model output" preview. Since fetchPreview is optional, the command still works fine — the preview pane just shows less detail than claimed. Consider either updating model_method_history_search.ts to call createOutputFetchPreview the same way model_output_search.ts does, or updating the PR description.

  2. Workflow r run action label doesn't hint at exit — The help bar shows r run, but pressing r shells out to swamp workflow run and exits the picker. Users familiar with Telescope-style pickers might expect the picker to still be usable after. A label like r launch or a trailing note in the help bar (e.g., r run ↗) could set expectations, but this is very minor.

  3. Dev-mode workflow run breakageworkflow_search.ts uses Deno.execPath() + args: ["workflow", "run", ...]. In compiled binary mode this is correct, but running via deno run dev would fail because Deno.execPath() returns the deno binary and "workflow" is not a valid Deno subcommand. Not a production concern, but worth noting for developers iterating on workflow search.

Verdict

PASS — the new Telescope-inspired picker is a clean UX upgrade across all 12 search commands. Help bar keybindings are clear and consistent, JSON mode behavior is correctly preserved, graceful degradation across four layout tiers is solid, and the alternate-screen-buffer exit is a nice touch. No blocking issues.

Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI UX Review

Blocking

None.

Suggestions

  1. model method history search missing rich previewsrc/cli/commands/model_method_history_search.ts was not updated to pass a fetchPreview to createModelOutputSearchRenderer. It gets the new picker UI and shows basic metadata (name, type, status, duration), but not the full output detail with provenance and artifacts. The PR description table claims this command has "Same as model output" preview. Since fetchPreview is optional, the command still works fine — the preview pane just shows less detail than claimed. Consider either updating model_method_history_search.ts to call createOutputFetchPreview the same way model_output_search.ts does, or updating the PR description.

  2. Workflow r run action label doesn't hint at exit — The help bar shows r run, but pressing r shells out to swamp workflow run and exits the picker. Users familiar with Telescope-style pickers might expect the picker to still be usable after. A label like r launch could set expectations, but this is very minor.

  3. Dev-mode workflow run breakageworkflow_search.ts uses Deno.execPath() + args: ["workflow", "run", ...]. In compiled binary mode this is correct, but running via deno run dev would fail because Deno.execPath() returns the deno binary and "workflow" is not a valid Deno subcommand. Not a production concern, but worth noting for developers iterating on workflow search.

Verdict

PASS — the new Telescope-inspired picker is a clean UX upgrade across all 12 search commands. Help bar keybindings are clear and consistent, JSON mode behavior is correctly preserved, graceful degradation across four layout tiers is solid, and the alternate-screen-buffer exit is a nice touch. No blocking issues.

@stack72 stack72 merged commit b1e5a08 into main Mar 26, 2026
10 checks passed
@stack72 stack72 deleted the search-picker branch March 26, 2026 19:58
@adamhjk adamhjk restored the search-picker branch March 27, 2026 05:57
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.

SearchPicker: Telescope-inspired preview pane for all search commands

2 participants