pi-ask-user 0.8.0 → 0.10.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 +23 -7
- package/index.ts +121 -20
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ High-quality video: [ask-user-demo.mp4](./media/ask-user-demo.mp4)
|
|
|
17
17
|
- User-toggleable extra context on structured selections
|
|
18
18
|
- Context display support
|
|
19
19
|
- Configurable display mode: `overlay` (modal, default) or `inline` (rendered directly in the flow)
|
|
20
|
-
- Runtime overlay toggle: press `alt+o` while the prompt is open to temporarily hide/show the popup so you can read prior agent output, then press
|
|
20
|
+
- Runtime overlay toggle: press the configured overlay-toggle key (`alt+o` by default, configurable per call or via env var) while the prompt is open to temporarily hide/show the popup so you can read prior agent output, then press it again to bring it back
|
|
21
21
|
- Pi-TUI-aligned keybinding and editor behavior
|
|
22
22
|
- Custom TUI rendering for tool calls and results
|
|
23
23
|
- System prompt integration via `promptSnippet` and `promptGuidelines`
|
|
@@ -66,6 +66,8 @@ The registered tool name is:
|
|
|
66
66
|
| `allowFreeform` | `boolean?` | `true` | Add a "Type something" freeform option |
|
|
67
67
|
| `allowComment` | `boolean?` | `false` | Expose a user-toggleable extra-context option in the custom UI (`ctrl+g` or the toggle row) and collect an optional comment in fallback dialogs |
|
|
68
68
|
| `displayMode` | `"overlay" \| "inline"?` | env var or `"overlay"` | Controls custom UI rendering: `overlay` shows the centered modal (current behavior), `inline` renders without overlay framing |
|
|
69
|
+
| `overlayToggleKey` | `string?` | env var or `"alt+o"` | Shortcut for hiding/showing the overlay popup (overlay mode only). Pi-TUI key spec, e.g. `"alt+o"`, `"ctrl+shift+h"`. Pass `"off"` to disable. |
|
|
70
|
+
| `commentToggleKey` | `string?` | env var or `"ctrl+g"` | Shortcut for toggling the optional comment/extra-context row when `allowComment: true`. Pass `"off"` to disable. |
|
|
69
71
|
| `timeout` | `number?` | — | Auto-dismiss after N ms and return `null` if the prompt times out |
|
|
70
72
|
|
|
71
73
|
## Example usage shape
|
|
@@ -87,30 +89,44 @@ The registered tool name is:
|
|
|
87
89
|
|
|
88
90
|
`displayMode: "inline"` uses the same interaction logic but skips overlay mode when calling `ctx.ui.custom(...)`. RPC/headless fallback behavior is unchanged.
|
|
89
91
|
|
|
90
|
-
## Personal
|
|
92
|
+
## Personal preferences via environment variables
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
Configure your defaults globally by setting these in your shell profile (`~/.zshrc`, `~/.bash_profile`, etc.):
|
|
93
95
|
|
|
94
96
|
```bash
|
|
95
97
|
export PI_ASK_USER_DISPLAY_MODE=inline
|
|
98
|
+
export PI_ASK_USER_OVERLAY_TOGGLE_KEY=alt+h
|
|
99
|
+
export PI_ASK_USER_COMMENT_TOGGLE_KEY=alt+c
|
|
96
100
|
```
|
|
97
101
|
|
|
98
|
-
|
|
102
|
+
### Display mode
|
|
103
|
+
|
|
104
|
+
Effective order:
|
|
99
105
|
|
|
100
106
|
1. Per-call `displayMode` parameter (if provided)
|
|
101
|
-
2. `PI_ASK_USER_DISPLAY_MODE`
|
|
107
|
+
2. `PI_ASK_USER_DISPLAY_MODE` (if set to `"overlay"` or `"inline"`)
|
|
102
108
|
3. Fallback default: `"overlay"`
|
|
103
109
|
|
|
104
110
|
Unrecognised values are silently ignored and fall back to `"overlay"`.
|
|
105
111
|
|
|
112
|
+
### Shortcuts
|
|
113
|
+
|
|
114
|
+
Effective order for both `overlayToggleKey` and `commentToggleKey`:
|
|
115
|
+
|
|
116
|
+
1. Per-call parameter (if provided)
|
|
117
|
+
2. Matching env var (`PI_ASK_USER_OVERLAY_TOGGLE_KEY` / `PI_ASK_USER_COMMENT_TOGGLE_KEY`)
|
|
118
|
+
3. Built-in defaults: `alt+o` and `ctrl+g`
|
|
119
|
+
|
|
120
|
+
Pass `"off"`, `"none"`, or `"disabled"` (at any level) to disable the shortcut entirely. Invalid specs are silently dropped and the next source is used. Specs follow the Pi-TUI [`KeyId`](https://github.com/earendil-works/pi-mono/blob/main/packages/tui/src/keys.ts) format: `[mod+]...key` where modifiers are `ctrl`, `shift`, `alt`, `super`, in any order, joined by `+` (e.g. `ctrl+g`, `alt+shift+x`, `escape`, `tab`).
|
|
121
|
+
|
|
106
122
|
## Controls
|
|
107
123
|
|
|
108
124
|
While an `ask_user` prompt is open:
|
|
109
125
|
|
|
110
126
|
| Key | Action |
|
|
111
127
|
|-----|--------|
|
|
112
|
-
| `alt+o` | Hide/show the overlay popup so you can read the agent's prior output. Available in `overlay` mode only. The first time you hide it, a notification reminds you
|
|
113
|
-
| `ctrl+g` | Toggle the optional comment/extra-context row (when `allowComment: true`). |
|
|
128
|
+
| `alt+o` (configurable via `overlayToggleKey`) | Hide/show the overlay popup so you can read the agent's prior output. Available in `overlay` mode only. The first time you hide it, a notification reminds you which key brings it back. |
|
|
129
|
+
| `ctrl+g` (configurable via `commentToggleKey`) | Toggle the optional comment/extra-context row (when `allowComment: true`). |
|
|
114
130
|
| `enter` | Confirm the focused option, submit a freeform response, or submit/skip an optional comment. |
|
|
115
131
|
| `esc` | Clear the search filter, exit freeform/comment mode, or cancel the prompt. |
|
|
116
132
|
| `↑` / `↓` | Navigate options. |
|
package/index.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* and a custom box border instead of manual ANSI box drawing.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { ExtensionAPI, Theme } from "@
|
|
9
|
-
import { getMarkdownTheme } from "@
|
|
8
|
+
import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
import { Type, type TUnsafe } from "@sinclair/typebox";
|
|
11
11
|
import {
|
|
12
12
|
Container,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
type TUI,
|
|
28
28
|
truncateToWidth,
|
|
29
29
|
wrapTextWithAnsi,
|
|
30
|
-
} from "@
|
|
30
|
+
} from "@earendil-works/pi-tui";
|
|
31
31
|
import { renderSingleSelectRows } from "./single-select-layout";
|
|
32
32
|
|
|
33
33
|
import { createRequire } from "node:module";
|
|
@@ -64,6 +64,8 @@ interface AskParams {
|
|
|
64
64
|
allowFreeform?: boolean;
|
|
65
65
|
allowComment?: boolean;
|
|
66
66
|
displayMode?: AskDisplayMode;
|
|
67
|
+
overlayToggleKey?: string | null;
|
|
68
|
+
commentToggleKey?: string | null;
|
|
67
69
|
timeout?: number;
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -245,12 +247,63 @@ function literalHint(theme: Theme, key: string, description: string): string {
|
|
|
245
247
|
return `${theme.fg("dim", key)}${theme.fg("muted", ` ${description}`)}`;
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
+
type ResolvedShortcut =
|
|
251
|
+
| { disabled: false; spec: string; matches: (data: string) => boolean }
|
|
252
|
+
| { disabled: true; spec: null; matches: (data: string) => false };
|
|
253
|
+
|
|
254
|
+
interface ResolvedAskShortcuts {
|
|
255
|
+
overlayToggle: ResolvedShortcut;
|
|
256
|
+
commentToggle: ResolvedShortcut;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const DISABLED_SHORTCUT: ResolvedShortcut = {
|
|
260
|
+
disabled: true,
|
|
261
|
+
spec: null,
|
|
262
|
+
matches: ((_data: string) => false) as (data: string) => false,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
const SHORTCUT_DISABLE_VALUES = new Set(["off", "none", "disabled", ""]);
|
|
266
|
+
|
|
267
|
+
function normalizeShortcutSpec(value: string | null | undefined): string | null | undefined {
|
|
268
|
+
if (value === undefined) return undefined;
|
|
269
|
+
if (value === null) return null;
|
|
270
|
+
const trimmed = value.trim().toLowerCase();
|
|
271
|
+
if (SHORTCUT_DISABLE_VALUES.has(trimmed)) return null;
|
|
272
|
+
return trimmed;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function isValidShortcutSpec(spec: string): boolean {
|
|
276
|
+
// KeyId is canonical lowercase: modifiers (`ctrl|shift|alt|super`) joined by `+`,
|
|
277
|
+
// plus a base key. We do a light syntactic sanity check; matchesKey() does the rest.
|
|
278
|
+
if (!spec) return false;
|
|
279
|
+
if (!/^[a-z0-9+_\-!@#$%^&*()|~`'":;,./<>?[\]{}=\\]+$/i.test(spec)) return false;
|
|
280
|
+
if (spec.startsWith("+") || spec.endsWith("+")) return false;
|
|
281
|
+
if (spec.includes("++")) return false;
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function buildShortcut(spec: string): ResolvedShortcut {
|
|
286
|
+
return {
|
|
287
|
+
disabled: false,
|
|
288
|
+
spec,
|
|
289
|
+
matches: (data: string) => matchesKey(data, spec as any),
|
|
290
|
+
};
|
|
250
291
|
}
|
|
251
292
|
|
|
252
|
-
function
|
|
253
|
-
|
|
293
|
+
function resolveShortcut(
|
|
294
|
+
paramValue: string | null | undefined,
|
|
295
|
+
envValue: string | undefined,
|
|
296
|
+
defaultSpec: string,
|
|
297
|
+
): ResolvedShortcut {
|
|
298
|
+
const candidates: Array<string | null | undefined> = [paramValue, envValue, defaultSpec];
|
|
299
|
+
for (const raw of candidates) {
|
|
300
|
+
const normalized = normalizeShortcutSpec(raw);
|
|
301
|
+
if (normalized === undefined) continue; // not provided, fall through
|
|
302
|
+
if (normalized === null) return DISABLED_SHORTCUT; // explicit disable
|
|
303
|
+
if (isValidShortcutSpec(normalized)) return buildShortcut(normalized);
|
|
304
|
+
// Invalid spec: silently fall through to next candidate.
|
|
305
|
+
}
|
|
306
|
+
return DISABLED_SHORTCUT;
|
|
254
307
|
}
|
|
255
308
|
|
|
256
309
|
type AskMode = "select" | "freeform" | "comment";
|
|
@@ -264,7 +317,8 @@ const SINGLE_SELECT_SPLIT_PANE_RIGHT_MIN_WIDTH = 28;
|
|
|
264
317
|
const SINGLE_SELECT_SPLIT_PANE_SEPARATOR = " │ ";
|
|
265
318
|
const FREEFORM_SENTINEL = "\u270f\ufe0f Type custom response...";
|
|
266
319
|
const COMMENT_TOGGLE_LABEL = "Add extra context after selection";
|
|
267
|
-
const
|
|
320
|
+
const DEFAULT_OVERLAY_TOGGLE_KEY = "alt+o";
|
|
321
|
+
const DEFAULT_COMMENT_TOGGLE_KEY = "ctrl+g";
|
|
268
322
|
|
|
269
323
|
function buildCustomUIOptions(
|
|
270
324
|
displayMode: AskDisplayMode,
|
|
@@ -309,6 +363,7 @@ class MultiSelectList implements Component {
|
|
|
309
363
|
private allowComment: boolean;
|
|
310
364
|
private theme: Theme;
|
|
311
365
|
private keybindings: KeybindingsManager;
|
|
366
|
+
private commentToggle: ResolvedShortcut;
|
|
312
367
|
private selectedIndex = 0;
|
|
313
368
|
private checked = new Set<number>();
|
|
314
369
|
private commentEnabled = false;
|
|
@@ -325,12 +380,14 @@ class MultiSelectList implements Component {
|
|
|
325
380
|
allowComment: boolean,
|
|
326
381
|
theme: Theme,
|
|
327
382
|
keybindings: KeybindingsManager,
|
|
383
|
+
commentToggle: ResolvedShortcut,
|
|
328
384
|
) {
|
|
329
385
|
this.options = options;
|
|
330
386
|
this.allowFreeform = allowFreeform;
|
|
331
387
|
this.allowComment = allowComment;
|
|
332
388
|
this.theme = theme;
|
|
333
389
|
this.keybindings = keybindings;
|
|
390
|
+
this.commentToggle = commentToggle;
|
|
334
391
|
}
|
|
335
392
|
|
|
336
393
|
public isCommentEnabled(): boolean {
|
|
@@ -387,7 +444,7 @@ class MultiSelectList implements Component {
|
|
|
387
444
|
return;
|
|
388
445
|
}
|
|
389
446
|
|
|
390
|
-
if (this.allowComment &&
|
|
447
|
+
if (this.allowComment && !this.commentToggle.disabled && this.commentToggle.matches(data)) {
|
|
391
448
|
this.toggleComment();
|
|
392
449
|
return;
|
|
393
450
|
}
|
|
@@ -531,6 +588,7 @@ class WrappedSingleSelectList implements Component {
|
|
|
531
588
|
private allowComment: boolean;
|
|
532
589
|
private theme: Theme;
|
|
533
590
|
private keybindings: KeybindingsManager;
|
|
591
|
+
private commentToggle: ResolvedShortcut;
|
|
534
592
|
private selectedIndex = 0;
|
|
535
593
|
private searchQuery = "";
|
|
536
594
|
private commentEnabled = false;
|
|
@@ -548,12 +606,14 @@ class WrappedSingleSelectList implements Component {
|
|
|
548
606
|
allowComment: boolean,
|
|
549
607
|
theme: Theme,
|
|
550
608
|
keybindings: KeybindingsManager,
|
|
609
|
+
commentToggle: ResolvedShortcut,
|
|
551
610
|
) {
|
|
552
611
|
this.options = options;
|
|
553
612
|
this.allowFreeform = allowFreeform;
|
|
554
613
|
this.allowComment = allowComment;
|
|
555
614
|
this.theme = theme;
|
|
556
615
|
this.keybindings = keybindings;
|
|
616
|
+
this.commentToggle = commentToggle;
|
|
557
617
|
}
|
|
558
618
|
|
|
559
619
|
public isCommentEnabled(): boolean {
|
|
@@ -774,7 +834,7 @@ class WrappedSingleSelectList implements Component {
|
|
|
774
834
|
return;
|
|
775
835
|
}
|
|
776
836
|
|
|
777
|
-
if (this.allowComment &&
|
|
837
|
+
if (this.allowComment && !this.commentToggle.disabled && this.commentToggle.matches(data)) {
|
|
778
838
|
this.toggleComment();
|
|
779
839
|
return;
|
|
780
840
|
}
|
|
@@ -883,6 +943,7 @@ class AskComponent extends Container {
|
|
|
883
943
|
private tui: TUI;
|
|
884
944
|
private theme: Theme;
|
|
885
945
|
private keybindings: KeybindingsManager;
|
|
946
|
+
private shortcuts: ResolvedAskShortcuts;
|
|
886
947
|
private onDone: (result: AskUIResult | null) => void;
|
|
887
948
|
|
|
888
949
|
private mode: AskMode = "select";
|
|
@@ -925,6 +986,7 @@ class AskComponent extends Container {
|
|
|
925
986
|
tui: TUI,
|
|
926
987
|
theme: Theme,
|
|
927
988
|
keybindings: KeybindingsManager,
|
|
989
|
+
shortcuts: ResolvedAskShortcuts,
|
|
928
990
|
onDone: (result: AskUIResult | null) => void,
|
|
929
991
|
) {
|
|
930
992
|
super();
|
|
@@ -939,6 +1001,7 @@ class AskComponent extends Container {
|
|
|
939
1001
|
this.tui = tui;
|
|
940
1002
|
this.theme = theme;
|
|
941
1003
|
this.keybindings = keybindings;
|
|
1004
|
+
this.shortcuts = shortcuts;
|
|
942
1005
|
this.onDone = onDone;
|
|
943
1006
|
|
|
944
1007
|
// Layout skeleton
|
|
@@ -1058,8 +1121,11 @@ class AskComponent extends Container {
|
|
|
1058
1121
|
|
|
1059
1122
|
private updateHelpText(): void {
|
|
1060
1123
|
const theme = this.theme;
|
|
1061
|
-
const overlayHint = this.displayMode === "overlay"
|
|
1062
|
-
? literalHint(theme,
|
|
1124
|
+
const overlayHint = this.displayMode === "overlay" && !this.shortcuts.overlayToggle.disabled
|
|
1125
|
+
? literalHint(theme, this.shortcuts.overlayToggle.spec, "hide")
|
|
1126
|
+
: null;
|
|
1127
|
+
const commentHint = this.allowComment && !this.shortcuts.commentToggle.disabled
|
|
1128
|
+
? literalHint(theme, this.shortcuts.commentToggle.spec, "toggle context")
|
|
1063
1129
|
: null;
|
|
1064
1130
|
if (this.mode === "freeform" || this.mode === "comment") {
|
|
1065
1131
|
const alternateCancelKeys = this.keybindings
|
|
@@ -1082,7 +1148,7 @@ class AskComponent extends Container {
|
|
|
1082
1148
|
const hints = [
|
|
1083
1149
|
literalHint(theme, "↑↓", "navigate"),
|
|
1084
1150
|
literalHint(theme, "space", "toggle"),
|
|
1085
|
-
|
|
1151
|
+
commentHint,
|
|
1086
1152
|
overlayHint,
|
|
1087
1153
|
keybindingHint(theme, this.keybindings, "tui.select.confirm", "submit"),
|
|
1088
1154
|
keybindingHint(theme, this.keybindings, "tui.select.cancel", "cancel"),
|
|
@@ -1098,7 +1164,7 @@ class AskComponent extends Container {
|
|
|
1098
1164
|
literalHint(theme, "type", "filter"),
|
|
1099
1165
|
keybindingHint(theme, this.keybindings, "tui.editor.deleteCharBackward", "erase"),
|
|
1100
1166
|
literalHint(theme, "↑↓", "navigate"),
|
|
1101
|
-
|
|
1167
|
+
commentHint,
|
|
1102
1168
|
overlayHint,
|
|
1103
1169
|
keybindingHint(theme, this.keybindings, "tui.select.confirm", "select"),
|
|
1104
1170
|
literalHint(theme, "esc", "clear/cancel"),
|
|
@@ -1121,6 +1187,7 @@ class AskComponent extends Container {
|
|
|
1121
1187
|
this.allowComment,
|
|
1122
1188
|
this.theme,
|
|
1123
1189
|
this.keybindings,
|
|
1190
|
+
this.shortcuts.commentToggle,
|
|
1124
1191
|
);
|
|
1125
1192
|
list.onSubmit = (result) => this.handleSelectionSubmit([result], list.isCommentEnabled());
|
|
1126
1193
|
list.onCancel = () => this.onDone(null);
|
|
@@ -1139,6 +1206,7 @@ class AskComponent extends Container {
|
|
|
1139
1206
|
this.allowComment,
|
|
1140
1207
|
this.theme,
|
|
1141
1208
|
this.keybindings,
|
|
1209
|
+
this.shortcuts.commentToggle,
|
|
1142
1210
|
);
|
|
1143
1211
|
list.onCancel = () => this.onDone(null);
|
|
1144
1212
|
list.onSubmit = (result) => this.handleSelectionSubmit(result, list.isCommentEnabled());
|
|
@@ -1409,6 +1477,18 @@ export default function(pi: ExtensionAPI) {
|
|
|
1409
1477
|
description: "UI rendering mode. 'overlay' shows a centered modal, 'inline' renders in-place. Default: PI_ASK_USER_DISPLAY_MODE env var if set, otherwise 'overlay'. Omit to respect the user's configured preference.",
|
|
1410
1478
|
}),
|
|
1411
1479
|
),
|
|
1480
|
+
overlayToggleKey: Type.Optional(
|
|
1481
|
+
Type.String({
|
|
1482
|
+
description:
|
|
1483
|
+
"Shortcut for hiding/showing the overlay popup (overlay mode only), e.g. 'alt+o' or 'ctrl+shift+h'. Pass 'off' to disable. Default: PI_ASK_USER_OVERLAY_TOGGLE_KEY env var if set, otherwise 'alt+o'.",
|
|
1484
|
+
}),
|
|
1485
|
+
),
|
|
1486
|
+
commentToggleKey: Type.Optional(
|
|
1487
|
+
Type.String({
|
|
1488
|
+
description:
|
|
1489
|
+
"Shortcut for toggling the optional comment/extra-context row when allowComment is true, e.g. 'ctrl+g'. Pass 'off' to disable. Default: PI_ASK_USER_COMMENT_TOGGLE_KEY env var if set, otherwise 'ctrl+g'.",
|
|
1490
|
+
}),
|
|
1491
|
+
),
|
|
1412
1492
|
timeout: Type.Optional(
|
|
1413
1493
|
Type.Number({ description: "Auto-dismiss after N milliseconds. Returns null (cancelled) when expired." }),
|
|
1414
1494
|
),
|
|
@@ -1430,12 +1510,26 @@ export default function(pi: ExtensionAPI) {
|
|
|
1430
1510
|
allowFreeform = true,
|
|
1431
1511
|
allowComment = false,
|
|
1432
1512
|
displayMode,
|
|
1513
|
+
overlayToggleKey,
|
|
1514
|
+
commentToggleKey,
|
|
1433
1515
|
timeout,
|
|
1434
1516
|
} = params as AskParams;
|
|
1435
1517
|
const envMode = process.env.PI_ASK_USER_DISPLAY_MODE;
|
|
1436
1518
|
const envDisplayMode: AskDisplayMode | undefined =
|
|
1437
1519
|
envMode === "overlay" || envMode === "inline" ? envMode : undefined;
|
|
1438
1520
|
const effectiveDisplayMode: AskDisplayMode = displayMode ?? envDisplayMode ?? "overlay";
|
|
1521
|
+
const shortcuts: ResolvedAskShortcuts = {
|
|
1522
|
+
overlayToggle: resolveShortcut(
|
|
1523
|
+
overlayToggleKey,
|
|
1524
|
+
process.env.PI_ASK_USER_OVERLAY_TOGGLE_KEY,
|
|
1525
|
+
DEFAULT_OVERLAY_TOGGLE_KEY,
|
|
1526
|
+
),
|
|
1527
|
+
commentToggle: resolveShortcut(
|
|
1528
|
+
commentToggleKey,
|
|
1529
|
+
process.env.PI_ASK_USER_COMMENT_TOGGLE_KEY,
|
|
1530
|
+
DEFAULT_COMMENT_TOGGLE_KEY,
|
|
1531
|
+
),
|
|
1532
|
+
};
|
|
1439
1533
|
const options = normalizeOptions(rawOptions);
|
|
1440
1534
|
const normalizedContext = context?.trim() || undefined;
|
|
1441
1535
|
|
|
@@ -1506,21 +1600,28 @@ export default function(pi: ExtensionAPI) {
|
|
|
1506
1600
|
tui,
|
|
1507
1601
|
theme,
|
|
1508
1602
|
keybindings,
|
|
1603
|
+
shortcuts,
|
|
1509
1604
|
done,
|
|
1510
1605
|
);
|
|
1511
1606
|
};
|
|
1512
1607
|
|
|
1513
|
-
// Register a raw terminal input listener for
|
|
1514
|
-
// toggled even while it is hidden (hidden overlays do not
|
|
1515
|
-
// Inline mode does not need this because the prompt is
|
|
1516
|
-
|
|
1608
|
+
// Register a raw terminal input listener for the overlay-toggle key so the
|
|
1609
|
+
// overlay can be toggled even while it is hidden (hidden overlays do not
|
|
1610
|
+
// receive input). Inline mode does not need this because the prompt is
|
|
1611
|
+
// already non-modal. Skipped entirely if the user disabled the shortcut.
|
|
1612
|
+
const overlayToggle = shortcuts.overlayToggle;
|
|
1613
|
+
if (
|
|
1614
|
+
effectiveDisplayMode === "overlay"
|
|
1615
|
+
&& !overlayToggle.disabled
|
|
1616
|
+
&& typeof ctx.ui.onTerminalInput === "function"
|
|
1617
|
+
) {
|
|
1517
1618
|
removeOverlayInputListener = ctx.ui.onTerminalInput((data) => {
|
|
1518
|
-
if (!
|
|
1619
|
+
if (!overlayToggle.matches(data) || !overlayHandle) return undefined;
|
|
1519
1620
|
const nextHidden = !overlayHandle.isHidden();
|
|
1520
1621
|
overlayHandle.setHidden(nextHidden);
|
|
1521
1622
|
if (nextHidden && !hasAnnouncedHide) {
|
|
1522
1623
|
hasAnnouncedHide = true;
|
|
1523
|
-
ctx.ui.notify?.(`ask_user hidden — press ${
|
|
1624
|
+
ctx.ui.notify?.(`ask_user hidden — press ${overlayToggle.spec} to reopen`, "info");
|
|
1524
1625
|
}
|
|
1525
1626
|
return { consume: true };
|
|
1526
1627
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ask-user",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Interactive ask_user tool for pi-coding-agent with searchable split-pane selection UI, multi-select, and freeform input",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"check": "npm pack --dry-run"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
47
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
48
|
+
"@earendil-works/pi-tui": "*",
|
|
49
49
|
"@sinclair/typebox": "*"
|
|
50
50
|
}
|
|
51
51
|
}
|