silvery 0.17.0 → 0.17.2

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 (171) hide show
  1. package/dist/UPNG-AVSMjiFE.mjs +5076 -0
  2. package/dist/UPNG-AVSMjiFE.mjs.map +1 -0
  3. package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs +6 -0
  4. package/dist/__vite-browser-external-2447137e-D3GdsvS_.mjs.map +1 -0
  5. package/dist/animation-C_PTO0uH.mjs +304 -0
  6. package/dist/animation-C_PTO0uH.mjs.map +1 -0
  7. package/dist/ansi-CXLE_pt1.mjs +71 -0
  8. package/dist/ansi-CXLE_pt1.mjs.map +1 -0
  9. package/dist/ansi-zmNzgkPB.d.mts +49 -0
  10. package/dist/ansi-zmNzgkPB.d.mts.map +1 -0
  11. package/dist/apng-DCWY913R.mjs +3 -0
  12. package/dist/apng-ENBAJk-H.mjs +70 -0
  13. package/dist/apng-ENBAJk-H.mjs.map +1 -0
  14. package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
  15. package/dist/backend-CkIkIHR-.mjs +13396 -0
  16. package/dist/backend-CkIkIHR-.mjs.map +1 -0
  17. package/dist/backends-CkvbG3js.mjs +1181 -0
  18. package/dist/backends-CkvbG3js.mjs.map +1 -0
  19. package/dist/backends-CyJqNLeK.mjs +3 -0
  20. package/dist/chunk-BSw8zbkd.mjs +37 -0
  21. package/dist/cli-B-k7Bm56.mjs +4 -0
  22. package/dist/context-QreF3UHr.mjs +64 -0
  23. package/dist/context-QreF3UHr.mjs.map +1 -0
  24. package/dist/derive-D7bFJdfU.d.mts +28 -0
  25. package/dist/derive-D7bFJdfU.d.mts.map +1 -0
  26. package/dist/devtools-CscuKaDK.mjs +89 -0
  27. package/dist/devtools-CscuKaDK.mjs.map +1 -0
  28. package/dist/devtools-D4oGc6LY.mjs +2 -0
  29. package/dist/eta-DLiVPaSD.mjs +110 -0
  30. package/dist/eta-DLiVPaSD.mjs.map +1 -0
  31. package/dist/flexily-zero-adapter-DmG4Ge8t.mjs +3376 -0
  32. package/dist/flexily-zero-adapter-DmG4Ge8t.mjs.map +1 -0
  33. package/dist/flexily-zero-adapter-GHwEW11s.mjs +2 -0
  34. package/dist/gif-BaJNREpP.mjs +3 -0
  35. package/dist/gif-Bp6fIyN3.mjs +73 -0
  36. package/dist/gif-Bp6fIyN3.mjs.map +1 -0
  37. package/dist/gifenc-GiVCZ9-3.mjs +730 -0
  38. package/dist/gifenc-GiVCZ9-3.mjs.map +1 -0
  39. package/dist/image-Dx7gYjkq.mjs +346 -0
  40. package/dist/image-Dx7gYjkq.mjs.map +1 -0
  41. package/dist/index-CBcSpGSM.d.mts +3416 -0
  42. package/dist/index-CBcSpGSM.d.mts.map +1 -0
  43. package/dist/index-DCVL3jHo.d.mts +634 -0
  44. package/dist/index-DCVL3jHo.d.mts.map +1 -0
  45. package/dist/index-p-wBs_wH.d.mts +175 -0
  46. package/dist/index-p-wBs_wH.d.mts.map +1 -0
  47. package/dist/index.d.mts +7296 -0
  48. package/dist/index.d.mts.map +1 -0
  49. package/dist/index.mjs +9399 -0
  50. package/dist/index.mjs.map +1 -0
  51. package/dist/key-mapping-BsUHe_nk.mjs +3 -0
  52. package/dist/key-mapping-DsyfLEdC.mjs +132 -0
  53. package/dist/key-mapping-DsyfLEdC.mjs.map +1 -0
  54. package/dist/layout-engine-B3dsnVLU.mjs +50 -0
  55. package/dist/layout-engine-B3dsnVLU.mjs.map +1 -0
  56. package/dist/layout-engine-D_lSR4i9.mjs +2 -0
  57. package/dist/multi-progress-C0-rkn86.d.mts +180 -0
  58. package/dist/multi-progress-C0-rkn86.d.mts.map +1 -0
  59. package/dist/multi-progress-CQVB9lES.mjs +219 -0
  60. package/dist/multi-progress-CQVB9lES.mjs.map +1 -0
  61. package/dist/node-Dedx-6xF.mjs +1085 -0
  62. package/dist/node-Dedx-6xF.mjs.map +1 -0
  63. package/dist/pipeline-DDOPrjuY.mjs +4387 -0
  64. package/dist/pipeline-DDOPrjuY.mjs.map +1 -0
  65. package/dist/progress-bar-COPSBlT9.mjs +155 -0
  66. package/dist/progress-bar-COPSBlT9.mjs.map +1 -0
  67. package/dist/reconciler-2lp5VXK7.mjs +16506 -0
  68. package/dist/reconciler-2lp5VXK7.mjs.map +1 -0
  69. package/dist/render-string-BXvxTg5P.mjs +201 -0
  70. package/dist/render-string-BXvxTg5P.mjs.map +1 -0
  71. package/dist/render-string-hvfpVtoP.mjs +2 -0
  72. package/dist/resvg-js-V6oMi8CY.mjs +203 -0
  73. package/dist/resvg-js-V6oMi8CY.mjs.map +1 -0
  74. package/dist/runtime-BjDHNTxJ.mjs +8723 -0
  75. package/dist/runtime-BjDHNTxJ.mjs.map +1 -0
  76. package/dist/runtime.d.mts +2 -0
  77. package/dist/runtime.mjs +3 -0
  78. package/dist/spinner-Cgej6Vnb.d.mts +127 -0
  79. package/dist/spinner-Cgej6Vnb.d.mts.map +1 -0
  80. package/dist/spinner-DSByknyx.mjs +298 -0
  81. package/dist/spinner-DSByknyx.mjs.map +1 -0
  82. package/dist/src-9B5k0JmY.mjs +1629 -0
  83. package/dist/src-9B5k0JmY.mjs.map +1 -0
  84. package/dist/src-C9f3hiVG.mjs +3620 -0
  85. package/dist/src-C9f3hiVG.mjs.map +1 -0
  86. package/dist/src-fJVbhdn-.mjs +816 -0
  87. package/dist/src-fJVbhdn-.mjs.map +1 -0
  88. package/dist/theme.d.mts +115 -0
  89. package/dist/theme.d.mts.map +1 -0
  90. package/dist/theme.mjs +8 -0
  91. package/dist/theme.mjs.map +1 -0
  92. package/dist/types-Bhj5QkIQ.mjs +13 -0
  93. package/dist/types-Bhj5QkIQ.mjs.map +1 -0
  94. package/dist/types-CDgkE-Rw.d.mts +241 -0
  95. package/dist/types-CDgkE-Rw.d.mts.map +1 -0
  96. package/dist/ui/animation.d.mts +2 -0
  97. package/dist/ui/animation.mjs +2 -0
  98. package/dist/ui/ansi.d.mts +2 -0
  99. package/dist/ui/ansi.mjs +2 -0
  100. package/dist/ui/cli.d.mts +5 -0
  101. package/dist/ui/cli.mjs +7 -0
  102. package/dist/ui/display.d.mts +35 -0
  103. package/dist/ui/display.d.mts.map +1 -0
  104. package/dist/ui/display.mjs +123 -0
  105. package/dist/ui/display.mjs.map +1 -0
  106. package/dist/ui/image.d.mts +2 -0
  107. package/dist/ui/image.mjs +2 -0
  108. package/dist/ui/input.d.mts +184 -0
  109. package/dist/ui/input.d.mts.map +1 -0
  110. package/dist/ui/input.mjs +285 -0
  111. package/dist/ui/input.mjs.map +1 -0
  112. package/dist/ui/progress.d.mts +249 -0
  113. package/dist/ui/progress.d.mts.map +1 -0
  114. package/dist/ui/progress.mjs +858 -0
  115. package/dist/ui/progress.mjs.map +1 -0
  116. package/dist/ui/react.d.mts +280 -0
  117. package/dist/ui/react.d.mts.map +1 -0
  118. package/dist/ui/react.mjs +413 -0
  119. package/dist/ui/react.mjs.map +1 -0
  120. package/dist/ui/utils.d.mts +86 -0
  121. package/dist/ui/utils.d.mts.map +1 -0
  122. package/dist/ui/utils.mjs +2 -0
  123. package/dist/ui/wrappers.d.mts +3 -0
  124. package/dist/ui/wrappers.mjs +2 -0
  125. package/dist/ui.d.mts +6 -0
  126. package/dist/ui.mjs +7 -0
  127. package/dist/useLatest-BMIYXd6e.d.mts +154 -0
  128. package/dist/useLatest-BMIYXd6e.d.mts.map +1 -0
  129. package/dist/useLayout-BG2cGl15.mjs +139 -0
  130. package/dist/useLayout-BG2cGl15.mjs.map +1 -0
  131. package/dist/with-text-input-CmHf_9d6.d.mts +284 -0
  132. package/dist/with-text-input-CmHf_9d6.d.mts.map +1 -0
  133. package/dist/wrapper-Dqh0zi2W.mjs +3527 -0
  134. package/dist/wrapper-Dqh0zi2W.mjs.map +1 -0
  135. package/dist/wrappers-hhL8EQ_n.mjs +810 -0
  136. package/dist/wrappers-hhL8EQ_n.mjs.map +1 -0
  137. package/dist/yoga-adapter-BJ9SOhTY.mjs +245 -0
  138. package/dist/yoga-adapter-BJ9SOhTY.mjs.map +1 -0
  139. package/dist/yoga-adapter-Daq6-dw1.mjs +2 -0
  140. package/package.json +48 -75
  141. package/CHANGELOG.md +0 -319
  142. package/dist/chalk.js +0 -4
  143. package/dist/index.js +0 -270
  144. package/dist/ink.js +0 -142
  145. package/dist/runtime.js +0 -135
  146. package/dist/theme.js +0 -7
  147. package/dist/ui/animation.js +0 -3
  148. package/dist/ui/ansi.js +0 -3
  149. package/dist/ui/cli.js +0 -9
  150. package/dist/ui/display.js +0 -4
  151. package/dist/ui/image.js +0 -4
  152. package/dist/ui/input.js +0 -3
  153. package/dist/ui/progress.js +0 -9
  154. package/dist/ui/react.js +0 -4
  155. package/dist/ui/utils.js +0 -3
  156. package/dist/ui/wrappers.js +0 -15
  157. package/dist/ui.js +0 -18
  158. package/src/index.ts +0 -73
  159. package/src/runtime.ts +0 -4
  160. package/src/theme.ts +0 -4
  161. package/src/ui/animation.ts +0 -2
  162. package/src/ui/ansi.ts +0 -2
  163. package/src/ui/cli.ts +0 -3
  164. package/src/ui/display.ts +0 -2
  165. package/src/ui/image.ts +0 -2
  166. package/src/ui/input.ts +0 -2
  167. package/src/ui/progress.ts +0 -2
  168. package/src/ui/react.ts +0 -2
  169. package/src/ui/utils.ts +0 -2
  170. package/src/ui/wrappers.ts +0 -2
  171. package/src/ui.ts +0 -4
@@ -0,0 +1,810 @@
1
+ import { a as chalk, r as Spinner } from "./spinner-DSByknyx.mjs";
2
+ import { f as isTTY, i as CURSOR_HIDE, m as write, s as CURSOR_SHOW, u as cursorUp } from "./ansi-CXLE_pt1.mjs";
3
+ import { t as ProgressBar } from "./progress-bar-COPSBlT9.mjs";
4
+ //#region packages/ag-react/src/ui/wrappers/with-spinner.ts
5
+ /**
6
+ * Wrap a promise with an animated spinner
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * // Simple usage
11
+ * const data = await withSpinner(fetchData(), "Loading data...");
12
+ *
13
+ * // With options
14
+ * const result = await withSpinner(
15
+ * processFiles(),
16
+ * "Processing...",
17
+ * { style: "arc", clearOnComplete: true }
18
+ * );
19
+ *
20
+ * // With dynamic text
21
+ * const result = await withSpinner(
22
+ * longOperation(),
23
+ * (elapsed) => `Processing... (${elapsed}s)`
24
+ * );
25
+ * ```
26
+ */
27
+ async function withSpinner(promise, text, options = {}) {
28
+ const spinner = new Spinner({
29
+ text: typeof text === "string" ? text : text(0),
30
+ style: options.style,
31
+ color: options.color
32
+ });
33
+ let timer = null;
34
+ const startTime = Date.now();
35
+ spinner.start();
36
+ if (typeof text === "function") timer = setInterval(() => {
37
+ spinner.currentText = text(Math.floor((Date.now() - startTime) / 1e3));
38
+ }, 1e3);
39
+ try {
40
+ const result = await (typeof promise === "function" ? promise() : promise);
41
+ if (timer) clearInterval(timer);
42
+ if (options.clearOnComplete) spinner.stop();
43
+ else spinner.succeed();
44
+ return result;
45
+ } catch (error) {
46
+ if (timer) clearInterval(timer);
47
+ spinner.fail(error instanceof Error ? error.message : "Failed");
48
+ throw error;
49
+ }
50
+ }
51
+ /**
52
+ * Attach a spinner to a promise for manual control
53
+ * Returns [result, spinner] tuple for custom control
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const [promise, spinner] = attachSpinner(fetchData(), "Loading...");
58
+ * spinner.text = "Still loading...";
59
+ * const result = await promise;
60
+ * spinner.succeed("Loaded!");
61
+ * ```
62
+ */
63
+ function attachSpinner(promise, text, options = {}) {
64
+ const spinner = new Spinner({
65
+ text,
66
+ style: options.style,
67
+ color: options.color
68
+ });
69
+ spinner.start();
70
+ async function wrapPromise() {
71
+ try {
72
+ return await promise;
73
+ } catch (error) {
74
+ spinner.fail(error instanceof Error ? error.message : "Failed");
75
+ throw error;
76
+ }
77
+ }
78
+ return [wrapPromise(), spinner];
79
+ }
80
+ //#endregion
81
+ //#region packages/ag-react/src/ui/wrappers/with-progress.ts
82
+ /**
83
+ * Wrap a function that takes a progress callback
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * // Wrap existing km sync API
88
+ * const result = await withProgress(
89
+ * (onProgress) => manager.syncFromFs(onProgress),
90
+ * {
91
+ * phases: {
92
+ * scanning: "Scanning files",
93
+ * reconciling: "Reconciling changes",
94
+ * rules: "Evaluating rules"
95
+ * }
96
+ * }
97
+ * );
98
+ *
99
+ * // Simple usage without phases
100
+ * await withProgress((onProgress) => rebuildState(onProgress));
101
+ *
102
+ * // With custom format
103
+ * await withProgress(
104
+ * (p) => processFiles(p),
105
+ * { format: ":phase :bar :percent" }
106
+ * );
107
+ *
108
+ * // Show loading immediately (showAfter: 0) or after delay
109
+ * await withProgress(
110
+ * (p) => slowOperation(p),
111
+ * { showAfter: 1000, initialMessage: "Loading..." }
112
+ * );
113
+ * ```
114
+ */
115
+ async function withProgress(fn, options = {}) {
116
+ const stream = process.stdout;
117
+ const isTty = isTTY(stream);
118
+ const bar = new ProgressBar({
119
+ format: options.format ?? (options.phases ? ":phase [:bar] :current/:total" : "[:bar] :current/:total :percent"),
120
+ phases: options.phases ?? {},
121
+ hideCursor: true
122
+ });
123
+ let lastPhase = null;
124
+ let started = false;
125
+ const showAfter = options.showAfter ?? 1e3;
126
+ const initialMessage = options.initialMessage ?? "Loading...";
127
+ let spinner = null;
128
+ let spinnerTimerId = null;
129
+ if (isTty) write(CURSOR_HIDE, stream);
130
+ if (isTty && showAfter >= 0) spinnerTimerId = setTimeout(() => {
131
+ if (!started) {
132
+ spinner = new Spinner({ text: initialMessage });
133
+ spinner.start();
134
+ }
135
+ }, showAfter);
136
+ const onProgress = (info) => {
137
+ if (spinner) {
138
+ spinner.stop();
139
+ spinner = null;
140
+ }
141
+ if (spinnerTimerId !== null) {
142
+ clearTimeout(spinnerTimerId);
143
+ spinnerTimerId = null;
144
+ }
145
+ if (info.phase && info.phase !== lastPhase) {
146
+ if (lastPhase !== null && isTty) write("\n", stream);
147
+ lastPhase = info.phase;
148
+ if (!started) {
149
+ bar.start(info.current, info.total);
150
+ started = true;
151
+ }
152
+ bar.setPhase(info.phase, {
153
+ current: info.current,
154
+ total: info.total
155
+ });
156
+ } else {
157
+ if (!started) {
158
+ bar.start(info.current, info.total);
159
+ started = true;
160
+ }
161
+ bar.update(info.current);
162
+ }
163
+ };
164
+ try {
165
+ const result = await fn(onProgress);
166
+ if (spinnerTimerId !== null) clearTimeout(spinnerTimerId);
167
+ const pendingSpinner = spinner;
168
+ if (pendingSpinner) pendingSpinner.stop();
169
+ if (started) bar.stop(options.clearOnComplete);
170
+ if (isTty) write(CURSOR_SHOW, stream);
171
+ return result;
172
+ } catch (error) {
173
+ if (spinnerTimerId !== null) clearTimeout(spinnerTimerId);
174
+ const errorSpinner = spinner;
175
+ if (errorSpinner) errorSpinner.stop();
176
+ if (started) bar.stop();
177
+ if (isTty) write(CURSOR_SHOW, stream);
178
+ throw error;
179
+ }
180
+ }
181
+ /**
182
+ * Create a progress callback that can be passed to existing APIs
183
+ * Returns [callback, complete] tuple
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * const [onProgress, complete] = createProgressCallback({
188
+ * phases: { scanning: "Scanning", reconciling: "Reconciling" }
189
+ * });
190
+ *
191
+ * const result = await manager.syncFromFs(onProgress);
192
+ * complete();
193
+ * ```
194
+ */
195
+ function createProgressCallback(options = {}) {
196
+ const stream = process.stdout;
197
+ const isTty = isTTY(stream);
198
+ const bar = new ProgressBar({
199
+ format: options.format ?? (options.phases ? ":phase [:bar] :current/:total" : "[:bar] :current/:total :percent"),
200
+ phases: options.phases ?? {},
201
+ hideCursor: true
202
+ });
203
+ let lastPhase = null;
204
+ let started = false;
205
+ if (isTty) write(CURSOR_HIDE, stream);
206
+ const callback = (info) => {
207
+ if (info.phase && info.phase !== lastPhase) {
208
+ if (lastPhase !== null && isTty) write("\n", stream);
209
+ lastPhase = info.phase;
210
+ if (!started) {
211
+ bar.start(info.current, info.total);
212
+ started = true;
213
+ }
214
+ bar.setPhase(info.phase, {
215
+ current: info.current,
216
+ total: info.total
217
+ });
218
+ } else {
219
+ if (!started) {
220
+ bar.start(info.current, info.total);
221
+ started = true;
222
+ }
223
+ bar.update(info.current);
224
+ }
225
+ };
226
+ const complete = () => {
227
+ if (started) bar.stop(options.clearOnComplete);
228
+ if (isTty) write(CURSOR_SHOW, stream);
229
+ };
230
+ return [callback, complete];
231
+ }
232
+ //#endregion
233
+ //#region packages/ag-react/src/ui/wrappers/wrap-generator.ts
234
+ /**
235
+ * Consume a progress generator while displaying progress
236
+ *
237
+ * @example
238
+ * ```ts
239
+ * // Wrap existing generator (like evaluateAllRules())
240
+ * await wrapGenerator(evaluateAllRules(), "Evaluating rules");
241
+ *
242
+ * // With custom format
243
+ * await wrapGenerator(
244
+ * processItems(),
245
+ * ({ current, total }) => `Processing: ${current}/${total}`
246
+ * );
247
+ *
248
+ * // Get the generator's return value
249
+ * const result = await wrapGenerator(generatorWithReturn(), "Processing");
250
+ * ```
251
+ */
252
+ async function wrapGenerator(generator, textOrFormat, options = {}) {
253
+ const stream = process.stdout;
254
+ const isTty = isTTY(stream);
255
+ const label = typeof textOrFormat === "function" ? "" : textOrFormat;
256
+ const bar = new ProgressBar({
257
+ format: label ? `${label} [:bar] :current/:total :percent` : ":bar :current/:total :percent",
258
+ hideCursor: true
259
+ });
260
+ if (isTty) write(CURSOR_HIDE, stream);
261
+ let started = false;
262
+ let result;
263
+ try {
264
+ while (true) {
265
+ result = generator.next();
266
+ if (result.done) break;
267
+ const { current, total } = result.value;
268
+ if (!started) {
269
+ bar.start(current, total);
270
+ started = true;
271
+ } else bar.update(current);
272
+ }
273
+ if (started) bar.stop(options.clearOnComplete);
274
+ if (isTty) write(CURSOR_SHOW, stream);
275
+ return result.value;
276
+ } catch (error) {
277
+ if (started) bar.stop();
278
+ if (isTty) write(CURSOR_SHOW, stream);
279
+ throw error;
280
+ }
281
+ }
282
+ /**
283
+ * Create an async iterable wrapper that shows progress
284
+ *
285
+ * @example
286
+ * ```ts
287
+ * const items = [1, 2, 3, 4, 5];
288
+ * for await (const item of withIterableProgress(items, "Processing")) {
289
+ * await processItem(item);
290
+ * }
291
+ * ```
292
+ */
293
+ async function* withIterableProgress(iterable, label, options = {}) {
294
+ const stream = process.stdout;
295
+ const isTty = isTTY(stream);
296
+ const total = (Array.isArray(iterable) ? iterable : null)?.length ?? 0;
297
+ const bar = new ProgressBar({
298
+ format: `${label} [:bar] :current/:total :percent`,
299
+ total,
300
+ hideCursor: true
301
+ });
302
+ if (isTty) write(CURSOR_HIDE, stream);
303
+ let current = 0;
304
+ bar.start(0, total);
305
+ try {
306
+ for await (const item of iterable) {
307
+ yield item;
308
+ current++;
309
+ bar.update(current);
310
+ }
311
+ bar.stop(options.clearOnComplete);
312
+ if (isTty) write(CURSOR_SHOW, stream);
313
+ } catch (error) {
314
+ bar.stop();
315
+ if (isTty) write(CURSOR_SHOW, stream);
316
+ throw error;
317
+ }
318
+ }
319
+ //#endregion
320
+ //#region packages/ag-react/src/ui/wrappers/wrap-emitter.ts
321
+ /**
322
+ * Track EventEmitter state changes with a spinner
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * const stop = wrapEmitter(syncManager, {
327
+ * initialText: "Starting sync...",
328
+ * events: {
329
+ * 'ready': { text: "Watcher ready", succeed: true },
330
+ * 'state-change': { getText: (s) => `State: ${s}` },
331
+ * 'error': { fail: true },
332
+ * 'idle': { stop: true }
333
+ * }
334
+ * });
335
+ *
336
+ * // Later, to stop manually
337
+ * stop();
338
+ * ```
339
+ */
340
+ function wrapEmitter(emitter, config) {
341
+ const spinner = new Spinner(config.initialText ?? "");
342
+ const handlers = /* @__PURE__ */ new Map();
343
+ spinner.start();
344
+ for (const [eventName, eventConfig] of Object.entries(config.events)) {
345
+ const handler = (data) => {
346
+ if (eventConfig.getText) spinner.currentText = eventConfig.getText(data);
347
+ else if (eventConfig.text) spinner.currentText = eventConfig.text;
348
+ if (eventConfig.succeed) {
349
+ spinner.succeed();
350
+ cleanup();
351
+ } else if (eventConfig.fail) {
352
+ const message = data instanceof Error ? data.message : String(data ?? "Failed");
353
+ spinner.fail(message);
354
+ cleanup();
355
+ } else if (eventConfig.stop) {
356
+ spinner.stop();
357
+ cleanup();
358
+ }
359
+ };
360
+ handlers.set(eventName, handler);
361
+ emitter.on(eventName, handler);
362
+ }
363
+ function cleanup() {
364
+ for (const [eventName, handler] of handlers) emitter.off(eventName, handler);
365
+ handlers.clear();
366
+ }
367
+ return () => {
368
+ spinner.stop();
369
+ cleanup();
370
+ };
371
+ }
372
+ /**
373
+ * Wait for an EventEmitter to emit a specific event
374
+ * Shows a spinner while waiting
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * await waitForEvent(syncManager, "ready", "Waiting for watcher...");
379
+ * ```
380
+ */
381
+ async function waitForEvent(emitter, eventName, text, options = {}) {
382
+ return new Promise((resolve, reject) => {
383
+ const spinner = new Spinner(text);
384
+ spinner.start();
385
+ let timer = null;
386
+ const cleanup = () => {
387
+ emitter.off(eventName, successHandler);
388
+ if (options.errorEvent) emitter.off(options.errorEvent, errorHandler);
389
+ if (timer) clearTimeout(timer);
390
+ };
391
+ const successHandler = (data) => {
392
+ cleanup();
393
+ spinner.succeed();
394
+ resolve(data);
395
+ };
396
+ const errorHandler = (error) => {
397
+ cleanup();
398
+ spinner.fail(error instanceof Error ? error.message : "Error");
399
+ reject(error instanceof Error ? error : new Error(String(error)));
400
+ };
401
+ emitter.once(eventName, successHandler);
402
+ if (options.errorEvent) emitter.once(options.errorEvent, errorHandler);
403
+ if (options.timeout) timer = setTimeout(() => {
404
+ cleanup();
405
+ spinner.fail("Timeout");
406
+ reject(/* @__PURE__ */ new Error(`Timeout waiting for ${eventName}`));
407
+ }, options.timeout);
408
+ });
409
+ }
410
+ //#endregion
411
+ //#region packages/ag-react/src/ui/wrappers/with-select.ts
412
+ /**
413
+ * withSelect - Interactive CLI selection list
414
+ */
415
+ /**
416
+ * Display an interactive selection list in the terminal
417
+ *
418
+ * @example
419
+ * ```ts
420
+ * // Simple usage
421
+ * const color = await withSelect("Choose a color:", [
422
+ * { label: "Red", value: "red" },
423
+ * { label: "Green", value: "green" },
424
+ * { label: "Blue", value: "blue" },
425
+ * ]);
426
+ *
427
+ * // With options
428
+ * const result = await withSelect(
429
+ * "Select item:",
430
+ * options,
431
+ * { initial: 2, maxVisible: 5 }
432
+ * );
433
+ * ```
434
+ */
435
+ async function withSelect(prompt, options, selectOptions = {}) {
436
+ const { initial = 0, maxVisible = 10 } = selectOptions;
437
+ const stream = process.stdout;
438
+ const stdin = process.stdin;
439
+ if (!isTTY(stream) || !stdin.isTTY) return options[initial]?.value ?? options[0].value;
440
+ return new Promise((resolve, reject) => {
441
+ let highlightIndex = Math.min(Math.max(0, initial), options.length - 1);
442
+ let linesRendered = 0;
443
+ stdin.setRawMode(true);
444
+ stdin.resume();
445
+ stdin.setEncoding("utf8");
446
+ write(CURSOR_HIDE, stream);
447
+ function render() {
448
+ if (linesRendered > 0) write(cursorUp(linesRendered), stream);
449
+ const scrollOffset = Math.max(0, Math.min(highlightIndex - Math.floor(maxVisible / 2), options.length - maxVisible));
450
+ const visibleCount = Math.min(maxVisible, options.length);
451
+ const visibleOptions = options.slice(scrollOffset, scrollOffset + visibleCount);
452
+ const hasMoreAbove = scrollOffset > 0;
453
+ const hasMoreBelow = scrollOffset + visibleCount < options.length;
454
+ write(`
455
+ let lines = 1;
456
+ if (hasMoreAbove) {
457
+ write(`
458
  ${chalk.dim("...")}\n`, stream);
459
+ lines++;
460
+ }
461
+ for (let i = 0; i < visibleOptions.length; i++) {
462
+ const option = visibleOptions[i];
463
+ const isHighlighted = scrollOffset + i === highlightIndex;
464
+ write(`
465
+ lines++;
466
+ }
467
+ if (hasMoreBelow) {
468
+ write(`
1
469
  ${chalk.dim("...")}\n`, stream);
470
+ lines++;
471
+ }
472
+ linesRendered = lines;
473
+ }
474
+ function cleanup() {
475
+ stdin.setRawMode(false);
476
+ stdin.pause();
477
+ stdin.removeListener("data", onKeypress);
478
+ write(CURSOR_SHOW, stream);
479
+ }
480
+ function onKeypress(key) {
481
+ key.charCodeAt(0);
482
+ if (key === "") {
483
+ cleanup();
484
+ reject(/* @__PURE__ */ new Error("User cancelled"));
485
+ return;
486
+ }
487
+ if (key === "\r" || key === "\n") {
488
+ cleanup();
489
+ resolve(options[highlightIndex].value);
490
+ return;
491
+ }
492
+ if (key === "\x1B" && key.length === 1) {
493
+ cleanup();
494
+ reject(/* @__PURE__ */ new Error("User cancelled"));
495
+ return;
496
+ }
497
+ if (key.startsWith("\x1B[")) {
498
+ const code = key.slice(2);
499
+ if (code === "A") {
500
+ highlightIndex = Math.max(0, highlightIndex - 1);
501
+ render();
502
+ } else if (code === "B") {
503
+ highlightIndex = Math.min(options.length - 1, highlightIndex + 1);
504
+ render();
505
+ }
506
+ return;
507
+ }
508
+ if (key === "j" || key === "J") {
509
+ highlightIndex = Math.min(options.length - 1, highlightIndex + 1);
510
+ render();
511
+ return;
512
+ }
513
+ if (key === "k" || key === "K") {
514
+ highlightIndex = Math.max(0, highlightIndex - 1);
515
+ render();
516
+ return;
517
+ }
518
+ if (key === " ") {
519
+ cleanup();
520
+ resolve(options[highlightIndex].value);
521
+ return;
522
+ }
523
+ }
524
+ stdin.on("data", onKeypress);
525
+ render();
526
+ });
527
+ }
528
+ /**
529
+ * Create a reusable select instance for multiple selections
530
+ *
531
+ * @example
532
+ * ```ts
533
+ * const select = createSelect({
534
+ * maxVisible: 5,
535
+ * });
536
+ *
537
+ * const first = await select("Choose first:", options1);
538
+ * const second = await select("Choose second:", options2);
539
+ * ```
540
+ */
541
+ function createSelect(defaultOptions = {}) {
542
+ return (prompt, options, overrides = {}) => withSelect(prompt, options, {
543
+ ...defaultOptions,
544
+ ...overrides
545
+ });
546
+ }
547
+ //#endregion
548
+ //#region packages/ag-react/src/ui/wrappers/with-text-input.ts
549
+ /**
550
+ * withTextInput - CLI wrapper for text input prompts
551
+ */
552
+ /**
553
+ * Prompt for text input in the terminal
554
+ *
555
+ * @example
556
+ * ```ts
557
+ * // Simple usage
558
+ * const name = await withTextInput("What is your name?");
559
+ *
560
+ * // With options
561
+ * const password = await withTextInput("Password:", { mask: "*" });
562
+ *
563
+ * // With validation
564
+ * const email = await withTextInput("Email:", {
565
+ * validate: (v) => v.includes("@") ? undefined : "Invalid email"
566
+ * });
567
+ *
568
+ * // With autocomplete
569
+ * const fruit = await withTextInput("Pick a fruit:", {
570
+ * autocomplete: ["apple", "banana", "cherry"]
571
+ * });
572
+ * ```
573
+ */
574
+ async function withTextInput(prompt, options = {}) {
575
+ const stream = options.stream ?? process.stdout;
576
+ const inputStream = options.inputStream ?? process.stdin;
577
+ const isTty = isTTY(stream);
578
+ let value = options.defaultValue ?? "";
579
+ let cursorPosition = value.length;
580
+ let errorMessage;
581
+ if (inputStream.isTTY) inputStream.setRawMode(true);
582
+ inputStream.resume();
583
+ const render = () => {
584
+ const displayValue = options.mask ? options.mask.repeat(value.length) : value;
585
+ const suggestion = getAutocompleteSuggestion(value, options.autocomplete);
586
+ const suggestionSuffix = suggestion ? chalk.dim(suggestion.slice(value.length)) : "";
587
+ const beforeCursor = displayValue.slice(0, cursorPosition);
588
+ const cursorChar = displayValue[cursorPosition] ?? " ";
589
+ const afterCursor = displayValue.slice(cursorPosition + 1);
590
+ const inputDisplay = !value && options.placeholder ? chalk.dim(options.placeholder) + chalk.inverse(" ") : beforeCursor + chalk.inverse(cursorChar) + afterCursor + suggestionSuffix;
591
+ const errorDisplay = errorMessage ? chalk.red(` (${errorMessage})`) : "";
592
+ const line = `${chalk.cyan("?")} ${chalk.bold(prompt)} ${inputDisplay}${errorDisplay}`;
593
+ if (isTty) write(`
594
+ };
595
+ if (isTty) write(CURSOR_HIDE, stream);
596
+ render();
597
+ return new Promise((resolve, reject) => {
598
+ const cleanup = () => {
599
+ inputStream.removeListener("data", onData);
600
+ inputStream.removeListener("error", onError);
601
+ if (inputStream.isTTY) inputStream.setRawMode(false);
602
+ inputStream.pause();
603
+ if (isTty) write(CURSOR_SHOW, stream);
604
+ };
605
+ const submit = () => {
606
+ if (options.validate) {
607
+ const error = options.validate(value);
608
+ if (error) {
609
+ errorMessage = error;
610
+ render();
611
+ return;
612
+ }
613
+ }
614
+ cleanup();
615
+ const displayValue = options.mask ? options.mask.repeat(value.length) : value;
616
+ write(`
617
+ resolve(value);
618
+ };
619
+ const onError = (err) => {
620
+ cleanup();
621
+ reject(err);
622
+ };
623
+ const onData = (data) => {
624
+ const input = data.toString();
625
+ errorMessage = void 0;
626
+ for (let i = 0; i < input.length; i++) {
627
+ const char = input[i];
628
+ const code = char.charCodeAt(0);
629
+ if (code === 13 || code === 10) {
630
+ submit();
631
+ return;
632
+ }
633
+ if (code === 3) {
634
+ cleanup();
635
+ write("\n", stream);
636
+ reject(/* @__PURE__ */ new Error("User aborted"));
637
+ return;
638
+ }
639
+ if (code === 27) {
640
+ if (input[i + 1] === "[") {
641
+ const arrowCode = input[i + 2];
642
+ if (arrowCode === "D") {
643
+ cursorPosition = Math.max(0, cursorPosition - 1);
644
+ i += 2;
645
+ continue;
646
+ }
647
+ if (arrowCode === "C") {
648
+ cursorPosition = Math.min(value.length, cursorPosition + 1);
649
+ i += 2;
650
+ continue;
651
+ }
652
+ if (arrowCode === "H") {
653
+ cursorPosition = 0;
654
+ i += 2;
655
+ continue;
656
+ }
657
+ if (arrowCode === "F") {
658
+ cursorPosition = value.length;
659
+ i += 2;
660
+ continue;
661
+ }
662
+ i += 2;
663
+ continue;
664
+ }
665
+ value = "";
666
+ cursorPosition = 0;
667
+ continue;
668
+ }
669
+ if (code === 127 || code === 8) {
670
+ if (cursorPosition > 0) {
671
+ value = value.slice(0, cursorPosition - 1) + value.slice(cursorPosition);
672
+ cursorPosition--;
673
+ }
674
+ continue;
675
+ }
676
+ if (code === 4) {
677
+ if (cursorPosition < value.length) value = value.slice(0, cursorPosition) + value.slice(cursorPosition + 1);
678
+ continue;
679
+ }
680
+ if (code === 9) {
681
+ const suggestion = getAutocompleteSuggestion(value, options.autocomplete);
682
+ if (suggestion) {
683
+ value = suggestion;
684
+ cursorPosition = value.length;
685
+ }
686
+ continue;
687
+ }
688
+ if (code === 1) {
689
+ cursorPosition = 0;
690
+ continue;
691
+ }
692
+ if (code === 5) {
693
+ cursorPosition = value.length;
694
+ continue;
695
+ }
696
+ if (code === 21) {
697
+ value = value.slice(cursorPosition);
698
+ cursorPosition = 0;
699
+ continue;
700
+ }
701
+ if (code === 11) {
702
+ value = value.slice(0, cursorPosition);
703
+ continue;
704
+ }
705
+ if (code === 23) {
706
+ const before = value.slice(0, cursorPosition);
707
+ const after = value.slice(cursorPosition);
708
+ const trimmed = before.trimEnd();
709
+ const lastSpace = trimmed.lastIndexOf(" ");
710
+ const newBefore = lastSpace === -1 ? "" : trimmed.slice(0, lastSpace + 1);
711
+ value = newBefore + after;
712
+ cursorPosition = newBefore.length;
713
+ continue;
714
+ }
715
+ if (code >= 32 && code < 127) {
716
+ value = value.slice(0, cursorPosition) + char + value.slice(cursorPosition);
717
+ cursorPosition++;
718
+ continue;
719
+ }
720
+ if (code > 127) {
721
+ value = value.slice(0, cursorPosition) + char + value.slice(cursorPosition);
722
+ cursorPosition++;
723
+ continue;
724
+ }
725
+ }
726
+ render();
727
+ };
728
+ inputStream.on("data", onData);
729
+ inputStream.on("error", onError);
730
+ });
731
+ }
732
+ /**
733
+ * Create a text input instance for manual control
734
+ *
735
+ * @example
736
+ * ```ts
737
+ * const input = createTextInput("Name:", { placeholder: "Enter name" });
738
+ * input.render();
739
+ *
740
+ * // Later, get the value
741
+ * const value = await input.waitForSubmit();
742
+ * ```
743
+ */
744
+ function createTextInput(prompt, options = {}) {
745
+ const stream = options.stream ?? process.stdout;
746
+ const isTty = isTTY(stream);
747
+ let value = options.defaultValue ?? "";
748
+ let cursorPosition = value.length;
749
+ const render = () => {
750
+ const displayValue = options.mask ? options.mask.repeat(value.length) : value;
751
+ const suggestion = getAutocompleteSuggestion(value, options.autocomplete);
752
+ const suggestionSuffix = suggestion ? chalk.dim(suggestion.slice(value.length)) : "";
753
+ const beforeCursor = displayValue.slice(0, cursorPosition);
754
+ const cursorChar = displayValue[cursorPosition] ?? " ";
755
+ const afterCursor = displayValue.slice(cursorPosition + 1);
756
+ const inputDisplay = !value && options.placeholder ? chalk.dim(options.placeholder) + chalk.inverse(" ") : beforeCursor + chalk.inverse(cursorChar) + afterCursor + suggestionSuffix;
757
+ const line = `${chalk.cyan("?")} ${chalk.bold(prompt)} ${inputDisplay}`;
758
+ if (isTty) write(`
759
+ };
760
+ return {
761
+ get value() {
762
+ return value;
763
+ },
764
+ set value(v) {
765
+ value = v;
766
+ cursorPosition = Math.min(cursorPosition, v.length);
767
+ },
768
+ get cursorPosition() {
769
+ return cursorPosition;
770
+ },
771
+ set cursorPosition(pos) {
772
+ cursorPosition = Math.max(0, Math.min(value.length, pos));
773
+ },
774
+ render,
775
+ insert(char) {
776
+ value = value.slice(0, cursorPosition) + char + value.slice(cursorPosition);
777
+ cursorPosition += char.length;
778
+ },
779
+ backspace() {
780
+ if (cursorPosition > 0) {
781
+ value = value.slice(0, cursorPosition - 1) + value.slice(cursorPosition);
782
+ cursorPosition--;
783
+ }
784
+ },
785
+ delete() {
786
+ if (cursorPosition < value.length) value = value.slice(0, cursorPosition) + value.slice(cursorPosition + 1);
787
+ },
788
+ clear() {
789
+ value = "";
790
+ cursorPosition = 0;
791
+ },
792
+ acceptSuggestion() {
793
+ const suggestion = getAutocompleteSuggestion(value, options.autocomplete);
794
+ if (suggestion) {
795
+ value = suggestion;
796
+ cursorPosition = value.length;
797
+ }
798
+ }
799
+ };
800
+ }
801
+ /**
802
+ * Find a matching autocomplete suggestion for the current input
803
+ */
804
+ function getAutocompleteSuggestion(value, autocomplete) {
805
+ if (!value || !autocomplete?.length) return;
806
+ const lowerValue = value.toLowerCase();
807
+ return autocomplete.find((item) => item.toLowerCase().startsWith(lowerValue) && item.length > value.length);
808
+ }
809
+ //#endregion
810
+ export { waitForEvent as a, wrapGenerator as c, attachSpinner as d, withSpinner as f, withSelect as i, createProgressCallback as l, withTextInput as n, wrapEmitter as o, createSelect as r, withIterableProgress as s, createTextInput as t, withProgress as u };
811
+
812
+ //# sourceMappingURL=wrappers-hhL8EQ_n.mjs.map