@nicknisi/pi-stash 0.1.0
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/LICENSE +21 -0
- package/README.md +52 -0
- package/index.ts +62 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nick Nisi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @nicknisi/pi-stash
|
|
2
|
+
|
|
3
|
+
Replicates Claude Code's `ctrl+s` message stash. Press `ctrl+s` to stash whatever you've typed in the input editor, go do something else (run a command, answer another prompt), 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
|
+
|
|
5
|
+
## What it adds
|
|
6
|
+
|
|
7
|
+
- **Keybinding:** `ctrl+s` — stash/restore toggle (see 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
|
+
- **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
|
+
- No slash commands, no tools, no custom entry types.
|
|
11
|
+
|
|
12
|
+
### Keybinding behavior
|
|
13
|
+
|
|
14
|
+
| Editor state on `ctrl+s` | Action |
|
|
15
|
+
| ----------------------------------------- | ------------------------------------------ |
|
|
16
|
+
| Contains text | Push text onto the stack, clear the editor |
|
|
17
|
+
| Empty (or whitespace) and stack non-empty | Pop the most recent stash into the editor |
|
|
18
|
+
| Empty and stack empty | No-op |
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
(type a long prompt, then need to ask something else first)
|
|
24
|
+
ctrl+s "⧉ stashed: Refactor the auth module to..." · editor cleared
|
|
25
|
+
(ask the other question; on submit, the stashed draft is restored automatically)
|
|
26
|
+
ctrl+s (with empty editor) pops the stash back manually
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The stash is in-memory only (per session, per process). It is not persisted across restarts.
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
None. No config files, no options, no environment variables.
|
|
34
|
+
|
|
35
|
+
## Dependencies
|
|
36
|
+
|
|
37
|
+
- **Peer:** `@earendil-works/pi-coding-agent` (`*`). Uses only the public extension API: `pi.registerShortcut`, `pi.on("before_agent_start")`, `ctx.ui.getEditorText` / `setEditorText` / `setWidget` / `theme`, and `ctx.hasUI`.
|
|
38
|
+
- No runtime npm dependencies, no workspace deps.
|
|
39
|
+
|
|
40
|
+
## Caveats
|
|
41
|
+
|
|
42
|
+
- UI-gated: every handler checks `ctx.hasUI`; the extension is a no-op in headless/non-TUI mode.
|
|
43
|
+
- 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+s` it back). This matches Claude Code's behavior.
|
|
45
|
+
- Stash stack is module-local state; it does not survive session reload or extension reload.
|
|
46
|
+
- No platform-specific behavior (works on any OS/terminal pi runs in). The widget preview uses the Unicode glyphs `⧉` and `…`.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pi install /Users/nicknisi/Developer/pi-extensions/packages/stash
|
|
52
|
+
```
|
package/index.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Stash Extension
|
|
3
|
+
*
|
|
4
|
+
* Replicates Claude Code's ctrl+s message stash: press ctrl+s to stash
|
|
5
|
+
* whatever you've typed in the input box, do something else, then press
|
|
6
|
+
* ctrl+s again (with an empty input) to restore it.
|
|
7
|
+
*
|
|
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
|
+
* - sending another message → auto-restores the most recent stash
|
|
11
|
+
*
|
|
12
|
+
* A widget above the editor shows how many messages are stashed with a
|
|
13
|
+
* one-line preview of the most recent one.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
17
|
+
|
|
18
|
+
const WIDGET_KEY = "message-stash";
|
|
19
|
+
|
|
20
|
+
export default function stash(pi: ExtensionAPI) {
|
|
21
|
+
const stack: string[] = [];
|
|
22
|
+
|
|
23
|
+
const updateWidget = (ctx: ExtensionContext) => {
|
|
24
|
+
if (!ctx.hasUI) return;
|
|
25
|
+
if (stack.length === 0) {
|
|
26
|
+
ctx.ui.setWidget(WIDGET_KEY, undefined);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const theme = ctx.ui.theme;
|
|
30
|
+
const latest = stack[stack.length - 1]!;
|
|
31
|
+
const firstLine = latest.split("\n")[0] ?? "";
|
|
32
|
+
const preview = firstLine.length > 60 ? `${firstLine.slice(0, 60)}…` : firstLine;
|
|
33
|
+
const count = stack.length > 1 ? theme.fg("dim", ` (+${stack.length - 1} more)`) : "";
|
|
34
|
+
ctx.ui.setWidget(WIDGET_KEY, [
|
|
35
|
+
`${theme.fg("accent", "⧉ stashed:")} ${theme.fg("muted", preview)}${count} ${theme.fg("dim", "· ctrl+s to restore")}`,
|
|
36
|
+
]);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
pi.registerShortcut("ctrl+s", {
|
|
40
|
+
description: "Stash / restore the typed message",
|
|
41
|
+
handler: async (ctx) => {
|
|
42
|
+
if (!ctx.hasUI) return;
|
|
43
|
+
const text = ctx.ui.getEditorText();
|
|
44
|
+
if (text.trim().length > 0) {
|
|
45
|
+
stack.push(text);
|
|
46
|
+
ctx.ui.setEditorText("");
|
|
47
|
+
} else if (stack.length > 0) {
|
|
48
|
+
ctx.ui.setEditorText(stack.pop()!);
|
|
49
|
+
}
|
|
50
|
+
updateWidget(ctx);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// After a message is submitted, auto-restore the most recent stash into
|
|
55
|
+
// the now-empty editor (mirrors Claude Code's behavior).
|
|
56
|
+
pi.on("before_agent_start", async (_event, ctx) => {
|
|
57
|
+
if (!ctx.hasUI || stack.length === 0) return;
|
|
58
|
+
if (ctx.ui.getEditorText().trim().length > 0) return;
|
|
59
|
+
ctx.ui.setEditorText(stack.pop()!);
|
|
60
|
+
updateWidget(ctx);
|
|
61
|
+
});
|
|
62
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nicknisi/pi-stash",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Stash and restore the current prompt draft",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi",
|
|
7
|
+
"pi-coding-agent",
|
|
8
|
+
"pi-package"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
"index.ts"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./index.ts"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
19
|
+
},
|
|
20
|
+
"pi": {
|
|
21
|
+
"extensions": [
|
|
22
|
+
"./index.ts"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/nicknisi/pi-extensions.git",
|
|
29
|
+
"directory": "packages/stash"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/nicknisi/pi-extensions/tree/main/packages/stash#readme"
|
|
32
|
+
}
|