@andares/pi-toolkits 0.5.0 → 0.7.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/README.md +158 -112
- package/README.zh-CN.md +337 -0
- package/package.json +6 -3
- package/src/features/autostart/autostart.test.ts +315 -0
- package/src/features/autostart/autostart.ts +108 -0
- package/src/features/autostart/index.ts +109 -0
- package/src/features/favorites/constants.ts +35 -5
- package/src/features/favorites/favorites.test.ts +23 -5
- package/src/features/favorites/index.ts +9 -5
- package/src/features/favorites/patch-selector.ts +7 -7
- package/src/index.ts +4 -1
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<!-- markdownlint-disable MD033 -->
|
|
2
|
-
<!-- Inline <a name> anchors
|
|
2
|
+
<!-- Inline <a name> anchors keep the TOC targets stable and identical across README.md and README.zh-CN.md. -->
|
|
3
3
|
# ⚙️ @andares/pi-toolkits
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**English** · [中文](README.zh-CN.md)
|
|
6
|
+
|
|
6
7
|
> Integrated toolkit extension for [pi](https://github.com/earendil-works/pi-coding-agent) — one package, growing new capabilities over time.
|
|
7
8
|
|
|
8
9
|
[](https://www.npmjs.com/package/@andares/pi-toolkits)
|
|
@@ -11,99 +12,100 @@
|
|
|
11
12
|
[](https://github.com/earendil-works/pi)
|
|
12
13
|
[](https://github.com/andares/pi-toolkits)
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
Currently ships five ready-to-use capabilities — **ask mode**, **model favorites**, **prompt stash**, **third-party code review** and a **dedicated compaction model** — with more to come.
|
|
15
|
+
In a nutshell: six ready-to-use capabilities — **read-only consult mode** `ask`, **model favorites** `favorites`, **prompt stash** `stash`, **third-party code review** `third-review`, **dedicated compaction model** `compact-model` and **session startup automation** `autostart` — with more to come.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
**Requirements**: pi `>=0.86.0 <2.0.0` (covering the four most recently released minor lines — 0.86.x / 0.87.x / 0.99.x / 1.0.x; 0.88–0.98 were never released). Every one of the 10 published versions inside that range was compared against the host `dist`: no differences in the extension APIs we use, and the two runtime patch targets used by favorites — `ModelSelectorComponent` / `AgentSession.cycleModel` — are byte-identical. `typecheck` plus the full test suite pass on each of 0.86.0, 0.86.1, 0.87.1, 0.99.2 and 1.0.2, and smoke-loading on real pi 1.0.2 produces no warnings. Note: pi ≥ 0.99 hosts require `@earendil-works/pi-tui` to be declared in `peerDependencies` as `"*"` (provided by the host); this package declares it as required.
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
## 📦
|
|
21
|
+
## 📦 Installation
|
|
22
22
|
|
|
23
23
|
<a name="install"></a>
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
#
|
|
26
|
+
# from npm (recommended)
|
|
27
27
|
pi install npm:@andares/pi-toolkits
|
|
28
28
|
|
|
29
|
-
#
|
|
29
|
+
# local development install
|
|
30
30
|
pi install .
|
|
31
31
|
|
|
32
|
-
#
|
|
32
|
+
# one-off session load, no install
|
|
33
33
|
pi -e ./src/index.ts
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
After installing, verify in any pi session:
|
|
37
37
|
|
|
38
|
-
- `/ask` →
|
|
39
|
-
- `/model`(
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
- `/compact-model
|
|
38
|
+
- `/ask` → a grey `ask` status appears in the footer, `write`/`edit` are hard-disabled
|
|
39
|
+
- `/model` (or `ctrl+l`) → a favorites hint line appears at the top of the selector
|
|
40
|
+
- press `ctrl+alt+y` in the input box → the current prompt is stashed and the input box is cleared
|
|
41
|
+
- after finishing a development task, type `/third-review` → switches to the review model and runs check + fix
|
|
42
|
+
- `/compact-model`, pick a cheap fast model → from then on both `/compact` and auto-compaction summarize with it (a grey `compact` status appears in the footer)
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
46
|
-
## 📚
|
|
46
|
+
## 📚 Contents
|
|
47
47
|
|
|
48
|
-
- [
|
|
49
|
-
- [
|
|
50
|
-
- [🛡️ ask —
|
|
51
|
-
- [⭐ favorites —
|
|
52
|
-
- [📥 stash —
|
|
53
|
-
- [🔎 review —
|
|
54
|
-
- [🗜️ compact —
|
|
55
|
-
- [
|
|
56
|
-
- [
|
|
57
|
-
- [
|
|
48
|
+
- [Installation](#install)
|
|
49
|
+
- [Features at a glance](#features)
|
|
50
|
+
- [🛡️ ask — read-only consult mode](#ask)
|
|
51
|
+
- [⭐ favorites — model favorites](#favorites)
|
|
52
|
+
- [📥 stash — prompt stash](#stash)
|
|
53
|
+
- [🔎 review — third-party code review](#review)
|
|
54
|
+
- [🗜️ compact — dedicated compaction model](#compact)
|
|
55
|
+
- [🚀 autostart — session startup automation](#autostart)
|
|
56
|
+
- [Development](#development)
|
|
57
|
+
- [Contributing](#contributing)
|
|
58
|
+
- [License](#license)
|
|
58
59
|
|
|
59
60
|
---
|
|
60
61
|
|
|
61
|
-
## ✨
|
|
62
|
+
## ✨ Features at a glance
|
|
62
63
|
|
|
63
64
|
<a name="features"></a>
|
|
64
65
|
|
|
65
|
-
|
|
|
66
|
+
| Feature | Entry point | One-line description |
|
|
66
67
|
| --- | --- | --- |
|
|
67
|
-
| 🛡️ **ask**
|
|
68
|
-
| ⭐ **favorites**
|
|
69
|
-
| 📥 **stash**
|
|
70
|
-
| 🔎 **review**
|
|
71
|
-
| 🗜️ **compact**
|
|
68
|
+
| 🛡️ **ask** read-only consult mode | `/ask` | enter read-only Q&A mode: `write`/`edit` hard-disabled, `bash` runs in a read-only sandbox |
|
|
69
|
+
| ⭐ **favorites** model favorites | `ctrl+alt+F` / `ctrl+J` inside `/model` | favorite the models you use most (marked in bold bright yellow), `ctrl+p` cycles only among favorites |
|
|
70
|
+
| 📥 **stash** prompt stash | `ctrl+alt+y` | a stash slot for one prompt: press to swap, press twice to stash and clear the input box |
|
|
71
|
+
| 🔎 **review** third-party code review | `/third-review` | summon the configured review model to check + fix the task just finished, focusing on "is this round's requirement implemented / is anything missing / is anything wrong" |
|
|
72
|
+
| 🗜️ **compact** dedicated compaction model | `/compact-model` | give `/compact` and auto-compact a cheap fast model to summarize with, leaving the main model free to focus on the conversation; zero overhead when unconfigured, falls back to pi's default on any failure |
|
|
73
|
+
| 🚀 **autostart** session startup automation | `.pi/autostart.toml` | declare slash commands to run automatically at session start, per project (first use case: mounting multi-repo directories with `/add-dir`); never runs in untrusted directories, unregistered commands are skipped instead of being sent to the model |
|
|
72
74
|
|
|
73
75
|
---
|
|
74
76
|
|
|
75
|
-
## 🛡️ ask —
|
|
77
|
+
## 🛡️ ask — read-only consult mode
|
|
76
78
|
|
|
77
79
|
<a name="ask"></a>
|
|
78
80
|
|
|
79
|
-
|
|
81
|
+
Enter with `/ask` (press it again to exit). Meant for the case where you only want to "ask questions and read code", and absolutely never want the model to modify any file.
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
**While active**:
|
|
82
84
|
|
|
83
|
-
- **`write` / `edit`
|
|
84
|
-
- **`bash`
|
|
85
|
-
-
|
|
86
|
-
-
|
|
85
|
+
- **`write` / `edit` hard-disabled** — removed from the active tool set; pi rejects calls to inactive tools outright ("Tool not found"), so file modification becomes mechanically impossible
|
|
86
|
+
- **`bash` kept, but sandboxed to read-only** — based on shell tokenization plus write-intent detection (blocks `curl -o/-O`, `wget -O`, `dd of=`, `tee`, redirections, and the like). Heuristic, not a security boundary
|
|
87
|
+
- **System prompt appendix** — a mode description is appended so the model behaves along the read-only constraint
|
|
88
|
+
- **Grey `ask` footer status** — a permanent reminder that read-only mode is on
|
|
87
89
|
|
|
88
|
-
|
|
90
|
+
**Exit**: press `/ask` again; the tool-set snapshot taken on entry is fully restored.
|
|
89
91
|
|
|
90
92
|
---
|
|
91
93
|
|
|
92
|
-
## ⭐ favorites —
|
|
94
|
+
## ⭐ favorites — model favorites
|
|
93
95
|
|
|
94
96
|
<a name="favorites"></a>
|
|
95
97
|
|
|
96
|
-
|
|
98
|
+
Mark the models you use often so that model switching "sticks" to them. Favorites are **persisted globally, across sessions and projects**.
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
**Inside the `/model` selector** (open it with `/model` or `ctrl+l`):
|
|
99
101
|
|
|
100
|
-
-
|
|
101
|
-
- `ctrl+F`
|
|
102
|
-
- `ctrl+J`
|
|
102
|
+
- The top hint line shows the keys and the current filter state
|
|
103
|
+
- `ctrl+alt+F` — toggle the favorite flag on the currently selected model; favorite models are rendered in **bold bright yellow**
|
|
104
|
+
- `ctrl+J` — toggle the "show only favorite models" filter (composable with the built-in search)
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
**Model cycling**: as long as ≥1 favorite exists, `ctrl+p` / `ctrl+shift+p` cycle **only among favorite models**. When the current model is not a favorite, `ctrl+p` jumps to the first favorite and `ctrl+shift+p` to the last; with exactly one favorite it stays put (`Only one model available`). `ctrl+l` / `/model` always allow picking any model freely, favorites or not. Set `"cycleOnlyFavorites": false` in the state file to restore full cycling.
|
|
105
107
|
|
|
106
|
-
|
|
108
|
+
**State file**: `<agent-dir>/pi-toolkits-favorites.json` (defaults to `~/.pi/agent/`, the same directory as the auto-naming-session config):
|
|
107
109
|
|
|
108
110
|
```json
|
|
109
111
|
{
|
|
@@ -112,117 +114,159 @@ pi -e ./src/index.ts
|
|
|
112
114
|
}
|
|
113
115
|
```
|
|
114
116
|
|
|
115
|
-
`/favorites`
|
|
117
|
+
The `/favorites` command lists the current favorites and the cycling mode.
|
|
116
118
|
|
|
117
|
-
>
|
|
119
|
+
> **Implementation notes**: pi's `app.model.cycleForward` (`ctrl+p`) and `cycleBackward` are **reserved keybindings** that extension shortcuts cannot override; extension shortcuts also only fire while the editor is focused. This feature therefore rebinds nothing; instead it patches two built-in prototypes at runtime (version-guarded, idempotent under `/reload`): `ModelSelectorComponent` (hint line, `ctrl+alt+F`/`ctrl+J`, bright-yellow rendering, favorites-only filter — the keys are consumed only inside the selector, so in the editor `ctrl+j` still inserts a newline) and `AgentSession.cycleModel` (favorites-only cycling). If a pi upgrade makes the patch inapplicable, it warns and degrades gracefully without affecting the other features.
|
|
120
|
+
>
|
|
121
|
+
> **Why `ctrl+alt+F` and not `ctrl+F`**: since pi 1.0 the default `tuiMode` is `fullscreen` (0.86–0.99 defaulted to `regular`), and on Windows/WSL the host resolves `tui.altScreen.search` to `ctrl+f`; `TuiAltScreen.handleViewportInput()` checks that binding **before** handing input to the focused overlay, so `ctrl+f` opened the transcript search instead of reaching the selector. `alt+f`, `shift+f` and `ctrl+shift+f` are all taken or unreliable as well — see `src/features/favorites/constants.ts` and `pnpm check:keybindings`.
|
|
118
122
|
|
|
119
123
|
---
|
|
120
124
|
|
|
121
|
-
## 📥 stash —
|
|
125
|
+
## 📥 stash — prompt stash
|
|
122
126
|
|
|
123
127
|
<a name="stash"></a>
|
|
124
128
|
|
|
125
|
-
|
|
129
|
+
One hotkey plus one stash slot, shuffling between "the prompt I am writing" and "the prompt I stashed": park a prompt to one side, free the input box for a new one, and take the old one back when you need it.
|
|
126
130
|
|
|
127
|
-
|
|
|
131
|
+
| Action | Effect |
|
|
128
132
|
| --- | --- |
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
| **400ms
|
|
133
|
+
| Press `ctrl+alt+y` once | current prompt → stash; stashed content → input box (**swap**) |
|
|
134
|
+
| Press again after a while | **toggle back and forth** between the two prompts |
|
|
135
|
+
| Press twice **within 400ms** | current prompt goes to the stash + **input box is cleared** (the old stash is discarded), so you can start writing the new prompt right away; later press once to take it back |
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
When the stash is empty, a single press means "stash + clear". The stash is **in-process memory and never written to disk** (prompts may contain sensitive content); `/new` switches sessions without clearing the stash, `/reload` clears it. While a selector (`/model`, `/tree`, …) is open the key does nothing (focus is on the component, not the editor).
|
|
134
138
|
|
|
135
|
-
|
|
139
|
+
**Why `ctrl+alt+y`** (the conclusion of a four-layer compatibility survey):
|
|
136
140
|
|
|
137
|
-
|
|
|
141
|
+
| Layer | Status | Notes |
|
|
138
142
|
| --- | --- | --- |
|
|
139
|
-
| pi
|
|
140
|
-
| Linux
|
|
141
|
-
| Windows Terminal | ✅ |
|
|
142
|
-
| Windows
|
|
143
|
+
| pi keybindings | ✅ | no default `ctrl+alt+<letter>` binding; extension shortcuts are dispatched first inside the editor |
|
|
144
|
+
| Linux terminals | ✅ | `alt` is encoded as an ESC prefix (`ctrl+alt+y` = `ESC + ctrl+y`), distinguishable without the kitty protocol |
|
|
145
|
+
| Windows Terminal | ✅ | no default `ctrl+alt` binding |
|
|
146
|
+
| Windows OS | ✅ | only `ctrl+alt+del` is reserved system-wide |
|
|
143
147
|
|
|
144
|
-
|
|
148
|
+
**Rejected candidates**: `ctrl+shift+<letter>` — terminal emulators on both Linux and Windows grab copy/paste/tabs; and on terminals without the kitty protocol it collapses into `ctrl+<letter>` (`ctrl+shift+m` is Enter, which would submit the prompt immediately — dangerous). Plain `ctrl+<letter>` — pi occupies almost all of them, and the only free one, `ctrl+q`, is the XON flow-control character, with historical baggage.
|
|
145
149
|
|
|
146
150
|
---
|
|
147
151
|
|
|
148
|
-
## 🔎 review —
|
|
152
|
+
## 🔎 review — third-party code review
|
|
149
153
|
|
|
150
154
|
<a name="review"></a>
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
After a development task is done, type the `/third-review` command to summon **a different model** as a third party to "check + fix" the code just written: the review model has **full tool permissions**, and confirmed problems are edited in place — this is not a read-only audit. The review turn stays in the current session transcript, and after the review **the session keeps the review model** (it does not switch back automatically).
|
|
153
157
|
|
|
154
|
-
>
|
|
158
|
+
> **Command-triggered only**: only `/third-review` starts a review. Typing `third-review` as chat text does not trigger it (that is sent to the model as an ordinary message), which avoids accidental launches.
|
|
155
159
|
|
|
156
|
-
|
|
160
|
+
**The review prompt focuses on three checks** (each gets an explicit verdict):
|
|
157
161
|
|
|
158
|
-
1.
|
|
159
|
-
2.
|
|
160
|
-
3.
|
|
162
|
+
1. **Is this round's requirement implemented** — is the requirement fully and correctly implemented, consistent with the requirement description
|
|
163
|
+
2. **Is anything missing** — feature points, edge cases, error handling, compatibility, tests, etc.
|
|
164
|
+
3. **Is anything wrong** — logic errors, potential bugs, type/compile errors, security and performance hazards, etc.
|
|
161
165
|
|
|
162
|
-
|
|
166
|
+
**Strict scope constraint** — the review is limited to **the changes made in the current round**, to avoid scope creep; only problems confirmed inside this round's changes are fixed directly, while pre-existing or unrelated issues outside that range are only recorded as notes and left untouched.
|
|
163
167
|
|
|
164
|
-
|
|
168
|
+
**Choosing the review model** (every `/third-review` opens a picker):
|
|
165
169
|
|
|
166
|
-
- `/third-review` →
|
|
167
|
-
-
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
+
- `/third-review` → opens the **same selector as `/model`** (height-limited scrolling + fuzzy search): **the currently configured model is selected by default** (✓ marker), so pressing **Enter** starts the review with it
|
|
171
|
+
- **Pick another model** → written back to the config immediately (**both on disk and in memory**), and **that model becomes the default next time**
|
|
172
|
+
- **Cancel** (Esc) → no review is run, the config is unchanged
|
|
173
|
+
- The config is persisted in `<agent-dir>/pi-toolkits-review.json` (defaults to `~/.pi/agent/`):
|
|
170
174
|
|
|
171
175
|
```json
|
|
172
176
|
{ "model": "anthropic/claude-sonnet-4" }
|
|
173
177
|
```
|
|
174
178
|
|
|
175
|
-
- `/review-model`
|
|
176
|
-
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
+
- `/review-model` — a separate config entry point: opens the same list (without changing the session model, only updating the default config)
|
|
180
|
+
- **Unconfigured / the configured model is no longer available** (e.g. it was deleted from pi's models.json) → a notice is shown and the list opens as usual (with no default entry in that case)
|
|
181
|
+
- Triggered while a task is still in progress (the agent is not idle) → you are told to wait and nothing runs; only one review may be active at a time
|
|
182
|
+
- A grey `review` status in the footer means a review model is configured
|
|
179
183
|
|
|
180
184
|
---
|
|
181
185
|
|
|
182
|
-
## 🗜️ compact —
|
|
186
|
+
## 🗜️ compact — dedicated compaction model
|
|
183
187
|
|
|
184
188
|
<a name="compact"></a>
|
|
185
189
|
|
|
186
|
-
pi
|
|
190
|
+
pi's `/compact` and auto-compact summarize the context **with the current session model** by default — the main model is usually expensive and slow, while compaction summarization is a textbook "a cheap fast model does this well" job. This feature configures a dedicated model to take over summarization for **all three compaction triggers**:
|
|
187
191
|
|
|
188
|
-
|
|
|
192
|
+
| Trigger | After takeover |
|
|
189
193
|
| --- | --- |
|
|
190
|
-
|
|
|
191
|
-
| auto-compact
|
|
192
|
-
| context overflow
|
|
194
|
+
| Manual `/compact [instructions]` | summarized by the compaction model, custom focus is injected as usual |
|
|
195
|
+
| auto-compact threshold reached | summarized by the compaction model |
|
|
196
|
+
| context overflow recovery | summarized by the compaction model, retry behavior unchanged |
|
|
193
197
|
|
|
194
|
-
|
|
198
|
+
**Parts that are identical to pi's built-in behavior after takeover** (the built-in implementation is mirrored verbatim — byte-identical since 0.87.1, verified up to 1.0.2 — and only the executing model changes):
|
|
195
199
|
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
200
|
+
- **Summary format** — the structured Goal / Progress / Key Decisions checkpoint; when a summary already exists, the iterative-update prompt is used so information carries over instead of being lost
|
|
201
|
+
- **Split behavior** — the `keepRecentTokens` retention policy, and `firstKeptEntryId` / `tokensBefore` passed back unchanged
|
|
202
|
+
- **Output budget** — the same formula as the built-in (history segment 0.8×, split-prefix segment 0.5× of `reserveTokens`, then capped by the model's max output)
|
|
203
|
+
- **File-list tail** — `<read-files>` / `<modified-files>` tags are appended to the summary as usual, with details maintained in the same shape
|
|
204
|
+
- **Usage accounting** — the compaction model's tokens/cost are counted in the session statistics
|
|
205
|
+
- **Cancellable** — `Esc` during compaction cancels cleanly (the signal is passed through to the underlying call)
|
|
202
206
|
|
|
203
|
-
|
|
207
|
+
**Configuration** (`<agent-dir>/pi-toolkits-compact.json`, defaults to `~/.pi/agent/`):
|
|
204
208
|
|
|
205
209
|
```json
|
|
206
210
|
{ "model": "google/gemini-2.5-flash" }
|
|
207
211
|
```
|
|
208
212
|
|
|
209
|
-
- `/compact-model`
|
|
210
|
-
-
|
|
213
|
+
- `/compact-model` — view/replace: the **same selector as `/model`** (height-limited scrolling + fuzzy search), with **the currently configured model selected by default**; Enter confirms, picking another model writes it, cancelling leaves it unchanged (to clear the config: edit `pi-toolkits-compact.json` and set `model` to `null`)
|
|
214
|
+
- Unconfigured = feature disabled, everything goes through pi's default at zero overhead; a grey `compact` status in the footer means it is configured
|
|
211
215
|
|
|
212
|
-
|
|
216
|
+
**Lossless fallback** (this feature can never "break" compaction):
|
|
213
217
|
|
|
214
|
-
|
|
|
218
|
+
| Situation | Behavior |
|
|
215
219
|
| --- | --- |
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
|
220
|
+
| Not configured | falls straight back to pi's default compaction |
|
|
221
|
+
| Configured model unavailable (e.g. deleted from models.json) | warning + fallback |
|
|
222
|
+
| Summarization failed / empty summary / token limit hit | notice + fallback to pi's default compaction |
|
|
223
|
+
| User cancelled (`Esc`) | clean cancel, no error spam |
|
|
224
|
+
|
|
225
|
+
> **Implementation notes**: the takeover point is the official `session_before_compact` extension event (all three triggers pass through it); returning a compaction result takes over completely, returning `undefined` falls back to the built-in. The auto-compact path never shows any dialog (the handler only calls `notify`). `/tree` branch summarization (`session_before_tree`) is a different event and is not taken over in this iteration — it is left for later.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 🚀 autostart — session startup automation
|
|
230
|
+
|
|
231
|
+
<a name="autostart"></a>
|
|
232
|
+
|
|
233
|
+
A first step for multi-repo projects: declare inside the project which slash commands should run automatically "when a new session starts" — the first use case being `/add-dir` mounting sibling repositories, so a new session does not have to replay them by hand.
|
|
234
|
+
|
|
235
|
+
**Configuration** (`<project root>/.pi/autostart.toml`, committed with the project; `.pi/` is pi's project-level config convention, following `.pi/mcp.json`):
|
|
236
|
+
|
|
237
|
+
```toml
|
|
238
|
+
version = 1
|
|
239
|
+
|
|
240
|
+
[command]
|
|
241
|
+
run = [
|
|
242
|
+
"/add-dir ../shop-frontend",
|
|
243
|
+
"/add-dir ../shop-api",
|
|
244
|
+
]
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
No file = feature disabled, zero overhead, silently skipped.
|
|
248
|
+
|
|
249
|
+
**When it runs**:
|
|
250
|
+
|
|
251
|
+
| session_start reason | Replayed | Why |
|
|
252
|
+
| --- | --- | --- |
|
|
253
|
+
| `startup` / `new` | ✅ | a new session, replay as declared |
|
|
254
|
+
| `fork` | ✅ | the branch point may predate the config's appearance |
|
|
255
|
+
| `resume` | ❌ | the restored branch already carries the mount state from its time, replaying would conflict |
|
|
256
|
+
| `reload` | ❌ | extensions are rebuilt, replaying would duplicate side effects |
|
|
257
|
+
|
|
258
|
+
**Safety gates** (in order):
|
|
259
|
+
|
|
260
|
+
1. **project trust** — no command runs automatically in an untrusted directory (a warning is shown); a config parse failure likewise prevents execution (an error is shown)
|
|
261
|
+
2. **Command pre-validation** — only commands **registered by extensions** are executed; an unregistered command name is **skipped with a warning** and never sent to the model (for an unhandled `/x`, `sendUserMessage` treats the text as an ordinary message and sends it to the LLM — this is exactly why pre-validation is mandatory)
|
|
262
|
+
|
|
263
|
+
**Key constraint: extension commands only**. Commands registered via `registerCommand` such as `/add-dir` (pi-add-dir) and `/cd` (pi-cd) work; built-in commands (`/compact`, `/reload`, `/resume`, …) are dispatched in the TUI layer and cannot be triggered from the extension layer; skill commands (`/skill:name`) are an expansion mechanism rather than an execution mechanism. The target extension you depend on (e.g. pi-add-dir) must be installed first.
|
|
220
264
|
|
|
221
|
-
>
|
|
265
|
+
> **Implementation notes**: execution uses `sendUserMessage(cmd, { expandPromptTemplates: true })` — that option routes `/cmd args` into command dispatch instead of the model prompt path (the wrapper defaults to `false`; verified against pi 0.86–1.0.4 sources, see the host-compatibility discipline in AGENTS.md). Pre-validation uses `pi.getCommands()` (accepting only `source: "extension"`). Depends on `smol-toml` (zero-dependency, ~10KB, TOML 1.0).
|
|
222
266
|
|
|
223
267
|
---
|
|
224
268
|
|
|
225
|
-
## 🛠️
|
|
269
|
+
## 🛠️ Development
|
|
226
270
|
|
|
227
271
|
<a name="development"></a>
|
|
228
272
|
|
|
@@ -234,7 +278,7 @@ pnpm typecheck # tsc --noEmit
|
|
|
234
278
|
pnpm test # vitest (all feature unit tests)
|
|
235
279
|
```
|
|
236
280
|
|
|
237
|
-
###
|
|
281
|
+
### Project structure
|
|
238
282
|
|
|
239
283
|
```text
|
|
240
284
|
src/
|
|
@@ -244,6 +288,8 @@ src/
|
|
|
244
288
|
└── features/ # feature modules — one directory per feature
|
|
245
289
|
├── ask/ # ask mode: command + state machine, bash sandbox,
|
|
246
290
|
│ # system prompt banner, tests
|
|
291
|
+
├── autostart/ # session startup automation: autostart.toml parsing,
|
|
292
|
+
│ # command pre-validation + replay, tests
|
|
247
293
|
├── compact/ # dedicated compaction model: session_before_compact
|
|
248
294
|
│ # takeover + /compact-model, store, prompts,
|
|
249
295
|
│ # tests
|
|
@@ -254,9 +300,9 @@ src/
|
|
|
254
300
|
└── stash/ # prompt stash: hotkey state machine + tests
|
|
255
301
|
```
|
|
256
302
|
|
|
257
|
-
|
|
303
|
+
**Adding a feature**: create `src/features/<name>/` exporting `registerXxx(pi)` and call it from `src/index.ts`. Existing modules stay untouched. Each feature ships its own `*.test.ts` (vitest) — keep them deterministic (inject clocks/state, no real agent-dir writes).
|
|
258
304
|
|
|
259
|
-
|
|
305
|
+
**Publishing** (pnpm-only, one command):
|
|
260
306
|
|
|
261
307
|
```bash
|
|
262
308
|
pnpm release patch # 0.1.2 → 0.1.3
|
|
@@ -265,11 +311,11 @@ pnpm release major # 0.1.2 → 1.0.0 (minor + patch zeroed)
|
|
|
265
311
|
pnpm release patch --dry-run # preview without changing anything
|
|
266
312
|
```
|
|
267
313
|
|
|
268
|
-
`release`
|
|
314
|
+
`release` requires exactly one of `major | minor | patch`; incrementing a higher level zeroes the lower ones. The chain is: **the working tree must be clean (any uncommitted change aborts before anything happens, guaranteeing tag content == published content)** → `typecheck + test` gate → version bump → git commit + `vX.Y.Z` tag (self-check that tag == HEAD and the tree is clean) → `pnpm publish` (with `prepublishOnly` as a second gate) → push only the current branch + the current tag and verify the remote hashes match (if the remote tag differs, GitHub Release creation is skipped).
|
|
269
315
|
|
|
270
316
|
---
|
|
271
317
|
|
|
272
|
-
## 🤝
|
|
318
|
+
## 🤝 Contributing
|
|
273
319
|
|
|
274
320
|
<a name="contributing"></a>
|
|
275
321
|
|
|
@@ -280,7 +326,7 @@ PRs and issues welcome. A few conventions:
|
|
|
280
326
|
- **Tests** — every feature ships vitest cases; keep them deterministic (injectable clocks/state), no writes to the real agent dir
|
|
281
327
|
- **Built-in patches** (favorites) must stay **version-guarded and idempotent** — verify the target prototype members exist before patching, guard against double-apply, degrade with a `console.warn` instead of breaking the extension
|
|
282
328
|
- **Built-in prompt sync** (compact) — the summarization prompts in `src/features/compact/prompt.ts` are copied verbatim from pi's built-in compaction; when upgrading the pi dependency, diff `dist/core/compaction/compaction.js` (and `utils.js`) and update the strings + assembly helpers to match, keeping takeover output byte-compatible with stock
|
|
283
|
-
- **Keybindings** — before picking a new shortcut, check pi defaults + reserved keys, terminal control chars, and OS/terminal-emulator grabs; prefer `ctrl+alt+<letter>` for cross-platform safety
|
|
329
|
+
- **Keybindings** — before picking a new shortcut, check pi defaults + reserved keys, terminal control chars, and OS/terminal-emulator grabs; prefer `ctrl+alt+<letter>` for cross-platform safety. Do not stop at "it works on my machine in the main screen": in `fullscreen` mode (pi's default since 1.0) the alt-screen layer consumes `tui.altScreen.*` **before** dialogs see the key, and on Windows/WSL several of those bindings differ from the Linux defaults. Run `pnpm check:keybindings [candidate...]` (and `pnpm check:keybindings --all` after a pi upgrade) — it probes the installed host's resolved keybinding table with the host's own `matchesKey`.
|
|
284
330
|
- **Quality gate** — `pnpm typecheck && pnpm test` must pass before submitting
|
|
285
331
|
|
|
286
332
|
---
|