feat: Telescope-inspired SearchPicker for all search commands#886
feat: Telescope-inspired SearchPicker for all search commands#886
Conversation
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)
There was a problem hiding this comment.
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
-
Duplicated
renderMethodArgumentsfunction —model_search.tsxandtype_search.tsxeach define an identicalrenderMethodArgumentsfunction. Consider extracting it into a shared utility (e.g., inrenderers/components/or alongsidemodel_get.tswhich already exportsformatMethodLines). -
Duplicated
STATUS_COLORS,STATUS_ICONS, andformatDurationSec—workflow_run_search.tsxandworkflow_history_search.tsxdefine identical copies of these constants and helper. A shared module (e.g.,renderers/components/workflow_status.ts) would reduce duplication. -
SPLIT_BORDER_COLS = 3comment is misleading — The comment inpicker_layout.tssays "1 column for vertical divider + 2 columns for left/right outer borders", butBorderedSplitLayoutdoesn'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. -
New
YamlWorkflowRunRepositorytype import in CLI commands —workflow_history_search.tsandworkflow_run_search.tsnow importtype { YamlWorkflowRunRepository }from the infrastructure layer. This couples CLI commands to a concrete repository implementation. Consider using the abstractWorkflowRunRepositoryinterface from the domain layer, or passing thefetchPreviewclosure from a higher level that already knows the concrete type. -
LruCache.get()returnsundefinedfor cachedundefinedvalues — Thegetmethod can't distinguish between "key not found" and "key maps toundefined". Since preview fetchers always return defined values this isn't a problem today, but it's worth noting in the class doc. Similarly,usePreviewFetchchecksif (cached !== undefined)which means a fetcher that legitimately returnsundefinedwould re-fetch every time. Again, not an issue with current usage.
There was a problem hiding this comment.
CLI UX Review
Blocking
None.
Suggestions
-
model method history searchmissing rich preview —src/cli/commands/model_method_history_search.tswas not updated to pass afetchPreviewtocreateModelOutputSearchRenderer. 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. SincefetchPreviewis optional, the command still works fine — the preview pane just shows less detail than claimed. Consider either updatingmodel_method_history_search.tsto callcreateOutputFetchPreviewthe same waymodel_output_search.tsdoes, or updating the PR description. -
Workflow
rrun action label doesn't hint at exit — The help bar showsr run, but pressingrshells out toswamp workflow runand exits the picker. Users familiar with Telescope-style pickers might expect the picker to still be usable after. A label liker launchor a trailing note in the help bar (e.g.,r run ↗) could set expectations, but this is very minor. -
Dev-mode workflow run breakage —
workflow_search.tsusesDeno.execPath()+args: ["workflow", "run", ...]. In compiled binary mode this is correct, but running viadeno run devwould fail becauseDeno.execPath()returns thedenobinary 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.
There was a problem hiding this comment.
CLI UX Review
Blocking
None.
Suggestions
-
model method history searchmissing rich preview —src/cli/commands/model_method_history_search.tswas not updated to pass afetchPreviewtocreateModelOutputSearchRenderer. 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. SincefetchPreviewis optional, the command still works fine — the preview pane just shows less detail than claimed. Consider either updatingmodel_method_history_search.tsto callcreateOutputFetchPreviewthe same waymodel_output_search.tsdoes, or updating the PR description. -
Workflow
rrun action label doesn't hint at exit — The help bar showsr run, but pressingrshells out toswamp workflow runand exits the picker. Users familiar with Telescope-style pickers might expect the picker to still be usable after. A label liker launchcould set expectations, but this is very minor. -
Dev-mode workflow run breakage —
workflow_search.tsusesDeno.execPath()+args: ["workflow", "run", ...]. In compiled binary mode this is correct, but running viadeno run devwould fail becauseDeno.execPath()returns thedenobinary 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.
Summary
Closes #866.
Replace the flat fzf-style
SearchTUIwith a newSearchPickercomponent 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
rto run a workflow,ito install an extension)Architecture
renderers/components/:SearchPicker,PickerBorders,ResultsList,PreviewPane,HelpBarusePreviewFetch(debounced async + LRU),usePreviewScrollcomputePickerLayout()function for tier selection (15 unit tests)LruCachewith 7 unit testsrenderInteractiveSearchtorenderInteractivePickerwithfetchPreviewcallbacksrenderers/pattern, nothing in legacyoutput/Simplifications
rkey shells out toswamp workflow runinstead; preview shows raw YAML with syntax highlightingCommands migrated
model searchdata searchextension searchtype searchvault searchvault type searchworkflow searchworkflow run searchworkflow history searchmodel output searchmodel method history searchreport searchTest Plan
🤖 Generated with Claude Code