@d3ara1n/pi-ask-user 1.0.0 → 2.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/README.md +112 -44
- package/package.json +3 -2
- package/src/index.ts +740 -311
package/README.md
CHANGED
|
@@ -4,24 +4,20 @@ A collapsible **ask-user** tool for [pi](https://github.com/earendil-works/pi).
|
|
|
4
4
|
|
|
5
5
|
## Why
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
they "collapse" they keep keyboard focus locked on the panel — so you **can't
|
|
7
|
+
Most ask-user tools render a panel that covers the transcript, so you **can't
|
|
9
8
|
scroll the conversation** to read the analysis that should inform your choice.
|
|
10
9
|
You end up choosing blind.
|
|
11
10
|
|
|
12
|
-
This tool fixes that
|
|
11
|
+
This tool fixes that by **not** using a screen overlay. The panel renders into
|
|
12
|
+
pi's bottom `editorContainer` slot (the same path `ctx.ui.select()` /
|
|
13
|
+
`ctx.ui.input()` take), so the transcript stays visible **above** the panel and
|
|
14
|
+
remains scrollable via the terminal's native scrollback — mouse wheel,
|
|
15
|
+
`Shift+PgUp`, `Cmd+↑`. This works because pi's TUI never enters alt-screen and
|
|
16
|
+
never tracks the mouse, so every rendered chat line lives in the terminal
|
|
17
|
+
buffer and can be scrolled back at any time, no focus gymnastics needed.
|
|
13
18
|
|
|
14
|
-
- **Collapse
|
|
15
|
-
|
|
16
|
-
transcript. Your normal scroll mechanisms work again — mouse wheel,
|
|
17
|
-
`Shift+PgUp`, `Ctrl+Left`/`Ctrl+Right` tree nav, `/tree`.
|
|
18
|
-
- **Re-expand works from anywhere.** A global shortcut (`pi.registerShortcut`)
|
|
19
|
-
captures `Ctrl+\` from the editor, so pressing it again re-expands and
|
|
20
|
-
re-focuses the panel — no matter where focus currently is.
|
|
21
|
-
|
|
22
|
-
> **Note:** Because pi removes the editor from the UI tree while an overlay is
|
|
23
|
-
> active, full transcript scrolling while collapsed depends on pi's overlay
|
|
24
|
-
> behavior. The collapse affordance is kept as best-effort.
|
|
19
|
+
- **Collapse** (`Ctrl+\`) shrinks the panel to a single status row, leaving
|
|
20
|
+
even more of the transcript on screen while you decide.
|
|
25
21
|
|
|
26
22
|
## Tool: `ask_user`
|
|
27
23
|
|
|
@@ -30,11 +26,11 @@ This tool fixes that:
|
|
|
30
26
|
"questions": [
|
|
31
27
|
{
|
|
32
28
|
"header": "Which layout?",
|
|
33
|
-
"
|
|
29
|
+
"tab": "layout",
|
|
34
30
|
"prompt": "Pick the layout for the new settings page.",
|
|
35
31
|
"options": [
|
|
36
|
-
{ "
|
|
37
|
-
{ "
|
|
32
|
+
{ "label": "Sidebar", "description": "Nav on the left…" },
|
|
33
|
+
{ "label": "Tabs", "description": "Top tabs…" }
|
|
38
34
|
]
|
|
39
35
|
}
|
|
40
36
|
]
|
|
@@ -48,10 +44,9 @@ This tool fixes that:
|
|
|
48
44
|
| Field | Type | Required | Description |
|
|
49
45
|
|-------|------|----------|-------------|
|
|
50
46
|
| `header` | string | yes | Short title shown in the panel header |
|
|
51
|
-
| `
|
|
47
|
+
| `tab` | string | yes | Short keyword identifying this question. Shown on the tab bar when there are multiple questions, and returned in the result as the answer's prefix. Write it in the user's language, not as a programmatic identifier. Must be unique across all questions in one call |
|
|
52
48
|
| `options` | array | yes | 2–4 options |
|
|
53
49
|
| `prompt` | string | no | Longer body text under the header |
|
|
54
|
-
| `allowOther` | boolean | no | Allow "Type something." custom input. Default `true` |
|
|
55
50
|
| `multiSelect` | boolean | no | Check multiple options. Default `false` |
|
|
56
51
|
| `allowSkip` | boolean | no | If `false`, the user MUST answer before proceeding. Default `true` |
|
|
57
52
|
|
|
@@ -60,9 +55,8 @@ This tool fixes that:
|
|
|
60
55
|
| Field | Type | Required | Description |
|
|
61
56
|
|-------|------|----------|-------------|
|
|
62
57
|
| `label` | string | yes | Display label |
|
|
63
|
-
| `value` | string | no | Returned value. Defaults to `label` if omitted |
|
|
64
58
|
| `description` | string | no | Short explanation under the label (wraps). Add one when the label alone isn't self-explanatory |
|
|
65
|
-
| `preview` | string | no |
|
|
59
|
+
| `preview` | string | no | Use when `description` (a short one-liner) isn't enough and the user genuinely benefits from more detail in a side column — ASCII layout demo, code skeleton, Pro/Cons breakdown, or the reasoning behind the option and what choosing it entails. Rendered verbatim. Don't treat it as extra text capacity — every line competes for the user's attention. If a short `description` already conveys the option, leave empty. Most options need only `description` |
|
|
66
60
|
|
|
67
61
|
### Icons
|
|
68
62
|
|
|
@@ -84,8 +78,9 @@ Moving `↑`/`↓` only moves the cursor; selection is committed separately.
|
|
|
84
78
|
|
|
85
79
|
### Custom input ("Type something.")
|
|
86
80
|
|
|
87
|
-
|
|
88
|
-
`Enter` on it to
|
|
81
|
+
Every question always shows a "Type something." row (this cannot be turned off),
|
|
82
|
+
so the user is never locked into the provided options. Press `Enter` on it to
|
|
83
|
+
open a text editor:
|
|
89
84
|
|
|
90
85
|
- After submitting, the row displays the committed text with a filled glyph
|
|
91
86
|
(`◉ ✎ your text`).
|
|
@@ -94,11 +89,22 @@ When `allowOther` is `true` (default), a "Type something." row appears. Press
|
|
|
94
89
|
- `Esc` discards the edit (the original answer is kept); `Enter` confirms the
|
|
95
90
|
change (the answer is updated).
|
|
96
91
|
|
|
92
|
+
**Multi-select + custom input.** In `multiSelect` mode the custom text is an
|
|
93
|
+
*extra* entry kept alongside the checked options — it never overwrites them.
|
|
94
|
+
You can check several options, then open "Type something.", type a value, and
|
|
95
|
+
submit: both the checks and the custom text are preserved and returned
|
|
96
|
+
together. The same holds in reverse — edit the question later from the review
|
|
97
|
+
screen to add or remove checks and the committed custom text stays intact
|
|
98
|
+
(and vice versa). Submitting an empty custom value clears only the custom
|
|
99
|
+
entry; any remaining checks are kept.
|
|
100
|
+
|
|
97
101
|
### Required questions
|
|
98
102
|
|
|
99
103
|
Set `allowSkip: false` to force an answer. The user cannot advance forward
|
|
100
|
-
(`Tab`/`→`) until they answer
|
|
101
|
-
|
|
104
|
+
(`Tab`/`→`) until they answer; the built-in "Type something." row always lets
|
|
105
|
+
them supply a custom answer, so they're never trapped by options they dislike.
|
|
106
|
+
Backward navigation (`Shift+Tab`/`←`) is always allowed so they can review/edit
|
|
107
|
+
earlier questions.
|
|
102
108
|
|
|
103
109
|
### Rich previews
|
|
104
110
|
|
|
@@ -111,19 +117,17 @@ cursor updates the right pane. Ideal for comparing ASCII layouts / code samples:
|
|
|
111
117
|
```jsonc
|
|
112
118
|
{
|
|
113
119
|
"header": "Which layout?",
|
|
114
|
-
"
|
|
120
|
+
"tab": "layout",
|
|
115
121
|
"options": [
|
|
116
122
|
{
|
|
117
123
|
"label": "Sidebar",
|
|
118
|
-
"value": "sidebar",
|
|
119
124
|
"description": "Left-side navigation with the main content to its right.",
|
|
120
|
-
"preview": "┌──┬────────┐\n
|
|
125
|
+
"preview": "┌──┬────────┐\n│NA│ body │\n│V │ │\n└──┴────────┘\nleft sidebar nav"
|
|
121
126
|
},
|
|
122
127
|
{
|
|
123
128
|
"label": "Top bar",
|
|
124
|
-
"value": "topbar",
|
|
125
129
|
"description": "Top horizontal nav with the main content below.",
|
|
126
|
-
"preview": "┌──────────────┐\n│
|
|
130
|
+
"preview": "┌──────────────┐\n│ nav bar │\n├──────────────┤\n│ body │\n└──────────────┘\ntop horizontal nav"
|
|
127
131
|
}
|
|
128
132
|
]
|
|
129
133
|
}
|
|
@@ -136,26 +140,90 @@ contains a newline renders verbatim as a fixed-width block.
|
|
|
136
140
|
|
|
137
141
|
After the last question is answered, a **review screen** lists every question
|
|
138
142
|
and its answer (multi-select answers are comma-joined and truncated with `…`
|
|
139
|
-
when too long; skipped questions show `(skipped)`). Each entry spans
|
|
140
|
-
|
|
143
|
+
when too long; skipped questions show `(skipped)`). Each question entry spans
|
|
144
|
+
two rows (header + answer), followed by a trailing **note entry**:
|
|
141
145
|
|
|
142
146
|
```
|
|
143
|
-
▸ Which layout?
|
|
144
|
-
|
|
145
|
-
Which database?
|
|
146
|
-
|
|
147
|
+
▸ 1. Which layout?
|
|
148
|
+
Sidebar
|
|
149
|
+
2. Which database?
|
|
150
|
+
Postgres
|
|
151
|
+
|
|
152
|
+
✎ Note to assistant
|
|
153
|
+
(optional — Tab to add a note)
|
|
147
154
|
```
|
|
148
155
|
|
|
149
|
-
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
Each title carries a fixed-width marker (`1.`/`2.`… for questions, `✎ ` for
|
|
157
|
+
the note) so every title aligns; the body is indented one level deeper to keep
|
|
158
|
+
header vs content visually distinct. An empty line sets the note apart from
|
|
159
|
+
the Q&A list above it.
|
|
160
|
+
|
|
161
|
+
Each title carries a fixed-width marker (`1.`/`2.`… for questions, `✎ ` for
|
|
162
|
+
the note) so every title aligns; the body is indented one level deeper to keep
|
|
163
|
+
header vs content visually distinct.
|
|
164
|
+
|
|
165
|
+
- `↑`/`↓` — move the cursor between entries (questions + the note)
|
|
166
|
+
- `PgUp`/`PgDn` — scroll by page (when there are more entries than rows)
|
|
167
|
+
- `Tab` — edit the focused entry: a question (returns to review after) or the
|
|
168
|
+
note (opens a free-form editor)
|
|
169
|
+
- `Enter` — confirm and submit all answers. `Enter` is always "submit" on the
|
|
170
|
+
review screen, never "edit" — this deliberately differs from the question
|
|
171
|
+
screens (where `Enter` edits/advances) so you can never submit by
|
|
172
|
+
double-tapping `Enter` while trying to edit something. Use `Tab` to edit.
|
|
153
173
|
- `Esc` — cancel
|
|
154
174
|
|
|
175
|
+
### Note to assistant
|
|
176
|
+
|
|
177
|
+
The review screen ends with a **note** entry — a free-form message the user
|
|
178
|
+
can attach for the assistant, about anything *beyond* the specific questions
|
|
179
|
+
(overall direction, pacing, priorities, a correction to the premise, …).
|
|
180
|
+
|
|
181
|
+
- Move the cursor to the note row and press `Tab` to open the editor.
|
|
182
|
+
- `Enter` saves the note (empty = no note); `Esc` returns to the review without
|
|
183
|
+
saving (the in-progress draft is kept).
|
|
184
|
+
- The note is **out-of-band**: it is not part of `questions`/`options` and the
|
|
185
|
+
assistant cannot request or pre-fill it. It surfaces only in the tool result
|
|
186
|
+
as `message`, and only when non-empty.
|
|
187
|
+
|
|
188
|
+
Because the note can reframe or override the answers, the assistant is told to
|
|
189
|
+
treat it as high-priority context.
|
|
190
|
+
|
|
155
191
|
### Result
|
|
156
192
|
|
|
157
|
-
The tool
|
|
158
|
-
|
|
193
|
+
The tool result returned to the model is **JSON**, shaped symmetrically with
|
|
194
|
+
the questions schema so the model can correlate each answer back to its own
|
|
195
|
+
question by the `tab` key:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"cancelled": false,
|
|
200
|
+
"answers": [
|
|
201
|
+
{ "tab": "layout", "answer": "Sidebar" },
|
|
202
|
+
{ "tab": "extras", "answers": ["dark-mode"], "custom": "also add export-to-pdf" },
|
|
203
|
+
{ "tab": "db", "skipped": true }
|
|
204
|
+
],
|
|
205
|
+
"message": "leaning towards the minimal option"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Only the relevant fields appear per answer (no noise):
|
|
210
|
+
|
|
211
|
+
| Situation | Fields |
|
|
212
|
+
|-----------|--------|
|
|
213
|
+
| single-select, option picked | `answer` |
|
|
214
|
+
| single-select, custom typed | `custom` |
|
|
215
|
+
| multi-select, options picked | `answers: [...]` |
|
|
216
|
+
| multi-select, options + custom | `answers` + `custom` |
|
|
217
|
+
| multi-select, custom only | `custom` |
|
|
218
|
+
| multi-select, empty commit (skippable, submitted with nothing) | `answers: []` |
|
|
219
|
+
| any question, Tab-skipped | `skipped: true` |
|
|
220
|
+
|
|
221
|
+
`custom` is always a sibling of `answer`/`answers`, never mixed in — it signals
|
|
222
|
+
the user typed something outside the offered options. The top-level `message`
|
|
223
|
+
(the user's review-screen note) appears only when non-empty. `cancelled: true`
|
|
224
|
+
means the user pressed `Esc`; `answers` still lists whatever was answered
|
|
225
|
+
before cancellation. This JSON shape replaces the old `"tab: answer"` text
|
|
226
|
+
format, which could break when a custom answer contained a colon or newline.
|
|
159
227
|
|
|
160
228
|
## Keys
|
|
161
229
|
|
|
@@ -164,8 +232,8 @@ mid-way, the message notes how many questions were answered before cancellation.
|
|
|
164
232
|
| `↑` `↓` / `PgUp` `PgDn` | Move cursor / scroll options |
|
|
165
233
|
| `Space` | Commit selection (single: select-only; multi: toggle) |
|
|
166
234
|
| `Enter` | Confirm & advance (single) / commit checked (multi) / enter custom input |
|
|
167
|
-
| `Tab` / `Shift+Tab` | Next / previous question (
|
|
168
|
-
| `→` / `←` |
|
|
235
|
+
| `Tab` / `Shift+Tab` | Next / previous question, **cycling** (last → first). Option list only — not hijacked inside the editor |
|
|
236
|
+
| `→` / `←` | Next / previous question, but **stop at the boundary** (no cycle) — safer than Tab when there are many questions |
|
|
169
237
|
| `Esc` | Cancel (or exit custom-input editor without saving) |
|
|
170
238
|
| `Ctrl+\` | Collapse / expand the panel |
|
|
171
239
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d3ara1n/pi-ask-user",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Ask-user tool for pi — renders in the bottom editor slot (not a screen overlay), so the transcript stays visible and scrollable above the panel while you decide",
|
|
5
6
|
"main": "src/index.ts",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"pi-package",
|