@markjaquith/agency 3.5.2 → 3.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.
@@ -0,0 +1,977 @@
1
+ // @bun
2
+ // src/utils/interactive.tsx
3
+ import { createComponent as _$createComponent } from "@opentui/solid";
4
+ import { createTextNode as _$createTextNode } from "@opentui/solid";
5
+ import { effect as _$effect } from "@opentui/solid";
6
+ import { insertNode as _$insertNode } from "@opentui/solid";
7
+ import { use as _$use } from "@opentui/solid";
8
+ import { insert as _$insert } from "@opentui/solid";
9
+ import { memo as _$memo } from "@opentui/solid";
10
+ import { setProp as _$setProp } from "@opentui/solid";
11
+ import { createElement as _$createElement } from "@opentui/solid";
12
+ import { createCliRenderer } from "@opentui/core";
13
+ import { render, useKeyboard, useTerminalDimensions } from "@opentui/solid";
14
+ import { createMemo, createSignal, For, Show } from "solid-js";
15
+ import { macchiato } from "./theme";
16
+ var interactiveRendererConfig = {
17
+ screenMode: "split-footer",
18
+ footerHeight: 5,
19
+ externalOutputMode: "capture-stdout",
20
+ consoleMode: "disabled",
21
+ clearOnShutdown: false,
22
+ exitOnCtrlC: false,
23
+ useMouse: false,
24
+ autoFocus: false,
25
+ openConsoleOnError: false
26
+ };
27
+ var interactiveSelectRendererConfig = {
28
+ ...interactiveRendererConfig,
29
+ screenMode: "alternate-screen",
30
+ externalOutputMode: "passthrough"
31
+ };
32
+ var isCancel = (key) => key.name === "escape" || key.ctrl && key.name === "c";
33
+ var removedText = (before, after) => {
34
+ let start = 0;
35
+ while (start < before.length && start < after.length && before[start] === after[start]) {
36
+ start++;
37
+ }
38
+ let end = 0;
39
+ while (before[before.length - end - 1] === after[after.length - end - 1] && end < before.length - start && end < after.length - start) {
40
+ end++;
41
+ }
42
+ return before.slice(start, before.length - end);
43
+ };
44
+ var createReadlineEditing = (getInput, onInput) => {
45
+ let value = "";
46
+ let killBuffer = "";
47
+ let beforeKill;
48
+ return {
49
+ get value() {
50
+ return value;
51
+ },
52
+ handleInput(next) {
53
+ if (beforeKill !== undefined) {
54
+ const killed = removedText(beforeKill, next);
55
+ if (killed)
56
+ killBuffer = killed;
57
+ beforeKill = undefined;
58
+ }
59
+ value = next;
60
+ onInput?.(next);
61
+ },
62
+ handleKey(key) {
63
+ const current = getInput()?.plainText;
64
+ if (current !== undefined && current !== value)
65
+ this.handleInput(current);
66
+ if (!key.ctrl)
67
+ return false;
68
+ if (key.name === "y") {
69
+ key.preventDefault();
70
+ key.stopPropagation();
71
+ if (killBuffer)
72
+ getInput()?.insertText(killBuffer);
73
+ return true;
74
+ }
75
+ if (key.name === "u" || key.name === "k" || key.name === "w") {
76
+ beforeKill = value;
77
+ }
78
+ return false;
79
+ }
80
+ };
81
+ };
82
+ var InteractiveTextPrompt = (props) => {
83
+ let input;
84
+ const editing = createReadlineEditing(() => input);
85
+ useKeyboard((key) => {
86
+ if (key.propagationStopped)
87
+ return;
88
+ if (props.embedded && key.name === "escape" && editing.value) {
89
+ key.preventDefault();
90
+ key.stopPropagation();
91
+ input?.clear();
92
+ editing.handleInput("");
93
+ return;
94
+ }
95
+ if (isCancel(key)) {
96
+ key.preventDefault();
97
+ key.stopPropagation();
98
+ if (key.ctrl && key.name === "c")
99
+ props.onQuit?.();
100
+ props.onDone(null);
101
+ return;
102
+ }
103
+ editing.handleKey(key);
104
+ });
105
+ return (() => {
106
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("textarea"), _el$4 = _$createElement("text");
107
+ _$insertNode(_el$, _el$2);
108
+ _$insertNode(_el$, _el$3);
109
+ _$insertNode(_el$, _el$4);
110
+ _$setProp(_el$, "flexDirection", "column");
111
+ _$setProp(_el$, "width", "100%");
112
+ _$setProp(_el$, "height", "100%");
113
+ _$insert(_el$, (() => {
114
+ var _c$ = _$memo(() => !!(props.fullScreen && !props.embedded));
115
+ return () => _c$() && [(() => {
116
+ var _el$5 = _$createElement("text");
117
+ _$insertNode(_el$5, _$createTextNode(`\uF21B Agency`));
118
+ _$effect((_$p) => _$setProp(_el$5, "fg", macchiato.blue, _$p));
119
+ return _el$5;
120
+ })(), (() => {
121
+ var _el$7 = _$createElement("box");
122
+ _$setProp(_el$7, "height", 1);
123
+ _$setProp(_el$7, "flexShrink", 0);
124
+ return _el$7;
125
+ })()];
126
+ })(), _el$2);
127
+ _$setProp(_el$2, "flexShrink", 0);
128
+ _$insert(_el$2, (() => {
129
+ var _c$2 = _$memo(() => !!props.fullScreen);
130
+ return () => _c$2() ? `\uF138 ${props.prompt}` : props.prompt;
131
+ })());
132
+ _$use((next) => {
133
+ input = next;
134
+ }, _el$3);
135
+ _$setProp(_el$3, "focused", true);
136
+ _$setProp(_el$3, "minHeight", 1);
137
+ _$setProp(_el$3, "wrapMode", "word");
138
+ _$setProp(_el$3, "keyBindings", [{
139
+ name: "return",
140
+ action: "submit"
141
+ }, {
142
+ name: "return",
143
+ shift: true,
144
+ action: "newline"
145
+ }]);
146
+ _$setProp(_el$3, "onSubmit", () => props.onDone(editing.value));
147
+ _$setProp(_el$3, "onContentChange", () => {
148
+ editing.handleInput(input?.plainText ?? "");
149
+ });
150
+ _$setProp(_el$4, "wrapMode", "none");
151
+ _$setProp(_el$4, "height", 1);
152
+ _$setProp(_el$4, "flexShrink", 0);
153
+ _$insert(_el$4, () => props.embedded ? "enter submit | shift-enter newline | esc clear/back" : "enter submit | shift-enter newline | esc cancel");
154
+ _$effect((_p$) => {
155
+ var _v$ = macchiato.base, _v$2 = macchiato.blue, _v$3 = props.fullScreen ? 0 : 2, _v$4 = props.fullScreen ? 1 : 0, _v$5 = macchiato.mantle, _v$6 = macchiato.surface0, _v$7 = macchiato.text, _v$8 = macchiato.text, _v$9 = macchiato.blue, _v$0 = macchiato.overlay1;
156
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$, "backgroundColor", _v$, _p$.e));
157
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$2, "fg", _v$2, _p$.t));
158
+ _v$3 !== _p$.a && (_p$.a = _$setProp(_el$3, "height", _v$3, _p$.a));
159
+ _v$4 !== _p$.o && (_p$.o = _$setProp(_el$3, "flexGrow", _v$4, _p$.o));
160
+ _v$5 !== _p$.i && (_p$.i = _$setProp(_el$3, "backgroundColor", _v$5, _p$.i));
161
+ _v$6 !== _p$.n && (_p$.n = _$setProp(_el$3, "focusedBackgroundColor", _v$6, _p$.n));
162
+ _v$7 !== _p$.s && (_p$.s = _$setProp(_el$3, "textColor", _v$7, _p$.s));
163
+ _v$8 !== _p$.h && (_p$.h = _$setProp(_el$3, "focusedTextColor", _v$8, _p$.h));
164
+ _v$9 !== _p$.r && (_p$.r = _$setProp(_el$3, "cursorColor", _v$9, _p$.r));
165
+ _v$0 !== _p$.d && (_p$.d = _$setProp(_el$4, "fg", _v$0, _p$.d));
166
+ return _p$;
167
+ }, {
168
+ e: undefined,
169
+ t: undefined,
170
+ a: undefined,
171
+ o: undefined,
172
+ i: undefined,
173
+ n: undefined,
174
+ s: undefined,
175
+ h: undefined,
176
+ r: undefined,
177
+ d: undefined
178
+ });
179
+ return _el$;
180
+ })();
181
+ };
182
+ var isWordBoundary = (value, index) => index === 0 || /[\s/_.:-]/.test(value[index - 1]);
183
+ var fuzzyScore = (value, query) => {
184
+ const candidate = value.toLowerCase();
185
+ const needle = query.toLowerCase();
186
+ let previous = new Float64Array(candidate.length);
187
+ let current = new Float64Array(candidate.length);
188
+ previous.fill(Number.NEGATIVE_INFINITY);
189
+ let bestScore = Number.NEGATIVE_INFINITY;
190
+ for (let queryIndex = 0;queryIndex < needle.length; queryIndex++) {
191
+ current.fill(Number.NEGATIVE_INFINITY);
192
+ let bestEarlier = Number.NEGATIVE_INFINITY;
193
+ bestScore = Number.NEGATIVE_INFINITY;
194
+ for (let index = 0;index < candidate.length; index++) {
195
+ if (queryIndex > 0 && index > 0) {
196
+ bestEarlier = Math.max(bestEarlier, previous[index - 1] + index - 1);
197
+ }
198
+ if (candidate[index] !== needle[queryIndex])
199
+ continue;
200
+ const boundaryBonus = isWordBoundary(candidate, index) ? 8 : 0;
201
+ if (queryIndex === 0) {
202
+ current[index] = 10 + boundaryBonus - index;
203
+ bestScore = Math.max(bestScore, current[index]);
204
+ continue;
205
+ }
206
+ const contiguous = index > 0 ? previous[index - 1] + 12 : Number.NEGATIVE_INFINITY;
207
+ const gapped = bestEarlier - index + 1;
208
+ current[index] = Math.max(contiguous, gapped) + 10 + boundaryBonus;
209
+ bestScore = Math.max(bestScore, current[index]);
210
+ }
211
+ if (!Number.isFinite(bestScore))
212
+ return null;
213
+ const swap = previous;
214
+ previous = current;
215
+ current = swap;
216
+ }
217
+ return bestScore - candidate.length / 1000;
218
+ };
219
+ var fuzzyChoices = (choices, query) => {
220
+ if (!query)
221
+ return choices;
222
+ return choices.map((choice, index) => ({
223
+ choice,
224
+ index,
225
+ score: fuzzyScore(choice.label, query)
226
+ })).filter((match) => match.score !== null).sort((left, right) => right.score - left.score || left.index - right.index).map((match) => match.choice);
227
+ };
228
+ var choiceDepth = (choice) => choice.depth ?? 0;
229
+ var hasSibling = (choices, index, direction) => {
230
+ const depth = choiceDepth(choices[index]);
231
+ for (let siblingIndex = index + direction;siblingIndex >= 0 && siblingIndex < choices.length; siblingIndex += direction) {
232
+ const siblingDepth = choiceDepth(choices[siblingIndex]);
233
+ if (siblingDepth < depth)
234
+ return false;
235
+ if (siblingDepth === depth)
236
+ return true;
237
+ }
238
+ return false;
239
+ };
240
+ var hierarchyPrefix = (choices, index) => {
241
+ const choice = choices[index];
242
+ if (!choice || choice.depth === undefined)
243
+ return "";
244
+ const depth = choiceDepth(choice);
245
+ let prefix = "";
246
+ let ancestorIndex = index;
247
+ for (let ancestorDepth = depth - 1;ancestorDepth >= 0; ancestorDepth--) {
248
+ for (ancestorIndex--;ancestorIndex >= 0; ancestorIndex--) {
249
+ if (choiceDepth(choices[ancestorIndex]) === ancestorDepth)
250
+ break;
251
+ }
252
+ prefix = `${ancestorIndex >= 0 && hasSibling(choices, ancestorIndex, 1) ? "\u2502 " : " "}${prefix}`;
253
+ }
254
+ const hasPrevious = hasSibling(choices, index, -1);
255
+ const hasNext = hasSibling(choices, index, 1);
256
+ return `${prefix}${!hasPrevious && hasNext ? "\u256D" : hasNext ? "\u251C" : "\u2570"}\u2500 `;
257
+ };
258
+ var InteractiveSelectPrompt = (props) => {
259
+ let input;
260
+ const dimensions = useTerminalDimensions();
261
+ const [query, setQuery] = createSignal("");
262
+ const editing = createReadlineEditing(() => input, setQuery);
263
+ const [selected, setSelected] = createSignal(0);
264
+ const choices = createMemo(() => fuzzyChoices(props.choices, query()));
265
+ const displaySegments = (choice) => choice.segments ?? [{
266
+ text: choice.label
267
+ }];
268
+ const move = (offset) => {
269
+ const count = choices().length;
270
+ if (count === 0)
271
+ return;
272
+ setSelected((current) => (current + offset + count) % count);
273
+ };
274
+ useKeyboard((key) => {
275
+ if (props.active === false || key.propagationStopped)
276
+ return;
277
+ if (key.name === "tab" && props.onTab) {
278
+ key.preventDefault();
279
+ key.stopPropagation();
280
+ props.onTab();
281
+ return;
282
+ }
283
+ if (key.name === "escape" && query()) {
284
+ key.preventDefault();
285
+ key.stopPropagation();
286
+ input?.clear();
287
+ editing.handleInput("");
288
+ setQuery("");
289
+ setSelected(0);
290
+ return;
291
+ }
292
+ if (isCancel(key)) {
293
+ key.preventDefault();
294
+ key.stopPropagation();
295
+ if (key.ctrl && key.name === "c")
296
+ props.onQuit?.();
297
+ props.onDone(null);
298
+ return;
299
+ }
300
+ if (key.name === "up" || key.ctrl && key.name === "p") {
301
+ key.preventDefault();
302
+ key.stopPropagation();
303
+ move(-1);
304
+ return;
305
+ }
306
+ if (key.name === "down" || key.ctrl && key.name === "n") {
307
+ key.preventDefault();
308
+ key.stopPropagation();
309
+ move(1);
310
+ return;
311
+ }
312
+ editing.handleKey(key);
313
+ });
314
+ const height = () => dimensions().height - (props.reservedRows ?? 0);
315
+ const background = () => props.backgroundColor ?? macchiato.base;
316
+ const brandHeight = () => !props.embedded && height() > 4 ? 1 : 0;
317
+ const gapHeight = () => height() > (props.embedded ? 3 : 5) ? 1 : 0;
318
+ const availableRows = () => height() - 2 - 2 * brandHeight() - gapHeight();
319
+ const rowHeight = () => props.choices.some((choice) => choice.details) && availableRows() >= 2 ? 2 : 1;
320
+ const contentWidth = createMemo(() => Math.max(0, ...props.choices.map(({
321
+ details
322
+ }) => details ? Math.max(...[details.title, details.metadata].map((row) => Bun.stringWidth(row.map((segment) => segment.text).join("")))) : 0)));
323
+ const detailWidth = () => Math.min(contentWidth(), Math.max(1, dimensions().width - 20));
324
+ const visible = () => {
325
+ const visibleCount = Math.max(Math.floor(availableRows() / rowHeight()), 1);
326
+ const start = Math.min(Math.max(selected() - Math.floor(visibleCount / 2), 0), Math.max(choices().length - visibleCount, 0));
327
+ return choices().slice(start, start + visibleCount).map((choice, offset) => ({
328
+ choice,
329
+ index: start + offset,
330
+ originalIndex: props.choices.indexOf(choice)
331
+ }));
332
+ };
333
+ return (() => {
334
+ var _el$8 = _$createElement("box"), _el$9 = _$createElement("box"), _el$0 = _$createElement("text"), _el$1 = _$createElement("box"), _el$10 = _$createElement("text"), _el$12 = _$createElement("box"), _el$13 = _$createElement("textarea"), _el$14 = _$createElement("box"), _el$15 = _$createElement("box");
335
+ _$insertNode(_el$8, _el$9);
336
+ _$insertNode(_el$8, _el$0);
337
+ _$insertNode(_el$8, _el$1);
338
+ _$insertNode(_el$8, _el$14);
339
+ _$insertNode(_el$8, _el$15);
340
+ _$setProp(_el$8, "flexDirection", "column");
341
+ _$setProp(_el$8, "width", "100%");
342
+ _$setProp(_el$8, "height", "100%");
343
+ _$insert(_el$8, (() => {
344
+ var _c$3 = _$memo(() => brandHeight() > 0);
345
+ return () => _c$3() && (() => {
346
+ var _el$16 = _$createElement("text");
347
+ _$insertNode(_el$16, _$createTextNode(`\uF21B Agency`));
348
+ _$setProp(_el$16, "height", 1);
349
+ _$setProp(_el$16, "flexShrink", 0);
350
+ _$setProp(_el$16, "wrapMode", "none");
351
+ _$effect((_$p) => _$setProp(_el$16, "fg", macchiato.blue, _$p));
352
+ return _el$16;
353
+ })();
354
+ })(), _el$9);
355
+ _$setProp(_el$9, "flexShrink", 0);
356
+ _$setProp(_el$0, "height", 1);
357
+ _$setProp(_el$0, "flexShrink", 0);
358
+ _$setProp(_el$0, "wrapMode", "none");
359
+ _$insert(_el$0, () => props.prompt);
360
+ _$insertNode(_el$1, _el$10);
361
+ _$insertNode(_el$1, _el$12);
362
+ _$setProp(_el$1, "flexDirection", "row");
363
+ _$setProp(_el$1, "width", "100%");
364
+ _$setProp(_el$1, "height", 1);
365
+ _$setProp(_el$1, "flexShrink", 0);
366
+ _$insertNode(_el$10, _$createTextNode(`\uF138 `));
367
+ _$insertNode(_el$12, _el$13);
368
+ _$setProp(_el$12, "flexDirection", "row");
369
+ _$setProp(_el$12, "flexGrow", 1);
370
+ _$setProp(_el$12, "minWidth", 10);
371
+ _$setProp(_el$12, "height", 1);
372
+ _$setProp(_el$12, "paddingLeft", 1);
373
+ _$setProp(_el$12, "paddingRight", 1);
374
+ _$use((next) => {
375
+ input = next;
376
+ }, _el$13);
377
+ _$setProp(_el$13, "flexGrow", 1);
378
+ _$setProp(_el$13, "minWidth", 8);
379
+ _$setProp(_el$13, "height", 1);
380
+ _$setProp(_el$13, "wrapMode", "none");
381
+ _$setProp(_el$13, "placeholder", "type to filter");
382
+ _$setProp(_el$13, "keyBindings", [{
383
+ name: "return",
384
+ action: "submit"
385
+ }]);
386
+ _$setProp(_el$13, "onSubmit", () => {
387
+ const choice = choices()[selected()];
388
+ if (choice)
389
+ props.onDone(choice.key);
390
+ });
391
+ _$setProp(_el$13, "onContentChange", () => {
392
+ editing.handleInput(input?.plainText ?? "");
393
+ setSelected(0);
394
+ });
395
+ _$setProp(_el$14, "flexShrink", 0);
396
+ _$setProp(_el$15, "flexDirection", "column");
397
+ _$setProp(_el$15, "flexGrow", 1);
398
+ _$insert(_el$15, _$createComponent(For, {
399
+ get each() {
400
+ return visible();
401
+ },
402
+ get fallback() {
403
+ return (() => {
404
+ var _el$18 = _$createElement("text");
405
+ _$insert(_el$18, (() => {
406
+ var _c$4 = _$memo(() => !!query());
407
+ return () => _c$4() ? "No matches" : props.emptyLabel ?? "No matches";
408
+ })());
409
+ _$effect((_$p) => _$setProp(_el$18, "fg", macchiato.overlay1, _$p));
410
+ return _el$18;
411
+ })();
412
+ },
413
+ children: ({
414
+ choice,
415
+ index,
416
+ originalIndex
417
+ }) => (() => {
418
+ var _el$19 = _$createElement("box");
419
+ _$setProp(_el$19, "width", "100%");
420
+ _$setProp(_el$19, "flexDirection", "row");
421
+ _$insert(_el$19, (() => {
422
+ var _c$5 = _$memo(() => !!(choice.details && rowHeight() === 2));
423
+ return () => _c$5() ? [(() => {
424
+ var _el$20 = _$createElement("text");
425
+ _$setProp(_el$20, "width", 2);
426
+ _$setProp(_el$20, "height", 2);
427
+ _$insert(_el$20, () => index === selected() ? `\u258C
428
+ \u258C` : "");
429
+ _$effect((_$p) => _$setProp(_el$20, "fg", macchiato.blue, _$p));
430
+ return _el$20;
431
+ })(), (() => {
432
+ var _el$21 = _$createElement("box");
433
+ _$setProp(_el$21, "flexDirection", "column");
434
+ _$setProp(_el$21, "height", 2);
435
+ _$setProp(_el$21, "flexShrink", 0);
436
+ _$insert(_el$21, _$createComponent(For, {
437
+ get each() {
438
+ return [choice.details.title, choice.details.metadata];
439
+ },
440
+ children: (row) => (() => {
441
+ var _el$24 = _$createElement("text");
442
+ _$setProp(_el$24, "height", 1);
443
+ _$setProp(_el$24, "wrapMode", "none");
444
+ _$insert(_el$24, _$createComponent(For, {
445
+ each: row,
446
+ children: (segment) => (() => {
447
+ var _el$25 = _$createElement("span");
448
+ _$insert(_el$25, () => segment.text);
449
+ _$effect((_$p) => _$setProp(_el$25, "style", {
450
+ fg: segment.color
451
+ }, _$p));
452
+ return _el$25;
453
+ })()
454
+ }));
455
+ return _el$24;
456
+ })()
457
+ }));
458
+ _$effect((_$p) => _$setProp(_el$21, "width", detailWidth(), _$p));
459
+ return _el$21;
460
+ })(), (() => {
461
+ var _el$22 = _$createElement("box");
462
+ _$setProp(_el$22, "width", 2);
463
+ _$setProp(_el$22, "flexShrink", 0);
464
+ return _el$22;
465
+ })(), (() => {
466
+ var _el$23 = _$createElement("text");
467
+ _$setProp(_el$23, "flexGrow", 1);
468
+ _$setProp(_el$23, "minWidth", 0);
469
+ _$setProp(_el$23, "width", 0);
470
+ _$setProp(_el$23, "height", 2);
471
+ _$setProp(_el$23, "wrapMode", "word");
472
+ _$insert(_el$23, () => choice.details.description);
473
+ _$effect((_$p) => _$setProp(_el$23, "fg", macchiato.subtext0, _$p));
474
+ return _el$23;
475
+ })()] : (() => {
476
+ var _el$26 = _$createElement("text"), _el$27 = _$createElement("span"), _el$28 = _$createElement("span");
477
+ _$insertNode(_el$26, _el$27);
478
+ _$insertNode(_el$26, _el$28);
479
+ _$setProp(_el$26, "wrapMode", "none");
480
+ _$insert(_el$27, () => index === selected() ? "\u258C " : " ");
481
+ _$insert(_el$28, (() => {
482
+ var _c$6 = _$memo(() => !!query());
483
+ return () => _c$6() ? "" : hierarchyPrefix(props.choices, originalIndex);
484
+ })());
485
+ _$insert(_el$26, _$createComponent(For, {
486
+ get each() {
487
+ return displaySegments(choice);
488
+ },
489
+ children: (segment) => (() => {
490
+ var _el$29 = _$createElement("span");
491
+ _$insert(_el$29, () => segment.text);
492
+ _$effect((_$p) => _$setProp(_el$29, "style", {
493
+ fg: segment.color
494
+ }, _$p));
495
+ return _el$29;
496
+ })()
497
+ }), null);
498
+ _$effect((_p$) => {
499
+ var _v$24 = index === selected() ? macchiato.text : macchiato.subtext0, _v$25 = index === selected() ? macchiato.surface1 : background(), _v$26 = {
500
+ fg: index === selected() ? macchiato.blue : undefined
501
+ }, _v$27 = {
502
+ fg: macchiato.overlay1
503
+ };
504
+ _v$24 !== _p$.e && (_p$.e = _$setProp(_el$26, "fg", _v$24, _p$.e));
505
+ _v$25 !== _p$.t && (_p$.t = _$setProp(_el$26, "bg", _v$25, _p$.t));
506
+ _v$26 !== _p$.a && (_p$.a = _$setProp(_el$27, "style", _v$26, _p$.a));
507
+ _v$27 !== _p$.o && (_p$.o = _$setProp(_el$28, "style", _v$27, _p$.o));
508
+ return _p$;
509
+ }, {
510
+ e: undefined,
511
+ t: undefined,
512
+ a: undefined,
513
+ o: undefined
514
+ });
515
+ return _el$26;
516
+ })();
517
+ })());
518
+ _$effect((_p$) => {
519
+ var _v$22 = rowHeight(), _v$23 = index === selected() ? macchiato.surface1 : background();
520
+ _v$22 !== _p$.e && (_p$.e = _$setProp(_el$19, "height", _v$22, _p$.e));
521
+ _v$23 !== _p$.t && (_p$.t = _$setProp(_el$19, "backgroundColor", _v$23, _p$.t));
522
+ return _p$;
523
+ }, {
524
+ e: undefined,
525
+ t: undefined
526
+ });
527
+ return _el$19;
528
+ })()
529
+ }));
530
+ _$effect((_p$) => {
531
+ var _v$1 = background(), _v$10 = brandHeight(), _v$11 = macchiato.blue, _v$12 = macchiato.blue, _v$13 = props.active === false ? macchiato.mantle : props.embedded ? macchiato.surface1 : macchiato.surface0, _v$14 = props.active !== false, _v$15 = macchiato.overlay0, _v$16 = macchiato.mantle, _v$17 = props.embedded ? macchiato.surface1 : macchiato.surface0, _v$18 = macchiato.text, _v$19 = macchiato.text, _v$20 = macchiato.blue, _v$21 = gapHeight();
532
+ _v$1 !== _p$.e && (_p$.e = _$setProp(_el$8, "backgroundColor", _v$1, _p$.e));
533
+ _v$10 !== _p$.t && (_p$.t = _$setProp(_el$9, "height", _v$10, _p$.t));
534
+ _v$11 !== _p$.a && (_p$.a = _$setProp(_el$0, "fg", _v$11, _p$.a));
535
+ _v$12 !== _p$.o && (_p$.o = _$setProp(_el$10, "fg", _v$12, _p$.o));
536
+ _v$13 !== _p$.i && (_p$.i = _$setProp(_el$12, "backgroundColor", _v$13, _p$.i));
537
+ _v$14 !== _p$.n && (_p$.n = _$setProp(_el$13, "focused", _v$14, _p$.n));
538
+ _v$15 !== _p$.s && (_p$.s = _$setProp(_el$13, "placeholderColor", _v$15, _p$.s));
539
+ _v$16 !== _p$.h && (_p$.h = _$setProp(_el$13, "backgroundColor", _v$16, _p$.h));
540
+ _v$17 !== _p$.r && (_p$.r = _$setProp(_el$13, "focusedBackgroundColor", _v$17, _p$.r));
541
+ _v$18 !== _p$.d && (_p$.d = _$setProp(_el$13, "textColor", _v$18, _p$.d));
542
+ _v$19 !== _p$.l && (_p$.l = _$setProp(_el$13, "focusedTextColor", _v$19, _p$.l));
543
+ _v$20 !== _p$.u && (_p$.u = _$setProp(_el$13, "cursorColor", _v$20, _p$.u));
544
+ _v$21 !== _p$.c && (_p$.c = _$setProp(_el$14, "height", _v$21, _p$.c));
545
+ return _p$;
546
+ }, {
547
+ e: undefined,
548
+ t: undefined,
549
+ a: undefined,
550
+ o: undefined,
551
+ i: undefined,
552
+ n: undefined,
553
+ s: undefined,
554
+ h: undefined,
555
+ r: undefined,
556
+ d: undefined,
557
+ l: undefined,
558
+ u: undefined,
559
+ c: undefined
560
+ });
561
+ return _el$8;
562
+ })();
563
+ };
564
+ var InteractiveTabbedPrompt = (props) => {
565
+ const dimensions = useTerminalDimensions();
566
+ const [active, setActive] = createSignal(props.initialTab ?? 0);
567
+ const showBrand = () => dimensions().width >= props.tabs.reduce((width, tab) => width + Bun.stringWidth(tab.label) + 4, 12);
568
+ const reservedRows = () => 1 + (props.notice ? 1 : 0);
569
+ const cycle = () => {
570
+ if (!props.tabs.length)
571
+ return;
572
+ const next = (active() + 1) % props.tabs.length;
573
+ setActive(next);
574
+ props.onTabChange?.(next);
575
+ };
576
+ useKeyboard((key) => {
577
+ if (!props.content || key.name !== "tab" || key.propagationStopped)
578
+ return;
579
+ key.preventDefault();
580
+ key.stopPropagation();
581
+ cycle();
582
+ });
583
+ return (() => {
584
+ var _el$30 = _$createElement("box"), _el$31 = _$createElement("box"), _el$32 = _$createElement("box"), _el$35 = _$createElement("box");
585
+ _$insertNode(_el$30, _el$31);
586
+ _$insertNode(_el$30, _el$35);
587
+ _$setProp(_el$30, "flexDirection", "column");
588
+ _$setProp(_el$30, "width", "100%");
589
+ _$setProp(_el$30, "height", "100%");
590
+ _$insertNode(_el$31, _el$32);
591
+ _$setProp(_el$31, "flexDirection", "row");
592
+ _$setProp(_el$31, "height", 1);
593
+ _$setProp(_el$31, "flexShrink", 0);
594
+ _$setProp(_el$31, "paddingLeft", 1);
595
+ _$setProp(_el$31, "paddingRight", 1);
596
+ _$insert(_el$31, _$createComponent(For, {
597
+ get each() {
598
+ return props.tabs;
599
+ },
600
+ children: (tab, index) => (() => {
601
+ var _el$37 = _$createElement("text"), _el$38 = _$createElement("span");
602
+ _$insertNode(_el$37, _el$38);
603
+ _$setProp(_el$37, "wrapMode", "none");
604
+ _$insert(_el$38, () => index() === active() ? "\u258E" : " ");
605
+ _$insert(_el$37, () => ` ${tab.label} `, null);
606
+ _$effect((_p$) => {
607
+ var _v$30 = index() === active() ? macchiato.text : macchiato.overlay1, _v$31 = index() === active() ? macchiato.base : macchiato.surface0, _v$32 = {
608
+ fg: macchiato.blue
609
+ };
610
+ _v$30 !== _p$.e && (_p$.e = _$setProp(_el$37, "fg", _v$30, _p$.e));
611
+ _v$31 !== _p$.t && (_p$.t = _$setProp(_el$37, "bg", _v$31, _p$.t));
612
+ _v$32 !== _p$.a && (_p$.a = _$setProp(_el$38, "style", _v$32, _p$.a));
613
+ return _p$;
614
+ }, {
615
+ e: undefined,
616
+ t: undefined,
617
+ a: undefined
618
+ });
619
+ return _el$37;
620
+ })()
621
+ }), _el$32);
622
+ _$setProp(_el$32, "flexGrow", 1);
623
+ _$setProp(_el$32, "minWidth", 1);
624
+ _$insert(_el$31, _$createComponent(Show, {
625
+ get when() {
626
+ return showBrand();
627
+ },
628
+ get children() {
629
+ var _el$33 = _$createElement("text");
630
+ _$insertNode(_el$33, _$createTextNode(`\uF21B Agency`));
631
+ _$setProp(_el$33, "flexShrink", 0);
632
+ _$setProp(_el$33, "wrapMode", "none");
633
+ _$effect((_$p) => _$setProp(_el$33, "fg", macchiato.blue, _$p));
634
+ return _el$33;
635
+ }
636
+ }), null);
637
+ _$setProp(_el$35, "flexDirection", "column");
638
+ _$setProp(_el$35, "flexGrow", 1);
639
+ _$setProp(_el$35, "minHeight", 0);
640
+ _$setProp(_el$35, "paddingLeft", 1);
641
+ _$setProp(_el$35, "paddingRight", 1);
642
+ _$insert(_el$35, _$createComponent(Show, {
643
+ get when() {
644
+ return props.notice;
645
+ },
646
+ get children() {
647
+ var _el$36 = _$createElement("text");
648
+ _$setProp(_el$36, "height", 1);
649
+ _$setProp(_el$36, "flexShrink", 0);
650
+ _$setProp(_el$36, "wrapMode", "none");
651
+ _$insert(_el$36, () => props.notice);
652
+ _$effect((_$p) => _$setProp(_el$36, "fg", macchiato.text, _$p));
653
+ return _el$36;
654
+ }
655
+ }), null);
656
+ _$insert(_el$35, (() => {
657
+ var _c$7 = _$memo(() => !!props.content);
658
+ return () => _c$7() ? props.content(reservedRows) : _$createComponent(For, {
659
+ get each() {
660
+ return props.tabs;
661
+ },
662
+ children: (tab, index) => (() => {
663
+ var _el$39 = _$createElement("box");
664
+ _$setProp(_el$39, "width", "100%");
665
+ _$setProp(_el$39, "flexGrow", 1);
666
+ _$setProp(_el$39, "minHeight", 0);
667
+ _$insert(_el$39, _$createComponent(InteractiveSelectPrompt, {
668
+ embedded: true,
669
+ get active() {
670
+ return index() === active();
671
+ },
672
+ get reservedRows() {
673
+ return reservedRows();
674
+ },
675
+ get backgroundColor() {
676
+ return macchiato.base;
677
+ },
678
+ get prompt() {
679
+ return tab.prompt;
680
+ },
681
+ get choices() {
682
+ return tab.choices;
683
+ },
684
+ get emptyLabel() {
685
+ return tab.emptyLabel;
686
+ },
687
+ onTab: cycle,
688
+ get onDone() {
689
+ return props.onDone;
690
+ },
691
+ get onQuit() {
692
+ return props.onQuit;
693
+ }
694
+ }));
695
+ _$effect((_$p) => _$setProp(_el$39, "visible", index() === active(), _$p));
696
+ return _el$39;
697
+ })()
698
+ });
699
+ })(), null);
700
+ _$effect((_p$) => {
701
+ var _v$28 = macchiato.surface0, _v$29 = macchiato.base;
702
+ _v$28 !== _p$.e && (_p$.e = _$setProp(_el$30, "backgroundColor", _v$28, _p$.e));
703
+ _v$29 !== _p$.t && (_p$.t = _$setProp(_el$35, "backgroundColor", _v$29, _p$.t));
704
+ return _p$;
705
+ }, {
706
+ e: undefined,
707
+ t: undefined
708
+ });
709
+ return _el$30;
710
+ })();
711
+ };
712
+ var shutdown = async (renderer) => {
713
+ try {
714
+ await renderer.idle();
715
+ } finally {
716
+ renderer.destroy();
717
+ }
718
+ };
719
+ var createInteractiveSession = async (onCancel = () => {}, initialTabs = []) => {
720
+ const [view, setView] = createSignal({
721
+ kind: "progress",
722
+ prompt: "Preparing\u2026"
723
+ });
724
+ let pending;
725
+ let closed = false;
726
+ let cancelled = false;
727
+ let quitRequested = false;
728
+ let activeTab = 0;
729
+ let frameTabs = initialTabs;
730
+ let navigationRequested = false;
731
+ const navigate = (index) => {
732
+ activeTab = index;
733
+ navigationRequested = true;
734
+ if (pending)
735
+ pending(null);
736
+ else {
737
+ cancelled = true;
738
+ onCancel();
739
+ }
740
+ };
741
+ const [notice, setNotice] = createSignal("");
742
+ const quit = () => {
743
+ quitRequested = true;
744
+ onCancel();
745
+ };
746
+ const Progress = (props) => {
747
+ useKeyboard((key) => {
748
+ if (key.propagationStopped)
749
+ return;
750
+ if (!isCancel(key))
751
+ return;
752
+ key.preventDefault();
753
+ key.stopPropagation();
754
+ cancelled = true;
755
+ if (key.ctrl && key.name === "c")
756
+ quitRequested = true;
757
+ onCancel();
758
+ });
759
+ return (() => {
760
+ var _el$40 = _$createElement("box"), _el$41 = _$createElement("text");
761
+ _$insertNode(_el$40, _el$41);
762
+ _$setProp(_el$40, "flexDirection", "column");
763
+ _$setProp(_el$40, "width", "100%");
764
+ _$setProp(_el$40, "height", "100%");
765
+ _$insert(_el$41, () => props.prompt);
766
+ _$effect((_p$) => {
767
+ var _v$33 = macchiato.base, _v$34 = macchiato.text;
768
+ _v$33 !== _p$.e && (_p$.e = _$setProp(_el$40, "backgroundColor", _v$33, _p$.e));
769
+ _v$34 !== _p$.t && (_p$.t = _$setProp(_el$41, "fg", _v$34, _p$.t));
770
+ return _p$;
771
+ }, {
772
+ e: undefined,
773
+ t: undefined
774
+ });
775
+ return _el$40;
776
+ })();
777
+ };
778
+ const renderer = await createCliRenderer({
779
+ ...interactiveSelectRendererConfig,
780
+ onDestroy: () => {
781
+ const external = !closed;
782
+ closed = true;
783
+ if (external)
784
+ quit();
785
+ pending?.(null);
786
+ }
787
+ });
788
+ try {
789
+ await render(() => _$createComponent(Show, {
790
+ get when() {
791
+ return view();
792
+ },
793
+ keyed: true,
794
+ children: (current) => current.kind === "tabs" ? _$createComponent(InteractiveTabbedPrompt, {
795
+ get tabs() {
796
+ return current.tabs;
797
+ },
798
+ get onDone() {
799
+ return current.finish;
800
+ },
801
+ onQuit: quit,
802
+ get notice() {
803
+ return notice();
804
+ },
805
+ initialTab: activeTab,
806
+ onTabChange: (index) => {
807
+ activeTab = index;
808
+ }
809
+ }) : _$createComponent(InteractiveTabbedPrompt, {
810
+ tabs: frameTabs,
811
+ initialTab: activeTab,
812
+ get notice() {
813
+ return notice();
814
+ },
815
+ onDone: () => {},
816
+ onTabChange: navigate,
817
+ content: (reservedRows) => current.kind === "select" ? _$createComponent(InteractiveSelectPrompt, {
818
+ embedded: true,
819
+ get reservedRows() {
820
+ return reservedRows();
821
+ },
822
+ get prompt() {
823
+ return current.prompt;
824
+ },
825
+ get choices() {
826
+ return current.choices;
827
+ },
828
+ get onDone() {
829
+ return current.finish;
830
+ },
831
+ onQuit: quit
832
+ }) : current.kind === "text" ? _$createComponent(InteractiveTextPrompt, {
833
+ fullScreen: true,
834
+ embedded: true,
835
+ get prompt() {
836
+ return current.prompt;
837
+ },
838
+ get onDone() {
839
+ return current.finish;
840
+ },
841
+ onQuit: quit
842
+ }) : _$createComponent(Progress, {
843
+ get prompt() {
844
+ return current.prompt;
845
+ }
846
+ })
847
+ })
848
+ }), renderer);
849
+ } catch (error) {
850
+ await shutdown(renderer);
851
+ throw error;
852
+ }
853
+ const ask = (prompt, choices, tabs) => {
854
+ if (closed || cancelled)
855
+ return Promise.resolve(null);
856
+ return new Promise((resolve) => {
857
+ pending = (value) => {
858
+ pending = undefined;
859
+ if (!closed)
860
+ setView({
861
+ kind: "progress",
862
+ prompt: "Preparing next step\u2026"
863
+ });
864
+ resolve(value);
865
+ };
866
+ setView(tabs ? {
867
+ kind: "tabs",
868
+ tabs,
869
+ finish: pending
870
+ } : choices ? {
871
+ kind: "select",
872
+ prompt,
873
+ choices,
874
+ finish: pending
875
+ } : {
876
+ kind: "text",
877
+ prompt,
878
+ finish: pending
879
+ });
880
+ renderer.requestRender();
881
+ });
882
+ };
883
+ return {
884
+ activateTab: (id) => {
885
+ const index = frameTabs.findIndex((tab) => tab.id === id);
886
+ if (index >= 0)
887
+ activeTab = index;
888
+ },
889
+ takeNavigation: () => {
890
+ const requested = navigationRequested;
891
+ navigationRequested = false;
892
+ return requested;
893
+ },
894
+ get navigationRequested() {
895
+ return navigationRequested;
896
+ },
897
+ get quitRequested() {
898
+ return quitRequested;
899
+ },
900
+ notice: (message) => {
901
+ cancelled = false;
902
+ setNotice(message);
903
+ },
904
+ tabs: (tabs) => {
905
+ frameTabs = tabs;
906
+ return ask("", undefined, tabs);
907
+ },
908
+ text: (prompt) => ask(prompt),
909
+ select: (prompt, choices) => ask(prompt, choices),
910
+ show: (prompt) => {
911
+ setView({
912
+ kind: "progress",
913
+ prompt
914
+ });
915
+ renderer.requestRender();
916
+ },
917
+ close: async () => {
918
+ if (closed)
919
+ return;
920
+ closed = true;
921
+ pending?.(null);
922
+ await shutdown(renderer);
923
+ }
924
+ };
925
+ };
926
+ async function runInteractive(view, config = interactiveRendererConfig) {
927
+ let finish;
928
+ let settled = false;
929
+ const result = new Promise((resolve) => {
930
+ finish = (value) => {
931
+ if (settled)
932
+ return;
933
+ settled = true;
934
+ resolve(value);
935
+ };
936
+ });
937
+ let renderer;
938
+ try {
939
+ renderer = await createCliRenderer({
940
+ ...config,
941
+ onDestroy: () => finish(null)
942
+ });
943
+ await render(() => view(finish), renderer);
944
+ renderer.requestRender();
945
+ return await result;
946
+ } finally {
947
+ if (renderer) {
948
+ await shutdown(renderer);
949
+ }
950
+ }
951
+ }
952
+ var promptText = async (prompt) => {
953
+ const result = await runInteractive((finish) => _$createComponent(InteractiveTextPrompt, {
954
+ prompt,
955
+ onDone: finish
956
+ }));
957
+ if (result === null)
958
+ throw new Error("Interactive input cancelled");
959
+ return result;
960
+ };
961
+ var promptSelect = (prompt, choices) => runInteractive((finish) => _$createComponent(InteractiveSelectPrompt, {
962
+ prompt,
963
+ choices,
964
+ onDone: finish
965
+ }), interactiveSelectRendererConfig);
966
+ export {
967
+ InteractiveSelectPrompt,
968
+ InteractiveTabbedPrompt,
969
+ InteractiveTextPrompt,
970
+ createInteractiveSession,
971
+ fuzzyChoices,
972
+ hierarchyPrefix,
973
+ interactiveRendererConfig,
974
+ interactiveSelectRendererConfig,
975
+ promptSelect,
976
+ promptText
977
+ };