Private
Public Access
0
0
Files
manual_slop/docs/superpowers/specs/2026-06-02-command-palette-design.md
T

7.7 KiB

Command Palette Implementation & Tests

Date: 2026-06-02 Status: Draft (pending review) Parent Track: command_palette_and_performance_20260602 (continuing Phase 2 + adding Phase 3) Spec: conductor/tracks/command_palette_and_performance_20260602/spec.md (existing)


Context & Motivation

A command_palette_and_performance_20260602 track was started in early June 2026. Phase 1 (Async Context Preview) is complete. Phase 2 (Command Palette) is unstarted — no src/command_palette.py, no src/commands.py, no test files. The user reports the palette doesn't pop up on Ctrl+Shift+P.

The existing spec says Ctrl+P; this design uses Ctrl+Shift+P (per the user's expectation and VSCode convention documented in docs/guide_command_palette.md).

This design finishes Phase 2 of the existing track and adds Phase 3 (tests).


Scope

In Scope

  • src/command_palette.py — Module-level: Command dataclass, CommandRegistry, fuzzy_match(), render_palette_modal(app), render_everything_modal(app)
  • src/commands.py — Static command definitions (~30-50 commands across categories)
  • src/gui_2.pyself.show_command_palette: bool in App.__init__, _render_command_palette(self) thin wrapper, Ctrl+Shift+P keyboard handler
  • tests/test_command_palette.py — Unit tests for fuzzy matcher, command registry, mode detection
  • tests/test_command_palette_sim.py — Integration tests via live_gui

Out of Scope

  • Async context preview (Phase 1; already complete)
  • The "Everything" mode async search worker (mentioned in the existing spec; defer to a follow-up track)
  • Visual theming of the palette (use existing ImGui style)

Design

Data Model: Command

@dataclass
class Command:
    id: str                    # Unique identifier
    title: str                 # Display name
    category: str              # Category for grouping
    shortcut: Optional[str]   # Optional default shortcut (e.g., "Ctrl+S")
    description: str = ""      # Optional help text
    enabled_when: Optional[str] = None  # Optional condition expression
    action: Callable = None    # Function to execute when selected

Command Registry

# src/commands.py
from src.command_palette import Command, CommandRegistry

registry = CommandRegistry()

@registry.register
def save_file(app: App) -> None:
    """Save File — File category, Ctrl+S"""
    # ... call app's save logic

Registration patterns:

  • Decorator: @registry.register for top-level functions
  • Explicit: registry.register(Command(id=..., title=..., action=...)) for closures or classes

Fuzzy Matcher

Implemented in src/command_palette.py as a pure function:

def fuzzy_match(query: str, candidates: List[Command], top_n: int = 20) -> List[ScoredCommand]:
    """
    Returns the top_n candidates matching query, ranked by score.
    
    Algorithm:
    1. Subsequence check: query chars must appear in title, in order
    2. Score calculation:
       - Exact prefix match: +1.0
       - Word boundary match: +0.5
       - Contiguous match: +0.3
       - Character distance penalty: -0.1 per gap
    3. Sort by score descending
    4. Return top_n
    """

Modal Rendering

The palette is a centered ImGui modal. Module-level function (per delegation pattern):

# src/command_palette.py
def render_palette_modal(app: App) -> None:
    """Render the Command Palette modal. Called from gui_2.py when app.show_command_palette is True."""
    if not app.show_command_palette:
        return
    imgui.set_next_window_position(...)  # Centered
    imgui.set_next_window_size(...)
    if imgui.begin("Command Palette##palette", closable=True):
        # Search input
        # Fuzzy-matched results list
        # Keyboard navigation
    imgui.end()

Keyboard Handler

In gui_2.py's main event loop:

io = imgui.get_io()
if io.key_ctrl and io.key_shift and imgui.is_key_pressed(imgui.Key.p):
    app.show_command_palette = not app.show_command_palette

File Structure

  • src/command_palette.py — NEW: Command, CommandRegistry, fuzzy_match, render_palette_modal
  • src/commands.py — NEW: Static command definitions and registry
  • src/gui_2.py — MODIFY: add self.show_command_palette, add _render_command_palette wrapper, add Ctrl+Shift+P handler, register the palette module
  • tests/test_command_palette.py — NEW: Unit tests
  • tests/test_command_palette_sim.py — NEW: Integration tests via live_gui

Tests

Unit Tests (tests/test_command_palette.py)

def test_fuzzy_match_prefix_ranks_first():
    from src.command_palette import fuzzy_match
    candidates = [
        Command(id="find", title="Find in Selection"),
        Command(id="fold", title="Fold All"),
        Command(id="config", title="Configure Settings"),
    ]
    results = fuzzy_match("fin", candidates)
    assert results[0].command.id == "find"
    assert results[0].score > 0.5

def test_fuzzy_match_rejects_no_match():
    from src.command_palette import fuzzy_match
    candidates = [Command(id="x", title="foo bar")]
    results = fuzzy_match("xyz", candidates)
    assert len(results) == 0

def test_command_registry_register_and_list():
    from src.command_palette import CommandRegistry
    from src.commands import registry
    assert "save_file" in registry.all()
    # All commands have id, title, category
    for cmd in registry.all():
        assert cmd.id and cmd.title and cmd.category

def test_command_registry_duplicate_raises():
    from src.command_palette import CommandRegistry, Command
    reg = CommandRegistry()
    reg.register(Command(id="x", title="X", category="test"))
    with pytest.raises(ValueError):
        reg.register(Command(id="x", title="X", category="test"))

Integration Tests (tests/test_command_palette_sim.py)

def test_ctrl_shift_p_opens_palette(live_gui):
    client = live_gui[1]
    # Press Ctrl+Shift+P
    client.press_key_combo("Ctrl+Shift+P")
    # Verify the palette is visible
    state = client.get_window_state("command_palette")
    assert state["visible"] == True

def test_palette_filters_as_user_types(live_gui):
    client = live_gui[1]
    client.press_key_combo("Ctrl+Shift+P")
    client.type_in_palette("save")
    results = client.get_palette_results()
    assert any("Save" in r.title for r in results)
    # Other commands not shown
    assert not any("Compress" in r.title for r in results)

def test_palette_executes_command_on_enter(live_gui):
    client = live_gui[1]
    client.press_key_combo("Ctrl+Shift+P")
    client.type_in_palette("Reset")
    client.press_key("Down")
    client.press_key("Enter")
    # Verify the reset command was executed (check via Hook API)
    state = client.get_session_state()
    assert state.get("discussion_history", []) == []

Acceptance Criteria

  • Ctrl+Shift+P opens the palette (verified via live_gui test)
  • Typing in the palette filters results via fuzzy match
  • Selecting a command (Enter key) executes it and closes the palette
  • Escape closes the palette without executing
  • All unit tests pass
  • All integration tests pass
  • The palette respects the existing theme (dark/light/nerv)
  • No new lint errors

Risks

  1. Keyboard handler conflicts: The Ctrl+Shift+P combo might be intercepted by other subsystems. Mitigation: check for other handlers in the codebase first; if conflicts, document them.
  2. Pyodide build dependencies: The image_bundle web backend (for Track 4) has a different architecture than this track. The two are independent but should be aware of each other.
  3. Test flakiness: live_gui tests can be flaky if the GUI doesn't initialize in time. Mitigation: the standard 15-second readiness polling is sufficient.