@nanstey/pi-command-shortcuts
v0.1.0
Published
Bind keyboard shortcuts to any extension slash command in pi via a JSON config
Maintainers
Readme
@nanstey/pi-command-shortcuts
Bind keyboard shortcuts to any extension slash command in pi.
pi's built-in keybindings.json only remaps built-in actions — it can't bind a
key to an extension command like /voice. This extension does, driven by a
small JSON config.
Install
pi install npm:@nanstey/pi-command-shortcutsUsage
Create ~/.pi/agent/command-shortcuts.json mapping keys to commands:
{
"ctrl+r": "voice",
"ctrl+g": { "command": "websearch", "args": "" }
}Reload with /reload (or restart pi). Press the key to run the command.
Each value is either:
- a string — the command name (no leading slash). The owning extension is auto-discovered by scanning your installed packages.
- an object —
{ "command": "...", "from": "...", "args": "..." }command— command name to run (required).from— package name (@scope/pkg) or module path that registers the command. Skips the scan; faster and unambiguous. Optional.args— default argument string passed to the command. Optional.
Keys use pi's key syntax, e.g. ctrl+r, ctrl+shift+v, alt+enter.
How it works
Extension command handlers are private to pi, and shortcut handlers have no
"run command by name" API. So this extension re-runs the owning extension's
factory with a Proxy of the real pi that:
- captures
registerCommand()handlers, - no-ops the other
register*/on()calls so nothing is double-registered, - forwards every other method (
sendMessage,sendUserMessage, …) to the realpi, so a captured handler behaves exactly like the real command.
The resolved handler is cached per binding and invoked when you press the key. Modules are loaded through pi's own loader, so TypeScript extensions work without a build step.
Notes
- Context limitation. Shortcut handlers receive an
ExtensionContext, not the richerExtensionCommandContext. Commands that rely on command-only methods (newSession,waitForIdle,fork, …) may not work from a key. This is a pi limitation tracked in pi#4422. Commands that only usectx.uiand messaging (like/voice) work fine. - Conflicts. If a key already drives a built-in action (e.g.
ctrl+ris the session-picker rename), pi logs a harmless conflict diagnostic and this binding wins in the editor. Pick a free combo (ctrl+shift+…) to avoid it. - Discovery. Prefer
fromfor speed and to avoid importing unrelated extensions during the auto-scan.
License
MIT
