@alexleekt/pi-ask-user-glimpse 0.2.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/CHANGELOG.md +113 -0
- package/CONTRIBUTING.md +51 -0
- package/LICENSE +21 -0
- package/README.md +272 -0
- package/dist/index.html +110 -0
- package/fallback/terminal-prompt.ts +169 -0
- package/index.ts +443 -0
- package/package.json +77 -0
- package/shared/ask-user.ts +38 -0
- package/tool/ask-user.ts +201 -0
- package/tool/response-formatter.ts +102 -0
- package/types/glimpseui.d.ts +57 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@alexleekt/pi-ask-user-glimpse` are documented in this file.
|
|
4
|
+
|
|
5
|
+
## [0.2.1] — 2026-05-16
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- **AGENTS.md stale references** — Removed references to deleted `util/detect-conflict.ts` and `util/safe-callback.ts` files.
|
|
9
|
+
- **`allowSkip` schema gap** — Added `allowSkip` parameter to the `defineTool` schema so the LLM can request partial questionnaire submission.
|
|
10
|
+
- **`visual-qa.ts` non-existent event** — Removed `"ready"` event listener which is not declared in `glimpseui.d.ts`.
|
|
11
|
+
- **Tailwind CSS build warning** — Fixed by running Vite from the `webview/` directory so Tailwind resolves content paths correctly.
|
|
12
|
+
- **`validate.ts` placeholder check** — Now checks for exact placeholder `/*ASK_USER_PAYLOAD*/` instead of substring match.
|
|
13
|
+
- **Missing `pi-ai` peer dependency** — Added `@earendil-works/pi-ai` to `peerDependencies` since `index.ts` imports `StringEnum` from it.
|
|
14
|
+
- **Repeated `window.glimpse.send` type assertion** — Extracted to `webview/src/util/glimpse.ts` helper with `sendToGlimpse()` and `sendCancelled()`.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **CONTRIBUTING.md** — Developer setup, build instructions, and pre-submission checklist.
|
|
18
|
+
- **README badges** — npm version and MIT license shields.
|
|
19
|
+
- **`engines` field** — Requires Node.js >= 18.0.0.
|
|
20
|
+
- **`CHANGELOG.md` in npm files** — Now included in the published tarball.
|
|
21
|
+
- **`.jj/` in `.gitignore`** — Jujutsu working directory ignored.
|
|
22
|
+
|
|
23
|
+
## [0.2.0] — 2026-05-16
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- **Two-panel layout with markdown context** — When `context` is provided, the dialog splits 40/60: left panel renders context as markdown (via `marked`), right panel shows the question and options. The question title spans the full width as a global header.
|
|
27
|
+
- **Progress bar and answered counter** in Questionnaire dialogs — thin `h-1` bar + "N / M answered" text.
|
|
28
|
+
- **Auto-scroll to first unanswered question** on Questionnaire open.
|
|
29
|
+
- **Auto-focus first option** in SingleSelect and MultiSelect when search box is hidden (≤6 options).
|
|
30
|
+
- **Auto-focus search input** when visible.
|
|
31
|
+
- **Submit loading state** — button text changes to "Submitting…" and is disabled across all dialog types, preventing double-clicks.
|
|
32
|
+
- **Platform-aware keyboard hints** — shows `⌘+Enter` on macOS, `Ctrl+Enter` elsewhere.
|
|
33
|
+
- **Inline SVG icons** for radio buttons and checkboxes (crisp at any scale, replaces text-based `✓` and CSS circles).
|
|
34
|
+
- **ARIA roles** — `role="listbox"`, `role="option"`, `aria-selected`, `aria-multiselectable`, `aria-checked`, `aria-expanded` across all option lists.
|
|
35
|
+
- **ErrorBoundary** around each panel in `App.tsx` — catches runtime React errors gracefully instead of crashing the webview.
|
|
36
|
+
- **Empty search state** — "No matching options" message with guidance when filter returns zero results.
|
|
37
|
+
- **"Clear all" link** in MultiSelect to reset all selections in one click.
|
|
38
|
+
- **Comment existence indicator** — button label changes from "Add comment" to "Edit comment" when text exists.
|
|
39
|
+
- **HTML sanitization** in `ContextPanel` — strips `<script>` tags and `on*` event handlers before `dangerouslySetInnerHTML`.
|
|
40
|
+
- **Questionnaire freeform auto-focus** — textarea gets focus on mount for the first unanswered freeform question.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- **Window size** — increased from `640×480` to `1200×900` to accommodate the two-panel layout and long option lists.
|
|
44
|
+
- **Option descriptions** — moved from a destructive sidebar preview pane to always-visible inline text with a left border indent.
|
|
45
|
+
- **"Other" button** — renamed to "Custom" and moved from bottom of scrollable list to directly under the search box.
|
|
46
|
+
- **Search box** — now conditional: hidden when `options.length <= 6` and `!allowFreeform`, reducing clutter for simple questions.
|
|
47
|
+
- **Cancel button** — changed from bordered secondary button to ghost style (no border, muted text) to reduce accidental clicks.
|
|
48
|
+
- **MultiSelect "N selected" badge** — moved from bottom bar to a primary-colored chip in the header area.
|
|
49
|
+
- **Comment toggle** — changed from invisible underlined text to an inline SVG icon button with hover background.
|
|
50
|
+
- **Keyboard hint placement** — moved from orphaned `text-xs` above buttons to inline with the action bar.
|
|
51
|
+
- **Questionnaire spacing** — tightened from `space-y-6` to `space-y-3`.
|
|
52
|
+
- **Questionnaire freeform input** — changed from `<input type="text">` to `<textarea rows={3}>`.
|
|
53
|
+
- **Description border color** — `border-border` → `border-muted-foreground/30` for visible contrast in both light and dark modes.
|
|
54
|
+
- **Custom button query truncation** — long queries are truncated to 30 chars with "…".
|
|
55
|
+
- **Response trimming** — `response-formatter.ts` now trims freeform text and questionnaire answers.
|
|
56
|
+
|
|
57
|
+
### Fixed
|
|
58
|
+
- **SingleSelect preview pane bug** — clicking to read a description no longer deselects the current choice.
|
|
59
|
+
- **Questionnaire `allAnswered` bug** — empty freeform strings no longer count as "answered".
|
|
60
|
+
- **SingleSelect keyboard Enter bypass** — `isSubmitting` guard now respected when selecting via keyboard.
|
|
61
|
+
- **Terminal fallback context** — `payload.context` was completely ignored in TUI fallback; now prepended to all prompts.
|
|
62
|
+
- **Terminal multi-select freeform** — picking "Other" no longer discards all prior selections.
|
|
63
|
+
- **Terminal questionnaire freeform** — open-ended questions now show context if provided.
|
|
64
|
+
- **`ctx.hasUI` guard** in `/ask-debug` — replaced crash-risk `ctx.ui.notify()` with `console.warn()`.
|
|
65
|
+
- **Dead code** — removed unused `util/safe-callback.ts` and cleaned up `tsconfig.json` / `package.json` `files` array.
|
|
66
|
+
- **README** — synced all stale references (preview pane → inline descriptions, Other → Custom, 640×480 → 1200×900).
|
|
67
|
+
|
|
68
|
+
## [0.1.1] — 2026-05-16
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
- Keyboard shortcuts in all webview dialogs:
|
|
72
|
+
- `Escape` — Close open comment textarea; if none open, cancel dialog
|
|
73
|
+
- `Enter` — Select+submit focused option (SingleSelect), submit questionnaire (Questionnaire), toggle option (MultiSelect/Questionnaire with Space)
|
|
74
|
+
- `ArrowUp`/`ArrowDown` — Navigate options with roving tabindex (SingleSelect, MultiSelect)
|
|
75
|
+
- `Space` — Toggle multi-select options
|
|
76
|
+
- `Ctrl+Enter` — Submit freeform/ questionnaire
|
|
77
|
+
- `Tab` — Natural focus movement
|
|
78
|
+
- Visual focus ring (`ring-2 ring-ring`) on keyboard-focused options
|
|
79
|
+
|
|
80
|
+
### Changed
|
|
81
|
+
- Extracted shared types (`AskUserPayload`, `Question`, `QuestionOption`) from `tool/ask-user.ts` and `webview/src/App.tsx` into `shared/ask-user.ts`. Both server and webview now import from the single source of truth.
|
|
82
|
+
- **Questionnaire `kind` consistency:** WebView and terminal fallback now send `kind: "questionnaire"` with per-question `kind` in `questionnaireDetails` (either `"selection"` or `"freeform"`). Previously all questionnaire answers were incorrectly labeled as `"selection"`.
|
|
83
|
+
|
|
84
|
+
### Fixed
|
|
85
|
+
- **Critical:** `allAnswered` check in Questionnaire no longer rejects empty-string freeform answers with strict equality (`=== ""`). Now correctly allows empty strings as valid freeform responses while still requiring non-empty arrays for multi-select answers.
|
|
86
|
+
- **Payload injection:** Production code in `tool/ask-user.ts` now properly escapes `<`, `>`, and `&` as `\u003c`, `\u003e`, `\u0026` when serializing JSON into the HTML template, preventing HTML injection attacks. Test scripts updated to match.
|
|
87
|
+
- **`resolveWebviewHtml` error propagation:** File-not-found errors now include the full list of paths tried and a clear instruction (`Run 'npm run build' first`), instead of an unhelpful generic error.
|
|
88
|
+
- **`displayMode` warning:** Runtime warning added when `displayMode` parameter is passed, since Glimpse always opens a centered dialog regardless of the parameter value. Previously the parameter was silently ignored.
|
|
89
|
+
|
|
90
|
+
## [0.1.0] — 2026-05-16
|
|
91
|
+
|
|
92
|
+
### Added
|
|
93
|
+
- Single-select dialog with searchable options and split-pane description preview
|
|
94
|
+
- Multi-select dialog with checkbox-style selection
|
|
95
|
+
- Freeform dialog with full-height textarea
|
|
96
|
+
- Questionnaire dialog with per-question options (single-select, multi-select, or freeform)
|
|
97
|
+
- Native WebView rendering via glimpseui (macOS WKWebView / Linux GTK4 / Windows WebView2)
|
|
98
|
+
- Terminal fallback when glimpseui native host is unavailable
|
|
99
|
+
- `/ask-debug` slash command for manual dialog testing
|
|
100
|
+
- Self-contained webview bundle (single inlined HTML file, zero external requests)
|
|
101
|
+
- Dark mode support via `prefers-color-scheme`
|
|
102
|
+
|
|
103
|
+
### Fixed
|
|
104
|
+
- **Critical:** Test scripts (`validate.ts`, `smoke-test.ts`, `visual-qa.ts`) now properly escape `>`, `&`, and `<` when injecting JSON into HTML, matching production escaping
|
|
105
|
+
- **Bug:** MultiSelect no longer allows empty submission when a search query is present but no option is selected
|
|
106
|
+
- **Dead code:** Removed unreachable `getQuestions` fallback in Questionnaire component
|
|
107
|
+
- **Config:** Removed stale `@earendil-works/pi-tui` peer dependency (never imported)
|
|
108
|
+
- **Config:** Added `prepack` script to ensure webview bundle is built before `npm publish`
|
|
109
|
+
- **Config:** Simplified `tsconfig.json` to use `noEmit: true` (Pi loads `.ts` directly)
|
|
110
|
+
- **Cleanup:** Removed ~24 duplicate stopwords from `STOPWORDS` set
|
|
111
|
+
- **Types:** Fixed `getInfo()` return type in hand-written `glimpseui.d.ts` (`void` → `unknown`)
|
|
112
|
+
|
|
113
|
+
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Contributing to pi-ask-user-glimpse
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving `@alexleekt/pi-ask-user-glimpse`!
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/alexleekt/pi-ask-user-glimpse.git
|
|
9
|
+
cd pi-ask-user-glimpse
|
|
10
|
+
npm install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Building
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run build # build CSS + webview bundle
|
|
17
|
+
npm run check # dry-run npm pack
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Testing
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run validate # checks dist exists, placeholder present, binary found
|
|
24
|
+
npm run validate:gui # same + opens actual WebView for visual check
|
|
25
|
+
npx tsx scripts/smoke-test.ts # opens WebView for 2s
|
|
26
|
+
npx tsx scripts/visual-qa.ts # cycles through all 5 scenarios
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Code Style
|
|
30
|
+
|
|
31
|
+
- **Indentation:** 2 spaces (TypeScript)
|
|
32
|
+
- **Imports:** Use `.js` extensions on relative imports (NodeNext module resolution)
|
|
33
|
+
- **Console output:** Use `[pi-ask-user-glimpse]` prefix for all `console.warn`/`console.error`
|
|
34
|
+
- **Peer deps:** Only list `@earendil-works/pi-coding-agent` and `@earendil-works/pi-ai` in `peerDependencies`
|
|
35
|
+
|
|
36
|
+
## Security Note
|
|
37
|
+
|
|
38
|
+
If you modify payload injection or test scripts, ensure HTML escaping matches production:
|
|
39
|
+
```ts
|
|
40
|
+
JSON.stringify(payload)
|
|
41
|
+
.replace(/</g, "\\u003c")
|
|
42
|
+
.replace(/>/g, "\\u003e")
|
|
43
|
+
.replace(/&/g, "\\u0026")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Before Submitting
|
|
47
|
+
|
|
48
|
+
- [ ] `npm run build` passes
|
|
49
|
+
- [ ] `npx tsc --noEmit` passes
|
|
50
|
+
- [ ] `npm run check` shows the expected files
|
|
51
|
+
- [ ] `npm run validate` passes
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Lee
|
|
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,272 @@
|
|
|
1
|
+
# @alexleekt/pi-ask-user-glimpse
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@alexleekt/pi-ask-user-glimpse)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A Pi extension that replaces `ask_user` with rich native WebView dialogs powered by [glimpseui](https://npmjs.com/package/glimpseui) and styled with shadcn/ui design tokens.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Single-select** — searchable option list with inline descriptions
|
|
11
|
+
- **Multi-select** — checkbox-style selection with submit/cancel
|
|
12
|
+
- **Freeform** — textarea input for open-ended responses
|
|
13
|
+
- **Questionnaire** — cards in a vertical list for structured questions, each with its own options
|
|
14
|
+
- **Native WebView** — renders in a real window (macOS WKWebView / Linux GTK4 / Windows WebView2)
|
|
15
|
+
- **Terminal fallback** — gracefully degrades to TUI prompts when glimpseui is unavailable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pi install npm:@alexleekt/pi-ask-user-glimpse
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires a Pi coding agent harness with extension support (e.g. `@earendil-works/pi-coding-agent`).
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
Once installed, the extension automatically replaces the built-in `ask_user` tool. The LLM calls it the same way as before — you don't need to do anything different.
|
|
29
|
+
|
|
30
|
+
### Single Select
|
|
31
|
+
|
|
32
|
+
Ask the user to pick exactly one option:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"question": "Which database should we use?",
|
|
37
|
+
"context": "We need something reliable for a production workload.",
|
|
38
|
+
"options": [
|
|
39
|
+
{ "title": "PostgreSQL", "description": "Relational, proven, great ecosystem" },
|
|
40
|
+
{ "title": "SQLite", "description": "Zero-config, embedded, serverless" }
|
|
41
|
+
],
|
|
42
|
+
"allowMultiple": false,
|
|
43
|
+
"allowFreeform": true,
|
|
44
|
+
"allowComment": true
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The dialog shows a full-width question header and a two-panel layout. When `context` is provided, the left panel renders it as markdown for reference while the right panel shows the searchable option list. Option descriptions appear inline below each title. The "Custom" button under the search box lets the user submit a freeform answer.
|
|
49
|
+
|
|
50
|
+
### Multi Select
|
|
51
|
+
|
|
52
|
+
Ask the user to pick multiple options:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"question": "Which features should we implement first?",
|
|
57
|
+
"context": "MVP is due in 2 weeks. Pick the most impactful items.",
|
|
58
|
+
"options": [
|
|
59
|
+
{ "title": "OAuth login", "description": "Google + GitHub sign-in" },
|
|
60
|
+
{ "title": "Real-time sync", "description": "WebSocket live updates" },
|
|
61
|
+
{ "title": "Email notifications", "description": "Digest + instant alerts" }
|
|
62
|
+
],
|
|
63
|
+
"allowMultiple": true,
|
|
64
|
+
"allowFreeform": true,
|
|
65
|
+
"allowComment": true
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Each option has a checkbox. A "Clear all" link resets selections. Submit is disabled until at least one item is selected.
|
|
70
|
+
|
|
71
|
+
### Freeform
|
|
72
|
+
|
|
73
|
+
Ask an open-ended question with no predefined options:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"question": "Describe the ideal user onboarding flow.",
|
|
78
|
+
"context": "We're redesigning first-time experience. Be specific about steps, copy, and timing.",
|
|
79
|
+
"allowFreeform": true
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Shows a full-height textarea with platform-aware keyboard hints (⌘+Enter on macOS, Ctrl+Enter elsewhere). Submit is disabled until text is entered.
|
|
84
|
+
|
|
85
|
+
### Questionnaire
|
|
86
|
+
|
|
87
|
+
Ask multiple structured questions in one dialog:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"question": "Project scoping questionnaire",
|
|
92
|
+
"context": "Answer each question to help us scope accurately.",
|
|
93
|
+
"questions": [
|
|
94
|
+
{
|
|
95
|
+
"title": "Database",
|
|
96
|
+
"description": "Which database should we use?",
|
|
97
|
+
"options": [
|
|
98
|
+
{ "title": "PostgreSQL", "description": "Relational, proven" },
|
|
99
|
+
{ "title": "SQLite", "description": "Zero-config" }
|
|
100
|
+
],
|
|
101
|
+
"allowMultiple": false
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"title": "Cache layer",
|
|
105
|
+
"description": "Select caching strategies",
|
|
106
|
+
"options": [
|
|
107
|
+
{ "title": "Redis", "description": "In-memory key-value" },
|
|
108
|
+
{ "title": "Memcached", "description": "Simple caching" }
|
|
109
|
+
],
|
|
110
|
+
"allowMultiple": true
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"title": "Notes",
|
|
114
|
+
"description": "Any additional thoughts?"
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"allowComment": true
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Each question is shown as a card with a progress bar at the top. Questions with `options` render as single-select (radio) or multi-select (checkbox) depending on `allowMultiple`. Questions without `options` render as a textarea. The dialog auto-scrolls to the first unanswered question on open. The comment button shows "Edit comment" when text exists. Submit is disabled until all questions have a non-empty answer, unless `allowSkip: true` is set.
|
|
122
|
+
|
|
123
|
+
### Parameters
|
|
124
|
+
|
|
125
|
+
| Parameter | Type | Default | Description |
|
|
126
|
+
|-----------|------|---------|-------------|
|
|
127
|
+
| `question` | `string` | *(required)* | The question to ask |
|
|
128
|
+
| `context` | `string` | — | Additional context shown in a left-side markdown panel |
|
|
129
|
+
| `options` | `Array<string \| {title, description?}>` | — | Options for flat single/multi-select mode |
|
|
130
|
+
| `questions` | `Array<{title, description?, options?, allowMultiple?}>` | — | Questions for questionnaire mode. When present, `options` is ignored. Each question can have its own `options` (same shape as top-level `options`) and `allowMultiple`. Questions without `options` render as freeform textareas. |
|
|
131
|
+
| `allowMultiple` | `boolean` | `false` | Allow selecting multiple options |
|
|
132
|
+
| `allowFreeform` | `boolean` | `true` | Show a freeform "Custom" option |
|
|
133
|
+
| `allowComment` | `boolean` | `false` | Collect an optional comment after selection |
|
|
134
|
+
| `allowSkip` | `boolean` | `false` | Allow submitting a questionnaire without answering all questions (questionnaire mode only) |
|
|
135
|
+
| `followCursor` | `boolean` | `false` | Make the 1200×900 dialog follow the terminal cursor |
|
|
136
|
+
| `displayMode` | `"overlay" \| "inline"` | — | Legacy option; ignored (always centered dialog) |
|
|
137
|
+
|
|
138
|
+
## Development
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
git clone https://github.com/alexleekt/pi-ask-user-glimpse.git
|
|
142
|
+
cd pi-ask-user-glimpse
|
|
143
|
+
npm install
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Build the webview bundle
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
npm run build # builds CSS + Vite webview → dist/index.html
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Dev server for webview
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm run dev:webview # Vite dev server on http://localhost:5173
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Validate
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm run validate # checks dist exists, placeholder present, binary found
|
|
162
|
+
npm run validate:gui # same + opens actual WebView for visual check
|
|
163
|
+
npm run check # dry-run npm pack
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Auto-Detection: When `ask_user` Is Used Automatically
|
|
167
|
+
|
|
168
|
+
Some skills instruct the agent to "ask questions one at a time" but never tell it to **use a tool** — so the agent writes plain text, bypassing the rich WebView dialog.
|
|
169
|
+
|
|
170
|
+
This extension auto-detects question-oriented sessions and injects a system-prompt mandate that tells the LLM to use `ask_user` for every question.
|
|
171
|
+
|
|
172
|
+
### Auto-detection
|
|
173
|
+
|
|
174
|
+
Before each LLM turn, the extension checks:
|
|
175
|
+
|
|
176
|
+
1. **Known question skills** — `grill-with-docs`, `questionnaire`, `interview`, `grill`
|
|
177
|
+
2. **Language patterns** in the system prompt — "ask the questions one at a time", "interview me", "grilling session", "wait for feedback"
|
|
178
|
+
3. **Manual toggle** — `/ask-style` overrides the behavior for the current session
|
|
179
|
+
|
|
180
|
+
When triggered, it appends: "You MUST use `ask_user` for every question. Do NOT write free-form text."
|
|
181
|
+
|
|
182
|
+
### Manual toggle: `/ask-style`
|
|
183
|
+
|
|
184
|
+
Override auto-detection for the current session:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
/ask-style
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Cycles through three states:
|
|
191
|
+
|
|
192
|
+
| State | Behavior |
|
|
193
|
+
|-------|----------|
|
|
194
|
+
| **AUTO** *(default)* | Auto-detect question sessions by skill name + language patterns |
|
|
195
|
+
| **Always Dialog** | Always use `ask_user` for every question, regardless of detection |
|
|
196
|
+
| **Plain Text** | Disable everything — let the agent write questions as plain text |
|
|
197
|
+
|
|
198
|
+
The setting is persisted in the session and survives restarts.
|
|
199
|
+
|
|
200
|
+
### Token cost
|
|
201
|
+
|
|
202
|
+
The injected mandate is ~100 tokens. It is only appended when detection triggers, so normal conversations pay nothing extra.
|
|
203
|
+
|
|
204
|
+
## Slash Command: `/ask-last`
|
|
205
|
+
|
|
206
|
+
When the assistant writes a question as free-form text (bypassing `ask_user`), use this command to retroactively open the rich dialog:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
/ask-last
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### How it works
|
|
213
|
+
|
|
214
|
+
1. Finds the last assistant message in the session
|
|
215
|
+
2. Extracts all sentences ending with `?`
|
|
216
|
+
3. If one question → opens a **freeform** dialog with the full message as context
|
|
217
|
+
4. If multiple questions → opens a **questionnaire** with each question as an item
|
|
218
|
+
5. Sends your answer back into the conversation as a user message
|
|
219
|
+
|
|
220
|
+
This is useful when:
|
|
221
|
+
- A skill or the agent itself wrote a question as plain text
|
|
222
|
+
- You want to answer via the rich WebView instead of typing inline
|
|
223
|
+
- The agent asked multiple things and you want to answer them all at once
|
|
224
|
+
|
|
225
|
+
## Slash Command: `/ask-debug`
|
|
226
|
+
|
|
227
|
+
Open a debug prompt that lets you manually test each dialog type:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
/ask-debug
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Options: `single-select`, `multi-select`, `freeform`, `questionnaire`. The result is shown as a Pi notification.
|
|
234
|
+
|
|
235
|
+
## Window Behavior
|
|
236
|
+
|
|
237
|
+
- **Title bar** — shows a condensed version of the question text (up to 3 content words)
|
|
238
|
+
- **Centered dialog** — normal stacking, not floating
|
|
239
|
+
- **Size** — 1200×900 by default
|
|
240
|
+
- **Cursor follow** — off by default; enable with `followCursor: true`
|
|
241
|
+
- **Dark mode** — automatically follows the system `prefers-color-scheme` setting
|
|
242
|
+
|
|
243
|
+
## Architecture
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
index.ts → Pi extension entrypoint (tool + command registration)
|
|
247
|
+
tool/ask-user.ts → constructs payload, injects into HTML, calls glimpseui.prompt()
|
|
248
|
+
tool/response-formatter.ts → normalizes WebView response for Pi
|
|
249
|
+
webview/src/components/ → SingleSelect, MultiSelect, Questionnaire, Freeform, ContextPanel, ErrorBoundary
|
|
250
|
+
fallback/terminal-prompt.ts → readline fallback when WebView unavailable
|
|
251
|
+
webview/ → Vite + React + Tailwind app
|
|
252
|
+
src/components/ → SingleSelect, MultiSelect, Questionnaire, Freeform
|
|
253
|
+
dist/index.html → single-file bundle (inlined JS + CSS)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Troubleshooting
|
|
257
|
+
|
|
258
|
+
### "Could not find webview bundle"
|
|
259
|
+
|
|
260
|
+
Run `npm run build` to generate `dist/index.html`. The extension cannot work without the webview bundle.
|
|
261
|
+
|
|
262
|
+
### WebView does not open (terminal fallback instead)
|
|
263
|
+
|
|
264
|
+
The extension falls back to TUI prompts when the glimpseui native host is unavailable. This is normal on headless systems or if the native binary is missing. Check `npm run validate` to see if the binary is detected.
|
|
265
|
+
|
|
266
|
+
### Dialog shows "Missing or invalid ask_user payload"
|
|
267
|
+
|
|
268
|
+
This means the HTML payload injection failed. Ensure `dist/index.html` contains the `/*ASK_USER_PAYLOAD*/` placeholder. Run `npm run build` to regenerate.
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
MIT
|