@d3ara1n/pi-command-palette 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # pi-command-palette
2
2
 
3
- Global command palette for [Pi Coding Agent](https://pi.dev) — press **Ctrl+Shift+P** to search and run commands from anywhere.
3
+ Global command palette for [Pi Coding Agent](https://pi.dev) — press **Ctrl+Alt+P** to search and run commands from anywhere.
4
4
 
5
5
  ## Why?
6
6
 
@@ -18,7 +18,7 @@ pi install npm:@d3ara1n/pi-command-palette
18
18
 
19
19
  Or add to `~/.pi/agent/settings.json`:
20
20
 
21
- ```jsonc
21
+ ```json
22
22
  {
23
23
  "extensions": [
24
24
  "/absolute/path/to/pi-extensions/packages/pi-command-palette"
@@ -30,7 +30,7 @@ Or add to `~/.pi/agent/settings.json`:
30
30
 
31
31
  | Shortcut | Action |
32
32
  |----------|--------|
33
- | `Ctrl+Shift+P` _(default, configurable)_ | Open command palette |
33
+ | `Ctrl+Alt+P` _(default, configurable)_ | Open command palette |
34
34
 
35
35
  The palette lists:
36
36
 
@@ -50,28 +50,28 @@ The "Model: Switch Model" action opens a secondary overlay listing all models wi
50
50
 
51
51
  ## Configuration
52
52
 
53
- The default shortcut is `Ctrl+Shift+P`. If it conflicts with your terminal, override it via either of the following (evaluated in order, first match wins).
53
+ The default shortcut is `Ctrl+Alt+P`. This avoids pi's built-in `Ctrl+P` / `Ctrl+Shift+P` model cycling shortcuts while keeping the palette mnemonic. If it conflicts with your terminal, override it via either of the following (evaluated in order, first match wins).
54
54
 
55
55
  ### 1. Environment variable
56
56
 
57
57
  Useful for terminals that intercept `Ctrl+Shift+<key>` before it reaches the session (e.g. Termius on Windows/WSL2):
58
58
 
59
59
  ```bash
60
- export PI_COMMAND_PALETTE_KEY=ctrl+alt+k
60
+ export PI_COMMAND_PALETTE_KEY=ctrl+shift+p
61
61
  ```
62
62
 
63
63
  Add it to your shell profile to persist (`~/.zshrc` on macOS, `~/.bashrc` on bash).
64
64
 
65
65
  ### 2. settings.json
66
66
 
67
- Set `commandPalette.shortcut` in `~/.pi/agent/settings.json` (global) or `.pi/settings.json` in your project (project overrides global):
67
+ Set `commandPalette.shortcut` in `~/.pi/agent/settings.json` (global) or `.pi/settings.json` in your project. A present project `commandPalette` block replaces the global block:
68
68
 
69
- ```jsonc
69
+ ```json
70
70
  {
71
71
  "commandPalette": {
72
- "shortcut": "ctrl+alt+k"
72
+ "shortcut": "ctrl+shift+p"
73
73
  }
74
74
  }
75
75
  ```
76
76
 
77
- Any valid pi keybinding string works (e.g. `ctrl+shift+k`, `ctrl+alt+p`, `ctrl+k`). Restart pi (or run `/reload`) after changing the shortcut.
77
+ Any valid pi keybinding string works (e.g. `ctrl+shift+p`, `ctrl+shift+k`, `ctrl+alt+k`, `ctrl+k`). Restart pi (or run `/reload`) after changing the shortcut.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d3ara1n/pi-command-palette",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Global command palette for pi — press Ctrl+Shift+P to search and run commands from anywhere",
6
6
  "main": "src/index.ts",
package/src/config.ts CHANGED
@@ -4,9 +4,9 @@
4
4
  * Priority (highest wins):
5
5
  * 1. `PI_COMMAND_PALETTE_KEY` env var — works even when the terminal intercepts
6
6
  * `Ctrl+Shift+P` before it reaches the session (e.g. Termius on Windows/WSL2).
7
- * 2. `settings.json` `commandPalette.shortcut` (project `.pi/settings.json`
8
- * overrides global `~/.pi/agent/settings.json`)
9
- * 3. default `"ctrl+shift+p"`
7
+ * 2. `settings.json` `commandPalette.shortcut` (a present project
8
+ * `commandPalette` block replaces the global block)
9
+ * 3. default `"ctrl+alt+p"`
10
10
  *
11
11
  * Why not a CLI flag? Flags are applied to the extension runtime AFTER extensions
12
12
  * load, so `pi.getFlag()` only returns the registered default at `registerShortcut()`
@@ -19,7 +19,7 @@ import * as os from "node:os";
19
19
  import * as path from "node:path";
20
20
  import type { KeyId } from "@earendil-works/pi-tui";
21
21
 
22
- export const DEFAULT_SHORTCUT = "ctrl+shift+p";
22
+ export const DEFAULT_SHORTCUT = "ctrl+alt+p";
23
23
 
24
24
  function getAgentDir(): string {
25
25
  const envDir = process.env.PI_AGENT_DIR;
@@ -54,12 +54,13 @@ export function resolveShortcutKey(cwd: string = process.cwd()): KeyId {
54
54
  const envKey = normalizeKey(process.env.PI_COMMAND_PALETTE_KEY);
55
55
  if (envKey) return envKey as KeyId;
56
56
 
57
- // 2. settings.json — global ~/.pi/agent/settings.json; project overrides global.
57
+ // 2. settings.json — a present project block replaces the global block.
58
58
  const globalSettings = readSettings(path.join(getAgentDir(), "settings.json"));
59
59
  const projectSettings = readSettings(path.join(cwd, ".pi", "settings.json"));
60
- const globalCfg = (globalSettings.commandPalette ?? {}) as { shortcut?: unknown };
61
- const projectCfg = (projectSettings.commandPalette ?? {}) as { shortcut?: unknown };
62
- const settingsKey = normalizeKey(projectCfg.shortcut ?? globalCfg.shortcut);
60
+ const globalRaw = globalSettings.commandPalette;
61
+ const projectRaw = projectSettings.commandPalette;
62
+ const config = (projectRaw ?? globalRaw ?? {}) as { shortcut?: unknown };
63
+ const settingsKey = normalizeKey(config.shortcut);
63
64
  if (settingsKey) return settingsKey as KeyId;
64
65
 
65
66
  // 3. default
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Regression tests for model reference parsing.
3
+ * Run: node --test packages/pi-command-palette/src/index.test.ts
4
+ */
5
+
6
+ import assert from "node:assert/strict";
7
+ import { test } from "node:test";
8
+ import { parseModelRef } from "./index.ts";
9
+
10
+ test("parseModelRef splits provider and model at the first slash", () => {
11
+ assert.deepEqual(parseModelRef("anthropic/claude-sonnet"), {
12
+ provider: "anthropic",
13
+ modelId: "claude-sonnet",
14
+ });
15
+ assert.deepEqual(parseModelRef("openrouter/vendor/model/with/slashes"), {
16
+ provider: "openrouter",
17
+ modelId: "vendor/model/with/slashes",
18
+ });
19
+ });
20
+
21
+ test("parseModelRef preserves empty provider or model segments", () => {
22
+ assert.equal(parseModelRef("model-without-provider"), undefined);
23
+ assert.deepEqual(parseModelRef("/model"), { provider: "", modelId: "model" });
24
+ assert.deepEqual(parseModelRef("provider/"), { provider: "provider", modelId: "" });
25
+ });
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * pi-command-palette — Global command palette for pi.
3
3
  *
4
- * Press Ctrl+Shift+P to open a searchable command palette overlay,
4
+ * Press Ctrl+Alt+P to open a searchable command palette overlay,
5
5
  * regardless of whether the editor has content.
6
6
  *
7
7
  * Features:
@@ -157,6 +157,18 @@ function buildPaletteItems(pi: ExtensionAPI, ctx: ExtensionContext): PaletteItem
157
157
 
158
158
  const STAR = "★ ";
159
159
 
160
+ /**
161
+ * @internal — exported for testing; parses the selector's `provider/model-id` values.
162
+ */
163
+ export function parseModelRef(modelRef: string): { provider: string; modelId: string } | undefined {
164
+ const slash = modelRef.indexOf("/");
165
+ if (slash === -1) return undefined;
166
+ return {
167
+ provider: modelRef.slice(0, slash),
168
+ modelId: modelRef.slice(slash + 1),
169
+ };
170
+ }
171
+
160
172
  /**
161
173
  * Resolve the set of "scoped" model full-ids (`provider/id`) — the same models
162
174
  * pi surfaces in its built-in selector's "scoped" tab and Ctrl+P cycling.
@@ -298,7 +310,9 @@ async function showModelSelector(pi: ExtensionAPI, ctx: ExtensionContext): Promi
298
310
 
299
311
  if (!result) return;
300
312
 
301
- const [provider, modelId] = result.split("/");
313
+ const parsed = parseModelRef(result);
314
+ if (!parsed) return;
315
+ const { provider, modelId } = parsed;
302
316
  const model = ctx.modelRegistry.find(provider, modelId);
303
317
  if (model) {
304
318
  const success = await pi.setModel(model);