@alexleekt/pi-ask-user-glimpse 0.4.1 → 0.5.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/CHANGELOG.md CHANGED
@@ -2,13 +2,36 @@
2
2
 
3
3
  All notable changes to `@alexleekt/pi-ask-user-glimpse` are documented in this file.
4
4
 
5
- ## [Unreleased]
5
+ ## [0.5.0] — 2026-05-24
6
+
7
+ ### Added
8
+ - **Kitchen-sink debug mode** — `/ask-debug` now includes a `kitchen-sink` option that opens a comprehensive questionnaire demonstrating every major feature in one dialog: HTML context panel, recommended badges, multi-select, single-select, freeform, comments, and skip. Replaces the previous 9-mode menu (which had 5 redundant single-select variations) with a clean 5-mode list.
9
+ - **HTML context iframe sizing fix** — Removed `loading="lazy"` from the sandboxed iframe. Glimpse's native WebView host (WKWebView on macOS / WebView2 on Windows) applies lazy-loading heuristics even to `srcDoc` iframes with no network request, causing the HTML content to never render in some versions. Changed the iframe container from `overflow-y-auto` to `overflow-hidden flex flex-col` so the iframe's `flex-1` sizing works reliably within the flex layout. The iframe now uses `flex-1 min-h-0` instead of `h-full` to avoid the 150px default-height fallback when percentage heights fail in nested flex contexts.
10
+ - **Recommendation badges** — Options can now include `recommended: true` to show a "Recommended" badge in the dialog. The badge renders next to the option title using the primary color token. Works in single-select, multi-select, and questionnaire modes. The LLM tool schema documents the field so agents can mark their top recommendation.
11
+ - **Option numbering** — Each option now displays a circular number badge (① ② ③…) between the checkbox/radio and the title text. Provides a quick visual reference for keyboard navigation and makes it easier to refer to options when discussing choices.
12
+ - **Markdown rendering in option text** — Option titles and descriptions are now rendered through inline markdown. Bold `**`, italic `*`, code `` ` ``, and links display correctly. During search, markdown rendering is temporarily disabled to avoid broken markup from injected `<mark>` highlight tags.
13
+ - ~~Auto-catch free-form questions~~ — **Removed.** The "Always Dialog" mode and its auto-catch behavior have been eliminated.
14
+ - **HTML context format** — New `contextFormat: "html"` option for the `ask_user` tool. When set, the `context` field renders inside a sandboxed iframe (`sandbox="allow-scripts"`) in the left panel instead of markdown. The iframe inherits the wrapper's CSS variables for automatic light/dark theme consistency. Theme changes are propagated via `postMessage`.
15
+ - **YOLO style** — New `/ask-style` state that tells the agent to proceed with its best recommendation without asking. Injects a mandate: "Do NOT ask the user for input or confirmation. Go with your best recommendation and proceed immediately. Only use `ask_user` if the action would cause irreversible harm, data loss, security compromise, or violate explicit hard constraints."
16
+
17
+ ### Removed
18
+ - **"Always Dialog" mode** — Removed the `ASK_USER_MANDATE` system-prompt injection and the auto-catch behavior that converted free-form agent questions into dialogs. These features caused excessive dialog interruptions and were too aggressive for general use. The `/ask` command and manual `ask_user` tool calls still work normally.
19
+
20
+ ### Changed
21
+ - **Plain Text is now the default** — The extension no longer injects any system-prompt mandate by default. The agent writes questions as free-form text unless the user manually triggers `/ask` or the agent calls `ask_user`. The `/ask-style` toggle now cycles through **Plain Text** → **YOLO** → **Plain Text**.
22
+ - **Two-state `/ask-style` cycle** — `Plain Text → YOLO → Plain Text`.
23
+ - **`deliverAs: "steer"` for all user message delivery** — Both auto-catch and `/ask` now use `steer` instead of `followUp` when sending answers back to the conversation. `steer` sends immediately and is processed as an active user intervention, avoiding the "Follow-up: queued messages" UI state where the answer was stuck waiting.
24
+ - **Removed terminal fallback** — Deleted `fallback/terminal-prompt.ts`. When the Glimpse native host is unavailable, the extension always returns an explicit error telling the agent to ask in free-form text. The previous TUI fallback (`ctx.ui.select()` / `ctx.ui.input()`) has been removed to simplify the codebase and provide consistent behavior.
25
+ - **Freeform empty submissions allowed** — Removed the guard that blocked empty freeform text submissions. This is consistent with questionnaire behavior where unanswered questions are allowed when `allowSkip: true`.
6
26
 
7
27
  ### Added
8
28
  - **Agent preamble capture** — When the agent writes an introductory message before calling `ask_user`, that text is now automatically captured and prepended to the context panel. The extension finds the most recent assistant journal entry, extracts its text content, and appends it to the dialog's left panel (separated by a horizontal rule from any explicit `context` provided by the agent). This ensures the user sees the full reasoning that led to the question, not just the question itself.
9
29
 
10
30
  ### Fixed
11
31
  - **Markdown in question header** — The `question` field is now rendered through `marked` so inline markdown (bold `**`, italic `*`, code `` ` ``, links) displays correctly instead of showing raw escape characters. The HTML is sanitized with the same defense-in-depth sanitizer used by the context panel. Extracted shared `sanitizeHtml()`, `renderMarkdown()`, and `renderMarkdownInline()` to `webview/src/util/markdown.ts`.
32
+ - **`sendUserMessage` error handling** — Wrapped `pi.sendUserMessage()` in `try/catch` with `await` in the `/ask` handler. Previously, the promise was fire-and-forget; when the framework threw "Agent is already processing" (or any other error), the rejection was unhandled and the dialog answer was silently lost. Errors are now logged to console with `[pi-ask-user-glimpse]` prefix and surfaced via UI notification.
33
+ - **`additionalComments` in questionnaire responses** — The `questionnaire` response kind was missing the `additionalComments` field that existed for `selection` and `freeform` kinds. Now all three kinds consistently include `additionalComments` when the user provides them.
34
+ - **Fast-escape when no UI available** — `askUserHandler` now returns an explicit error message ("No UI available for ask_user dialog...") instead of falling back to a terminal prompt when `!ctx.hasUI`. The `before_agent_start` mandate injection is also skipped in headless environments, preventing the agent from being forced to use a tool that cannot work.
12
35
 
13
36
  ## [0.4.1] — 2026-05-20
14
37
 
package/CONTRIBUTING.md CHANGED
@@ -23,10 +23,10 @@ npm run check # dry-run npm pack
23
23
  npm run validate # checks dist exists, placeholder present, binary found
24
24
  npm run validate:gui # same + opens actual WebView for visual check
25
25
  npm run test:with-context # opens WebView with context panel + resizable splitter
26
- npx tsx scripts/smoke-test.ts # opens WebView for 2s
27
- npx tsx scripts/visual-qa.ts # cycles through all 5 scenarios
28
26
  ```
29
27
 
28
+ For manual visual testing, use `/ask-debug` inside a Pi session. It offers five scenarios: `single-select`, `multi-select`, `freeform`, `questionnaire`, and `kitchen-sink` (comprehensive questionnaire with HTML context panel).
29
+
30
30
  ## Code Style
31
31
 
32
32
  - **Indentation:** 2 spaces (TypeScript)
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
1
  # @alexleekt/pi-ask-user-glimpse
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@alexleekt/pi-ask-user-glimpse.svg)](https://www.npmjs.com/package/@alexleekt/pi-ask-user-glimpse)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
3
+ [![npm](https://img.shields.io/npm/v/@alexleekt/pi-ask-user-glimpse)](https://www.npmjs.com/package/@alexleekt/pi-ask-user-glimpse)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
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.
6
+ > Ask better questions. Get better answers.
7
+
8
+ Rich native WebView dialogs powered by [glimpseui](https://npmjs.com/package/glimpseui) and styled with shadcn/ui design tokens.
7
9
 
8
10
  > **Stop reading terminal walls of text.** This extension turns every `ask_user` call into a beautiful, searchable, keyboard-navigable dialog — complete with markdown context panels, inline descriptions, and dark mode. Your agent asks better questions. You answer faster.
9
11
 
@@ -30,16 +32,16 @@ The agent gets a clean selection back. You get a decision made in seconds, not m
30
32
 
31
33
  ## Features
32
34
 
33
- - **Single-select** — searchable option list with inline descriptions and search highlight
34
- - **Multi-select** — checkbox-style selection with quick-select all/none links
35
- - **Freeform** — textarea input with live character counter and platform-aware keyboard shortcuts
36
- - **Questionnaire** — cards in a vertical list for structured questions, with required-field badges and per-question character counters
35
+ - **Single-select** — searchable option list with inline descriptions, numbered option badges (① ② ③), inline markdown rendering, and search highlight
36
+ - **Multi-select** — checkbox-style selection with quick-select all/none links, numbered badges, and inline markdown
37
+ - **Freeform** — textarea input with live character counter and platform-aware keyboard shortcuts. Empty submissions are allowed (useful when the agent asks an open question but you have nothing to add)
38
+ - **Questionnaire** — cards in a vertical list for structured questions, with required-field badges, per-question character counters, numbered option badges, and inline markdown in option text
37
39
  - **Theme toggle** — dark / light / system mode switcher in the dialog header
38
40
  - **Animation levels** — none / minimal / all, controlling transition intensity across the UI
39
41
  - **Keyboard shortcuts legend** — press `?` in the header bar to see all available shortcuts
40
42
  - **Prominent question header** — full non-truncated question text in the header bar, with settings cog and keyboard-shortcuts help
41
43
  - **Native WebView** — renders in a real window (macOS WKWebView / Linux GTK4 / Windows WebView2)
42
- - **Terminal fallback** — gracefully degrades to TUI prompts when glimpseui is unavailable
44
+ - **Graceful degradation** — returns clear error when no UI is available, prompting the agent to ask in free-form text
43
45
 
44
46
  ## Install
45
47
 
@@ -94,6 +96,28 @@ Ask the user to pick multiple options:
94
96
 
95
97
  Each option has a checkbox. "Select all" and "Select none" links appear above the list (when not searching). A "Clear all" link resets selections. Submit is disabled until at least one item is selected. Use ⌘+Enter (macOS) or Ctrl+Enter to submit.
96
98
 
99
+ ### HTML Context (Visualizations)
100
+
101
+ When text and Mermaid diagrams aren't enough, render rich HTML in the context panel:
102
+
103
+ ```json
104
+ {
105
+ "question": "Which layout performs better?",
106
+ "context": "<div style='display:flex;gap:1rem;justify-content:center'>...</div>",
107
+ "contextFormat": "html",
108
+ "options": [
109
+ { "title": "Layout A", "description": "Dense grid with sidebar" },
110
+ { "title": "Layout B", "description": "Spacious single column" }
111
+ ]
112
+ }
113
+ ```
114
+
115
+ The `context` HTML renders inside a **sandboxed iframe** (`sandbox="allow-scripts"`) in the left panel. It inherits the wrapper's CSS variables (`--background`, `--foreground`, `--primary`, etc.) for automatic light/dark theme consistency. The iframe auto-updates its theme class when the user toggles settings. This is ideal for throwaway bar charts, tables, decision trees, or any visualization that helps the user decide.
116
+
117
+ **Security:** The iframe is isolated from the wrapper app. It cannot access `localStorage`, cookies, or the parent DOM. Only inline scripts are permitted (for animations/interactivity). The agent should not include `<script src="...">` tags that load external resources — inline JS and CSS only.
118
+
119
+ **Glimpse behavior:** The HTML context panel runs inside Glimpse's native WebView host (WKWebView on macOS, WebView2 on Windows). The iframe receives an opaque ("null") origin because Glimpse loads the page via `loadHTMLString` without a base URL. This means `window.location.origin` is `null`, and `localStorage` access throws a `SecurityError`. Theme changes are propagated via `postMessage` instead of DOM sharing.
120
+
97
121
  ### Freeform
98
122
 
99
123
  Ask an open-ended question with no predefined options:
@@ -106,7 +130,7 @@ Ask an open-ended question with no predefined options:
106
130
  }
107
131
  ```
108
132
 
109
- Shows a full-height textarea with a live character counter and platform-aware keyboard hints (⌘+Enter on macOS, Ctrl+Enter elsewhere). Submit is disabled until text is entered.
133
+ Shows a full-height textarea with a live character counter and platform-aware keyboard hints (⌘+Enter on macOS, Ctrl+Enter elsewhere). Submit is always enabled you can send an empty answer if you have nothing to add.
110
134
 
111
135
  ### Questionnaire
112
136
 
@@ -151,8 +175,9 @@ Each question is shown as a card with a progress bar at the top. Questions with
151
175
  | Parameter | Type | Default | Description |
152
176
  |-----------|------|---------|-------------|
153
177
  | `question` | `string` | *(required)* | The question to ask |
154
- | `context` | `string` | — | Additional context shown in a left-side markdown panel |
155
- | `options` | `Array<string &#124; {title, description?}>` | — | Options for flat single/multi-select mode |
178
+ | `context` | `string` | — | Additional context shown in a left-side panel |
179
+ | `contextFormat` | `"markdown" &#124; "html"` | `"markdown"` | Format of the `context` field. `markdown` renders formatted text with Mermaid diagram support. `html` renders in a sandboxed iframe useful for throwaway charts, tables, or interactive visualizations. The iframe inherits the wrapper's CSS variables for theme consistency. |
180
+ | `options` | `Array<string &#124; {title, description?, recommended?}>` | — | Options for flat single/multi-select mode. Set `recommended: true` to show a "Recommended" badge. |
156
181
  | `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. |
157
182
  | `allowMultiple` | `boolean` | `false` | Allow selecting multiple options |
158
183
  | `allowFreeform` | `boolean` | `true` | Show a freeform "Custom" option |
@@ -189,43 +214,37 @@ npm run validate:gui # same + opens actual WebView for visual check
189
214
  npm run check # dry-run npm pack
190
215
  ```
191
216
 
192
- ## Auto-Detection: When `ask_user` Is Used Automatically
217
+ ## Ask-Style Toggle: `/ask-style`
193
218
 
194
- 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.
219
+ By default, the agent asks questions as free-form text. You can change this per-session:
195
220
 
196
- This extension auto-detects question-oriented sessions and injects a system-prompt mandate that tells the LLM to use `ask_user` for every question.
221
+ ```
222
+ /ask-style
223
+ ```
197
224
 
198
- ### Auto-detection
225
+ Cycles through two states:
199
226
 
200
- Before each LLM turn, the extension checks:
227
+ | State | Behavior |
228
+ |-------|----------|
229
+ | **Plain Text** *(default)* | Agent writes questions as free-form text |
230
+ | **YOLO** | Agent proceeds with its best recommendation without asking |
201
231
 
202
- 1. **Known question skills** `grill-with-docs`, `questionnaire`, `interview`, `grill`
203
- 2. **Language patterns** in the system prompt — "ask the questions one at a time", "interview me", "grilling session", "wait for feedback"
204
- 3. **Manual toggle** — `/ask-style` overrides the behavior for the current session
232
+ The setting is persisted in the session and survives restarts.
205
233
 
206
- When triggered, it appends: "You MUST use `ask_user` for every question. Do NOT write free-form text."
234
+ ### YOLO style
207
235
 
208
- ### Manual toggle: `/ask-style`
236
+ When YOLO is active, the extension injects a mandate telling the agent **not** to ask for input or confirmation. Instead, the agent goes with its best recommendation and keeps moving. It will only use `ask_user` if the action would cause irreversible harm, data loss, or security compromise.
209
237
 
210
- Override auto-detection for the current session:
238
+ Use this when you trust the agent's judgment and want maximum speed:
211
239
 
212
240
  ```
213
241
  /ask-style
242
+ → ask_user style: YOLO — go with your recommendation
214
243
  ```
215
244
 
216
- Cycles through three states:
217
-
218
- | State | Behavior |
219
- |-------|----------|
220
- | **AUTO** *(default)* | Auto-detect question sessions by skill name + language patterns |
221
- | **Always Dialog** | Always use `ask_user` for every question, regardless of detection |
222
- | **Plain Text** | Disable everything — let the agent write questions as plain text |
223
-
224
- The setting is persisted in the session and survives restarts.
225
-
226
245
  ### Token cost
227
246
 
228
- The injected mandate is ~100 tokens. It is only appended when detection triggers, so normal conversations pay nothing extra.
247
+ The injected mandate is ~100 tokens. It is appended on every turn when `ask_user` is available in the tool set.
229
248
 
230
249
  ## Slash Command: `/ask`
231
250
 
@@ -256,7 +275,9 @@ Open a debug prompt that lets you manually test each dialog type:
256
275
  /ask-debug
257
276
  ```
258
277
 
259
- Options: `single-select`, `multi-select`, `freeform`, `questionnaire`. The result is shown as a Pi notification.
278
+ Options: `single-select`, `multi-select`, `freeform`, `questionnaire`, `kitchen-sink`. The result is shown as a Pi notification.
279
+
280
+ The **kitchen-sink** option opens a comprehensive questionnaire with an HTML context panel, recommended badges, multi-select, freeform, comments, and skip — every major feature in one dialog.
260
281
 
261
282
  ## Window Behavior
262
283
 
@@ -276,7 +297,7 @@ index.ts → Pi extension entrypoint (tool + command registration)
276
297
  constants/ → STOPWORDS, PROTECTED_ABBREVIATIONS
277
298
  tool/ask-user.ts → constructs payload, injects into HTML, calls glimpseui.prompt()
278
299
  tool/response-formatter.ts → normalizes WebView response for Pi
279
- fallback/terminal-prompt.ts readline fallback when WebView unavailable
300
+ (no terminal fallback — fast-escape with error when UI unavailable)
280
301
  webview/ → Vite + React + Tailwind app
281
302
  src/components/ → SingleSelect, MultiSelect, Questionnaire, Freeform, ContextPanel, ErrorBoundary, HeaderBar, ShortcutsModal, AdditionalComments
282
303
  src/util/ → settings.tsx (theme/animation context), glimpse.ts (host bridge), platform.ts (modKey), html.ts (escapeHtml + highlightMatch)
@@ -289,9 +310,9 @@ webview/ → Vite + React + Tailwind app
289
310
 
290
311
  Run `npm run build` to generate `dist/index.html`. The extension cannot work without the webview bundle.
291
312
 
292
- ### WebView does not open (terminal fallback instead)
313
+ ### WebView does not open
293
314
 
294
- 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.
315
+ If the glimpseui native host is unavailable, the extension returns an error to the agent, which will ask the question in free-form text instead. This is normal on headless systems or if the native binary is missing. Check `npm run validate` to see if the binary is detected.
295
316
 
296
317
  ### Dialog shows "Missing or invalid ask_user payload"
297
318