@onesi/genesis-cli 0.0.1-stage → 0.2.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.
Files changed (93) hide show
  1. package/README.md +64 -0
  2. package/bin/genesis.js +3 -0
  3. package/dist/auth.d.ts +30 -0
  4. package/dist/auth.js +273 -0
  5. package/dist/beacons.d.ts +3 -0
  6. package/dist/beacons.js +162 -0
  7. package/dist/device-login.d.ts +25 -0
  8. package/dist/device-login.js +173 -0
  9. package/dist/dials.d.ts +7 -0
  10. package/dist/dials.js +99 -0
  11. package/dist/fleets.d.ts +4 -0
  12. package/dist/fleets.js +102 -0
  13. package/dist/flocks.d.ts +9 -0
  14. package/dist/flocks.js +326 -0
  15. package/dist/function-input.d.ts +3 -0
  16. package/dist/function-input.js +49 -0
  17. package/dist/henry.d.ts +7 -0
  18. package/dist/henry.js +85 -0
  19. package/dist/hives-coverage.d.ts +12 -0
  20. package/dist/hives-coverage.js +116 -0
  21. package/dist/hives-marketplace.d.ts +10 -0
  22. package/dist/hives-marketplace.js +29 -0
  23. package/dist/hives-node-transport.d.ts +6 -0
  24. package/dist/hives-node-transport.js +150 -0
  25. package/dist/hives-operations.d.ts +10 -0
  26. package/dist/hives-operations.js +63 -0
  27. package/dist/hives-platform.d.ts +13 -0
  28. package/dist/hives-platform.js +133 -0
  29. package/dist/hives-resources.d.ts +9 -0
  30. package/dist/hives-resources.js +94 -0
  31. package/dist/iam-directory.d.ts +15 -0
  32. package/dist/iam-directory.js +71 -0
  33. package/dist/index.d.ts +23 -0
  34. package/dist/index.js +872 -0
  35. package/dist/lifeid-native.d.ts +24 -0
  36. package/dist/lifeid-native.js +113 -0
  37. package/dist/minds-owner.d.ts +3 -0
  38. package/dist/minds-owner.js +42 -0
  39. package/dist/minds.d.ts +3 -0
  40. package/dist/minds.js +125 -0
  41. package/dist/onboard/art.d.ts +50 -0
  42. package/dist/onboard/art.js +139 -0
  43. package/dist/onboard/brand.d.ts +56 -0
  44. package/dist/onboard/brand.js +134 -0
  45. package/dist/onboard/caps.d.ts +90 -0
  46. package/dist/onboard/caps.js +232 -0
  47. package/dist/onboard/encode.d.ts +23 -0
  48. package/dist/onboard/encode.js +235 -0
  49. package/dist/onboard/eye.d.ts +103 -0
  50. package/dist/onboard/eye.js +147 -0
  51. package/dist/onboard/index.d.ts +61 -0
  52. package/dist/onboard/index.js +562 -0
  53. package/dist/onboard/mcp.d.ts +35 -0
  54. package/dist/onboard/mcp.js +118 -0
  55. package/dist/onboard/raster.d.ts +43 -0
  56. package/dist/onboard/raster.js +253 -0
  57. package/dist/onboard/sound.d.ts +2 -0
  58. package/dist/onboard/sound.js +54 -0
  59. package/dist/onboard/state.d.ts +24 -0
  60. package/dist/onboard/state.js +48 -0
  61. package/dist/onboard/term.d.ts +69 -0
  62. package/dist/onboard/term.js +292 -0
  63. package/dist/onboard/ui.d.ts +97 -0
  64. package/dist/onboard/ui.js +615 -0
  65. package/dist/orgs.d.ts +16 -0
  66. package/dist/orgs.js +89 -0
  67. package/dist/output.d.ts +28 -0
  68. package/dist/output.js +46 -0
  69. package/dist/products.d.ts +18 -0
  70. package/dist/products.js +311 -0
  71. package/dist/relays-commands/certificates.d.ts +3 -0
  72. package/dist/relays-commands/certificates.js +20 -0
  73. package/dist/relays-commands/domains.d.ts +3 -0
  74. package/dist/relays-commands/domains.js +23 -0
  75. package/dist/relays-commands/index.d.ts +4 -0
  76. package/dist/relays-commands/index.js +10 -0
  77. package/dist/relays-commands/monitoring.d.ts +3 -0
  78. package/dist/relays-commands/monitoring.js +41 -0
  79. package/dist/relays-commands/telemetry.d.ts +3 -0
  80. package/dist/relays-commands/telemetry.js +28 -0
  81. package/dist/relays-commands/zones.d.ts +5 -0
  82. package/dist/relays-commands/zones.js +9 -0
  83. package/dist/relays-enrollment.d.ts +3 -0
  84. package/dist/relays-enrollment.js +7 -0
  85. package/dist/runner.d.ts +4 -0
  86. package/dist/runner.js +57 -0
  87. package/dist/secret-input.d.ts +14 -0
  88. package/dist/secret-input.js +85 -0
  89. package/dist/store.d.ts +39 -0
  90. package/dist/store.js +33 -0
  91. package/dist/wasm-input.d.ts +2 -0
  92. package/dist/wasm-input.js +31 -0
  93. package/package.json +54 -1
@@ -0,0 +1,292 @@
1
+ /**
2
+ * The terminal for one setup run: a live region redrawn in place (never the alternate screen, so the whole setup
3
+ * stays in scrollback), frames bracketed in synchronized output (DECSET 2026) so nothing tears, a steady frame clock,
4
+ * and one cleanup that always runs (Ctrl-C, an error, a normal exit) and puts back the cursor, its shape, the window
5
+ * title, focus reporting, raw mode and the tab's progress indicator.
6
+ */
7
+ import { homedir } from 'node:os';
8
+ const ESC = '\x1b';
9
+ export const strip = (s) => s.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b_[^\x1b]*\x1b\\|\x1bP[^\x1b]*\x1b\\/g, '');
10
+ /** Display width: wide East Asian and emoji count two. Enough for our own copy and server names passed through safe(). */
11
+ export function width(s) {
12
+ let w = 0;
13
+ for (const ch of strip(s)) {
14
+ const cp = ch.codePointAt(0);
15
+ if (cp < 32 || (cp >= 0x300 && cp < 0x370) || cp === 0x200d || (cp >= 0xfe00 && cp <= 0xfe0f))
16
+ continue;
17
+ w += (cp >= 0x1100 && (cp <= 0x115f || (cp >= 0x2e80 && cp <= 0xa4cf) || (cp >= 0xac00 && cp <= 0xd7a3) || (cp >= 0xf900 && cp <= 0xfaff) || (cp >= 0xfe30 && cp <= 0xfe4f) || (cp >= 0xff00 && cp <= 0xff60) || (cp >= 0x1f300 && cp <= 0x1faff))) ? 2 : 1;
18
+ }
19
+ return w;
20
+ }
21
+ export function parseKeys(data) {
22
+ const keys = [];
23
+ let i = 0;
24
+ while (i < data.length) {
25
+ const rest = data.slice(i);
26
+ // A reply to setup's own probe that arrived after its deadline (a slow SSH link): OSC 11, DECRQM, CSI … t,
27
+ // DA1, or a Kitty graphics answer. It is the terminal talking, not the user typing, so it is dropped.
28
+ const reply = /^(?:\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[\d;]*\$y|\x1b\[\d+;\d+;\d+t|\x1b\[\?[\d;]*c|\x1b_[^\x1b]*\x1b\\)/.exec(rest);
29
+ if (reply) {
30
+ i += reply[0].length;
31
+ continue;
32
+ }
33
+ const paste = /^\x1b\[200~([\s\S]*?)\x1b\[201~/.exec(rest);
34
+ if (paste) {
35
+ keys.push({ name: 'paste', ch: paste[1] });
36
+ i += paste[0].length;
37
+ continue;
38
+ }
39
+ const m = /^\x1b\[(\d*)(?:;(\d+))?([A-DHFIOZ~])/.exec(rest);
40
+ if (m) {
41
+ const map = { A: 'up', B: 'down', C: 'right', D: 'left', H: 'home', F: 'end', I: 'focus-in', O: 'focus-out', Z: 'backtab' };
42
+ keys.push({ name: m[3] === '~' ? ({ '3': 'delete', '1': 'home', '4': 'end', '5': 'pageup', '6': 'pagedown' }[m[1]] ?? 'unknown') : map[m[3]] });
43
+ i += m[0].length;
44
+ continue;
45
+ }
46
+ const ss3 = /^\x1bO([A-DHF])/.exec(rest);
47
+ if (ss3) {
48
+ keys.push({ name: { A: 'up', B: 'down', C: 'right', D: 'left', H: 'home', F: 'end' }[ss3[1]] });
49
+ i += 3;
50
+ continue;
51
+ }
52
+ const c = rest[0];
53
+ if (c === '\x1b') {
54
+ keys.push({ name: 'escape' });
55
+ i += rest.length > 1 && rest[1] !== '\x1b' && rest[1] !== '[' ? 2 : 1;
56
+ continue;
57
+ }
58
+ if (c === '\r' || c === '\n')
59
+ keys.push({ name: 'enter' });
60
+ else if (c === '\x7f' || c === '\b')
61
+ keys.push({ name: 'backspace' });
62
+ else if (c === '\t')
63
+ keys.push({ name: 'tab' });
64
+ else if (c === ' ')
65
+ keys.push({ name: 'space', ch: ' ' });
66
+ else if (c === '\x03')
67
+ keys.push({ name: 'c', ctrl: true });
68
+ else if (c === '\x04')
69
+ keys.push({ name: 'd', ctrl: true });
70
+ else if (c.charCodeAt(0) < 32)
71
+ keys.push({ name: String.fromCharCode(c.charCodeAt(0) + 96), ctrl: true });
72
+ else {
73
+ const cp = rest.codePointAt(0);
74
+ const ch = String.fromCodePoint(cp);
75
+ keys.push({ name: ch.toLowerCase(), ch });
76
+ i += ch.length;
77
+ continue;
78
+ }
79
+ i++;
80
+ }
81
+ return keys;
82
+ }
83
+ export class Interrupted extends Error {
84
+ constructor() { super('Setup paused.'); }
85
+ }
86
+ export class Term {
87
+ caps;
88
+ stdout;
89
+ stdin;
90
+ live = 0; // rows the live region occupies
91
+ liveWidth = 0;
92
+ liveEmpty = false;
93
+ cleanups = [];
94
+ keyWaiters = [];
95
+ onData = (b) => { for (const k of parseKeys(b.toString('utf8')))
96
+ this.dispatch(k); };
97
+ /** Every line setup draws sits two columns in from the edge; a step's own lines sit four in, under its header. */
98
+ margin = ' ';
99
+ focused = true;
100
+ focusListeners = new Set();
101
+ /** Ctrl-C while nothing reads keys (a network wait). Setup replaces it to say where it will pick up. */
102
+ onInterrupt = () => { this.restore(); process.exit(130); };
103
+ restored = false;
104
+ constructor(caps, stdout, stdin) {
105
+ this.caps = caps;
106
+ this.stdout = stdout;
107
+ this.stdin = stdin;
108
+ }
109
+ write(s) { this.stdout.write(s); }
110
+ get columns() { return Math.max(20, this.stdout.columns || this.caps.columns || 80); }
111
+ /** Start the session: raw keys, focus events, bracketed paste, hidden cursor, our title pushed onto the stack. */
112
+ start(title) {
113
+ if (!this.caps.interactive)
114
+ return;
115
+ this.stdin.setRawMode(true);
116
+ this.stdin.resume();
117
+ this.stdin.on('data', this.onData);
118
+ let s = `${ESC}[?1004h${ESC}[?2004h`;
119
+ if (this.caps.motion)
120
+ s += `${ESC}[?25l`;
121
+ s += `${ESC}[22;0t${ESC}]2;${title}\x07`;
122
+ this.write(s);
123
+ const restore = () => this.restore();
124
+ const sig = () => { this.restore(); process.exit(130); };
125
+ process.once('exit', restore);
126
+ process.once('SIGTERM', sig);
127
+ this.cleanups.push(() => { process.off('exit', restore); process.off('SIGTERM', sig); });
128
+ }
129
+ title(t) { if (this.caps.interactive)
130
+ this.write(`${ESC}]2;${t}\x07`); }
131
+ /** Tab/taskbar progress (OSC 9;4): 0 hidden, 1 value, 3 indeterminate. */
132
+ progress(state, value = 0) {
133
+ if (this.caps.progress)
134
+ this.write(`${ESC}]9;4;${state};${Math.round(value)}\x07`);
135
+ }
136
+ /** A desktop notification, only when the window is not in front (the user went to the browser). */
137
+ notify(title, body) {
138
+ if (this.focused || !this.caps.notify)
139
+ return;
140
+ const clean = (s) => s.replace(/[\x00-\x1f\x7f;]/g, ' ');
141
+ if (this.caps.notify === 'osc9')
142
+ this.write(`${ESC}]9;${clean(title)}: ${clean(body)}\x07`);
143
+ else if (this.caps.notify === 'osc777')
144
+ this.write(`${ESC}]777;notify;${clean(title)};${clean(body)}\x07`);
145
+ else
146
+ this.write(`${ESC}]99;i=1:d=0;${clean(title)}${ESC}\\${ESC}]99;i=1:d=1:p=body;${clean(body)}${ESC}\\`);
147
+ }
148
+ /** DECSCUSR: 6 steady bar (the emblem's bar as the caret), 0 the user's default. */
149
+ cursorShape(n) { if (this.caps.interactive)
150
+ this.write(`${ESC}[${n} q`); }
151
+ cursor(show) { if (this.caps.interactive)
152
+ this.write(show ? `${ESC}[?25h` : `${ESC}[?25l`); }
153
+ /** OSC 8 where the terminal supports it; elsewhere the label and the address, so the URL is never hidden. */
154
+ link(url, text = url) {
155
+ if (this.caps.hyperlinks)
156
+ return `${ESC}]8;;${url}${ESC}\\${text}${ESC}]8;;${ESC}\\`;
157
+ // A label that is itself an address (the device page) stands alone; a word label gets the address after it.
158
+ return text === url || /^https?:\/\//.test(strip(text)) ? text : `${text} ${url}`;
159
+ }
160
+ /**
161
+ * Replace the live region with `lines`, in one synchronized frame. The region shrinks and grows as needed; lines are
162
+ * clipped to the window so a narrow terminal never wraps a frame into garbage.
163
+ */
164
+ frame(lines) {
165
+ const cols = this.columns;
166
+ let s = `${ESC}[?2026h`;
167
+ if (this.live > 0)
168
+ s += `\r${this.live > 1 ? `${ESC}[${this.live - 1}A` : ''}`;
169
+ const fitted = (lines.length ? lines : ['']).map((l) => (l ? this.margin + this.mask(l) : l)).map((l) => (width(l) > cols - 1 ? clip(l, cols - 1) : l));
170
+ for (let i = 0; i < Math.max(fitted.length, this.live); i++) {
171
+ s += `${ESC}[2K${fitted[i] ?? ''}`;
172
+ if (i < Math.max(fitted.length, this.live) - 1)
173
+ s += '\n';
174
+ }
175
+ // Leave the cursor on the last line of the new region.
176
+ const extra = Math.max(0, this.live - fitted.length);
177
+ if (extra)
178
+ s += `${ESC}[${extra}A`;
179
+ s += `${ESC}[?2026l`;
180
+ this.write(s);
181
+ this.live = Math.max(1, fitted.length);
182
+ this.liveEmpty = fitted.every((l) => l === '');
183
+ this.liveWidth = cols;
184
+ }
185
+ /** Freeze the live region into scrollback; the next frame starts below it. */
186
+ commit() {
187
+ // An empty region (a finished one-line wait) is reused rather than left as a blank line.
188
+ if (this.live > 0)
189
+ this.write(this.liveEmpty ? `\r${this.live > 1 ? `${ESC}[${this.live - 1}A` : ''}` : '\n');
190
+ this.live = 0;
191
+ this.liveEmpty = false;
192
+ }
193
+ /** Plain append, for screen readers and still mode: never rewrites what was said. */
194
+ say(line = '') { this.commit(); this.write((line ? this.margin + this.mask(line) : '') + '\n'); }
195
+ /** In screencast mode, every identifier (h_…, o_…, w_…, pr_…, sess_…, keys) and email that setup prints is masked. */
196
+ mask(line) { return this.caps.screencast ? maskIdentifiers(line) : line; }
197
+ dispatch(k) {
198
+ if (k.name === 'focus-in' || k.name === 'focus-out') {
199
+ this.focused = k.name === 'focus-in';
200
+ for (const f of this.focusListeners)
201
+ f(this.focused);
202
+ return;
203
+ }
204
+ if (k.ctrl && (k.name === 'c' || k.name === 'd')) {
205
+ // Ctrl-C always works: it stops whatever is waiting on a key, or, mid-request with nothing listening, the run.
206
+ if (this.keyWaiters.length) {
207
+ for (const w of this.keyWaiters.splice(0))
208
+ w(k);
209
+ return;
210
+ }
211
+ this.onInterrupt();
212
+ return;
213
+ }
214
+ const w = this.keyWaiters.shift();
215
+ if (w)
216
+ w(k);
217
+ }
218
+ /** The next key; Ctrl-C rejects with Interrupted so every step can stop cleanly and be resumed. */
219
+ key(signal) {
220
+ return new Promise((resolve, reject) => {
221
+ const done = (k) => { signal?.removeEventListener('abort', abort); if (k.ctrl && (k.name === 'c' || k.name === 'd'))
222
+ reject(new Interrupted());
223
+ else
224
+ resolve(k); };
225
+ const abort = () => { this.keyWaiters = this.keyWaiters.filter((w) => w !== done); resolve({ name: 'abort' }); };
226
+ signal?.addEventListener('abort', abort, { once: true });
227
+ this.keyWaiters.push(done);
228
+ });
229
+ }
230
+ /** Any pending key, without waiting (for "press any key to skip" during animations). */
231
+ pollKey() { return this.key(); }
232
+ restore() {
233
+ if (this.restored)
234
+ return;
235
+ this.restored = true;
236
+ for (const c of this.cleanups.splice(0))
237
+ c();
238
+ if (!this.caps.interactive)
239
+ return;
240
+ this.progress(0);
241
+ this.write(`${ESC}[?2026l${ESC}[0m${ESC}[?1004l${ESC}[?2004l${ESC}[0 q${ESC}[?25h${ESC}[23;0t`);
242
+ try {
243
+ this.stdin.off('data', this.onData);
244
+ this.stdin.setRawMode(false);
245
+ this.stdin.pause();
246
+ }
247
+ catch { /* closed */ }
248
+ }
249
+ }
250
+ const ID = /(?<![A-Za-z0-9])(h|o|w|pr|pf|fl|sess|key|sk|gk|org|user)_[A-Za-z0-9_-]{4,}/g;
251
+ // The home directory (and so the OS user name) in a config path becomes ~.
252
+ const HOME = new RegExp(homedir().replace(/[.*+?^${}()|[\]\\]/g, '\\$&') || '\\0nohome', 'g');
253
+ const EMAIL = /\b[\w.+-]+@[\w-]+(?:\.[\w-]+)+\b/g;
254
+ const SGR_OR_OSC = /(\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\))/;
255
+ /** Masks the text between escape sequences, so an identifier right after a colour code (…m o_…) is still found. */
256
+ export function maskIdentifiers(line) {
257
+ return line.split(SGR_OR_OSC).map((part, i) => i % 2 ? part
258
+ : part.replace(ID, (_, p) => `${p}_••••••••`).replace(EMAIL, '•••@•••').replace(HOME, '~')).join('');
259
+ }
260
+ /** Clip to `cols` display columns, keeping escape sequences intact and closing any open style and link. */
261
+ export function clip(line, cols) {
262
+ let out = '', w = 0, i = 0;
263
+ while (i < line.length && w < cols) {
264
+ const esc = /^(?:\x1b\[[0-9;?]*[ -/]*[@-~]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\))/.exec(line.slice(i));
265
+ if (esc) {
266
+ out += esc[0];
267
+ i += esc[0].length;
268
+ continue;
269
+ }
270
+ const ch = String.fromCodePoint(line.codePointAt(i));
271
+ const cw = width(ch);
272
+ if (w + cw > cols)
273
+ break;
274
+ out += ch;
275
+ w += cw;
276
+ i += ch.length;
277
+ }
278
+ return out + '\x1b[0m\x1b]8;;\x1b\\';
279
+ }
280
+ /** A steady clock: calls `draw(t)` at `fps` until it returns false, sleeping the remainder of each frame. */
281
+ export async function animate(fps, draw, signal) {
282
+ const start = performance.now(), period = 1000 / fps;
283
+ for (let n = 0;; n++) {
284
+ if (signal?.aborted)
285
+ return;
286
+ const t = (performance.now() - start) / 1000;
287
+ if (!(await draw(t)))
288
+ return;
289
+ const next = start + (n + 1) * period, wait = next - performance.now();
290
+ await new Promise((r) => setTimeout(r, Math.max(0, wait)));
291
+ }
292
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Setup's pieces: the welcome (the hybrid ONE drawing itself, its O waking as One's eye and hopping through the Ones),
3
+ * type that arrives, choices with a rail that glides between rows in eighth-cell steps, a confirmation, a text field
4
+ * whose caret is the emblem's bar, and a waiting card where One's eye keeps you company.
5
+ *
6
+ * Every piece has a still form that is the same words in the same order, so reduced motion, screen readers, NO_COLOR,
7
+ * TERM=dumb and pipes get exactly the same setup.
8
+ */
9
+ import { type Color } from './raster.js';
10
+ import { type LogoState, type Tone } from './art.js';
11
+ import { type OneShape } from './brand.js';
12
+ import { kittyDelete } from './encode.js';
13
+ import { type Key, type Term } from './term.js';
14
+ export declare class Style {
15
+ readonly term: Term;
16
+ readonly tone: Tone;
17
+ readonly ink: Color | null;
18
+ readonly mutedColor: Color | null;
19
+ constructor(term: Term);
20
+ private sgr;
21
+ bold: (s: string) => string;
22
+ muted: (s: string) => string;
23
+ /** Text partway through arriving: from the background toward ink, in linear light. */
24
+ arriving(s: string, k: number): string;
25
+ error: (s: string) => string;
26
+ get check(): "✓" | "ok";
27
+ get dot(): "-" | "·";
28
+ }
29
+ /** Pick three Ones for the parade: random per run, fixed by GENESIS_DEMO_SEED so recordings repeat. */
30
+ export declare function paradeCast(seed?: number): OneShape[];
31
+ /** The logotype's state at time t of the welcome. Pure, so the tests can check any frame. */
32
+ export declare function welcomeAt(t: number, cast: OneShape[], short?: boolean): LogoState & {
33
+ done: boolean;
34
+ };
35
+ export interface Hero {
36
+ rows: number;
37
+ px: number;
38
+ draw(state: LogoState): string[];
39
+ }
40
+ export declare function hero(term: Term, style: Style): Hero | null;
41
+ export declare function welcome(term: Term, style: Style, opts: {
42
+ short: boolean;
43
+ tagline: string[];
44
+ seed?: number;
45
+ }): Promise<void>;
46
+ /** Lines that type themselves in: a little faster on spaces, a breath at punctuation, each glyph fading up to ink. */
47
+ export declare function typeLines(term: Term, style: Style, lines: string[]): Promise<void>;
48
+ export interface Option<T> {
49
+ label: string;
50
+ value: T;
51
+ hint?: string;
52
+ disabled?: boolean;
53
+ }
54
+ /**
55
+ * One row's rail cell when the rail (one row tall) sits at fractional row `pos`. Lower eighths draw the rail coming in
56
+ * from below; reverse video of the same glyphs draws it leaving through the bottom (the terminal swaps its own ink
57
+ * and paper, so this works without knowing either).
58
+ */
59
+ export declare function railCell(row: number, pos: number): string;
60
+ export declare function select<T>(term: Term, style: Style, q: {
61
+ title: string;
62
+ options: Option<T>[];
63
+ initial?: number;
64
+ skippable?: boolean;
65
+ }): Promise<T | 'skip'>;
66
+ export declare function confirm(term: Term, style: Style, question: string, initial: boolean): Promise<boolean>;
67
+ /** A one-line field. The caret is a steady bar (DECSCUSR 6), the emblem's bar; typed letters fade up to ink. */
68
+ export declare function input(term: Term, style: Style, q: {
69
+ label: string;
70
+ initial: string;
71
+ validate?: (v: string) => string | null;
72
+ }): Promise<string>;
73
+ export interface WaitResult<T> {
74
+ value?: T;
75
+ key?: Key;
76
+ }
77
+ /**
78
+ * Wait for `task` beside One's eye. The eye idles as on the site (blinks, glances at the text), turns to look at you
79
+ * when you come back to the window, and the tab shows indeterminate progress. Keys in `keys` end the wait early and
80
+ * are returned (e.g. "d" to switch to a device code); Ctrl-C stops setup, resumably.
81
+ */
82
+ export declare function waitBeside<T>(term: Term, style: Style, lines: () => string[], task: Promise<T>, keys?: string[]): Promise<WaitResult<T>>;
83
+ /** The moment it works: One smiles, and the light fills the eye and leaves. */
84
+ export declare function delight(term: Term, style: Style, line: string): Promise<void>;
85
+ export { kittyDelete };
86
+ /** Several choices at once (space toggles, a selects all, enter confirms). Screen readers type numbers. */
87
+ export declare function pick<T>(term: Term, style: Style, q: {
88
+ title: string;
89
+ options: (Option<T> & {
90
+ checked: boolean;
91
+ })[];
92
+ }): Promise<T[]>;
93
+ /**
94
+ * A short wait on one line: the emblem's bar blinking on agent-eye's timing (its lid closing as lower eighth blocks),
95
+ * then the line resolves to its result. Still terminals print the label once.
96
+ */
97
+ export declare function busy<T>(term: Term, style: Style, label: string, task: Promise<T>): Promise<T>;