fix(tui): `/skills` opens the Altimate skills browser, and its actions work

Merged
SA
2mo ago
+453-26

Issue for this PR

Closes #1328

Type of change

  • Bug fix

What does this PR do?

Root cause was not the chord — it was which dialog /skills opened. Two commands registered slashName: "skills": the core prompt's prompt.skills (upstream's plain selector: Enter inserts /<skill>, no actions) and the Altimate plugin's altimate.skill.list. Autocomplete listed two /skills rows and Enter took the first, so users landed in the plain selector — which is exactly what the issue describes ("Enter inserts /<skill>", "ctrl+a does nothing"). The browser with Actions / New / Install was only reachable via <leader>k.

Changes:

  • The core prompt.skills keeps its palette entry and loses its slash name; the Altimate browser owns /skills.
  • Enter uses the skill — inserts /<skill> into the prompt via api.prompt.active(), as the docs say and the core selector did. The action picker is ctrl+a and the Actions footer button.
  • Actions / New / Install are DialogSelect actions with in-dialog bindings (ctrl+a / ctrl+e / ctrl+i) instead of a plugin-level keymap layer that the open dialog outranks (the model dialog binds ctrl+a the same way). They render as Tab-reachable footer buttons, so the picker no longer depends on a chord. New is ctrl+e because ctrl+n is every dialog's "next". The dialog actions have their own command names so the footer labels show the chords that actually work there.
  • Plugin DialogSelect API gains actions and bindings, forwarded by the adapter.
  • Latent upstream bug fixed: DialogSelect evaluated its action list eagerly, before selected was declared, so a function-valued disabled (needed to keep the synthetic Install row out of the picker) threw Cannot access 'selected' before initialization. Every existing caller passed a boolean, which never touched selected. Evaluated lazily now.
  • Docs table updated (ctrl+e for New, Tab for the footer buttons, /skills opens the browser).

How did you verify your code works?

  • vhs on a local build (Set Width 1200 / Height 800, configured home): before — after /skills, Down, Ctrl+A the frame is the unchanged plain selector. After — the footer reads Actions ctrl+a · New ctrl+e · Install ctrl+i, and Down + Ctrl+A opens Actions: dbt-pr-review (Show details / Test for a built-in). Enter on a row leaves /dbt-pr-review in the prompt at 0.7 s, 1.5 s and 3 s — no auto-submit.
  • New packages/tui/test/ui/dialog-select-actions.test.tsx: mounts a real DialogSelect in the provider stack and presses keys — ctrl+a fires the action for the highlighted row; follows the highlight after Down; ctrl+e fires the second action; no binding → nothing fires; the same with the plugin's global layer registering the same command name; the footer renders the buttons with their chords; and the function-valued disabled case that crashed before the lazy fix.
  • packages/tui: test/ui, test/keymap, test/plugin, test/cli/tui — 84 pass. packages/opencode: test/altimate/plugin, test/cli/skill, test/cli/help — 91 pass. Typecheck clean in plugin/tui/opencode; upstream marker guard clean.

Screenshots / recordings

Final vhs frame after Down + Ctrl+A:

                 Actions: dbt-pr-review                           esc
                 Search
                 Show details View skill info, tools, and location
                 Test Validate the paired CLI tool works

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6


Summary by cubic

Makes /skills open the Altimate skills browser instead of the plain core selector, so Actions, New, and Install work while the dialog is open.

  • /skills had two registrations (core prompt.skills and the Altimate browser), and Enter took the first, landing users in the action-less selector; the browser now owns the slash name.
  • Enter uses the skill, inserting /<skill> into the prompt; the action picker is ctrl+a.
  • Actions, New, and Install are dialog-level actions with in-dialog keybinds (ctrl+a, ctrl+e, ctrl+g), rendered as Tab-reachable footer buttons — the picker no longer depends on a chord the open dialog overrides. New and Install are standalone, firing even when no row matches the filter.
  • Install is ctrl+g (not ctrl+i, which is Tab for most terminals) and stays dialog-local to avoid the session route's messages_first.
  • The core prompt.skills now hands off to the browser when it's registered and hides itself from the palette then.
  • The plugin DialogSelect API gains actions and bindings, forwarded by the adapter.
  • Fixed a latent bug where DialogSelect evaluated its action list before selected was declared, throwing on function-valued disabled options.

Summary by CodeRabbit

  • New Features

    • Added an improved skills browser with footer actions for browsing, creating, and installing skills.
    • Added keyboard shortcuts for navigating between actions, creating skills, and installing skills.
    • Selecting a skill now inserts it into the active prompt and closes the browser.
    • Skill creation and installation retain the current search text.
    • Added dialog action buttons and keybindings for supported workflows.
  • Bug Fixes

    • Resolved conflicts between the /skills command and skills browser autocomplete.
    • Fixed an error when displaying actions with selection-dependent disabled states.