@nicknisi/pi-stash 0.1.3 → 0.1.5

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,17 +1,17 @@
1
1
  # @nicknisi/pi-stash
2
2
 
3
- Replicates Claude Code's message stash using `ctrl+shift+s` to avoid conflicts with Pi's built-in `ctrl+s` shortcuts. Press `ctrl+shift+s` to stash whatever you've typed in the input editor, go do something else, then press `ctrl+shift+s` again with an empty editor to pop the most recent stash back. Stashes live on a stack, so multiple drafts can be parked and restored LIFO.
3
+ Replicates Claude Code's message stash using `ctrl+s`. Rebind Pi's built-in `ctrl+s` actions as shown below to avoid shortcut conflicts. Press `ctrl+s` to stash whatever you've typed in the input editor, go do something else, then press `ctrl+s` again with an empty editor to pop the most recent stash back. Stashes live on a stack, so multiple drafts can be parked and restored LIFO.
4
4
 
5
5
  ## What it adds
6
6
 
7
- - **Keybinding:** `ctrl+shift+s` toggles stash/restore. See the behavior table below.
8
- - **Widget:** a single-line widget above the editor, visible whenever the stash stack is non-empty, showing a 60-char preview of the most recent stash, the count of additional stashes (`(+N more)`), and a `ctrl+shift+s to restore` hint
7
+ - **Keybinding:** `ctrl+s` toggles stash/restore. See the behavior table below.
8
+ - **Widget:** a single-line widget above the editor, visible whenever the stash stack is non-empty, showing a 60-char preview of the most recent stash, the count of additional stashes (`(+N more)`), and a `ctrl+s to restore` hint
9
9
  - **Events hooked:** `before_agent_start` — after a message is submitted and the agent starts, the most recent stash is auto-restored into the now-empty editor (mirrors Claude Code)
10
10
  - No slash commands, no tools, no custom entry types.
11
11
 
12
12
  ### Keybinding behavior
13
13
 
14
- | Editor state on `ctrl+shift+s` | Action |
14
+ | Editor state on `ctrl+s` | Action |
15
15
  | ----------------------------------------- | ------------------------------------------ |
16
16
  | Contains text | Push text onto the stack, clear the editor |
17
17
  | Empty (or whitespace) and stack non-empty | Pop the most recent stash into the editor |
@@ -21,16 +21,26 @@ Replicates Claude Code's message stash using `ctrl+shift+s` to avoid conflicts w
21
21
 
22
22
  ```text
23
23
  (type a long prompt, then need to ask something else first)
24
- ctrl+shift+s "⧉ stashed: Refactor the auth module to..." · editor cleared
24
+ ctrl+s "⧉ stashed: Refactor the auth module to..." · editor cleared
25
25
  (ask the other question; on submit, the stashed draft is restored automatically)
26
- ctrl+shift+s (with empty editor) pops the stash back manually
26
+ ctrl+s (with empty editor) pops the stash back manually
27
27
  ```
28
28
 
29
29
  The stash is in-memory only (per session, per process). It is not persisted across restarts.
30
30
 
31
31
  ## Configuration
32
32
 
33
- None. No config files, no options, no environment variables.
33
+ The stash shortcut is fixed at `ctrl+s`. Move Pi's built-in actions off that key in `~/.pi/agent/keybindings.json`:
34
+
35
+ ```json
36
+ {
37
+ "app.models.save": ["ctrl+shift+v"],
38
+ "app.thinking.save": ["ctrl+shift+v"],
39
+ "app.session.toggleSort": ["ctrl+shift+r"]
40
+ }
41
+ ```
42
+
43
+ Merge these entries into your existing config, then run `/reload`. Model-save and thinking-save use separate selectors, so they can share a key. `pi-web-access` can keep its default `ctrl+shift+s` curator shortcut.
34
44
 
35
45
  ## Dependencies
36
46
 
@@ -41,9 +51,9 @@ None. No config files, no options, no environment variables.
41
51
 
42
52
  - UI-gated: every handler checks `ctx.hasUI`; the extension is a no-op in headless/non-TUI mode.
43
53
  - Depends on the editor text APIs (`ctx.ui.getEditorText` / `setEditorText`) and the widget system (`ctx.ui.setWidget`) — these are stable pi extension APIs, but a pi version that changes editor or widget semantics could affect it.
44
- - The `before_agent_start` auto-restore pops a stash whenever a message is sent with an empty editor. If you intentionally sent a quick command and wanted the stash to stay parked, it will still be restored into the editor (you can `ctrl+shift+s` it back). This matches Claude Code's behavior.
54
+ - The `before_agent_start` auto-restore pops a stash whenever a message is sent with an empty editor. If you intentionally sent a quick command and wanted the stash to stay parked, it will still be restored into the editor (you can `ctrl+s` it back). This matches Claude Code's behavior.
45
55
  - Stash stack is module-local state; it does not survive session reload or extension reload.
46
- - The terminal must distinguish `ctrl+shift+s` from `ctrl+s`, for example through the Kitty keyboard protocol. Legacy terminals may need a key mapping. The widget preview uses the Unicode glyphs `⧉` and `…`.
56
+ - The shifted replacement shortcuts require a terminal that reports them distinctly, for example through the Kitty keyboard protocol. The widget preview uses the Unicode glyphs `⧉` and `…`.
47
57
 
48
58
  ## Install
49
59
 
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Message Stash Extension
3
3
  *
4
- * Replicates Claude Code's message stash: press ctrl+shift+s to stash
4
+ * Replicates Claude Code's message stash: press ctrl+s to stash
5
5
  * whatever you've typed in the input box, do something else, then press
6
- * ctrl+shift+s again (with an empty input) to restore it.
6
+ * ctrl+s again (with an empty input) to restore it.
7
7
  *
8
- * - ctrl+shift+s with text in the editor → pushes it onto a stack and clears
9
- * - ctrl+shift+s with an empty editor → pops the most recent stash back
8
+ * - ctrl+s with text in the editor → pushes it onto a stack and clears
9
+ * - ctrl+s with an empty editor → pops the most recent stash back
10
10
  * - sending another message → auto-restores the most recent stash
11
11
  *
12
12
  * A widget above the editor shows how many messages are stashed with a
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Message Stash Extension
3
3
  *
4
- * Replicates Claude Code's message stash: press ctrl+shift+s to stash
4
+ * Replicates Claude Code's message stash: press ctrl+s to stash
5
5
  * whatever you've typed in the input box, do something else, then press
6
- * ctrl+shift+s again (with an empty input) to restore it.
6
+ * ctrl+s again (with an empty input) to restore it.
7
7
  *
8
- * - ctrl+shift+s with text in the editor → pushes it onto a stack and clears
9
- * - ctrl+shift+s with an empty editor → pops the most recent stash back
8
+ * - ctrl+s with text in the editor → pushes it onto a stack and clears
9
+ * - ctrl+s with an empty editor → pops the most recent stash back
10
10
  * - sending another message → auto-restores the most recent stash
11
11
  *
12
12
  * A widget above the editor shows how many messages are stashed with a
@@ -28,10 +28,10 @@ export default function stash(pi) {
28
28
  const preview = firstLine.length > 60 ? `${firstLine.slice(0, 60)}…` : firstLine;
29
29
  const count = stack.length > 1 ? theme.fg('dim', ` (+${stack.length - 1} more)`) : '';
30
30
  ctx.ui.setWidget(WIDGET_KEY, [
31
- `${theme.fg('accent', '⧉ stashed:')} ${theme.fg('muted', preview)}${count} ${theme.fg('dim', '· ctrl+shift+s to restore')}`,
31
+ `${theme.fg('accent', '⧉ stashed:')} ${theme.fg('muted', preview)}${count} ${theme.fg('dim', '· ctrl+s to restore')}`,
32
32
  ]);
33
33
  };
34
- pi.registerShortcut('ctrl+shift+s', {
34
+ pi.registerShortcut('ctrl+s', {
35
35
  description: 'Stash / restore the typed message',
36
36
  handler: async (ctx) => {
37
37
  if (!ctx.hasUI)
@@ -1,11 +1,11 @@
1
1
  import { expect, it, vi } from 'vitest';
2
2
  import stash from './index.js';
3
- it('stashes and restores drafts with Ctrl+Shift+S and shows the matching hint', async () => {
3
+ it('stashes and restores drafts with Ctrl+S and shows the matching hint', async () => {
4
4
  const registerShortcut = vi.fn();
5
5
  stash({ registerShortcut, on: vi.fn() });
6
6
  expect(registerShortcut).toHaveBeenCalledOnce();
7
7
  const [key, { handler }] = registerShortcut.mock.calls[0];
8
- expect(key).toBe('ctrl+shift+s');
8
+ expect(key).toBe('ctrl+s');
9
9
  let text = 'first draft';
10
10
  const setWidget = vi.fn();
11
11
  const ctx = {
@@ -21,7 +21,7 @@ it('stashes and restores drafts with Ctrl+Shift+S and shows the matching hint',
21
21
  };
22
22
  await handler(ctx);
23
23
  expect(text).toBe('');
24
- expect(setWidget).toHaveBeenLastCalledWith('message-stash', [expect.stringContaining('ctrl+shift+s to restore')]);
24
+ expect(setWidget).toHaveBeenLastCalledWith('message-stash', [expect.stringContaining('ctrl+s to restore')]);
25
25
  text = 'second draft';
26
26
  await handler(ctx);
27
27
  expect(text).toBe('');
package/index.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Message Stash Extension
3
3
  *
4
- * Replicates Claude Code's message stash: press ctrl+shift+s to stash
4
+ * Replicates Claude Code's message stash: press ctrl+s to stash
5
5
  * whatever you've typed in the input box, do something else, then press
6
- * ctrl+shift+s again (with an empty input) to restore it.
6
+ * ctrl+s again (with an empty input) to restore it.
7
7
  *
8
- * - ctrl+shift+s with text in the editor → pushes it onto a stack and clears
9
- * - ctrl+shift+s with an empty editor → pops the most recent stash back
8
+ * - ctrl+s with text in the editor → pushes it onto a stack and clears
9
+ * - ctrl+s with an empty editor → pops the most recent stash back
10
10
  * - sending another message → auto-restores the most recent stash
11
11
  *
12
12
  * A widget above the editor shows how many messages are stashed with a
@@ -32,11 +32,11 @@ export default function stash(pi: ExtensionAPI) {
32
32
  const preview = firstLine.length > 60 ? `${firstLine.slice(0, 60)}…` : firstLine;
33
33
  const count = stack.length > 1 ? theme.fg('dim', ` (+${stack.length - 1} more)`) : '';
34
34
  ctx.ui.setWidget(WIDGET_KEY, [
35
- `${theme.fg('accent', '⧉ stashed:')} ${theme.fg('muted', preview)}${count} ${theme.fg('dim', '· ctrl+shift+s to restore')}`,
35
+ `${theme.fg('accent', '⧉ stashed:')} ${theme.fg('muted', preview)}${count} ${theme.fg('dim', '· ctrl+s to restore')}`,
36
36
  ]);
37
37
  };
38
38
 
39
- pi.registerShortcut('ctrl+shift+s', {
39
+ pi.registerShortcut('ctrl+s', {
40
40
  description: 'Stash / restore the typed message',
41
41
  handler: async (ctx) => {
42
42
  if (!ctx.hasUI) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nicknisi/pi-stash",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Stash and restore the current prompt draft",
5
5
  "keywords": [
6
6
  "pi",