Add hqt palette CLI subcommand (fzf tool launcher)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 08:13:31 -04:00
parent a798c2bcf4
commit e35828d819
2 changed files with 106 additions and 0 deletions
+62
View File
@@ -169,6 +169,68 @@ def tool_cmd(tool, window):
raise SystemExit(1)
PALETTE_ENTRIES = ["nvim", "lazygit", "shell", "clone"]
# fzf colors matching the Catppuccin Frappé status bar / the Alt+o switcher.
_PALETTE_FZF_COLORS = (
"bg:#292c3c,bg+:#414559,fg:#c6d0f5,fg+:#c6d0f5,hl:#ef9f76,hl+:#ef9f76,"
"pointer:#ef9f76,prompt:#8caaee,info:#838ba7,border:#838ba7"
)
def _palette_popup_command(window: str) -> str:
"""Shell pipeline for the fzf popup; `window` is baked in as a literal.
display-popup does NOT format-expand its command, so the window name must be
concrete here (run-shell already expanded #{window_name} before `hqt palette`
ran). The selected entry runs `hqt tool <choice> <window>`.
"""
import shlex
entries = "\\n".join(PALETTE_ENTRIES) + "\\n"
return (
f"printf '{entries}' | "
f"fzf --reverse --no-info --prompt='tool ' --pointer='' "
f"--color='{_PALETTE_FZF_COLORS}' | "
f"xargs -r -I{{}} hqt tool {{}} {shlex.quote(window)}"
)
@main.command(name="palette")
@click.argument("window")
def palette_cmd(window):
"""Pop an fzf tool palette for the session in tmux WINDOW (bound to M-p)."""
from hqt.config import get_settings
settings = get_settings()
svc = _build_session_service()
if svc.session_id_for_window(window) is None:
subprocess.run(
[
settings.tmux_path,
"display-message",
"hqt: open the tool palette from a harness window",
]
)
return
subprocess.run(
[
settings.tmux_path,
"display-popup",
"-E",
"-w",
"40%",
"-h",
"30%",
"-T",
" open tool ",
"-S",
"fg=#838ba7",
_palette_popup_command(window),
]
)
@main.command(name="list")
def list_cmd():
"""List projects and sessions."""
+44
View File
@@ -63,3 +63,47 @@ def test_tool_cmd_reports_service_error(monkeypatch, tmp_path):
assert result.exit_code == 1
assert "not an hqt session window" in result.output
def test_palette_cmd_shows_popup_for_session_window(monkeypatch, tmp_path):
monkeypatch.setattr(
"hqt.config.get_settings", lambda: Settings(db_path=tmp_path / "t.db")
)
monkeypatch.setattr(
"hqt.sessions.service.SessionService.session_id_for_window",
lambda self, window: 5,
)
runs = []
monkeypatch.setattr(cli.subprocess, "run", lambda argv, **kw: runs.append(argv))
result = CliRunner().invoke(cli.main, ["palette", "hqt-5"])
assert result.exit_code == 0, result.output
assert len(runs) == 1
argv = runs[0]
assert "display-popup" in argv
popup_cmd = argv[-1]
assert "fzf" in popup_cmd
assert "nvim" in popup_cmd and "clone" in popup_cmd
# the window is baked into the command for `hqt tool {} <window>`
assert "hqt-5" in popup_cmd
def test_palette_cmd_hints_for_non_session_window(monkeypatch, tmp_path):
monkeypatch.setattr(
"hqt.config.get_settings", lambda: Settings(db_path=tmp_path / "t.db")
)
monkeypatch.setattr(
"hqt.sessions.service.SessionService.session_id_for_window",
lambda self, window: None,
)
runs = []
monkeypatch.setattr(cli.subprocess, "run", lambda argv, **kw: runs.append(argv))
result = CliRunner().invoke(cli.main, ["palette", "nvim"])
assert result.exit_code == 0, result.output
assert len(runs) == 1
argv = runs[0]
assert "display-message" in argv
assert "display-popup" not in argv