@black942026/pi-ask-user 0.1.1 → 0.1.3
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 +160 -25
- package/package.json +1 -1
- package/src/adapters/pi.ts +5 -2
- package/src/answers.ts +119 -33
- package/src/config.ts +11 -9
- package/src/core.ts +23 -6
- package/src/index.ts +19 -3
- package/src/parse.ts +17 -0
- package/src/schema.ts +201 -90
- package/src/types.ts +113 -13
- package/src/ui/custom.ts +395 -16
- package/src/ui/native.ts +232 -60
package/src/types.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* answered through one of two routes:
|
|
6
6
|
*
|
|
7
7
|
* - `custom` — a custom terminal UI (only a real Pi TUI)
|
|
8
|
-
* - `native` — native
|
|
9
|
-
* at a time
|
|
8
|
+
* - `native` — native dialogs (`ctx.hasUI` + callable input), one logical
|
|
9
|
+
* question at a time (a form uses sequential per-field dialogs)
|
|
10
10
|
*
|
|
11
11
|
* The route is resolved **once, when the host adapter is created**, from
|
|
12
12
|
* trustworthy inputs only:
|
|
@@ -25,7 +25,10 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
/** The kind of question. */
|
|
28
|
-
export type QuestionKind = "single" | "multi" | "input";
|
|
28
|
+
export type QuestionKind = "single" | "multi" | "input" | "bool" | "simple-form";
|
|
29
|
+
|
|
30
|
+
/** The non-nesting field kinds accepted by a `simple-form` question. */
|
|
31
|
+
export type FormFieldKind = Exclude<QuestionKind, "simple-form">;
|
|
29
32
|
|
|
30
33
|
/** Custom-UI presentation: floating overlay or inline prompt area. */
|
|
31
34
|
export type AskUserDisplayMode = "overlay" | "inline";
|
|
@@ -40,31 +43,110 @@ export interface AskUserOption {
|
|
|
40
43
|
preview?: string;
|
|
41
44
|
}
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
interface AskUserFormFieldBase {
|
|
47
|
+
/** Literal output key: 1..64 ASCII letters/digits/`_`/`-`, starting with a letter or `_`. */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Label shown beside the field. */
|
|
50
|
+
label: string;
|
|
51
|
+
/** When true, an explicit non-empty value (or a valid default) is required. */
|
|
52
|
+
required?: boolean;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface AskUserBoolField extends AskUserFormFieldBase {
|
|
56
|
+
kind: "bool";
|
|
57
|
+
options?: never;
|
|
58
|
+
default?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface AskUserSingleField extends AskUserFormFieldBase {
|
|
62
|
+
kind: "single";
|
|
63
|
+
options: AskUserOption[];
|
|
64
|
+
default?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface AskUserMultiField extends AskUserFormFieldBase {
|
|
68
|
+
kind: "multi";
|
|
69
|
+
options: AskUserOption[];
|
|
70
|
+
default?: string[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface AskUserInputField extends AskUserFormFieldBase {
|
|
74
|
+
kind: "input";
|
|
75
|
+
options?: never;
|
|
76
|
+
default?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** One non-nesting, kind-typed field in a flat `simple-form` question. */
|
|
80
|
+
export type AskUserFormField = AskUserBoolField | AskUserSingleField | AskUserMultiField | AskUserInputField;
|
|
81
|
+
|
|
82
|
+
/** Flat typed value returned by a `simple-form`. */
|
|
83
|
+
export type AskUserFormValue = Record<string, boolean | string | string[]>;
|
|
84
|
+
|
|
85
|
+
interface AskUserQuestionBase {
|
|
45
86
|
/** Stable id. Generated (`q1`, `q2`, ...) when omitted. */
|
|
46
87
|
id?: string;
|
|
47
88
|
/** Question heading (required). */
|
|
48
89
|
title: string;
|
|
49
90
|
/** Optional extra hint or context rendered under the heading. */
|
|
50
91
|
prompt?: string;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface AskUserSingleQuestion extends AskUserQuestionBase {
|
|
95
|
+
kind: "single";
|
|
96
|
+
options: AskUserOption[];
|
|
97
|
+
default?: string;
|
|
98
|
+
fields?: never;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface AskUserMultiQuestion extends AskUserQuestionBase {
|
|
102
|
+
kind: "multi";
|
|
103
|
+
options: AskUserOption[];
|
|
104
|
+
default?: string;
|
|
105
|
+
fields?: never;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface AskUserInputQuestion extends AskUserQuestionBase {
|
|
109
|
+
kind: "input";
|
|
110
|
+
/** Kept for legacy callers: validated by normalization, then dropped. */
|
|
54
111
|
options?: AskUserOption[];
|
|
55
|
-
/**
|
|
56
|
-
* Default answer. When present the question may be skipped and the default
|
|
57
|
-
* is used; when absent the question must be answered.
|
|
58
|
-
*/
|
|
59
112
|
default?: string;
|
|
113
|
+
fields?: never;
|
|
60
114
|
}
|
|
61
115
|
|
|
116
|
+
export interface AskUserBoolQuestion extends AskUserQuestionBase {
|
|
117
|
+
kind: "bool";
|
|
118
|
+
options?: never;
|
|
119
|
+
default?: boolean;
|
|
120
|
+
fields?: never;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface AskUserSimpleFormQuestion extends AskUserQuestionBase {
|
|
124
|
+
kind: "simple-form";
|
|
125
|
+
options?: never;
|
|
126
|
+
default?: never;
|
|
127
|
+
fields: AskUserFormField[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** One kind-typed question in a questionnaire. */
|
|
131
|
+
export type AskUserQuestion =
|
|
132
|
+
| AskUserSingleQuestion
|
|
133
|
+
| AskUserMultiQuestion
|
|
134
|
+
| AskUserInputQuestion
|
|
135
|
+
| AskUserBoolQuestion
|
|
136
|
+
| AskUserSimpleFormQuestion;
|
|
137
|
+
|
|
62
138
|
/** A model-facing (or caller-facing) request. */
|
|
63
139
|
export interface AskUserRequest {
|
|
64
140
|
/** 1..5 questions. */
|
|
65
141
|
questions: AskUserQuestion[];
|
|
66
142
|
/** Optional heading shown above the questionnaire. */
|
|
67
143
|
header?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Allow supplemental/free-text answers on single/multi questions. Defaults to true.
|
|
146
|
+
* False also uses native selectors for single/bool (including form fields);
|
|
147
|
+
* native multi/text continue using input boxes.
|
|
148
|
+
*/
|
|
149
|
+
allowFreeText?: boolean;
|
|
68
150
|
/** Custom-UI presentation. Defaults to `overlay`. */
|
|
69
151
|
displayMode?: AskUserDisplayMode;
|
|
70
152
|
/**
|
|
@@ -88,6 +170,8 @@ export interface AskUserAnswer {
|
|
|
88
170
|
freeText?: string;
|
|
89
171
|
/** True when the answer came from the question default rather than user input. */
|
|
90
172
|
usedDefault: boolean;
|
|
173
|
+
/** Typed value for `bool` and `simple-form`. `false` is a complete answer. */
|
|
174
|
+
value?: boolean | AskUserFormValue;
|
|
91
175
|
}
|
|
92
176
|
|
|
93
177
|
/**
|
|
@@ -325,12 +409,28 @@ export interface NormalizedQuestion {
|
|
|
325
409
|
prompt?: string;
|
|
326
410
|
kind: QuestionKind;
|
|
327
411
|
options: AskUserOption[];
|
|
328
|
-
|
|
412
|
+
/** False disables free text for single/multi; absent preserves legacy behavior. */
|
|
413
|
+
allowFreeText?: boolean;
|
|
414
|
+
default?: string | boolean;
|
|
415
|
+
hasDefault: boolean;
|
|
416
|
+
/** Present for `simple-form`; omitted by older already-normalized callers. */
|
|
417
|
+
fields?: NormalizedFormField[];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export interface NormalizedFormField {
|
|
421
|
+
name: string;
|
|
422
|
+
label: string;
|
|
423
|
+
kind: FormFieldKind;
|
|
424
|
+
required: boolean;
|
|
425
|
+
options: AskUserOption[];
|
|
426
|
+
default?: boolean | string | string[];
|
|
329
427
|
hasDefault: boolean;
|
|
330
428
|
}
|
|
331
429
|
|
|
332
430
|
export interface NormalizedRequest {
|
|
333
431
|
header?: string;
|
|
432
|
+
/** Absent in older normalized callers means true. */
|
|
433
|
+
allowFreeText?: boolean;
|
|
334
434
|
questions: NormalizedQuestion[];
|
|
335
435
|
displayMode: AskUserDisplayMode;
|
|
336
436
|
timeoutPerQuestionMs: number;
|