@hank-warren/pi-ask-user-question 0.6.0 → 0.6.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 +13 -0
- package/README.md +4 -0
- package/ask-user-question.ts +14 -0
- package/package.json +2 -2
- package/questionnaire.ts +1 -1
- package/tool/envelope.ts +2 -2
- package/tool/schema.ts +6 -6
- package/tool/validate.ts +2 -2
- package/view/dialog.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @hank-warren/pi-ask-user-question
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1035138: Report a waiting question to Herdr as `blocked`.
|
|
8
|
+
|
|
9
|
+
`ask_user_question` and Plan Mode's `plan_mode_question` now emit the same
|
|
10
|
+
`herdr:blocked` event pi-auto-permissions emits for an approval prompt, labelled
|
|
11
|
+
`question` / `plan question` and cleared in a `finally`, so Herdr's pi
|
|
12
|
+
integration shows a session waiting on a question as `blocked` rather than
|
|
13
|
+
`working`. A supervising agent in another pane can wait on that state and answer
|
|
14
|
+
the dialog. No-op outside Herdr.
|
|
15
|
+
|
|
3
16
|
## 0.6.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -123,6 +123,10 @@ pi.events.on("hank:ask-user:prompt", ({ questions }) => {
|
|
|
123
123
|
Channel names are immutable and payloads are append-only — see
|
|
124
124
|
[`events.ts`](./events.ts) for the full stability policy.
|
|
125
125
|
|
|
126
|
+
## Changelog
|
|
127
|
+
|
|
128
|
+
See [CHANGELOG.md](CHANGELOG.md) for release history.
|
|
129
|
+
|
|
126
130
|
## License
|
|
127
131
|
|
|
128
132
|
MIT
|
package/ask-user-question.ts
CHANGED
|
@@ -65,9 +65,23 @@ function emitPrompt(pi: ExtensionAPI, params: AskUserParams): void {
|
|
|
65
65
|
pi.events.emit(ASK_USER_PROMPT_EVENT, payload);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Label Herdr shows for a pane waiting on this dialog. A supervising agent
|
|
70
|
+
* reads it to tell a question from an Auto Permissions prompt (whose label
|
|
71
|
+
* is the gate name, e.g. `shell command`).
|
|
72
|
+
*/
|
|
73
|
+
export const HERDR_BLOCKED_LABEL = "question";
|
|
74
|
+
|
|
68
75
|
function emitBlocked(pi: ExtensionAPI, active: boolean): void {
|
|
69
76
|
const payload: AskUserBlockedEventPayload = { active };
|
|
70
77
|
pi.events.emit(ASK_USER_BLOCKED_EVENT, payload);
|
|
78
|
+
// Herdr's pi integration turns `herdr:blocked` into `agent_status: "blocked"`,
|
|
79
|
+
// which is how an orchestrator in another pane learns this session is
|
|
80
|
+
// waiting on a human rather than working. Same contract pi-auto-permissions
|
|
81
|
+
// uses (`setHerdrBlocked`); duplicated rather than imported, because a
|
|
82
|
+
// questionnaire must not pull in the permissions engine. No-op outside Herdr.
|
|
83
|
+
if (process.env.HERDR_ENV !== "1") return;
|
|
84
|
+
pi.events.emit("herdr:blocked", active ? { active: true, label: HERDR_BLOCKED_LABEL } : { active: false });
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
export function registerTool(pi: ExtensionAPI): void {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hank-warren/pi-ask-user-question",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Structured questionnaire tool for Pi with numbered options, digit hotkeys and Tab-to-comment, composed from the shared permission-selector component.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"homepage": "https://github.com/hank-warren/pi-extensions/tree/main/packages/pi-ask-user-question#readme",
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": ">=22.19.0"
|
|
28
28
|
},
|
|
29
29
|
"pi": {
|
|
30
30
|
"extensions": [
|
package/questionnaire.ts
CHANGED
package/tool/envelope.ts
CHANGED
|
@@ -14,7 +14,7 @@ export const DECLINE_MESSAGE = "User declined to answer questions";
|
|
|
14
14
|
export const ENVELOPE_PREFIX = "User has answered your questions:";
|
|
15
15
|
export const ENVELOPE_SUFFIX = "You can now continue with the user's answers in mind.";
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
interface ToolResult {
|
|
18
18
|
content: Array<{ type: "text"; text: string }>;
|
|
19
19
|
details: QuestionnaireResult;
|
|
20
20
|
}
|
|
@@ -28,7 +28,7 @@ export function buildToolResult(text: string, details: QuestionnaireResult): Too
|
|
|
28
28
|
* preview and the user's note appended when present. Order and wording match
|
|
29
29
|
* rpiv's envelope and are pinned by tests.
|
|
30
30
|
*/
|
|
31
|
-
|
|
31
|
+
function buildAnswerSegment(a: QuestionAnswer): string {
|
|
32
32
|
const parts: string[] = [`"${a.question}"="${a.answer}"`];
|
|
33
33
|
if (a.preview && a.preview.length > 0) parts.push(`selected preview: ${a.preview}`);
|
|
34
34
|
if (a.notes && a.notes.length > 0) parts.push(`user notes: ${a.notes}`);
|
package/tool/schema.ts
CHANGED
|
@@ -12,13 +12,13 @@ import { Type } from "typebox";
|
|
|
12
12
|
export const TOOL_NAME = "ask_user_question";
|
|
13
13
|
|
|
14
14
|
export const MIN_OPTIONS = 2;
|
|
15
|
-
|
|
15
|
+
const MAX_OPTIONS = 4;
|
|
16
16
|
/**
|
|
17
17
|
* Multi-select questions get a larger cap. Checkboxes are a shortlist UI, not a
|
|
18
18
|
* pick-one UI, so six is where a list stops fitting comfortably above the input
|
|
19
19
|
* dock — not where it stops being a decision.
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
const MAX_MULTI_OPTIONS = 6;
|
|
22
22
|
export const MIN_QUESTIONS = 1;
|
|
23
23
|
export const MAX_QUESTIONS = 4;
|
|
24
24
|
|
|
@@ -42,7 +42,7 @@ export const CUSTOM_ANSWER_VALUE = "\u0000custom-answer";
|
|
|
42
42
|
/** Separator joining a multi-select answer's labels into `answer` (spec §5.4). */
|
|
43
43
|
export const MULTI_SELECT_JOIN = ", ";
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
const OptionSchema = Type.Object({
|
|
46
46
|
label: Type.String({
|
|
47
47
|
description:
|
|
48
48
|
"The display text for this option that the user will see and select. Aim for 1-5 words, but there is no hard limit: a longer label is fine when it genuinely helps, and long labels wrap in the dialog rather than being rejected.",
|
|
@@ -59,7 +59,7 @@ export const OptionSchema = Type.Object({
|
|
|
59
59
|
),
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
const QuestionSchema = Type.Object({
|
|
63
63
|
question: Type.String({
|
|
64
64
|
description:
|
|
65
65
|
"The complete question to ask the user. Should be clear, specific, and end with a question mark.",
|
|
@@ -91,13 +91,13 @@ export const QuestionParamsSchema = Type.Object({
|
|
|
91
91
|
}),
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
interface OptionParams {
|
|
95
95
|
label: string;
|
|
96
96
|
description: string;
|
|
97
97
|
preview?: string;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
interface QuestionParams {
|
|
101
101
|
question: string;
|
|
102
102
|
header: string;
|
|
103
103
|
/** Checkbox mode: the user may check several options. Default false. */
|
package/tool/validate.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
RESERVED_LABELS,
|
|
25
25
|
} from "./schema.ts";
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
type ValidationCode =
|
|
28
28
|
| "bad_question_count"
|
|
29
29
|
| "bad_option_count"
|
|
30
30
|
| "header_too_long"
|
|
@@ -33,7 +33,7 @@ export type ValidationCode =
|
|
|
33
33
|
| "duplicate_label"
|
|
34
34
|
| "empty_question";
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
interface ValidationError {
|
|
37
37
|
code: ValidationCode;
|
|
38
38
|
message: string;
|
|
39
39
|
}
|
package/view/dialog.ts
CHANGED
|
@@ -64,11 +64,11 @@ import type { QuestionnaireSession } from "../questionnaire.ts";
|
|
|
64
64
|
import type { QuestionnaireResult } from "../tool/schema.ts";
|
|
65
65
|
|
|
66
66
|
/** Structural subset of pi's Theme used here; keeps the view unit-testable. */
|
|
67
|
-
|
|
67
|
+
interface DialogTheme {
|
|
68
68
|
fg(role: string, text: string): string;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
interface DialogOptions {
|
|
72
72
|
session: QuestionnaireSession;
|
|
73
73
|
theme?: DialogTheme;
|
|
74
74
|
/** Called exactly once with the final outcome. */
|