caique 0.2.0 → 0.3.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/README.md +3 -5
- package/dist/ask.js +0 -46
- package/dist/binding.js +2 -32
- package/dist/clack.d.ts +44 -0
- package/dist/clack.js +97 -0
- package/dist/decide.js +0 -33
- package/dist/index.js +0 -12
- package/dist/inquirer-errors.d.ts +38 -0
- package/dist/inquirer-errors.js +21 -0
- package/dist/inquirer-hooks.d.ts +86 -0
- package/dist/inquirer-hooks.js +124 -0
- package/dist/inquirer-keys.d.ts +31 -0
- package/dist/inquirer-keys.js +22 -0
- package/dist/inquirer-screen.d.ts +131 -0
- package/dist/inquirer-screen.js +122 -0
- package/dist/inquirer-theme.d.ts +58 -0
- package/dist/inquirer-theme.js +51 -0
- package/dist/inquirer.d.ts +72 -0
- package/dist/inquirer.js +207 -0
- package/dist/plugin.js +0 -64
- package/dist/raw.js +0 -60
- package/dist/runtime.js +0 -12
- package/dist/schema.json +1 -300
- package/dist/spec.js +0 -26
- package/dist/terminal.js +0 -36
- package/package.json +15 -4
package/dist/schema.json
CHANGED
|
@@ -1,300 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://github.com/ofri-peretz/burgee/blob/main/packages/flagstaff/src/schema.json",
|
|
4
|
-
"title": "flagstaff plugin",
|
|
5
|
-
"description": "A plugin is one plain object. Everything in it is data that can be read without running it; the only functions allowed are a component's `static` (required) and `frame` (optional). A spinner or component without a static projection is refused at register().",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"required": [
|
|
8
|
-
"name"
|
|
9
|
-
],
|
|
10
|
-
"additionalProperties": true,
|
|
11
|
-
"properties": {
|
|
12
|
-
"name": {
|
|
13
|
-
"type": "string",
|
|
14
|
-
"minLength": 1,
|
|
15
|
-
"description": "The plugin's name; also the prefix a host may use when two plugins contribute the same key."
|
|
16
|
-
},
|
|
17
|
-
"contract": {
|
|
18
|
-
"type": "integer",
|
|
19
|
-
"minimum": 1,
|
|
20
|
-
"description": "The plugin contract this object follows. A host refuses a newer contract than it knows."
|
|
21
|
-
},
|
|
22
|
-
"tokens": {
|
|
23
|
-
"type": "object",
|
|
24
|
-
"description": "A roundel theme: semantic token name to a hex colour, contrast-checked when flown.",
|
|
25
|
-
"additionalProperties": {
|
|
26
|
-
"type": "string",
|
|
27
|
-
"pattern": "^#[0-9a-fA-F]{6}$"
|
|
28
|
-
},
|
|
29
|
-
"propertyNames": {
|
|
30
|
-
"enum": [
|
|
31
|
-
"error",
|
|
32
|
-
"warn",
|
|
33
|
-
"ok",
|
|
34
|
-
"hint",
|
|
35
|
-
"muted",
|
|
36
|
-
"command",
|
|
37
|
-
"flag",
|
|
38
|
-
"value",
|
|
39
|
-
"heading",
|
|
40
|
-
"ground"
|
|
41
|
-
],
|
|
42
|
-
"description": "roundel's ten semantic tokens, and nothing else — `roundel`'s own validate() refuses any other name."
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
"glyphs": {
|
|
46
|
-
"type": "object",
|
|
47
|
-
"description": "Symbols by meaning: `ok`, `fail`, `warn`, `info`, `running`. A plugin that ships glyphs changes every built-in that draws one.",
|
|
48
|
-
"additionalProperties": {
|
|
49
|
-
"type": "string",
|
|
50
|
-
"minLength": 1
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
"spinners": {
|
|
54
|
-
"type": "object",
|
|
55
|
-
"description": "Spinner styles by name, in cli-spinners' shape plus the static projection.",
|
|
56
|
-
"additionalProperties": {
|
|
57
|
-
"$ref": "#/$defs/spinner"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"borders": {
|
|
61
|
-
"type": "object",
|
|
62
|
-
"description": "Border styles a box can be drawn with, by name.",
|
|
63
|
-
"additionalProperties": {
|
|
64
|
-
"$ref": "#/$defs/border"
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
"components": {
|
|
68
|
-
"type": "object",
|
|
69
|
-
"description": "Components by name: `static(state)` returns the text a pipe, an agent or a screen reader gets; `frame(t, state)` is the optional animated form.",
|
|
70
|
-
"additionalProperties": {
|
|
71
|
-
"$ref": "#/$defs/component"
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
"capabilities": {
|
|
75
|
-
"$ref": "#/$defs/capabilities"
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
"$defs": {
|
|
79
|
-
"spinner": {
|
|
80
|
-
"type": "object",
|
|
81
|
-
"required": [
|
|
82
|
-
"frames",
|
|
83
|
-
"interval",
|
|
84
|
-
"static"
|
|
85
|
-
],
|
|
86
|
-
"properties": {
|
|
87
|
-
"frames": {
|
|
88
|
-
"type": "array",
|
|
89
|
-
"items": {
|
|
90
|
-
"type": "string"
|
|
91
|
-
},
|
|
92
|
-
"minItems": 1
|
|
93
|
-
},
|
|
94
|
-
"interval": {
|
|
95
|
-
"type": "integer",
|
|
96
|
-
"minimum": 1,
|
|
97
|
-
"description": "Milliseconds between frames on a terminal."
|
|
98
|
-
},
|
|
99
|
-
"static": {
|
|
100
|
-
"type": "string",
|
|
101
|
-
"description": "What a pipe prints instead of the animation."
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
"component": {
|
|
106
|
-
"type": "object",
|
|
107
|
-
"required": [
|
|
108
|
-
"static"
|
|
109
|
-
],
|
|
110
|
-
"properties": {
|
|
111
|
-
"static": {
|
|
112
|
-
"description": "(state) => string. Required: the projection every non-terminal mode prints."
|
|
113
|
-
},
|
|
114
|
-
"frame": {
|
|
115
|
-
"description": "(t, state) => string. Optional: the frame at t milliseconds since hoisting."
|
|
116
|
-
},
|
|
117
|
-
"sample": {
|
|
118
|
-
"type": "object",
|
|
119
|
-
"required": [
|
|
120
|
-
"running",
|
|
121
|
-
"done"
|
|
122
|
-
],
|
|
123
|
-
"description": "Two states to *show* this component with: `flagstaff check` and the docs gallery render `running` then `done`. Omitted, they assume `{ phase: 'running' }` and `{ phase: 'done' }` and say so in the output. The loop never reads it — a running program's state comes from the program.",
|
|
124
|
-
"properties": {
|
|
125
|
-
"running": {
|
|
126
|
-
"description": "The state to open with."
|
|
127
|
-
},
|
|
128
|
-
"done": {
|
|
129
|
-
"description": "The state to close with."
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
},
|
|
133
|
-
"interval": {
|
|
134
|
-
"type": "integer",
|
|
135
|
-
"minimum": 1,
|
|
136
|
-
"description": "Milliseconds between repaints when `frame` is given; 80 when omitted."
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
"border": {
|
|
141
|
-
"type": "object",
|
|
142
|
-
"required": [
|
|
143
|
-
"topLeft",
|
|
144
|
-
"top",
|
|
145
|
-
"topRight",
|
|
146
|
-
"left",
|
|
147
|
-
"right",
|
|
148
|
-
"bottomLeft",
|
|
149
|
-
"bottom",
|
|
150
|
-
"bottomRight"
|
|
151
|
-
],
|
|
152
|
-
"description": "cli-boxes' shape exactly, so that corpus imports unchanged.",
|
|
153
|
-
"properties": {
|
|
154
|
-
"topLeft": {
|
|
155
|
-
"type": "string"
|
|
156
|
-
},
|
|
157
|
-
"top": {
|
|
158
|
-
"type": "string"
|
|
159
|
-
},
|
|
160
|
-
"topRight": {
|
|
161
|
-
"type": "string"
|
|
162
|
-
},
|
|
163
|
-
"left": {
|
|
164
|
-
"type": "string"
|
|
165
|
-
},
|
|
166
|
-
"right": {
|
|
167
|
-
"type": "string"
|
|
168
|
-
},
|
|
169
|
-
"bottomLeft": {
|
|
170
|
-
"type": "string"
|
|
171
|
-
},
|
|
172
|
-
"bottom": {
|
|
173
|
-
"type": "string"
|
|
174
|
-
},
|
|
175
|
-
"bottomRight": {
|
|
176
|
-
"type": "string"
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
"capability": {
|
|
181
|
-
"type": "object",
|
|
182
|
-
"required": [
|
|
183
|
-
"name",
|
|
184
|
-
"osc",
|
|
185
|
-
"when",
|
|
186
|
-
"encode",
|
|
187
|
-
"fallback"
|
|
188
|
-
],
|
|
189
|
-
"additionalProperties": false,
|
|
190
|
-
"description": "One paratext capability: what it says to the terminal, when the terminal is believed to understand it, and what prints when it does not. No functions, so it travels through JSON. `encode` and `fallback` are templates: `{field}` is the field's value, `{field|base64}` is it base64-encoded, and `[ … ]` is emitted only when every field inside it has a value.",
|
|
191
|
-
"properties": {
|
|
192
|
-
"name": {
|
|
193
|
-
"type": "string",
|
|
194
|
-
"minLength": 1,
|
|
195
|
-
"description": "How callers name it. Registering an existing name replaces it — how a caller corrects a guess we got wrong."
|
|
196
|
-
},
|
|
197
|
-
"osc": {
|
|
198
|
-
"description": "The OSC code this speaks, or 'BEL' for the bell and for protocols that are not OSC at all, such as Kitty's.",
|
|
199
|
-
"oneOf": [
|
|
200
|
-
{
|
|
201
|
-
"type": "integer",
|
|
202
|
-
"minimum": 0
|
|
203
|
-
},
|
|
204
|
-
{
|
|
205
|
-
"const": "BEL"
|
|
206
|
-
}
|
|
207
|
-
]
|
|
208
|
-
},
|
|
209
|
-
"when": {
|
|
210
|
-
"type": "object",
|
|
211
|
-
"description": "When the terminal is believed to understand it. Every clause must hold; `termProgram` and `envAny` are ORs within themselves. Guesses — no terminal answers 'do you do OSC 1337' — and therefore data a caller can replace.",
|
|
212
|
-
"additionalProperties": false,
|
|
213
|
-
"properties": {
|
|
214
|
-
"tty": {
|
|
215
|
-
"type": "boolean",
|
|
216
|
-
"description": "Refuse a pipe. Almost always true: a file that receives OSC gets control bytes in it."
|
|
217
|
-
},
|
|
218
|
-
"termProgram": {
|
|
219
|
-
"type": "array",
|
|
220
|
-
"items": {
|
|
221
|
-
"type": "string"
|
|
222
|
-
},
|
|
223
|
-
"description": "Any one of these TERM_PROGRAM values."
|
|
224
|
-
},
|
|
225
|
-
"envAny": {
|
|
226
|
-
"type": "array",
|
|
227
|
-
"items": {
|
|
228
|
-
"type": "string"
|
|
229
|
-
},
|
|
230
|
-
"description": "Any one of these environment variables merely being set, as VTE announces itself."
|
|
231
|
-
},
|
|
232
|
-
"term": {
|
|
233
|
-
"type": "string",
|
|
234
|
-
"description": "An exact TERM — Kitty is xterm-kitty."
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
"encode": {
|
|
239
|
-
"type": "string",
|
|
240
|
-
"minLength": 1,
|
|
241
|
-
"description": "The bytes, as a template, for a terminal that does understand."
|
|
242
|
-
},
|
|
243
|
-
"fallback": {
|
|
244
|
-
"type": "string",
|
|
245
|
-
"description": "What to print when it does not — PRINCIPLES rule 6. '' is a legitimate answer, a window title having nothing to say in a log; absence is not, which is why this is required and may be ''."
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
"examples": [
|
|
249
|
-
{
|
|
250
|
-
"name": "kitty-image",
|
|
251
|
-
"osc": "BEL",
|
|
252
|
-
"when": {
|
|
253
|
-
"tty": true,
|
|
254
|
-
"term": "xterm-kitty"
|
|
255
|
-
},
|
|
256
|
-
"encode": "\u001b_Ga=T,f=100;{base64}\u001b\\",
|
|
257
|
-
"fallback": "{caption}"
|
|
258
|
-
}
|
|
259
|
-
]
|
|
260
|
-
},
|
|
261
|
-
"capabilities": {
|
|
262
|
-
"type": "object",
|
|
263
|
-
"description": "paratext capabilities by name — the OSC section of a plugin, read the way flagstaff reads `spinners`.",
|
|
264
|
-
"additionalProperties": {
|
|
265
|
-
"$ref": "#/$defs/capability"
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
"capabilityDocument": {
|
|
269
|
-
"description": "What paratext's `check()` accepts. Two shapes, and only one of them survives 1.0.",
|
|
270
|
-
"oneOf": [
|
|
271
|
-
{
|
|
272
|
-
"description": "The family shape: a plugin carrying its capabilities under `capabilities`.",
|
|
273
|
-
"type": "object",
|
|
274
|
-
"required": [
|
|
275
|
-
"name",
|
|
276
|
-
"capabilities"
|
|
277
|
-
],
|
|
278
|
-
"properties": {
|
|
279
|
-
"name": {
|
|
280
|
-
"type": "string",
|
|
281
|
-
"minLength": 1
|
|
282
|
-
},
|
|
283
|
-
"contract": {
|
|
284
|
-
"type": "integer",
|
|
285
|
-
"minimum": 1
|
|
286
|
-
},
|
|
287
|
-
"capabilities": {
|
|
288
|
-
"$ref": "#/$defs/capabilities"
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
"deprecated": true,
|
|
294
|
-
"description": "Deprecated: one capability as the whole document, the shape paratext's schema had before this one absorbed it. Accepted for one minor release, removed at 1.0 — `check()` validates it and says so.",
|
|
295
|
-
"$ref": "#/$defs/capability"
|
|
296
|
-
}
|
|
297
|
-
]
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
1
|
+
{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://github.com/ofri-peretz/burgee/blob/main/packages/flagstaff/src/schema.json","title":"flagstaff plugin","description":"A plugin is one plain object. Everything in it is data that can be read without running it; the only functions allowed are a component's `static` (required) and `frame` (optional). A spinner or component without a static projection is refused at register().","type":"object","required":["name"],"additionalProperties":true,"properties":{"name":{"type":"string","minLength":1,"description":"The plugin's name; also the prefix a host may use when two plugins contribute the same key."},"contract":{"type":"integer","minimum":1,"description":"The plugin contract this object follows. A host refuses a newer contract than it knows."},"tokens":{"type":"object","description":"A roundel theme: semantic token name to a hex colour, contrast-checked when flown.","additionalProperties":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},"propertyNames":{"enum":["error","warn","ok","hint","muted","command","flag","value","heading","ground"],"description":"roundel's ten semantic tokens, and nothing else — `roundel`'s own validate() refuses any other name."}},"glyphs":{"type":"object","description":"Symbols by meaning: `ok`, `fail`, `warn`, `info`, `running`. A plugin that ships glyphs changes every built-in that draws one.","additionalProperties":{"type":"string","minLength":1}},"spinners":{"type":"object","description":"Spinner styles by name, in cli-spinners' shape plus the static projection.","additionalProperties":{"$ref":"#/$defs/spinner"}},"borders":{"type":"object","description":"Border styles a box can be drawn with, by name.","additionalProperties":{"$ref":"#/$defs/border"}},"components":{"type":"object","description":"Components by name: `static(state)` returns the text a pipe, an agent or a screen reader gets; `frame(t, state)` is the optional animated form.","additionalProperties":{"$ref":"#/$defs/component"}},"capabilities":{"$ref":"#/$defs/capabilities"}},"$defs":{"spinner":{"type":"object","required":["frames","interval","static"],"properties":{"frames":{"type":"array","items":{"type":"string"},"minItems":1},"interval":{"type":"integer","minimum":1,"description":"Milliseconds between frames on a terminal."},"static":{"type":"string","description":"What a pipe prints instead of the animation."}}},"component":{"type":"object","required":["static"],"properties":{"static":{"description":"(state) => string. Required: the projection every non-terminal mode prints."},"frame":{"description":"(t, state) => string. Optional: the frame at t milliseconds since hoisting."},"sample":{"type":"object","required":["running","done"],"description":"Two states to *show* this component with: `flagstaff check` and the docs gallery render `running` then `done`. Omitted, they assume `{ phase: 'running' }` and `{ phase: 'done' }` and say so in the output. The loop never reads it — a running program's state comes from the program.","properties":{"running":{"description":"The state to open with."},"done":{"description":"The state to close with."}}},"interval":{"type":"integer","minimum":1,"description":"Milliseconds between repaints when `frame` is given; 80 when omitted."}}},"border":{"type":"object","required":["topLeft","top","topRight","left","right","bottomLeft","bottom","bottomRight"],"description":"cli-boxes' shape exactly, so that corpus imports unchanged.","properties":{"topLeft":{"type":"string"},"top":{"type":"string"},"topRight":{"type":"string"},"left":{"type":"string"},"right":{"type":"string"},"bottomLeft":{"type":"string"},"bottom":{"type":"string"},"bottomRight":{"type":"string"}}},"capability":{"type":"object","required":["name","osc","when","encode","fallback"],"additionalProperties":false,"description":"One paratext capability: what it says to the terminal, when the terminal is believed to understand it, and what prints when it does not. No functions, so it travels through JSON. `encode` and `fallback` are templates: `{field}` is the field's value, `{field|base64}` is it base64-encoded, and `[ … ]` is emitted only when every field inside it has a value.","properties":{"name":{"type":"string","minLength":1,"description":"How callers name it. Registering an existing name replaces it — how a caller corrects a guess we got wrong."},"osc":{"description":"The OSC code this speaks, or 'BEL' for the bell and for protocols that are not OSC at all, such as Kitty's.","oneOf":[{"type":"integer","minimum":0},{"const":"BEL"}]},"when":{"type":"object","description":"When the terminal is believed to understand it. Every clause must hold; `termProgram` and `envAny` are ORs within themselves. Guesses — no terminal answers 'do you do OSC 1337' — and therefore data a caller can replace.","additionalProperties":false,"properties":{"tty":{"type":"boolean","description":"Refuse a pipe. Almost always true: a file that receives OSC gets control bytes in it."},"termProgram":{"type":"array","items":{"type":"string"},"description":"Any one of these TERM_PROGRAM values."},"envAny":{"type":"array","items":{"type":"string"},"description":"Any one of these environment variables merely being set, as VTE announces itself."},"term":{"type":"string","description":"An exact TERM — Kitty is xterm-kitty."}}},"encode":{"type":"string","minLength":1,"description":"The bytes, as a template, for a terminal that does understand."},"fallback":{"type":"string","description":"What to print when it does not — PRINCIPLES rule 6. '' is a legitimate answer, a window title having nothing to say in a log; absence is not, which is why this is required and may be ''."}},"examples":[{"name":"kitty-image","osc":"BEL","when":{"tty":true,"term":"xterm-kitty"},"encode":"\u001b_Ga=T,f=100;{base64}\u001b\\","fallback":"{caption}"}]},"capabilities":{"type":"object","description":"paratext capabilities by name — the OSC section of a plugin, read the way flagstaff reads `spinners`.","additionalProperties":{"$ref":"#/$defs/capability"}},"capabilityDocument":{"description":"What paratext's `check()` accepts. Two shapes, and only one of them survives 1.0.","oneOf":[{"description":"The family shape: a plugin carrying its capabilities under `capabilities`.","type":"object","required":["name","capabilities"],"properties":{"name":{"type":"string","minLength":1},"contract":{"type":"integer","minimum":1},"capabilities":{"$ref":"#/$defs/capabilities"}}},{"deprecated":true,"description":"Deprecated: one capability as the whole document, the shape paratext's schema had before this one absorbed it. Accepted for one minor release, removed at 1.0 — `check()` validates it and says so.","$ref":"#/$defs/capability"}]}}}
|
package/dist/spec.js
CHANGED
|
@@ -1,32 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* What a prompt *is*, before anything draws one (R1).
|
|
3
|
-
*
|
|
4
|
-
* A `PromptSpec` hangs off an option, not off a call site, and that is the whole
|
|
5
|
-
* inversion: the option is the thing that exists in the manifest, in `--help`, in the MCP
|
|
6
|
-
* tool schema and on the command line, and the prompt is one more projection of it. A
|
|
7
|
-
* program written this way can be answered by a flag, by an environment variable, by a
|
|
8
|
-
* config file or by a person, and nothing in it has to know which happened.
|
|
9
|
-
*
|
|
10
|
-
* Nothing here imports a runtime, a stream or a terminal. This file is data.
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* The six caique draws itself, as data rather than as a `switch` nobody can read back.
|
|
14
|
-
*
|
|
15
|
-
* `caique/plugin` needs this set to answer two questions a plugin makes askable for the
|
|
16
|
-
* first time: whether a kind is already spoken for, and which kinds a refusal should name.
|
|
17
|
-
* Deriving it from the widget dispatch in `ask.ts` would mean two lists that agree only by
|
|
18
|
-
* inspection, which is the drift the family's locks exist to prevent.
|
|
19
|
-
*/
|
|
20
1
|
export const BUILT_IN_KINDS = new Set(['text', 'confirm', 'select', 'multiselect', 'password', 'path']);
|
|
21
|
-
/** `--output-dir`, which is what a refusal has to say to be actionable. */
|
|
22
2
|
export function flagOf(option) {
|
|
23
3
|
return `--${option}`;
|
|
24
4
|
}
|
|
25
|
-
/**
|
|
26
|
-
* A `select` without choices, or a `confirm` with them, is a spec that cannot be drawn.
|
|
27
|
-
* Caught here rather than in the widget, so a program with a malformed prompt fails on the
|
|
28
|
-
* first run instead of the first time someone reaches that option.
|
|
29
|
-
*/
|
|
30
5
|
export function problemWith(spec) {
|
|
31
6
|
const needsChoices = spec.kind === 'select' || spec.kind === 'multiselect';
|
|
32
7
|
if (needsChoices && (spec.choices === undefined || spec.choices.length === 0))
|
|
@@ -37,4 +12,3 @@ export function problemWith(spec) {
|
|
|
37
12
|
return 'a prompt needs a message: it is what a person is asked, and what an agent is told when it cannot be';
|
|
38
13
|
return undefined;
|
|
39
14
|
}
|
|
40
|
-
//# sourceMappingURL=spec.js.map
|
package/dist/terminal.js
CHANGED
|
@@ -1,48 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A `Reader` and `Writer` over real streams — the one file in this package that touches a
|
|
3
|
-
* terminal, and the reason `ask()` can be used by a program rather than only by a test.
|
|
4
|
-
*
|
|
5
|
-
* Everything above this is strings in and strings out. That is deliberate: the widgets, the
|
|
6
|
-
* decision and the binding are all testable without a PTY, and this is the thin layer that
|
|
7
|
-
* has to be got right once. It reads lines through `node:readline`, which handles the
|
|
8
|
-
* line editing, the backspace and the `Ctrl-D` a person expects.
|
|
9
|
-
*
|
|
10
|
-
* **Hiding a password happens here**, because this is the only layer that knows what echo
|
|
11
|
-
* is. `ask()` says which prompts are hidden; nothing above has to remember to mute anything,
|
|
12
|
-
* and a widget cannot leak a secret by writing it, since no widget writes what it read.
|
|
13
|
-
*/
|
|
14
1
|
import { createInterface } from 'node:readline';
|
|
15
|
-
import {} from './ask.js';
|
|
16
2
|
import { processRuntime } from './runtime.js';
|
|
17
|
-
/** A runtime's two streams as the pair `createIo` takes — the mapping, written down once. */
|
|
18
3
|
export const streamsOf = (runtime) => ({ input: runtime.stdin, output: runtime.stdout });
|
|
19
|
-
/** Accepts a chunk and writes nothing: what a muted stream's `write` does. */
|
|
20
4
|
const swallow = () => true;
|
|
21
|
-
/**
|
|
22
|
-
* `readline` echoes what it reads. For a hidden answer the echo is suppressed by
|
|
23
|
-
* intercepting the interface's own output for the duration of the question — not by
|
|
24
|
-
* turning the terminal's echo off, which would leave it off if the process died mid-prompt.
|
|
25
|
-
*/
|
|
26
5
|
function mute(rl, streams) {
|
|
27
6
|
const target = rl.output ?? streams.output;
|
|
28
7
|
const original = target.write.bind(target);
|
|
29
|
-
// `readline` writes the prompt through the same stream it echoes through, so the prompt
|
|
30
|
-
// has already been written by the time this is installed: everything after it is input.
|
|
31
8
|
target.write = swallow;
|
|
32
9
|
return () => {
|
|
33
10
|
target.write = original;
|
|
34
11
|
};
|
|
35
12
|
}
|
|
36
|
-
/**
|
|
37
|
-
* A reader and writer over a real stream pair.
|
|
38
|
-
*
|
|
39
|
-
* The reader resolves `undefined` when the stream ends, which `ask()` reads as a
|
|
40
|
-
* cancellation — `Ctrl-D` and a closed pipe both arrive that way, and both mean nobody is
|
|
41
|
-
* going to type.
|
|
42
|
-
*
|
|
43
|
-
* With no argument it builds over the real process, read when it is called and not at
|
|
44
|
-
* import: a program that wants the terminal it was started in writes `createIo()`.
|
|
45
|
-
*/
|
|
46
13
|
export function createIo(streams = streamsOf(processRuntime())) {
|
|
47
14
|
const rl = createInterface({ input: streams.input, output: streams.output, terminal: streams.output.isTTY === true });
|
|
48
15
|
let ended = false;
|
|
@@ -70,8 +37,6 @@ export function createIo(streams = streamsOf(processRuntime())) {
|
|
|
70
37
|
}
|
|
71
38
|
finally {
|
|
72
39
|
unmute?.();
|
|
73
|
-
// The newline the person typed was swallowed with the echo; put it back so the
|
|
74
|
-
// next question does not start on the same line as the hidden answer.
|
|
75
40
|
if (hidden)
|
|
76
41
|
streams.output.write('\n');
|
|
77
42
|
}
|
|
@@ -84,4 +49,3 @@ export function createIo(streams = streamsOf(processRuntime())) {
|
|
|
84
49
|
};
|
|
85
50
|
return { reader, writer, close: () => rl.close() };
|
|
86
51
|
}
|
|
87
|
-
//# sourceMappingURL=terminal.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "caique",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "The parrot that always answers back, and the boat that goes between ship and shore. Prompts that are flags first, so agents answer before they are asked and non-TTY callers get an error naming the flag, never a hang. Drop-in path for inquirer and clack.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,11 +23,21 @@
|
|
|
23
23
|
"import": "./dist/binding.js",
|
|
24
24
|
"default": "./dist/binding.js"
|
|
25
25
|
},
|
|
26
|
+
"./clack": {
|
|
27
|
+
"types": "./dist/clack.d.ts",
|
|
28
|
+
"import": "./dist/clack.js",
|
|
29
|
+
"default": "./dist/clack.js"
|
|
30
|
+
},
|
|
26
31
|
"./decide": {
|
|
27
32
|
"types": "./dist/decide.d.ts",
|
|
28
33
|
"import": "./dist/decide.js",
|
|
29
34
|
"default": "./dist/decide.js"
|
|
30
35
|
},
|
|
36
|
+
"./inquirer": {
|
|
37
|
+
"types": "./dist/inquirer.d.ts",
|
|
38
|
+
"import": "./dist/inquirer.js",
|
|
39
|
+
"default": "./dist/inquirer.js"
|
|
40
|
+
},
|
|
31
41
|
"./plugin": {
|
|
32
42
|
"types": "./dist/plugin.d.ts",
|
|
33
43
|
"import": "./dist/plugin.js",
|
|
@@ -56,7 +66,7 @@
|
|
|
56
66
|
"!dist/**/*.test.*"
|
|
57
67
|
],
|
|
58
68
|
"scripts": {
|
|
59
|
-
"build": "tsc -p tsconfig.build.json && node ../../scripts/schema-to-dist.mjs",
|
|
69
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/schema-to-dist.mjs && node ../../scripts/strip-comments.mjs dist",
|
|
60
70
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
61
71
|
"test": "vitest run --passWithNoTests",
|
|
62
72
|
"coverage": "vitest run --coverage.enabled",
|
|
@@ -83,9 +93,10 @@
|
|
|
83
93
|
"non-tty"
|
|
84
94
|
],
|
|
85
95
|
"dependencies": {
|
|
86
|
-
"closeout": "^0.2.
|
|
96
|
+
"closeout": "^0.2.1",
|
|
97
|
+
"linegauge": "^0.3.1"
|
|
87
98
|
},
|
|
88
99
|
"devDependencies": {
|
|
89
|
-
"vitest": "^5.0.
|
|
100
|
+
"vitest": "^5.0.1"
|
|
90
101
|
}
|
|
91
102
|
}
|