zapdev 0.11.0 → 1.1.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 (3) hide show
  1. package/README.md +72 -39
  2. package/dist/cli.js +1814 -2080
  3. package/package.json +2 -3
package/dist/cli.js CHANGED
@@ -84,1698 +84,1700 @@ var require_src = __commonJS({
84
84
  }
85
85
  });
86
86
 
87
- // node_modules/@clack/core/dist/index.mjs
88
- import { styleText } from "node:util";
89
- import { stdout, stdin } from "node:process";
90
- import * as l from "node:readline";
91
- import l__default from "node:readline";
92
-
93
- // node_modules/fast-string-truncated-width/dist/utils.js
94
- var getCodePointsLength = /* @__PURE__ */ (() => {
95
- const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
96
- return (input) => {
97
- let surrogatePairsNr = 0;
98
- SURROGATE_PAIR_RE.lastIndex = 0;
99
- while (SURROGATE_PAIR_RE.test(input)) {
100
- surrogatePairsNr += 1;
101
- }
102
- return input.length - surrogatePairsNr;
103
- };
104
- })();
105
- var isFullWidth = (x2) => {
106
- return x2 === 12288 || x2 >= 65281 && x2 <= 65376 || x2 >= 65504 && x2 <= 65510;
107
- };
108
- var isWideNotCJKTNotEmoji = (x2) => {
109
- return x2 === 8987 || x2 === 9001 || x2 >= 12272 && x2 <= 12287 || x2 >= 12289 && x2 <= 12350 || x2 >= 12441 && x2 <= 12543 || x2 >= 12549 && x2 <= 12591 || x2 >= 12593 && x2 <= 12686 || x2 >= 12688 && x2 <= 12771 || x2 >= 12783 && x2 <= 12830 || x2 >= 12832 && x2 <= 12871 || x2 >= 12880 && x2 <= 19903 || x2 >= 65040 && x2 <= 65049 || x2 >= 65072 && x2 <= 65106 || x2 >= 65108 && x2 <= 65126 || x2 >= 65128 && x2 <= 65131 || x2 >= 127488 && x2 <= 127490 || x2 >= 127504 && x2 <= 127547 || x2 >= 127552 && x2 <= 127560 || x2 >= 131072 && x2 <= 196605 || x2 >= 196608 && x2 <= 262141;
110
- };
111
-
112
- // node_modules/fast-string-truncated-width/dist/index.js
113
- var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
114
- var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
115
- var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
116
- var TAB_RE = /\t{1,1000}/y;
117
- var EMOJI_RE = new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*", "yu");
118
- var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
119
- var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
120
- var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
121
- var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
122
- const LIMIT = truncationOptions.limit ?? Infinity;
123
- const ELLIPSIS = truncationOptions.ellipsis ?? "";
124
- const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
125
- const ANSI_WIDTH = 0;
126
- const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
127
- const TAB_WIDTH = widthOptions.tabWidth ?? 8;
128
- const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
129
- const FULL_WIDTH_WIDTH = 2;
130
- const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
131
- const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
132
- const PARSE_BLOCKS = [
133
- [LATIN_RE, REGULAR_WIDTH],
134
- [ANSI_RE, ANSI_WIDTH],
135
- [CONTROL_RE, CONTROL_WIDTH],
136
- [TAB_RE, TAB_WIDTH],
137
- [EMOJI_RE, EMOJI_WIDTH],
138
- [CJKT_WIDE_RE, WIDE_WIDTH]
139
- ];
140
- let indexPrev = 0;
141
- let index = 0;
142
- let length = input.length;
143
- let lengthExtra = 0;
144
- let truncationEnabled = false;
145
- let truncationIndex = length;
146
- let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
147
- let unmatchedStart = 0;
148
- let unmatchedEnd = 0;
149
- let width = 0;
150
- let widthExtra = 0;
151
- outer: while (true) {
152
- if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
153
- const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
154
- lengthExtra = 0;
155
- for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
156
- const codePoint = char.codePointAt(0) || 0;
157
- if (isFullWidth(codePoint)) {
158
- widthExtra = FULL_WIDTH_WIDTH;
159
- } else if (isWideNotCJKTNotEmoji(codePoint)) {
160
- widthExtra = WIDE_WIDTH;
161
- } else {
162
- widthExtra = REGULAR_WIDTH;
163
- }
164
- if (width + widthExtra > truncationLimit) {
165
- truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
166
- }
167
- if (width + widthExtra > LIMIT) {
168
- truncationEnabled = true;
169
- break outer;
170
- }
171
- lengthExtra += char.length;
172
- width += widthExtra;
173
- }
174
- unmatchedStart = unmatchedEnd = 0;
175
- }
176
- if (index >= length) {
177
- break outer;
178
- }
179
- for (let i3 = 0, l3 = PARSE_BLOCKS.length; i3 < l3; i3++) {
180
- const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i3];
181
- BLOCK_RE.lastIndex = index;
182
- if (BLOCK_RE.test(input)) {
183
- lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
184
- widthExtra = lengthExtra * BLOCK_WIDTH;
185
- if (width + widthExtra > truncationLimit) {
186
- truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
187
- }
188
- if (width + widthExtra > LIMIT) {
189
- truncationEnabled = true;
190
- break outer;
191
- }
192
- width += widthExtra;
193
- unmatchedStart = indexPrev;
194
- unmatchedEnd = index;
195
- index = indexPrev = BLOCK_RE.lastIndex;
196
- continue outer;
197
- }
198
- }
199
- index += 1;
200
- }
201
- return {
202
- width: truncationEnabled ? truncationLimit : width,
203
- index: truncationEnabled ? truncationIndex : length,
204
- truncated: truncationEnabled,
205
- ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
206
- };
207
- };
208
- var dist_default = getStringTruncatedWidth;
209
-
210
- // node_modules/fast-string-width/dist/index.js
211
- var NO_TRUNCATION2 = {
212
- limit: Infinity,
213
- ellipsis: "",
214
- ellipsisWidth: 0
215
- };
216
- var fastStringWidth = (input, options = {}) => {
217
- return dist_default(input, NO_TRUNCATION2, options).width;
218
- };
219
- var dist_default2 = fastStringWidth;
220
-
221
- // node_modules/fast-wrap-ansi/lib/main.js
222
- var ESC = "\x1B";
223
- var CSI = "\x9B";
224
- var END_CODE = 39;
225
- var ANSI_ESCAPE_BELL = "\x07";
226
- var ANSI_CSI = "[";
227
- var ANSI_OSC = "]";
228
- var ANSI_SGR_TERMINATOR = "m";
229
- var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
230
- var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
231
- var getClosingCode = (openingCode) => {
232
- if (openingCode >= 30 && openingCode <= 37)
233
- return 39;
234
- if (openingCode >= 90 && openingCode <= 97)
235
- return 39;
236
- if (openingCode >= 40 && openingCode <= 47)
237
- return 49;
238
- if (openingCode >= 100 && openingCode <= 107)
239
- return 49;
240
- if (openingCode === 1 || openingCode === 2)
241
- return 22;
242
- if (openingCode === 3)
243
- return 23;
244
- if (openingCode === 4)
245
- return 24;
246
- if (openingCode === 7)
247
- return 27;
248
- if (openingCode === 8)
249
- return 28;
250
- if (openingCode === 9)
251
- return 29;
252
- if (openingCode === 0)
253
- return 0;
254
- return void 0;
255
- };
256
- var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
257
- var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
258
- var wrapWord = (rows, word, columns) => {
259
- const characters = word[Symbol.iterator]();
260
- let isInsideEscape = false;
261
- let isInsideLinkEscape = false;
262
- let lastRow = rows.at(-1);
263
- let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
264
- let currentCharacter = characters.next();
265
- let nextCharacter = characters.next();
266
- let rawCharacterIndex = 0;
267
- while (!currentCharacter.done) {
268
- const character = currentCharacter.value;
269
- const characterLength = dist_default2(character);
270
- if (visible + characterLength <= columns) {
271
- rows[rows.length - 1] += character;
272
- } else {
273
- rows.push(character);
274
- visible = 0;
275
- }
276
- if (character === ESC || character === CSI) {
277
- isInsideEscape = true;
278
- isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
279
- }
280
- if (isInsideEscape) {
281
- if (isInsideLinkEscape) {
282
- if (character === ANSI_ESCAPE_BELL) {
283
- isInsideEscape = false;
284
- isInsideLinkEscape = false;
285
- }
286
- } else if (character === ANSI_SGR_TERMINATOR) {
287
- isInsideEscape = false;
288
- }
289
- } else {
290
- visible += characterLength;
291
- if (visible === columns && !nextCharacter.done) {
292
- rows.push("");
293
- visible = 0;
294
- }
295
- }
296
- currentCharacter = nextCharacter;
297
- nextCharacter = characters.next();
298
- rawCharacterIndex += character.length;
299
- }
300
- lastRow = rows.at(-1);
301
- if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
302
- rows[rows.length - 2] += rows.pop();
303
- }
304
- };
305
- var stringVisibleTrimSpacesRight = (string) => {
306
- const words = string.split(" ");
307
- let last = words.length;
308
- while (last) {
309
- if (dist_default2(words[last - 1])) {
310
- break;
311
- }
312
- last--;
313
- }
314
- if (last === words.length) {
315
- return string;
316
- }
317
- return words.slice(0, last).join(" ") + words.slice(last).join("");
318
- };
319
- var exec = (string, columns, options = {}) => {
320
- if (options.trim !== false && string.trim() === "") {
321
- return "";
322
- }
323
- let returnValue = "";
324
- let escapeCode;
325
- let escapeUrl;
326
- const words = string.split(" ");
327
- let rows = [""];
328
- let rowLength = 0;
329
- for (let index = 0; index < words.length; index++) {
330
- const word = words[index];
331
- if (options.trim !== false) {
332
- const row = rows.at(-1) ?? "";
333
- const trimmed = row.trimStart();
334
- if (row.length !== trimmed.length) {
335
- rows[rows.length - 1] = trimmed;
336
- rowLength = dist_default2(trimmed);
337
- }
338
- }
339
- if (index !== 0) {
340
- if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
341
- rows.push("");
342
- rowLength = 0;
343
- }
344
- if (rowLength || options.trim === false) {
345
- rows[rows.length - 1] += " ";
346
- rowLength++;
347
- }
348
- }
349
- const wordLength = dist_default2(word);
350
- if (options.hard && wordLength > columns) {
351
- const remainingColumns = columns - rowLength;
352
- const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
353
- const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
354
- if (breaksStartingNextLine < breaksStartingThisLine) {
355
- rows.push("");
356
- }
357
- wrapWord(rows, word, columns);
358
- rowLength = dist_default2(rows.at(-1) ?? "");
359
- continue;
360
- }
361
- if (rowLength + wordLength > columns && rowLength && wordLength) {
362
- if (options.wordWrap === false && rowLength < columns) {
363
- wrapWord(rows, word, columns);
364
- rowLength = dist_default2(rows.at(-1) ?? "");
365
- continue;
366
- }
367
- rows.push("");
368
- rowLength = 0;
369
- }
370
- if (rowLength + wordLength > columns && options.wordWrap === false) {
371
- wrapWord(rows, word, columns);
372
- rowLength = dist_default2(rows.at(-1) ?? "");
373
- continue;
374
- }
375
- rows[rows.length - 1] += word;
376
- rowLength += wordLength;
377
- }
378
- if (options.trim !== false) {
379
- rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
380
- }
381
- const preString = rows.join("\n");
382
- let inSurrogate = false;
383
- for (let i3 = 0; i3 < preString.length; i3++) {
384
- const character = preString[i3];
385
- returnValue += character;
386
- if (!inSurrogate) {
387
- inSurrogate = character >= "\uD800" && character <= "\uDBFF";
388
- if (inSurrogate) {
389
- continue;
390
- }
391
- } else {
392
- inSurrogate = false;
393
- }
394
- if (character === ESC || character === CSI) {
395
- GROUP_REGEX.lastIndex = i3 + 1;
396
- const groupsResult = GROUP_REGEX.exec(preString);
397
- const groups = groupsResult?.groups;
398
- if (groups?.code !== void 0) {
399
- const code = Number.parseFloat(groups.code);
400
- escapeCode = code === END_CODE ? void 0 : code;
401
- } else if (groups?.uri !== void 0) {
402
- escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
403
- }
404
- }
405
- if (preString[i3 + 1] === "\n") {
406
- if (escapeUrl) {
407
- returnValue += wrapAnsiHyperlink("");
408
- }
409
- const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
410
- if (escapeCode && closingCode) {
411
- returnValue += wrapAnsiCode(closingCode);
412
- }
413
- } else if (character === "\n") {
414
- if (escapeCode && getClosingCode(escapeCode)) {
415
- returnValue += wrapAnsiCode(escapeCode);
416
- }
417
- if (escapeUrl) {
418
- returnValue += wrapAnsiHyperlink(escapeUrl);
419
- }
420
- }
421
- }
422
- return returnValue;
423
- };
424
- var CRLF_OR_LF = /\r?\n/;
425
- function wrapAnsi(string, columns, options) {
426
- return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
427
- }
428
-
429
- // node_modules/@clack/core/dist/index.mjs
430
- var import_sisteransi = __toESM(require_src(), 1);
431
- import { ReadStream } from "node:tty";
432
- function findCursor(s2, o2, l3) {
433
- if (!l3.some((r3) => !r3.disabled))
434
- return s2;
435
- const t3 = s2 + o2, n4 = Math.max(l3.length - 1, 0), e2 = t3 < 0 ? n4 : t3 > n4 ? 0 : t3;
436
- return l3[e2]?.disabled ? findCursor(e2, o2 < 0 ? -1 : 1, l3) : e2;
437
- }
438
- var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
439
- var t = [
440
- "January",
441
- "February",
442
- "March",
443
- "April",
444
- "May",
445
- "June",
446
- "July",
447
- "August",
448
- "September",
449
- "October",
450
- "November",
451
- "December"
452
- ];
453
- var settings = {
454
- actions: new Set(a$1),
455
- aliases: /* @__PURE__ */ new Map([
456
- // vim support
457
- ["k", "up"],
458
- ["j", "down"],
459
- ["h", "left"],
460
- ["l", "right"],
461
- ["", "cancel"],
462
- // opinionated defaults!
463
- ["escape", "cancel"]
464
- ]),
465
- messages: {
466
- cancel: "Canceled",
467
- error: "Something went wrong"
468
- },
469
- withGuide: true,
470
- date: {
471
- monthNames: [...t],
472
- messages: {
473
- required: "Please enter a valid date",
474
- invalidMonth: "There are only 12 months in a year",
475
- invalidDay: (n4, e2) => `There are only ${n4} days in ${e2}`,
476
- afterMin: (n4) => `Date must be on or after ${n4.toISOString().slice(0, 10)}`,
477
- beforeMax: (n4) => `Date must be on or before ${n4.toISOString().slice(0, 10)}`
478
- }
479
- }
480
- };
481
- function isActionKey(n4, e2) {
482
- if (typeof n4 == "string")
483
- return settings.aliases.get(n4) === e2;
484
- for (const s2 of n4)
485
- if (s2 !== void 0 && isActionKey(s2, e2))
486
- return true;
487
- return false;
488
- }
489
- function diffLines(i3, s2) {
490
- if (i3 === s2) return;
491
- const e2 = i3.split(`
492
- `), t3 = s2.split(`
493
- `), r3 = Math.max(e2.length, t3.length), f2 = [];
494
- for (let n4 = 0; n4 < r3; n4++)
495
- e2[n4] !== t3[n4] && f2.push(n4);
496
- return {
497
- lines: f2,
498
- numLinesBefore: e2.length,
499
- numLinesAfter: t3.length,
500
- numLines: r3
501
- };
502
- }
503
- var R = globalThis.process.platform.startsWith("win");
504
- var CANCEL_SYMBOL = /* @__PURE__ */ Symbol("clack:cancel");
505
- function isCancel(e2) {
506
- return e2 === CANCEL_SYMBOL;
507
- }
508
- function setRawMode(e2, r3) {
509
- const o2 = e2;
510
- o2.isTTY && o2.setRawMode(r3);
511
- }
512
- function block({
513
- input: e2 = stdin,
514
- output: r3 = stdout,
515
- overwrite: o2 = true,
516
- hideCursor: t3 = true
517
- } = {}) {
518
- const s2 = l.createInterface({
519
- input: e2,
520
- output: r3,
521
- prompt: "",
522
- tabSize: 1
523
- });
524
- l.emitKeypressEvents(e2, s2), e2 instanceof ReadStream && e2.isTTY && e2.setRawMode(true);
525
- const n4 = (f2, { name: a3, sequence: p2 }) => {
526
- const c3 = String(f2);
527
- if (isActionKey([c3, a3, p2], "cancel")) {
528
- t3 && r3.write(import_sisteransi.cursor.show), process.exit(0);
529
- return;
530
- }
531
- if (!o2) return;
532
- const i3 = a3 === "return" ? 0 : -1, m2 = a3 === "return" ? -1 : 0;
533
- l.moveCursor(r3, i3, m2, () => {
534
- l.clearLine(r3, 1, () => {
535
- e2.once("keypress", n4);
536
- });
537
- });
538
- };
539
- return t3 && r3.write(import_sisteransi.cursor.hide), e2.once("keypress", n4), () => {
540
- e2.off("keypress", n4), t3 && r3.write(import_sisteransi.cursor.show), e2 instanceof ReadStream && e2.isTTY && !R && e2.setRawMode(false), s2.terminal = false, s2.close();
541
- };
542
- }
543
- var getColumns = (e2) => "columns" in e2 && typeof e2.columns == "number" ? e2.columns : 80;
544
- var getRows = (e2) => "rows" in e2 && typeof e2.rows == "number" ? e2.rows : 20;
545
- function wrapTextWithPrefix(e2, r3, o2, t3 = o2, s2 = o2, n4) {
546
- const f2 = getColumns(e2 ?? stdout);
547
- return wrapAnsi(r3, f2 - o2.length, {
548
- hard: true,
549
- trim: false
550
- }).split(`
551
- `).map((c3, i3, m2) => {
552
- const d2 = n4 ? n4(c3, i3) : c3;
553
- return i3 === 0 ? `${t3}${d2}` : i3 === m2.length - 1 ? `${s2}${d2}` : `${o2}${d2}`;
554
- }).join(`
555
- `);
556
- }
557
- function runValidation(e2, n4) {
558
- if ("~standard" in e2) {
559
- const a3 = e2["~standard"].validate(n4);
560
- if (a3 instanceof Promise)
561
- throw new TypeError(
562
- "Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic."
563
- );
564
- return a3.issues?.at(0)?.message;
565
- }
566
- return e2(n4);
567
- }
568
- var V = class {
569
- input;
570
- output;
571
- _abortSignal;
572
- rl;
573
- opts;
574
- _render;
575
- _track = false;
576
- _prevFrame = "";
577
- _subscribers = /* @__PURE__ */ new Map();
578
- _cursor = 0;
579
- state = "initial";
580
- error = "";
581
- value;
582
- userInput = "";
583
- constructor(t3, e2 = true) {
584
- const { input: i3 = stdin, output: n4 = stdout, render: s2, signal: r3, ...o2 } = t3;
585
- this.opts = o2, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s2.bind(this), this._track = e2, this._abortSignal = r3, this.input = i3, this.output = n4;
586
- }
587
- /**
588
- * Unsubscribe all listeners
589
- */
590
- unsubscribe() {
591
- this._subscribers.clear();
592
- }
593
- /**
594
- * Set a subscriber with opts
595
- * @param event - The event name
596
- */
597
- setSubscriber(t3, e2) {
598
- const i3 = this._subscribers.get(t3) ?? [];
599
- i3.push(e2), this._subscribers.set(t3, i3);
600
- }
601
- /**
602
- * Subscribe to an event
603
- * @param event - The event name
604
- * @param cb - The callback
605
- */
606
- on(t3, e2) {
607
- this.setSubscriber(t3, { cb: e2 });
608
- }
609
- /**
610
- * Subscribe to an event once
611
- * @param event - The event name
612
- * @param cb - The callback
613
- */
614
- once(t3, e2) {
615
- this.setSubscriber(t3, { cb: e2, once: true });
616
- }
617
- /**
618
- * Emit an event with data
619
- * @param event - The event name
620
- * @param data - The data to pass to the callback
621
- */
622
- emit(t3, ...e2) {
623
- const i3 = this._subscribers.get(t3) ?? [], n4 = [];
624
- for (const s2 of i3)
625
- s2.cb(...e2), s2.once && n4.push(() => i3.splice(i3.indexOf(s2), 1));
626
- for (const s2 of n4)
627
- s2();
628
- }
629
- prompt() {
630
- return new Promise((t3) => {
631
- if (this._abortSignal) {
632
- if (this._abortSignal.aborted)
633
- return this.state = "cancel", this.close(), t3(CANCEL_SYMBOL);
634
- this._abortSignal.addEventListener(
635
- "abort",
636
- () => {
637
- this.state = "cancel", this.close();
638
- },
639
- { once: true }
640
- );
87
+ // node_modules/citty/dist/_chunks/libs/scule.mjs
88
+ var NUMBER_CHAR_RE = /\d/;
89
+ var STR_SPLITTERS = [
90
+ "-",
91
+ "_",
92
+ "/",
93
+ "."
94
+ ];
95
+ function isUppercase(char = "") {
96
+ if (NUMBER_CHAR_RE.test(char)) return;
97
+ return char !== char.toLowerCase();
98
+ }
99
+ function splitByCase(str, separators) {
100
+ const splitters = separators ?? STR_SPLITTERS;
101
+ const parts = [];
102
+ if (!str || typeof str !== "string") return parts;
103
+ let buff = "";
104
+ let previousUpper;
105
+ let previousSplitter;
106
+ for (const char of str) {
107
+ const isSplitter = splitters.includes(char);
108
+ if (isSplitter === true) {
109
+ parts.push(buff);
110
+ buff = "";
111
+ previousUpper = void 0;
112
+ continue;
113
+ }
114
+ const isUpper = isUppercase(char);
115
+ if (previousSplitter === false) {
116
+ if (previousUpper === false && isUpper === true) {
117
+ parts.push(buff);
118
+ buff = char;
119
+ previousUpper = isUpper;
120
+ continue;
641
121
  }
642
- this.rl = l__default.createInterface({
643
- input: this.input,
644
- tabSize: 2,
645
- prompt: "",
646
- escapeCodeTimeout: 50,
647
- terminal: true
648
- }), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
649
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t3(this.value);
650
- }), this.once("cancel", () => {
651
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t3(CANCEL_SYMBOL);
652
- });
653
- });
654
- }
655
- _isActionKey(t3, e2) {
656
- return t3 === " ";
657
- }
658
- _shouldSubmit(t3, e2) {
659
- return true;
660
- }
661
- _setValue(t3) {
662
- this.value = t3, this.emit("value", this.value);
663
- }
664
- _setUserInput(t3, e2) {
665
- this.userInput = t3 ?? "", this.emit("userInput", this.userInput), e2 && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
666
- }
667
- _clearUserInput() {
668
- this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
669
- }
670
- onKeypress(t3, e2) {
671
- if (this._track && e2.name !== "return" && (e2.name && this._isActionKey(t3, e2) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e2?.name && (!this._track && settings.aliases.has(e2.name) && this.emit("cursor", settings.aliases.get(e2.name)), settings.actions.has(e2.name) && this.emit("cursor", e2.name)), t3 && (t3.toLowerCase() === "y" || t3.toLowerCase() === "n") && this.emit("confirm", t3.toLowerCase() === "y"), this.emit("key", t3, e2), e2?.name === "return" && this._shouldSubmit(t3, e2)) {
672
- if (this.opts.validate) {
673
- const i3 = runValidation(this.opts.validate, this.value);
674
- i3 && (this.error = i3 instanceof Error ? i3.message : i3, this.state = "error", this.rl?.write(this.userInput));
122
+ if (previousUpper === true && isUpper === false && buff.length > 1) {
123
+ const lastChar = buff.at(-1);
124
+ parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
125
+ buff = lastChar + char;
126
+ previousUpper = isUpper;
127
+ continue;
675
128
  }
676
- this.state !== "error" && (this.state = "submit");
677
129
  }
678
- isActionKey([t3, e2?.name, e2?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
679
- }
680
- close() {
681
- this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
682
- `), setRawMode(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
683
- }
684
- restoreCursor() {
685
- const t3 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
686
- `).length - 1;
687
- this.output.write(import_sisteransi.cursor.move(-999, t3 * -1));
130
+ buff += char;
131
+ previousUpper = isUpper;
132
+ previousSplitter = isSplitter;
688
133
  }
689
- render() {
690
- const t3 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
691
- hard: true,
692
- trim: false
693
- });
694
- if (t3 !== this._prevFrame) {
695
- if (this.state === "initial")
696
- this.output.write(import_sisteransi.cursor.hide);
697
- else {
698
- const e2 = diffLines(this._prevFrame, t3), i3 = getRows(this.output);
699
- if (this.restoreCursor(), e2) {
700
- const n4 = Math.max(0, e2.numLinesAfter - i3), s2 = Math.max(0, e2.numLinesBefore - i3);
701
- let r3 = e2.lines.find((o2) => o2 >= n4);
702
- if (r3 === void 0) {
703
- this._prevFrame = t3;
704
- return;
705
- }
706
- if (e2.lines.length === 1) {
707
- this.output.write(import_sisteransi.cursor.move(0, r3 - s2)), this.output.write(import_sisteransi.erase.lines(1));
708
- const o2 = t3.split(`
709
- `);
710
- this.output.write(o2[r3]), this._prevFrame = t3, this.output.write(import_sisteransi.cursor.move(0, o2.length - r3 - 1));
711
- return;
712
- } else if (e2.lines.length > 1) {
713
- if (n4 < s2)
714
- r3 = n4;
715
- else {
716
- const h3 = r3 - s2;
717
- h3 > 0 && this.output.write(import_sisteransi.cursor.move(0, h3));
718
- }
719
- this.output.write(import_sisteransi.erase.down());
720
- const f2 = t3.split(`
721
- `).slice(r3);
722
- this.output.write(f2.join(`
723
- `)), this._prevFrame = t3;
724
- return;
725
- }
726
- }
727
- this.output.write(import_sisteransi.erase.down());
728
- }
729
- this.output.write(t3), this.state === "initial" && (this.state = "active"), this._prevFrame = t3;
730
- }
134
+ parts.push(buff);
135
+ return parts;
136
+ }
137
+ function upperFirst(str) {
138
+ return str ? str[0].toUpperCase() + str.slice(1) : "";
139
+ }
140
+ function lowerFirst(str) {
141
+ return str ? str[0].toLowerCase() + str.slice(1) : "";
142
+ }
143
+ function pascalCase(str, opts) {
144
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => upperFirst(opts?.normalize ? p2.toLowerCase() : p2)).join("") : "";
145
+ }
146
+ function camelCase(str, opts) {
147
+ return lowerFirst(pascalCase(str || "", opts));
148
+ }
149
+ function kebabCase(str, joiner) {
150
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => p2.toLowerCase()).join(joiner ?? "-") : "";
151
+ }
152
+ function snakeCase(str) {
153
+ return kebabCase(str || "", "_");
154
+ }
155
+
156
+ // node_modules/citty/dist/index.mjs
157
+ import { parseArgs as parseArgs$1 } from "node:util";
158
+ function toArray(val) {
159
+ if (Array.isArray(val)) return val;
160
+ return val === void 0 ? [] : [val];
161
+ }
162
+ function formatLineColumns(lines, linePrefix = "") {
163
+ const maxLength = [];
164
+ for (const line of lines) for (const [i3, element] of line.entries()) maxLength[i3] = Math.max(maxLength[i3] || 0, element.length);
165
+ return lines.map((l3) => l3.map((c3, i3) => linePrefix + c3[i3 === 0 ? "padStart" : "padEnd"](maxLength[i3])).join(" ")).join("\n");
166
+ }
167
+ function resolveValue(input) {
168
+ return typeof input === "function" ? input() : input;
169
+ }
170
+ var CLIError = class extends Error {
171
+ code;
172
+ constructor(message, code) {
173
+ super(message);
174
+ this.name = "CLIError";
175
+ this.code = code;
731
176
  }
732
177
  };
733
- var r = class extends V {
734
- get cursor() {
735
- return this.value ? 0 : 1;
736
- }
737
- get _value() {
738
- return this.cursor === 0;
178
+ function parseRawArgs(args = [], opts = {}) {
179
+ const booleans = new Set(opts.boolean || []);
180
+ const strings = new Set(opts.string || []);
181
+ const aliasMap = opts.alias || {};
182
+ const defaults = opts.default || {};
183
+ const aliasToMain = /* @__PURE__ */ new Map();
184
+ const mainToAliases = /* @__PURE__ */ new Map();
185
+ for (const [key, value] of Object.entries(aliasMap)) {
186
+ const targets = value;
187
+ for (const target of targets) {
188
+ aliasToMain.set(key, target);
189
+ if (!mainToAliases.has(target)) mainToAliases.set(target, []);
190
+ mainToAliases.get(target).push(key);
191
+ aliasToMain.set(target, key);
192
+ if (!mainToAliases.has(key)) mainToAliases.set(key, []);
193
+ mainToAliases.get(key).push(target);
194
+ }
739
195
  }
740
- constructor(t3) {
741
- super(t3, false), this.value = !!t3.initialValue, this.on("userInput", () => {
742
- this.value = this._value;
743
- }), this.on("confirm", (i3) => {
744
- this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i3, this.state = "submit", this.close();
745
- }), this.on("cursor", () => {
746
- this.value = !this.value;
747
- });
196
+ const options = {};
197
+ function getType(name) {
198
+ if (booleans.has(name)) return "boolean";
199
+ const aliases = mainToAliases.get(name) || [];
200
+ for (const alias of aliases) if (booleans.has(alias)) return "boolean";
201
+ return "string";
748
202
  }
749
- };
750
- var n$1 = class n extends V {
751
- options;
752
- cursor = 0;
753
- get _selectedValue() {
754
- return this.options[this.cursor];
203
+ function isStringType(name) {
204
+ if (strings.has(name)) return true;
205
+ const aliases = mainToAliases.get(name) || [];
206
+ for (const alias of aliases) if (strings.has(alias)) return true;
207
+ return false;
755
208
  }
756
- changeValue() {
757
- const e2 = this._selectedValue;
758
- this.value = e2 === void 0 ? void 0 : e2.value;
209
+ const allOptions = /* @__PURE__ */ new Set([
210
+ ...booleans,
211
+ ...strings,
212
+ ...Object.keys(aliasMap),
213
+ ...Object.values(aliasMap).flat(),
214
+ ...Object.keys(defaults)
215
+ ]);
216
+ for (const name of allOptions) if (!options[name]) options[name] = {
217
+ type: getType(name),
218
+ default: defaults[name]
219
+ };
220
+ for (const [alias, main2] of aliasToMain.entries()) if (alias.length === 1 && options[main2] && !options[main2].short) options[main2].short = alias;
221
+ const processedArgs = [];
222
+ const negatedFlags = {};
223
+ for (let i3 = 0; i3 < args.length; i3++) {
224
+ const arg = args[i3];
225
+ if (arg === "--") {
226
+ processedArgs.push(...args.slice(i3));
227
+ break;
228
+ }
229
+ if (arg.startsWith("--no-")) {
230
+ const flagName = arg.slice(5);
231
+ negatedFlags[flagName] = true;
232
+ continue;
233
+ }
234
+ processedArgs.push(arg);
759
235
  }
760
- constructor(e2) {
761
- super(e2, false), this.options = e2.options;
762
- const o2 = this.options.findIndex(({ value: s2 }) => s2 === e2.initialValue), t3 = o2 === -1 ? 0 : o2;
763
- this.cursor = this.options[t3]?.disabled ? findCursor(t3, 1, this.options) : t3, this.changeValue(), this.on("cursor", (s2) => {
764
- switch (s2) {
765
- case "left":
766
- case "up":
767
- this.cursor = findCursor(this.cursor, -1, this.options);
768
- break;
769
- case "down":
770
- case "right":
771
- this.cursor = findCursor(this.cursor, 1, this.options);
772
- break;
773
- }
774
- this.changeValue();
236
+ let parsed;
237
+ try {
238
+ parsed = parseArgs$1({
239
+ args: processedArgs,
240
+ options: Object.keys(options).length > 0 ? options : void 0,
241
+ allowPositionals: true,
242
+ strict: false
775
243
  });
244
+ } catch {
245
+ parsed = {
246
+ values: {},
247
+ positionals: processedArgs
248
+ };
776
249
  }
777
- };
778
- var n2 = class extends V {
779
- get userInputWithCursor() {
780
- if (this.state === "submit")
781
- return this.userInput;
782
- const t3 = this.userInput;
783
- if (this.cursor >= t3.length)
784
- return `${this.userInput}\u2588`;
785
- const r3 = t3.slice(0, this.cursor), s2 = t3.slice(this.cursor, this.cursor + 1), e2 = t3.slice(this.cursor + 1);
786
- return `${r3}${styleText("inverse", s2)}${e2}`;
250
+ const out = { _: [] };
251
+ out._ = parsed.positionals;
252
+ for (const [key, value] of Object.entries(parsed.values)) {
253
+ let coerced = value;
254
+ if (getType(key) === "boolean" && typeof value === "string") coerced = value !== "false";
255
+ else if (isStringType(key) && typeof value === "boolean") coerced = "";
256
+ out[key] = coerced;
787
257
  }
788
- get cursor() {
789
- return this._cursor;
258
+ for (const [name] of Object.entries(negatedFlags)) {
259
+ out[name] = false;
260
+ const mainName = aliasToMain.get(name);
261
+ if (mainName) out[mainName] = false;
262
+ const aliases = mainToAliases.get(name);
263
+ if (aliases) for (const alias of aliases) out[alias] = false;
790
264
  }
791
- constructor(t3) {
792
- super({
793
- ...t3,
794
- initialUserInput: t3.initialUserInput ?? t3.initialValue
795
- }), this.on("userInput", (r3) => {
796
- this._setValue(r3);
797
- }), this.on("finalize", () => {
798
- this.value || (this.value = t3.defaultValue), this.value === void 0 && (this.value = "");
799
- });
265
+ for (const [alias, main2] of aliasToMain.entries()) {
266
+ if (out[alias] !== void 0 && out[main2] === void 0) out[main2] = out[alias];
267
+ if (out[main2] !== void 0 && out[alias] === void 0) out[alias] = out[main2];
268
+ if (out[alias] !== out[main2] && defaults[main2] === out[main2]) out[main2] = out[alias];
800
269
  }
801
- };
802
-
803
- // node_modules/@clack/prompts/dist/index.mjs
804
- import { styleText as styleText2, stripVTControlCharacters } from "node:util";
805
- import process$1 from "node:process";
806
- var import_sisteransi2 = __toESM(require_src(), 1);
807
- function isUnicodeSupported() {
808
- if (process$1.platform !== "win32") {
809
- return process$1.env.TERM !== "linux";
270
+ return out;
271
+ }
272
+ var noColor = /* @__PURE__ */ (() => {
273
+ const env = globalThis.process?.env ?? {};
274
+ return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
275
+ })();
276
+ var _c = (c3, r3 = 39) => (t3) => noColor ? t3 : `\x1B[${c3}m${t3}\x1B[${r3}m`;
277
+ var bold = /* @__PURE__ */ _c(1, 22);
278
+ var cyan = /* @__PURE__ */ _c(36);
279
+ var gray = /* @__PURE__ */ _c(90);
280
+ var underline = /* @__PURE__ */ _c(4, 24);
281
+ function parseArgs(rawArgs, argsDef) {
282
+ const parseOptions = {
283
+ boolean: [],
284
+ string: [],
285
+ alias: {},
286
+ default: {}
287
+ };
288
+ const args = resolveArgs(argsDef);
289
+ for (const arg of args) {
290
+ if (arg.type === "positional") continue;
291
+ if (arg.type === "string" || arg.type === "enum") parseOptions.string.push(arg.name);
292
+ else if (arg.type === "boolean") parseOptions.boolean.push(arg.name);
293
+ if (arg.default !== void 0) parseOptions.default[arg.name] = arg.default;
294
+ if (arg.alias) parseOptions.alias[arg.name] = arg.alias;
295
+ const camelName = camelCase(arg.name);
296
+ const kebabName = kebabCase(arg.name);
297
+ if (camelName !== arg.name || kebabName !== arg.name) {
298
+ const existingAliases = toArray(parseOptions.alias[arg.name] || []);
299
+ if (camelName !== arg.name && !existingAliases.includes(camelName)) existingAliases.push(camelName);
300
+ if (kebabName !== arg.name && !existingAliases.includes(kebabName)) existingAliases.push(kebabName);
301
+ if (existingAliases.length > 0) parseOptions.alias[arg.name] = existingAliases;
302
+ }
810
303
  }
811
- return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
304
+ const parsed = parseRawArgs(rawArgs, parseOptions);
305
+ const [...positionalArguments] = parsed._;
306
+ const parsedArgsProxy = new Proxy(parsed, { get(target, prop) {
307
+ return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
308
+ } });
309
+ for (const [, arg] of args.entries()) if (arg.type === "positional") {
310
+ const nextPositionalArgument = positionalArguments.shift();
311
+ if (nextPositionalArgument !== void 0) parsedArgsProxy[arg.name] = nextPositionalArgument;
312
+ else if (arg.default === void 0 && arg.required !== false) throw new CLIError(`Missing required positional argument: ${arg.name.toUpperCase()}`, "EARG");
313
+ else parsedArgsProxy[arg.name] = arg.default;
314
+ } else if (arg.type === "enum") {
315
+ const argument = parsedArgsProxy[arg.name];
316
+ const options = arg.options || [];
317
+ if (argument !== void 0 && options.length > 0 && !options.includes(argument)) throw new CLIError(`Invalid value for argument: ${cyan(`--${arg.name}`)} (${cyan(argument)}). Expected one of: ${options.map((o2) => cyan(o2)).join(", ")}.`, "EARG");
318
+ } else if (arg.required && parsedArgsProxy[arg.name] === void 0) throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
319
+ return parsedArgsProxy;
812
320
  }
813
- var unicode = isUnicodeSupported();
814
- var isCI = () => process.env.CI === "true";
815
- var unicodeOr = (o2, e2) => unicode ? o2 : e2;
816
- var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
817
- var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
818
- var S_STEP_ERROR = unicodeOr("\u25B2", "x");
819
- var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
820
- var S_BAR_START = unicodeOr("\u250C", "T");
821
- var S_BAR = unicodeOr("\u2502", "|");
822
- var S_BAR_END = unicodeOr("\u2514", "\u2014");
823
- var S_BAR_START_RIGHT = unicodeOr("\u2510", "T");
824
- var S_BAR_END_RIGHT = unicodeOr("\u2518", "\u2014");
825
- var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
826
- var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
827
- var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
828
- var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
829
- var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
830
- var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
831
- var S_BAR_H = unicodeOr("\u2500", "-");
832
- var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
833
- var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
834
- var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
835
- var S_CORNER_BOTTOM_LEFT = unicodeOr("\u2570", "+");
836
- var S_CORNER_TOP_LEFT = unicodeOr("\u256D", "+");
837
- var S_INFO = unicodeOr("\u25CF", "\u2022");
838
- var S_SUCCESS = unicodeOr("\u25C6", "*");
839
- var S_WARN = unicodeOr("\u25B2", "!");
840
- var S_ERROR = unicodeOr("\u25A0", "x");
841
- var symbol = (o2) => {
842
- switch (o2) {
843
- case "initial":
844
- case "active":
845
- return styleText2("cyan", S_STEP_ACTIVE);
846
- case "cancel":
847
- return styleText2("red", S_STEP_CANCEL);
848
- case "error":
849
- return styleText2("yellow", S_STEP_ERROR);
850
- case "submit":
851
- return styleText2("green", S_STEP_SUBMIT);
321
+ function resolveArgs(argsDef) {
322
+ const args = [];
323
+ for (const [name, argDef] of Object.entries(argsDef || {})) args.push({
324
+ ...argDef,
325
+ name,
326
+ alias: toArray(argDef.alias)
327
+ });
328
+ return args;
329
+ }
330
+ async function resolvePlugins(plugins) {
331
+ return Promise.all(plugins.map((p2) => resolveValue(p2)));
332
+ }
333
+ function defineCommand(def) {
334
+ return def;
335
+ }
336
+ async function runCommand(cmd, opts) {
337
+ const cmdArgs = await resolveValue(cmd.args || {});
338
+ const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
339
+ const context = {
340
+ rawArgs: opts.rawArgs,
341
+ args: parsedArgs,
342
+ data: opts.data,
343
+ cmd
344
+ };
345
+ const plugins = await resolvePlugins(cmd.plugins ?? []);
346
+ let result;
347
+ let runError;
348
+ try {
349
+ for (const plugin of plugins) await plugin.setup?.(context);
350
+ if (typeof cmd.setup === "function") await cmd.setup(context);
351
+ const subCommands = await resolveValue(cmd.subCommands);
352
+ if (subCommands && Object.keys(subCommands).length > 0) {
353
+ const subCommandArgIndex = findSubCommandIndex(opts.rawArgs, cmdArgs);
354
+ const explicitName = opts.rawArgs[subCommandArgIndex];
355
+ if (explicitName) {
356
+ const subCommand = await _findSubCommand(subCommands, explicitName);
357
+ if (!subCommand) throw new CLIError(`Unknown command ${cyan(explicitName)}`, "E_UNKNOWN_COMMAND");
358
+ await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
359
+ } else {
360
+ const defaultSubCommand = await resolveValue(cmd.default);
361
+ if (defaultSubCommand) {
362
+ if (cmd.run) throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
363
+ const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
364
+ if (!subCommand) throw new CLIError(`Default sub command ${cyan(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
365
+ await runCommand(subCommand, { rawArgs: opts.rawArgs });
366
+ } else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
367
+ }
368
+ }
369
+ if (typeof cmd.run === "function") result = await cmd.run(context);
370
+ } catch (error) {
371
+ runError = error;
852
372
  }
853
- };
854
- var symbolBar = (o2) => {
855
- switch (o2) {
856
- case "initial":
857
- case "active":
858
- return styleText2("cyan", S_BAR);
859
- case "cancel":
860
- return styleText2("red", S_BAR);
861
- case "error":
862
- return styleText2("yellow", S_BAR);
863
- case "submit":
864
- return styleText2("green", S_BAR);
373
+ const cleanupErrors = [];
374
+ if (typeof cmd.cleanup === "function") try {
375
+ await cmd.cleanup(context);
376
+ } catch (error) {
377
+ cleanupErrors.push(error);
378
+ }
379
+ for (const plugin of [...plugins].reverse()) try {
380
+ await plugin.cleanup?.(context);
381
+ } catch (error) {
382
+ cleanupErrors.push(error);
383
+ }
384
+ if (runError) throw runError;
385
+ if (cleanupErrors.length === 1) throw cleanupErrors[0];
386
+ if (cleanupErrors.length > 1) throw new Error("Multiple cleanup errors", { cause: cleanupErrors });
387
+ return { result };
388
+ }
389
+ async function resolveSubCommand(cmd, rawArgs, parent) {
390
+ const subCommands = await resolveValue(cmd.subCommands);
391
+ if (subCommands && Object.keys(subCommands).length > 0) {
392
+ const subCommandArgIndex = findSubCommandIndex(rawArgs, await resolveValue(cmd.args || {}));
393
+ const subCommandName = rawArgs[subCommandArgIndex];
394
+ const subCommand = await _findSubCommand(subCommands, subCommandName);
395
+ if (subCommand) return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
865
396
  }
866
- };
867
- function formatInstructionFooter(o2, e2) {
868
- const r3 = [`${e2 ? `${styleText2("cyan", S_BAR)} ` : ""}${o2.join(" \u2022 ")}`];
869
- return e2 && r3.push(styleText2("cyan", S_BAR_END)), r3;
397
+ return [cmd, parent];
870
398
  }
871
- var I = (l3, e2, w2, p2, b2, C2 = false) => {
872
- let r3 = e2, O2 = 0;
873
- if (C2)
874
- for (let i3 = p2 - 1; i3 >= w2; i3--) {
875
- const m2 = l3[i3];
876
- if (m2 && (r3 -= m2.length), O2++, r3 <= b2) break;
399
+ async function _findSubCommand(subCommands, name) {
400
+ if (name in subCommands) return resolveValue(subCommands[name]);
401
+ for (const sub of Object.values(subCommands)) {
402
+ const resolved = await resolveValue(sub);
403
+ const meta = await resolveValue(resolved?.meta);
404
+ if (meta?.alias) {
405
+ if (toArray(meta.alias).includes(name)) return resolved;
877
406
  }
878
- else
879
- for (let i3 = w2; i3 < p2; i3++) {
880
- const m2 = l3[i3];
881
- if (m2 && (r3 -= m2.length), O2++, r3 <= b2) break;
407
+ }
408
+ }
409
+ function findSubCommandIndex(rawArgs, argsDef) {
410
+ for (let i3 = 0; i3 < rawArgs.length; i3++) {
411
+ const arg = rawArgs[i3];
412
+ if (arg === "--") return -1;
413
+ if (arg.startsWith("-")) {
414
+ if (!arg.includes("=") && _isValueFlag(arg, argsDef)) i3++;
415
+ continue;
882
416
  }
883
- return { lineCount: r3, removals: O2 };
884
- };
885
- var limitOptions = ({
886
- cursor: l3,
887
- options: e2,
888
- style: w2,
889
- output: p2 = process.stdout,
890
- maxItems: b2 = Number.POSITIVE_INFINITY,
891
- columnPadding: C2 = 0,
892
- rowPadding: r3 = 4
893
- }) => {
894
- const i3 = getColumns(p2) - C2, m2 = getRows(p2), M = styleText2("dim", "..."), v2 = Math.max(m2 - r3, 0), a3 = Math.max(Math.min(b2, v2), 5);
895
- let f2 = 0;
896
- l3 >= a3 - 3 && (f2 = Math.max(
897
- Math.min(l3 - a3 + 3, e2.length - a3),
898
- 0
899
- ));
900
- let d2 = a3 < e2.length && f2 > 0, c3 = a3 < e2.length && f2 + a3 < e2.length;
901
- const W2 = Math.min(
902
- f2 + a3,
903
- e2.length
904
- ), s2 = [];
905
- let g2 = 0;
906
- d2 && g2++, c3 && g2++;
907
- const T2 = f2 + (d2 ? 1 : 0), y2 = W2 - (c3 ? 1 : 0);
908
- for (let t3 = T2; t3 < y2; t3++) {
909
- const n4 = e2[t3], o2 = n4 ? w2(n4, t3 === l3) : "", h3 = wrapAnsi(o2, i3, {
910
- hard: true,
911
- trim: false
912
- }).split(`
913
- `);
914
- s2.push(h3), g2 += h3.length;
417
+ return i3;
915
418
  }
916
- if (g2 > v2) {
917
- let t3 = 0, n4 = 0, o2 = g2;
918
- const h3 = l3 - T2;
919
- let u4 = v2;
920
- const L = () => I(s2, o2, 0, h3, u4), E2 = () => I(
921
- s2,
922
- o2,
923
- h3 + 1,
924
- s2.length,
925
- u4,
926
- true
927
- );
928
- d2 ? ({ lineCount: o2, removals: t3 } = L(), o2 > u4 && (c3 || (u4 -= 1), { lineCount: o2, removals: n4 } = E2())) : (c3 || (u4 -= 1), { lineCount: o2, removals: n4 } = E2(), o2 > u4 && (u4 -= 1, { lineCount: o2, removals: t3 } = L())), t3 > 0 && (d2 = true, s2.splice(0, t3)), n4 > 0 && (c3 = true, s2.splice(s2.length - n4, n4));
419
+ return -1;
420
+ }
421
+ function _isValueFlag(flag, argsDef) {
422
+ const name = flag.replace(/^-{1,2}/, "");
423
+ const normalized = camelCase(name);
424
+ for (const [key, def] of Object.entries(argsDef)) {
425
+ if (def.type !== "string" && def.type !== "enum") continue;
426
+ if (normalized === camelCase(key)) return true;
427
+ if ((Array.isArray(def.alias) ? def.alias : def.alias ? [def.alias] : []).includes(name)) return true;
929
428
  }
930
- const x2 = [];
931
- d2 && x2.push(M);
932
- for (const t3 of s2)
933
- for (const n4 of t3)
934
- x2.push(n4);
935
- return c3 && x2.push(M), x2;
936
- };
937
- var confirm = (i3) => {
938
- const a3 = i3.active ?? "Yes", s2 = i3.inactive ?? "No";
939
- return new r({
940
- active: a3,
941
- inactive: s2,
942
- signal: i3.signal,
943
- input: i3.input,
944
- output: i3.output,
945
- initialValue: i3.initialValue ?? true,
946
- render() {
947
- const e2 = i3.withGuide ?? settings.withGuide, u4 = `${symbol(this.state)} `, l3 = e2 ? `${styleText2("gray", S_BAR)} ` : "", f2 = wrapTextWithPrefix(
948
- i3.output,
949
- i3.message,
950
- l3,
951
- u4
952
- ), o2 = `${e2 ? `${styleText2("gray", S_BAR)}
953
- ` : ""}${f2}
954
- `, c3 = this.value ? a3 : s2;
955
- switch (this.state) {
956
- case "submit": {
957
- const r3 = e2 ? `${styleText2("gray", S_BAR)} ` : "";
958
- return `${o2}${r3}${styleText2("dim", c3)}`;
959
- }
960
- case "cancel": {
961
- const r3 = e2 ? `${styleText2("gray", S_BAR)} ` : "";
962
- return `${o2}${r3}${styleText2(["strikethrough", "dim"], c3)}${e2 ? `
963
- ${styleText2("gray", S_BAR)}` : ""}`;
964
- }
965
- default: {
966
- const r3 = e2 ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e2 ? styleText2("cyan", S_BAR_END) : "";
967
- return `${o2}${r3}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a3}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a3)}`}${i3.vertical ? e2 ? `
968
- ${styleText2("cyan", S_BAR)} ` : `
969
- ` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s2)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s2}`}
970
- ${g2}
971
- `;
972
- }
973
- }
429
+ return false;
430
+ }
431
+ async function showUsage(cmd, parent) {
432
+ try {
433
+ console.log(await renderUsage(cmd, parent) + "\n");
434
+ } catch (error) {
435
+ console.error(error);
436
+ }
437
+ }
438
+ var negativePrefixRe = /^no[-A-Z]/;
439
+ async function renderUsage(cmd, parent) {
440
+ const cmdMeta = await resolveValue(cmd.meta || {});
441
+ const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
442
+ const parentMeta = await resolveValue(parent?.meta || {});
443
+ const commandName = `${parentMeta.name ? `${parentMeta.name} ` : ""}` + (cmdMeta.name || process.argv[1]);
444
+ const argLines = [];
445
+ const posLines = [];
446
+ const commandsLines = [];
447
+ const usageLine = [];
448
+ for (const arg of cmdArgs) if (arg.type === "positional") {
449
+ const name = arg.name.toUpperCase();
450
+ const isRequired = arg.required !== false && arg.default === void 0;
451
+ posLines.push([cyan(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
452
+ usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
453
+ } else {
454
+ const isRequired = arg.required === true && arg.default === void 0;
455
+ const argStr = [...(arg.alias || []).map((a3) => `-${a3}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
456
+ argLines.push([cyan(argStr), renderDescription(arg, isRequired)]);
457
+ if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
458
+ const negativeArgStr = [...(arg.alias || []).map((a3) => `--no-${a3}`), `--no-${arg.name}`].join(", ");
459
+ argLines.push([cyan(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
974
460
  }
975
- }).prompt();
976
- };
977
- var MULTISELECT_INSTRUCTIONS = [
978
- `${styleText2("dim", "\u2191/\u2193")} to navigate`,
979
- `${styleText2("dim", "Space:")} select`,
980
- `${styleText2("dim", "Enter:")} confirm`
981
- ];
982
- var log = {
983
- message: (s2 = [], {
984
- symbol: e2 = styleText2("gray", S_BAR),
985
- secondarySymbol: r3 = styleText2("gray", S_BAR),
986
- output: m2 = process.stdout,
987
- spacing: l3 = 1,
988
- withGuide: c3
989
- } = {}) => {
990
- const t3 = [], o2 = c3 ?? settings.withGuide, f2 = o2 ? r3 : "", O2 = o2 ? `${e2} ` : "", u4 = o2 ? `${r3} ` : "";
991
- for (let i3 = 0; i3 < l3; i3++)
992
- t3.push(f2);
993
- const g2 = Array.isArray(s2) ? s2 : s2.split(`
994
- `);
995
- if (g2.length > 0) {
996
- const [i3, ...y2] = g2;
997
- i3.length > 0 ? t3.push(`${O2}${i3}`) : t3.push(o2 ? e2 : "");
998
- for (const p2 of y2)
999
- p2.length > 0 ? t3.push(`${u4}${p2}`) : t3.push(o2 ? r3 : "");
461
+ if (isRequired) usageLine.push(`--${arg.name}` + renderValueHint(arg));
462
+ }
463
+ if (cmd.subCommands) {
464
+ const commandNames = [];
465
+ const subCommands = await resolveValue(cmd.subCommands);
466
+ for (const [name, sub] of Object.entries(subCommands)) {
467
+ const meta = await resolveValue((await resolveValue(sub))?.meta);
468
+ if (meta?.hidden) continue;
469
+ const aliases = toArray(meta?.alias);
470
+ const label = [name, ...aliases].join(", ");
471
+ commandsLines.push([cyan(label), meta?.description || ""]);
472
+ commandNames.push(name, ...aliases);
1000
473
  }
1001
- m2.write(`${t3.join(`
1002
- `)}
1003
- `);
474
+ usageLine.push(commandNames.join("|"));
475
+ }
476
+ const usageLines = [];
477
+ const version = cmdMeta.version || parentMeta.version;
478
+ usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
479
+ const hasOptions = argLines.length > 0 || posLines.length > 0;
480
+ usageLines.push(`${underline(bold("USAGE"))} ${cyan(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
481
+ if (posLines.length > 0) {
482
+ usageLines.push(underline(bold("ARGUMENTS")), "");
483
+ usageLines.push(formatLineColumns(posLines, " "));
484
+ usageLines.push("");
485
+ }
486
+ if (argLines.length > 0) {
487
+ usageLines.push(underline(bold("OPTIONS")), "");
488
+ usageLines.push(formatLineColumns(argLines, " "));
489
+ usageLines.push("");
490
+ }
491
+ if (commandsLines.length > 0) {
492
+ usageLines.push(underline(bold("COMMANDS")), "");
493
+ usageLines.push(formatLineColumns(commandsLines, " "));
494
+ usageLines.push("", `Use ${cyan(`${commandName} <command> --help`)} for more information about a command.`);
495
+ }
496
+ return usageLines.filter((l3) => typeof l3 === "string").join("\n");
497
+ }
498
+ function renderValueHint(arg) {
499
+ const valueHint = arg.valueHint ? `=<${arg.valueHint}>` : "";
500
+ const fallbackValueHint = valueHint || `=<${snakeCase(arg.name)}>`;
501
+ if (!arg.type || arg.type === "positional" || arg.type === "boolean") return valueHint;
502
+ if (arg.type === "enum" && arg.options?.length) return `=<${arg.options.join("|")}>`;
503
+ return fallbackValueHint;
504
+ }
505
+ function renderDescription(arg, required) {
506
+ const requiredHint = required ? gray("(Required)") : "";
507
+ const defaultHint = arg.default === void 0 ? "" : gray(`(Default: ${arg.default})`);
508
+ return [
509
+ arg.description,
510
+ requiredHint,
511
+ defaultHint
512
+ ].filter(Boolean).join(" ");
513
+ }
514
+ async function runMain(cmd, opts = {}) {
515
+ const rawArgs = opts.rawArgs || process.argv.slice(2);
516
+ const showUsage$1 = opts.showUsage || showUsage;
517
+ try {
518
+ const builtinFlags = await _resolveBuiltinFlags(cmd);
519
+ if (builtinFlags.help.length > 0 && rawArgs.some((arg) => builtinFlags.help.includes(arg))) {
520
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
521
+ process.exit(0);
522
+ } else if (rawArgs.length === 1 && builtinFlags.version.includes(rawArgs[0])) {
523
+ const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
524
+ if (!meta?.version) throw new CLIError("No version specified", "E_NO_VERSION");
525
+ console.log(meta.version);
526
+ } else await runCommand(cmd, { rawArgs });
527
+ } catch (error) {
528
+ if (error instanceof CLIError) {
529
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
530
+ console.error(error.message);
531
+ } else console.error(error, "\n");
532
+ process.exit(1);
533
+ }
534
+ }
535
+ async function _resolveBuiltinFlags(cmd) {
536
+ const argsDef = await resolveValue(cmd.args || {});
537
+ const userNames = /* @__PURE__ */ new Set();
538
+ const userAliases = /* @__PURE__ */ new Set();
539
+ for (const [name, def] of Object.entries(argsDef)) {
540
+ userNames.add(name);
541
+ for (const alias of toArray(def.alias)) userAliases.add(alias);
542
+ }
543
+ return {
544
+ help: _getBuiltinFlags("help", "h", userNames, userAliases),
545
+ version: _getBuiltinFlags("version", "v", userNames, userAliases)
546
+ };
547
+ }
548
+ function _getBuiltinFlags(long, short, userNames, userAliases) {
549
+ if (userNames.has(long) || userAliases.has(long)) return [];
550
+ if (userNames.has(short) || userAliases.has(short)) return [`--${long}`];
551
+ return [`--${long}`, `-${short}`];
552
+ }
553
+
554
+ // package.json
555
+ var package_default = {
556
+ name: "zapdev",
557
+ version: "1.1.0",
558
+ description: "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
559
+ type: "module",
560
+ bin: {
561
+ zapdev: "./dist/index.js"
1004
562
  },
1005
- info: (s2, e2) => {
1006
- log.message(s2, { ...e2, symbol: styleText2("blue", S_INFO) });
563
+ files: [
564
+ "dist"
565
+ ],
566
+ engines: {
567
+ node: ">=20"
1007
568
  },
1008
- success: (s2, e2) => {
1009
- log.message(s2, { ...e2, symbol: styleText2("green", S_SUCCESS) });
569
+ keywords: [
570
+ "git",
571
+ "cli",
572
+ "commit",
573
+ "conventional-commits",
574
+ "llm",
575
+ "ai"
576
+ ],
577
+ author: "Matthieu Vagnon <hi@mvagnon.dev>",
578
+ license: "MIT",
579
+ repository: {
580
+ type: "git",
581
+ url: "git+https://github.com/mvagnon/zapdev.git"
1010
582
  },
1011
- step: (s2, e2) => {
1012
- log.message(s2, { ...e2, symbol: styleText2("green", S_STEP_SUBMIT) });
583
+ homepage: "https://github.com/mvagnon/zapdev#readme",
584
+ bugs: {
585
+ url: "https://github.com/mvagnon/zapdev/issues"
1013
586
  },
1014
- warn: (s2, e2) => {
1015
- log.message(s2, { ...e2, symbol: styleText2("yellow", S_WARN) });
587
+ publishConfig: {
588
+ access: "public"
1016
589
  },
1017
- /** alias for `log.warn()`. */
1018
- warning: (s2, e2) => {
1019
- log.warn(s2, e2);
590
+ scripts: {
591
+ zapdev: "npm run build && node dist/index.js",
592
+ build: "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node20 --loader:.md=text --outfile=dist/cli.js && esbuild src/index.ts --platform=node --format=esm --target=node20 --outfile=dist/index.js",
593
+ lint: "eslint .",
594
+ typecheck: "tsc --noEmit",
595
+ test: "vitest run",
596
+ prepack: "npm run build"
1020
597
  },
1021
- error: (s2, e2) => {
1022
- log.message(s2, { ...e2, symbol: styleText2("red", S_ERROR) });
598
+ devDependencies: {
599
+ "@clack/prompts": "^1.6.0",
600
+ "@eslint/js": "^10.0.1",
601
+ "@eslint/json": "^2.0.0",
602
+ "@eslint/markdown": "^8.0.2",
603
+ "@types/node": "^26.1.1",
604
+ citty: "^0.2.2",
605
+ esbuild: "^0.28.1",
606
+ eslint: "^10.6.0",
607
+ jiti: "^2.7.0",
608
+ tinyexec: "^1.2.4",
609
+ typescript: "^6.0.3",
610
+ "typescript-eslint": "^8.62.1",
611
+ vitest: "^4.1.9"
1023
612
  }
1024
613
  };
1025
- var cancel = (o2 = "", t3) => {
1026
- const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
1027
- i3.write(`${e2}${styleText2("red", o2)}
1028
614
 
1029
- `);
1030
- };
1031
- var intro = (o2 = "", t3) => {
1032
- const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
1033
- i3.write(`${e2}${o2}
1034
- `);
1035
- };
1036
- var outro = (o2 = "", t3) => {
1037
- const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
1038
- ${styleText2("gray", S_BAR_END)} ` : "";
1039
- i3.write(`${e2}${o2}
615
+ // src/commands/commit.ts
616
+ import { basename } from "node:path";
1040
617
 
1041
- `);
1042
- };
1043
- var W = (l3) => styleText2("magenta", l3);
1044
- var spinner = ({
1045
- indicator: l3 = "dots",
1046
- onCancel: h3,
1047
- output: n4 = process.stdout,
1048
- cancelMessage: G,
1049
- errorMessage: O2,
1050
- frames: E2 = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
1051
- delay: F2 = unicode ? 80 : 120,
1052
- signal: m2,
1053
- ...I3
1054
- } = {}) => {
1055
- const u4 = isCI();
1056
- let M, T2, d2 = false, S2 = false, s2 = "", p2, w2 = performance.now();
1057
- const x2 = getColumns(n4), k2 = I3?.styleFrame ?? W, g2 = (e2) => {
1058
- const r3 = e2 > 1 ? O2 ?? settings.messages.error : G ?? settings.messages.cancel;
1059
- S2 = e2 === 1, d2 && (a3(r3, e2), S2 && typeof h3 == "function" && h3());
1060
- }, f2 = () => g2(2), i3 = () => g2(1), A = () => {
1061
- process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i3), process.on("SIGTERM", i3), process.on("exit", g2), m2 && m2.addEventListener("abort", i3);
1062
- }, H = () => {
1063
- process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i3), process.removeListener("SIGTERM", i3), process.removeListener("exit", g2), m2 && m2.removeEventListener("abort", i3);
1064
- }, y2 = () => {
1065
- if (p2 === void 0) return;
1066
- u4 && n4.write(`
1067
- `);
1068
- const r3 = wrapAnsi(p2, x2, {
1069
- hard: true,
1070
- trim: false
1071
- }).split(`
1072
- `);
1073
- r3.length > 1 && n4.write(import_sisteransi2.cursor.up(r3.length - 1)), n4.write(import_sisteransi2.cursor.to(0)), n4.write(import_sisteransi2.erase.down());
1074
- }, C2 = (e2) => e2.replace(/\.+$/, ""), _2 = (e2) => {
1075
- const r3 = (performance.now() - e2) / 1e3, t3 = Math.floor(r3 / 60), o2 = Math.floor(r3 % 60);
1076
- return t3 > 0 ? `[${t3}m ${o2}s]` : `[${o2}s]`;
1077
- }, N2 = I3.withGuide ?? settings.withGuide, P2 = (e2 = "") => {
1078
- d2 = true, M = block({ output: n4 }), s2 = C2(e2), w2 = performance.now(), N2 && n4.write(`${styleText2("gray", S_BAR)}
1079
- `);
1080
- let r3 = 0, t3 = 0;
1081
- A(), T2 = setInterval(() => {
1082
- if (u4 && s2 === p2)
1083
- return;
1084
- y2(), p2 = s2;
1085
- const o2 = k2(E2[r3]);
1086
- let v2;
1087
- if (u4)
1088
- v2 = `${o2} ${s2}...`;
1089
- else if (l3 === "timer")
1090
- v2 = `${o2} ${s2} ${_2(w2)}`;
1091
- else {
1092
- const B = ".".repeat(Math.floor(t3)).slice(0, 3);
1093
- v2 = `${o2} ${s2}${B}`;
1094
- }
1095
- const j2 = wrapAnsi(v2, x2, {
1096
- hard: true,
1097
- trim: false
1098
- });
1099
- n4.write(j2), r3 = r3 + 1 < E2.length ? r3 + 1 : 0, t3 = t3 < 4 ? t3 + 0.125 : 0;
1100
- }, F2);
1101
- }, a3 = (e2 = "", r3 = 0, t3 = false) => {
1102
- if (!d2) return;
1103
- d2 = false, clearInterval(T2), y2();
1104
- const o2 = r3 === 0 ? styleText2("green", S_STEP_SUBMIT) : r3 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
1105
- s2 = e2 ?? s2, t3 || (l3 === "timer" ? n4.write(`${o2} ${s2} ${_2(w2)}
1106
- `) : n4.write(`${o2} ${s2}
1107
- `)), H(), M();
1108
- };
1109
- return {
1110
- start: P2,
1111
- stop: (e2 = "") => a3(e2, 0),
1112
- message: (e2 = "") => {
1113
- s2 = C2(e2 ?? s2);
1114
- },
1115
- cancel: (e2 = "") => a3(e2, 1),
1116
- error: (e2 = "") => a3(e2, 2),
1117
- clear: () => a3("", 0, true),
1118
- get isCancelled() {
1119
- return S2;
1120
- }
1121
- };
1122
- };
1123
- var u2 = {
1124
- light: unicodeOr("\u2500", "-"),
1125
- heavy: unicodeOr("\u2501", "="),
1126
- block: unicodeOr("\u2588", "#")
1127
- };
1128
- var SELECT_INSTRUCTIONS = [
1129
- `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1130
- `${styleText2("dim", "Enter:")} confirm`
1131
- ];
1132
- var c = (t3, o2) => t3.includes(`
1133
- `) ? t3.split(`
1134
- `).map((d2) => o2(d2)).join(`
1135
- `) : o2(t3);
1136
- var select = (t3) => {
1137
- const o2 = (n4, m2) => {
1138
- if (n4 === void 0)
1139
- return "";
1140
- const s2 = n4.label ?? String(n4.value);
1141
- switch (m2) {
1142
- case "disabled":
1143
- return `${styleText2("gray", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("gray", i3))}${n4.hint ? ` ${styleText2("dim", `(${n4.hint ?? "disabled"})`)}` : ""}`;
1144
- case "selected":
1145
- return `${c(s2, (i3) => styleText2("dim", i3))}`;
1146
- case "active":
1147
- return `${styleText2("green", S_RADIO_ACTIVE)} ${s2}${n4.hint ? ` ${styleText2("dim", `(${n4.hint})`)}` : ""}`;
1148
- case "cancelled":
1149
- return `${c(s2, (i3) => styleText2(["strikethrough", "dim"], i3))}`;
1150
- default:
1151
- return `${styleText2("dim", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("dim", i3))}`;
1152
- }
1153
- }, d2 = t3.showInstructions ?? true;
1154
- return new n$1({
1155
- options: t3.options,
1156
- signal: t3.signal,
1157
- input: t3.input,
1158
- output: t3.output,
1159
- initialValue: t3.initialValue,
1160
- render() {
1161
- const n4 = t3.withGuide ?? settings.withGuide, m2 = `${symbol(this.state)} `, s2 = `${symbolBar(this.state)} `, i3 = wrapTextWithPrefix(
1162
- t3.output,
1163
- t3.message,
1164
- s2,
1165
- m2
1166
- ), u4 = `${n4 ? `${styleText2("gray", S_BAR)}
1167
- ` : ""}${i3}
1168
- `;
1169
- switch (this.state) {
1170
- case "submit": {
1171
- const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1172
- t3.output,
1173
- o2(this.options[this.cursor], "selected"),
1174
- r3
1175
- );
1176
- return `${u4}${a3}`;
618
+ // node_modules/@clack/core/dist/index.mjs
619
+ import { styleText } from "node:util";
620
+ import { stdout, stdin } from "node:process";
621
+ import * as l from "node:readline";
622
+ import l__default from "node:readline";
623
+
624
+ // node_modules/fast-string-truncated-width/dist/utils.js
625
+ var getCodePointsLength = /* @__PURE__ */ (() => {
626
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
627
+ return (input) => {
628
+ let surrogatePairsNr = 0;
629
+ SURROGATE_PAIR_RE.lastIndex = 0;
630
+ while (SURROGATE_PAIR_RE.test(input)) {
631
+ surrogatePairsNr += 1;
632
+ }
633
+ return input.length - surrogatePairsNr;
634
+ };
635
+ })();
636
+ var isFullWidth = (x2) => {
637
+ return x2 === 12288 || x2 >= 65281 && x2 <= 65376 || x2 >= 65504 && x2 <= 65510;
638
+ };
639
+ var isWideNotCJKTNotEmoji = (x2) => {
640
+ return x2 === 8987 || x2 === 9001 || x2 >= 12272 && x2 <= 12287 || x2 >= 12289 && x2 <= 12350 || x2 >= 12441 && x2 <= 12543 || x2 >= 12549 && x2 <= 12591 || x2 >= 12593 && x2 <= 12686 || x2 >= 12688 && x2 <= 12771 || x2 >= 12783 && x2 <= 12830 || x2 >= 12832 && x2 <= 12871 || x2 >= 12880 && x2 <= 19903 || x2 >= 65040 && x2 <= 65049 || x2 >= 65072 && x2 <= 65106 || x2 >= 65108 && x2 <= 65126 || x2 >= 65128 && x2 <= 65131 || x2 >= 127488 && x2 <= 127490 || x2 >= 127504 && x2 <= 127547 || x2 >= 127552 && x2 <= 127560 || x2 >= 131072 && x2 <= 196605 || x2 >= 196608 && x2 <= 262141;
641
+ };
642
+
643
+ // node_modules/fast-string-truncated-width/dist/index.js
644
+ var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
645
+ var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
646
+ var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
647
+ var TAB_RE = /\t{1,1000}/y;
648
+ var EMOJI_RE = new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*", "yu");
649
+ var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
650
+ var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
651
+ var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
652
+ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
653
+ const LIMIT = truncationOptions.limit ?? Infinity;
654
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
655
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
656
+ const ANSI_WIDTH = 0;
657
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
658
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
659
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
660
+ const FULL_WIDTH_WIDTH = 2;
661
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
662
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
663
+ const PARSE_BLOCKS = [
664
+ [LATIN_RE, REGULAR_WIDTH],
665
+ [ANSI_RE, ANSI_WIDTH],
666
+ [CONTROL_RE, CONTROL_WIDTH],
667
+ [TAB_RE, TAB_WIDTH],
668
+ [EMOJI_RE, EMOJI_WIDTH],
669
+ [CJKT_WIDE_RE, WIDE_WIDTH]
670
+ ];
671
+ let indexPrev = 0;
672
+ let index = 0;
673
+ let length = input.length;
674
+ let lengthExtra = 0;
675
+ let truncationEnabled = false;
676
+ let truncationIndex = length;
677
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
678
+ let unmatchedStart = 0;
679
+ let unmatchedEnd = 0;
680
+ let width = 0;
681
+ let widthExtra = 0;
682
+ outer: while (true) {
683
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
684
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
685
+ lengthExtra = 0;
686
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
687
+ const codePoint = char.codePointAt(0) || 0;
688
+ if (isFullWidth(codePoint)) {
689
+ widthExtra = FULL_WIDTH_WIDTH;
690
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
691
+ widthExtra = WIDE_WIDTH;
692
+ } else {
693
+ widthExtra = REGULAR_WIDTH;
1177
694
  }
1178
- case "cancel": {
1179
- const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1180
- t3.output,
1181
- o2(this.options[this.cursor], "cancelled"),
1182
- r3
1183
- );
1184
- return `${u4}${a3}${n4 ? `
1185
- ${styleText2("gray", S_BAR)}` : ""}`;
695
+ if (width + widthExtra > truncationLimit) {
696
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
1186
697
  }
1187
- default: {
1188
- const r3 = n4 ? `${styleText2("cyan", S_BAR)} ` : "", a3 = u4.split(`
1189
- `).length, p2 = d2 ? formatInstructionFooter(SELECT_INSTRUCTIONS, n4) : n4 ? [styleText2("cyan", S_BAR_END)] : [], b2 = p2.join(`
1190
- `), f2 = p2.length + 1;
1191
- return `${u4}${r3}${limitOptions({
1192
- output: t3.output,
1193
- cursor: this.cursor,
1194
- options: this.options,
1195
- maxItems: t3.maxItems,
1196
- columnPadding: r3.length,
1197
- rowPadding: a3 + f2,
1198
- style: (g2, x2) => o2(g2, g2.disabled ? "disabled" : x2 ? "active" : "inactive")
1199
- }).join(`
1200
- ${r3}`)}
1201
- ${b2}
1202
- `;
698
+ if (width + widthExtra > LIMIT) {
699
+ truncationEnabled = true;
700
+ break outer;
1203
701
  }
702
+ lengthExtra += char.length;
703
+ width += widthExtra;
1204
704
  }
705
+ unmatchedStart = unmatchedEnd = 0;
1205
706
  }
1206
- }).prompt();
1207
- };
1208
- var i = `${styleText2("gray", S_BAR)} `;
1209
- var text = (e2) => new n2({
1210
- validate: e2.validate,
1211
- placeholder: e2.placeholder,
1212
- defaultValue: e2.defaultValue,
1213
- initialValue: e2.initialValue,
1214
- output: e2.output,
1215
- signal: e2.signal,
1216
- input: e2.input,
1217
- render() {
1218
- const i3 = e2?.withGuide ?? settings.withGuide, s2 = `${`${i3 ? `${styleText2("gray", S_BAR)}
1219
- ` : ""}${symbol(this.state)} `}${e2.message}
1220
- `, c3 = e2.placeholder && e2.placeholder.length > 0 ? (
1221
- // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
1222
- styleText2("inverse", e2.placeholder[0]) + styleText2("dim", e2.placeholder.slice(1))
1223
- ) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, l3 = this.value ?? "";
1224
- switch (this.state) {
1225
- case "error": {
1226
- const n4 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r3 = i3 ? `${styleText2("yellow", S_BAR)} ` : "", d2 = i3 ? styleText2("yellow", S_BAR_END) : "";
1227
- return `${s2.trim()}
1228
- ${r3}${o2}
1229
- ${d2}${n4}
1230
- `;
1231
- }
1232
- case "submit": {
1233
- const n4 = l3 ? ` ${styleText2("dim", l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1234
- return `${s2}${r3}${n4}`;
1235
- }
1236
- case "cancel": {
1237
- const n4 = l3 ? ` ${styleText2(["strikethrough", "dim"], l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1238
- return `${s2}${r3}${n4}${l3.trim() ? `
1239
- ${r3}` : ""}`;
1240
- }
1241
- default: {
1242
- const n4 = i3 ? `${styleText2("cyan", S_BAR)} ` : "", r3 = i3 ? styleText2("cyan", S_BAR_END) : "";
1243
- return `${s2}${n4}${o2}
1244
- ${r3}
1245
- `;
707
+ if (index >= length) {
708
+ break outer;
709
+ }
710
+ for (let i3 = 0, l3 = PARSE_BLOCKS.length; i3 < l3; i3++) {
711
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i3];
712
+ BLOCK_RE.lastIndex = index;
713
+ if (BLOCK_RE.test(input)) {
714
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
715
+ widthExtra = lengthExtra * BLOCK_WIDTH;
716
+ if (width + widthExtra > truncationLimit) {
717
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
718
+ }
719
+ if (width + widthExtra > LIMIT) {
720
+ truncationEnabled = true;
721
+ break outer;
722
+ }
723
+ width += widthExtra;
724
+ unmatchedStart = indexPrev;
725
+ unmatchedEnd = index;
726
+ index = indexPrev = BLOCK_RE.lastIndex;
727
+ continue outer;
1246
728
  }
1247
729
  }
730
+ index += 1;
1248
731
  }
1249
- }).prompt();
732
+ return {
733
+ width: truncationEnabled ? truncationLimit : width,
734
+ index: truncationEnabled ? truncationIndex : length,
735
+ truncated: truncationEnabled,
736
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
737
+ };
738
+ };
739
+ var dist_default = getStringTruncatedWidth;
1250
740
 
1251
- // node_modules/citty/dist/_chunks/libs/scule.mjs
1252
- var NUMBER_CHAR_RE = /\d/;
1253
- var STR_SPLITTERS = [
1254
- "-",
1255
- "_",
1256
- "/",
1257
- "."
1258
- ];
1259
- function isUppercase(char = "") {
1260
- if (NUMBER_CHAR_RE.test(char)) return;
1261
- return char !== char.toLowerCase();
1262
- }
1263
- function splitByCase(str, separators) {
1264
- const splitters = separators ?? STR_SPLITTERS;
1265
- const parts = [];
1266
- if (!str || typeof str !== "string") return parts;
1267
- let buff = "";
1268
- let previousUpper;
1269
- let previousSplitter;
1270
- for (const char of str) {
1271
- const isSplitter = splitters.includes(char);
1272
- if (isSplitter === true) {
1273
- parts.push(buff);
1274
- buff = "";
1275
- previousUpper = void 0;
1276
- continue;
741
+ // node_modules/fast-string-width/dist/index.js
742
+ var NO_TRUNCATION2 = {
743
+ limit: Infinity,
744
+ ellipsis: "",
745
+ ellipsisWidth: 0
746
+ };
747
+ var fastStringWidth = (input, options = {}) => {
748
+ return dist_default(input, NO_TRUNCATION2, options).width;
749
+ };
750
+ var dist_default2 = fastStringWidth;
751
+
752
+ // node_modules/fast-wrap-ansi/lib/main.js
753
+ var ESC = "\x1B";
754
+ var CSI = "\x9B";
755
+ var END_CODE = 39;
756
+ var ANSI_ESCAPE_BELL = "\x07";
757
+ var ANSI_CSI = "[";
758
+ var ANSI_OSC = "]";
759
+ var ANSI_SGR_TERMINATOR = "m";
760
+ var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
761
+ var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
762
+ var getClosingCode = (openingCode) => {
763
+ if (openingCode >= 30 && openingCode <= 37)
764
+ return 39;
765
+ if (openingCode >= 90 && openingCode <= 97)
766
+ return 39;
767
+ if (openingCode >= 40 && openingCode <= 47)
768
+ return 49;
769
+ if (openingCode >= 100 && openingCode <= 107)
770
+ return 49;
771
+ if (openingCode === 1 || openingCode === 2)
772
+ return 22;
773
+ if (openingCode === 3)
774
+ return 23;
775
+ if (openingCode === 4)
776
+ return 24;
777
+ if (openingCode === 7)
778
+ return 27;
779
+ if (openingCode === 8)
780
+ return 28;
781
+ if (openingCode === 9)
782
+ return 29;
783
+ if (openingCode === 0)
784
+ return 0;
785
+ return void 0;
786
+ };
787
+ var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
788
+ var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
789
+ var wrapWord = (rows, word, columns) => {
790
+ const characters = word[Symbol.iterator]();
791
+ let isInsideEscape = false;
792
+ let isInsideLinkEscape = false;
793
+ let lastRow = rows.at(-1);
794
+ let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
795
+ let currentCharacter = characters.next();
796
+ let nextCharacter = characters.next();
797
+ let rawCharacterIndex = 0;
798
+ while (!currentCharacter.done) {
799
+ const character = currentCharacter.value;
800
+ const characterLength = dist_default2(character);
801
+ if (visible + characterLength <= columns) {
802
+ rows[rows.length - 1] += character;
803
+ } else {
804
+ rows.push(character);
805
+ visible = 0;
1277
806
  }
1278
- const isUpper = isUppercase(char);
1279
- if (previousSplitter === false) {
1280
- if (previousUpper === false && isUpper === true) {
1281
- parts.push(buff);
1282
- buff = char;
1283
- previousUpper = isUpper;
1284
- continue;
807
+ if (character === ESC || character === CSI) {
808
+ isInsideEscape = true;
809
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
810
+ }
811
+ if (isInsideEscape) {
812
+ if (isInsideLinkEscape) {
813
+ if (character === ANSI_ESCAPE_BELL) {
814
+ isInsideEscape = false;
815
+ isInsideLinkEscape = false;
816
+ }
817
+ } else if (character === ANSI_SGR_TERMINATOR) {
818
+ isInsideEscape = false;
1285
819
  }
1286
- if (previousUpper === true && isUpper === false && buff.length > 1) {
1287
- const lastChar = buff.at(-1);
1288
- parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
1289
- buff = lastChar + char;
1290
- previousUpper = isUpper;
1291
- continue;
820
+ } else {
821
+ visible += characterLength;
822
+ if (visible === columns && !nextCharacter.done) {
823
+ rows.push("");
824
+ visible = 0;
1292
825
  }
1293
826
  }
1294
- buff += char;
1295
- previousUpper = isUpper;
1296
- previousSplitter = isSplitter;
827
+ currentCharacter = nextCharacter;
828
+ nextCharacter = characters.next();
829
+ rawCharacterIndex += character.length;
1297
830
  }
1298
- parts.push(buff);
1299
- return parts;
1300
- }
1301
- function upperFirst(str) {
1302
- return str ? str[0].toUpperCase() + str.slice(1) : "";
1303
- }
1304
- function lowerFirst(str) {
1305
- return str ? str[0].toLowerCase() + str.slice(1) : "";
1306
- }
1307
- function pascalCase(str, opts) {
1308
- return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => upperFirst(opts?.normalize ? p2.toLowerCase() : p2)).join("") : "";
1309
- }
1310
- function camelCase(str, opts) {
1311
- return lowerFirst(pascalCase(str || "", opts));
1312
- }
1313
- function kebabCase(str, joiner) {
1314
- return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => p2.toLowerCase()).join(joiner ?? "-") : "";
1315
- }
1316
- function snakeCase(str) {
1317
- return kebabCase(str || "", "_");
1318
- }
1319
-
1320
- // node_modules/citty/dist/index.mjs
1321
- import { parseArgs as parseArgs$1 } from "node:util";
1322
- function toArray(val) {
1323
- if (Array.isArray(val)) return val;
1324
- return val === void 0 ? [] : [val];
1325
- }
1326
- function formatLineColumns(lines, linePrefix = "") {
1327
- const maxLength = [];
1328
- for (const line of lines) for (const [i3, element] of line.entries()) maxLength[i3] = Math.max(maxLength[i3] || 0, element.length);
1329
- return lines.map((l3) => l3.map((c3, i3) => linePrefix + c3[i3 === 0 ? "padStart" : "padEnd"](maxLength[i3])).join(" ")).join("\n");
1330
- }
1331
- function resolveValue(input) {
1332
- return typeof input === "function" ? input() : input;
1333
- }
1334
- var CLIError = class extends Error {
1335
- code;
1336
- constructor(message, code) {
1337
- super(message);
1338
- this.name = "CLIError";
1339
- this.code = code;
831
+ lastRow = rows.at(-1);
832
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
833
+ rows[rows.length - 2] += rows.pop();
1340
834
  }
1341
835
  };
1342
- function parseRawArgs(args = [], opts = {}) {
1343
- const booleans = new Set(opts.boolean || []);
1344
- const strings = new Set(opts.string || []);
1345
- const aliasMap = opts.alias || {};
1346
- const defaults = opts.default || {};
1347
- const aliasToMain = /* @__PURE__ */ new Map();
1348
- const mainToAliases = /* @__PURE__ */ new Map();
1349
- for (const [key, value] of Object.entries(aliasMap)) {
1350
- const targets = value;
1351
- for (const target of targets) {
1352
- aliasToMain.set(key, target);
1353
- if (!mainToAliases.has(target)) mainToAliases.set(target, []);
1354
- mainToAliases.get(target).push(key);
1355
- aliasToMain.set(target, key);
1356
- if (!mainToAliases.has(key)) mainToAliases.set(key, []);
1357
- mainToAliases.get(key).push(target);
836
+ var stringVisibleTrimSpacesRight = (string) => {
837
+ const words = string.split(" ");
838
+ let last = words.length;
839
+ while (last) {
840
+ if (dist_default2(words[last - 1])) {
841
+ break;
1358
842
  }
843
+ last--;
1359
844
  }
1360
- const options = {};
1361
- function getType(name) {
1362
- if (booleans.has(name)) return "boolean";
1363
- const aliases = mainToAliases.get(name) || [];
1364
- for (const alias of aliases) if (booleans.has(alias)) return "boolean";
1365
- return "string";
845
+ if (last === words.length) {
846
+ return string;
1366
847
  }
1367
- function isStringType(name) {
1368
- if (strings.has(name)) return true;
1369
- const aliases = mainToAliases.get(name) || [];
1370
- for (const alias of aliases) if (strings.has(alias)) return true;
1371
- return false;
848
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
849
+ };
850
+ var exec = (string, columns, options = {}) => {
851
+ if (options.trim !== false && string.trim() === "") {
852
+ return "";
1372
853
  }
1373
- const allOptions = /* @__PURE__ */ new Set([
1374
- ...booleans,
1375
- ...strings,
1376
- ...Object.keys(aliasMap),
1377
- ...Object.values(aliasMap).flat(),
1378
- ...Object.keys(defaults)
1379
- ]);
1380
- for (const name of allOptions) if (!options[name]) options[name] = {
1381
- type: getType(name),
1382
- default: defaults[name]
1383
- };
1384
- for (const [alias, main2] of aliasToMain.entries()) if (alias.length === 1 && options[main2] && !options[main2].short) options[main2].short = alias;
1385
- const processedArgs = [];
1386
- const negatedFlags = {};
1387
- for (let i3 = 0; i3 < args.length; i3++) {
1388
- const arg = args[i3];
1389
- if (arg === "--") {
1390
- processedArgs.push(...args.slice(i3));
1391
- break;
854
+ let returnValue = "";
855
+ let escapeCode;
856
+ let escapeUrl;
857
+ const words = string.split(" ");
858
+ let rows = [""];
859
+ let rowLength = 0;
860
+ for (let index = 0; index < words.length; index++) {
861
+ const word = words[index];
862
+ if (options.trim !== false) {
863
+ const row = rows.at(-1) ?? "";
864
+ const trimmed = row.trimStart();
865
+ if (row.length !== trimmed.length) {
866
+ rows[rows.length - 1] = trimmed;
867
+ rowLength = dist_default2(trimmed);
868
+ }
1392
869
  }
1393
- if (arg.startsWith("--no-")) {
1394
- const flagName = arg.slice(5);
1395
- negatedFlags[flagName] = true;
870
+ if (index !== 0) {
871
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
872
+ rows.push("");
873
+ rowLength = 0;
874
+ }
875
+ if (rowLength || options.trim === false) {
876
+ rows[rows.length - 1] += " ";
877
+ rowLength++;
878
+ }
879
+ }
880
+ const wordLength = dist_default2(word);
881
+ if (options.hard && wordLength > columns) {
882
+ const remainingColumns = columns - rowLength;
883
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
884
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
885
+ if (breaksStartingNextLine < breaksStartingThisLine) {
886
+ rows.push("");
887
+ }
888
+ wrapWord(rows, word, columns);
889
+ rowLength = dist_default2(rows.at(-1) ?? "");
1396
890
  continue;
1397
891
  }
1398
- processedArgs.push(arg);
1399
- }
1400
- let parsed;
1401
- try {
1402
- parsed = parseArgs$1({
1403
- args: processedArgs,
1404
- options: Object.keys(options).length > 0 ? options : void 0,
1405
- allowPositionals: true,
1406
- strict: false
1407
- });
1408
- } catch {
1409
- parsed = {
1410
- values: {},
1411
- positionals: processedArgs
1412
- };
1413
- }
1414
- const out = { _: [] };
1415
- out._ = parsed.positionals;
1416
- for (const [key, value] of Object.entries(parsed.values)) {
1417
- let coerced = value;
1418
- if (getType(key) === "boolean" && typeof value === "string") coerced = value !== "false";
1419
- else if (isStringType(key) && typeof value === "boolean") coerced = "";
1420
- out[key] = coerced;
892
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
893
+ if (options.wordWrap === false && rowLength < columns) {
894
+ wrapWord(rows, word, columns);
895
+ rowLength = dist_default2(rows.at(-1) ?? "");
896
+ continue;
897
+ }
898
+ rows.push("");
899
+ rowLength = 0;
900
+ }
901
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
902
+ wrapWord(rows, word, columns);
903
+ rowLength = dist_default2(rows.at(-1) ?? "");
904
+ continue;
905
+ }
906
+ rows[rows.length - 1] += word;
907
+ rowLength += wordLength;
1421
908
  }
1422
- for (const [name] of Object.entries(negatedFlags)) {
1423
- out[name] = false;
1424
- const mainName = aliasToMain.get(name);
1425
- if (mainName) out[mainName] = false;
1426
- const aliases = mainToAliases.get(name);
1427
- if (aliases) for (const alias of aliases) out[alias] = false;
909
+ if (options.trim !== false) {
910
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
1428
911
  }
1429
- for (const [alias, main2] of aliasToMain.entries()) {
1430
- if (out[alias] !== void 0 && out[main2] === void 0) out[main2] = out[alias];
1431
- if (out[main2] !== void 0 && out[alias] === void 0) out[alias] = out[main2];
1432
- if (out[alias] !== out[main2] && defaults[main2] === out[main2]) out[main2] = out[alias];
912
+ const preString = rows.join("\n");
913
+ let inSurrogate = false;
914
+ for (let i3 = 0; i3 < preString.length; i3++) {
915
+ const character = preString[i3];
916
+ returnValue += character;
917
+ if (!inSurrogate) {
918
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
919
+ if (inSurrogate) {
920
+ continue;
921
+ }
922
+ } else {
923
+ inSurrogate = false;
924
+ }
925
+ if (character === ESC || character === CSI) {
926
+ GROUP_REGEX.lastIndex = i3 + 1;
927
+ const groupsResult = GROUP_REGEX.exec(preString);
928
+ const groups = groupsResult?.groups;
929
+ if (groups?.code !== void 0) {
930
+ const code = Number.parseFloat(groups.code);
931
+ escapeCode = code === END_CODE ? void 0 : code;
932
+ } else if (groups?.uri !== void 0) {
933
+ escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
934
+ }
935
+ }
936
+ if (preString[i3 + 1] === "\n") {
937
+ if (escapeUrl) {
938
+ returnValue += wrapAnsiHyperlink("");
939
+ }
940
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
941
+ if (escapeCode && closingCode) {
942
+ returnValue += wrapAnsiCode(closingCode);
943
+ }
944
+ } else if (character === "\n") {
945
+ if (escapeCode && getClosingCode(escapeCode)) {
946
+ returnValue += wrapAnsiCode(escapeCode);
947
+ }
948
+ if (escapeUrl) {
949
+ returnValue += wrapAnsiHyperlink(escapeUrl);
950
+ }
951
+ }
1433
952
  }
1434
- return out;
953
+ return returnValue;
954
+ };
955
+ var CRLF_OR_LF = /\r?\n/;
956
+ function wrapAnsi(string, columns, options) {
957
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
1435
958
  }
1436
- var noColor = /* @__PURE__ */ (() => {
1437
- const env = globalThis.process?.env ?? {};
1438
- return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
1439
- })();
1440
- var _c = (c3, r3 = 39) => (t3) => noColor ? t3 : `\x1B[${c3}m${t3}\x1B[${r3}m`;
1441
- var bold = /* @__PURE__ */ _c(1, 22);
1442
- var cyan = /* @__PURE__ */ _c(36);
1443
- var gray = /* @__PURE__ */ _c(90);
1444
- var underline = /* @__PURE__ */ _c(4, 24);
1445
- function parseArgs(rawArgs, argsDef) {
1446
- const parseOptions = {
1447
- boolean: [],
1448
- string: [],
1449
- alias: {},
1450
- default: {}
1451
- };
1452
- const args = resolveArgs(argsDef);
1453
- for (const arg of args) {
1454
- if (arg.type === "positional") continue;
1455
- if (arg.type === "string" || arg.type === "enum") parseOptions.string.push(arg.name);
1456
- else if (arg.type === "boolean") parseOptions.boolean.push(arg.name);
1457
- if (arg.default !== void 0) parseOptions.default[arg.name] = arg.default;
1458
- if (arg.alias) parseOptions.alias[arg.name] = arg.alias;
1459
- const camelName = camelCase(arg.name);
1460
- const kebabName = kebabCase(arg.name);
1461
- if (camelName !== arg.name || kebabName !== arg.name) {
1462
- const existingAliases = toArray(parseOptions.alias[arg.name] || []);
1463
- if (camelName !== arg.name && !existingAliases.includes(camelName)) existingAliases.push(camelName);
1464
- if (kebabName !== arg.name && !existingAliases.includes(kebabName)) existingAliases.push(kebabName);
1465
- if (existingAliases.length > 0) parseOptions.alias[arg.name] = existingAliases;
959
+
960
+ // node_modules/@clack/core/dist/index.mjs
961
+ var import_sisteransi = __toESM(require_src(), 1);
962
+ import { ReadStream } from "node:tty";
963
+ function findCursor(s2, o2, l3) {
964
+ if (!l3.some((r3) => !r3.disabled))
965
+ return s2;
966
+ const t3 = s2 + o2, n4 = Math.max(l3.length - 1, 0), e2 = t3 < 0 ? n4 : t3 > n4 ? 0 : t3;
967
+ return l3[e2]?.disabled ? findCursor(e2, o2 < 0 ? -1 : 1, l3) : e2;
968
+ }
969
+ var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
970
+ var t = [
971
+ "January",
972
+ "February",
973
+ "March",
974
+ "April",
975
+ "May",
976
+ "June",
977
+ "July",
978
+ "August",
979
+ "September",
980
+ "October",
981
+ "November",
982
+ "December"
983
+ ];
984
+ var settings = {
985
+ actions: new Set(a$1),
986
+ aliases: /* @__PURE__ */ new Map([
987
+ // vim support
988
+ ["k", "up"],
989
+ ["j", "down"],
990
+ ["h", "left"],
991
+ ["l", "right"],
992
+ ["", "cancel"],
993
+ // opinionated defaults!
994
+ ["escape", "cancel"]
995
+ ]),
996
+ messages: {
997
+ cancel: "Canceled",
998
+ error: "Something went wrong"
999
+ },
1000
+ withGuide: true,
1001
+ date: {
1002
+ monthNames: [...t],
1003
+ messages: {
1004
+ required: "Please enter a valid date",
1005
+ invalidMonth: "There are only 12 months in a year",
1006
+ invalidDay: (n4, e2) => `There are only ${n4} days in ${e2}`,
1007
+ afterMin: (n4) => `Date must be on or after ${n4.toISOString().slice(0, 10)}`,
1008
+ beforeMax: (n4) => `Date must be on or before ${n4.toISOString().slice(0, 10)}`
1466
1009
  }
1467
1010
  }
1468
- const parsed = parseRawArgs(rawArgs, parseOptions);
1469
- const [...positionalArguments] = parsed._;
1470
- const parsedArgsProxy = new Proxy(parsed, { get(target, prop) {
1471
- return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
1472
- } });
1473
- for (const [, arg] of args.entries()) if (arg.type === "positional") {
1474
- const nextPositionalArgument = positionalArguments.shift();
1475
- if (nextPositionalArgument !== void 0) parsedArgsProxy[arg.name] = nextPositionalArgument;
1476
- else if (arg.default === void 0 && arg.required !== false) throw new CLIError(`Missing required positional argument: ${arg.name.toUpperCase()}`, "EARG");
1477
- else parsedArgsProxy[arg.name] = arg.default;
1478
- } else if (arg.type === "enum") {
1479
- const argument = parsedArgsProxy[arg.name];
1480
- const options = arg.options || [];
1481
- if (argument !== void 0 && options.length > 0 && !options.includes(argument)) throw new CLIError(`Invalid value for argument: ${cyan(`--${arg.name}`)} (${cyan(argument)}). Expected one of: ${options.map((o2) => cyan(o2)).join(", ")}.`, "EARG");
1482
- } else if (arg.required && parsedArgsProxy[arg.name] === void 0) throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
1483
- return parsedArgsProxy;
1011
+ };
1012
+ function isActionKey(n4, e2) {
1013
+ if (typeof n4 == "string")
1014
+ return settings.aliases.get(n4) === e2;
1015
+ for (const s2 of n4)
1016
+ if (s2 !== void 0 && isActionKey(s2, e2))
1017
+ return true;
1018
+ return false;
1484
1019
  }
1485
- function resolveArgs(argsDef) {
1486
- const args = [];
1487
- for (const [name, argDef] of Object.entries(argsDef || {})) args.push({
1488
- ...argDef,
1489
- name,
1490
- alias: toArray(argDef.alias)
1491
- });
1492
- return args;
1020
+ function diffLines(i3, s2) {
1021
+ if (i3 === s2) return;
1022
+ const e2 = i3.split(`
1023
+ `), t3 = s2.split(`
1024
+ `), r3 = Math.max(e2.length, t3.length), f2 = [];
1025
+ for (let n4 = 0; n4 < r3; n4++)
1026
+ e2[n4] !== t3[n4] && f2.push(n4);
1027
+ return {
1028
+ lines: f2,
1029
+ numLinesBefore: e2.length,
1030
+ numLinesAfter: t3.length,
1031
+ numLines: r3
1032
+ };
1493
1033
  }
1494
- async function resolvePlugins(plugins) {
1495
- return Promise.all(plugins.map((p2) => resolveValue(p2)));
1034
+ var R = globalThis.process.platform.startsWith("win");
1035
+ var CANCEL_SYMBOL = /* @__PURE__ */ Symbol("clack:cancel");
1036
+ function isCancel(e2) {
1037
+ return e2 === CANCEL_SYMBOL;
1496
1038
  }
1497
- function defineCommand(def) {
1498
- return def;
1039
+ function setRawMode(e2, r3) {
1040
+ const o2 = e2;
1041
+ o2.isTTY && o2.setRawMode(r3);
1499
1042
  }
1500
- async function runCommand(cmd, opts) {
1501
- const cmdArgs = await resolveValue(cmd.args || {});
1502
- const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
1503
- const context = {
1504
- rawArgs: opts.rawArgs,
1505
- args: parsedArgs,
1506
- data: opts.data,
1507
- cmd
1043
+ function block({
1044
+ input: e2 = stdin,
1045
+ output: r3 = stdout,
1046
+ overwrite: o2 = true,
1047
+ hideCursor: t3 = true
1048
+ } = {}) {
1049
+ const s2 = l.createInterface({
1050
+ input: e2,
1051
+ output: r3,
1052
+ prompt: "",
1053
+ tabSize: 1
1054
+ });
1055
+ l.emitKeypressEvents(e2, s2), e2 instanceof ReadStream && e2.isTTY && e2.setRawMode(true);
1056
+ const n4 = (f2, { name: a3, sequence: p2 }) => {
1057
+ const c3 = String(f2);
1058
+ if (isActionKey([c3, a3, p2], "cancel")) {
1059
+ t3 && r3.write(import_sisteransi.cursor.show), process.exit(0);
1060
+ return;
1061
+ }
1062
+ if (!o2) return;
1063
+ const i3 = a3 === "return" ? 0 : -1, m2 = a3 === "return" ? -1 : 0;
1064
+ l.moveCursor(r3, i3, m2, () => {
1065
+ l.clearLine(r3, 1, () => {
1066
+ e2.once("keypress", n4);
1067
+ });
1068
+ });
1508
1069
  };
1509
- const plugins = await resolvePlugins(cmd.plugins ?? []);
1510
- let result;
1511
- let runError;
1512
- try {
1513
- for (const plugin of plugins) await plugin.setup?.(context);
1514
- if (typeof cmd.setup === "function") await cmd.setup(context);
1515
- const subCommands = await resolveValue(cmd.subCommands);
1516
- if (subCommands && Object.keys(subCommands).length > 0) {
1517
- const subCommandArgIndex = findSubCommandIndex(opts.rawArgs, cmdArgs);
1518
- const explicitName = opts.rawArgs[subCommandArgIndex];
1519
- if (explicitName) {
1520
- const subCommand = await _findSubCommand(subCommands, explicitName);
1521
- if (!subCommand) throw new CLIError(`Unknown command ${cyan(explicitName)}`, "E_UNKNOWN_COMMAND");
1522
- await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
1523
- } else {
1524
- const defaultSubCommand = await resolveValue(cmd.default);
1525
- if (defaultSubCommand) {
1526
- if (cmd.run) throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
1527
- const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
1528
- if (!subCommand) throw new CLIError(`Default sub command ${cyan(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
1529
- await runCommand(subCommand, { rawArgs: opts.rawArgs });
1530
- } else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
1070
+ return t3 && r3.write(import_sisteransi.cursor.hide), e2.once("keypress", n4), () => {
1071
+ e2.off("keypress", n4), t3 && r3.write(import_sisteransi.cursor.show), e2 instanceof ReadStream && e2.isTTY && !R && e2.setRawMode(false), s2.terminal = false, s2.close();
1072
+ };
1073
+ }
1074
+ var getColumns = (e2) => "columns" in e2 && typeof e2.columns == "number" ? e2.columns : 80;
1075
+ var getRows = (e2) => "rows" in e2 && typeof e2.rows == "number" ? e2.rows : 20;
1076
+ function wrapTextWithPrefix(e2, r3, o2, t3 = o2, s2 = o2, n4) {
1077
+ const f2 = getColumns(e2 ?? stdout);
1078
+ return wrapAnsi(r3, f2 - o2.length, {
1079
+ hard: true,
1080
+ trim: false
1081
+ }).split(`
1082
+ `).map((c3, i3, m2) => {
1083
+ const d2 = n4 ? n4(c3, i3) : c3;
1084
+ return i3 === 0 ? `${t3}${d2}` : i3 === m2.length - 1 ? `${s2}${d2}` : `${o2}${d2}`;
1085
+ }).join(`
1086
+ `);
1087
+ }
1088
+ function runValidation(e2, n4) {
1089
+ if ("~standard" in e2) {
1090
+ const a3 = e2["~standard"].validate(n4);
1091
+ if (a3 instanceof Promise)
1092
+ throw new TypeError(
1093
+ "Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic."
1094
+ );
1095
+ return a3.issues?.at(0)?.message;
1096
+ }
1097
+ return e2(n4);
1098
+ }
1099
+ var V = class {
1100
+ input;
1101
+ output;
1102
+ _abortSignal;
1103
+ rl;
1104
+ opts;
1105
+ _render;
1106
+ _track = false;
1107
+ _prevFrame = "";
1108
+ _subscribers = /* @__PURE__ */ new Map();
1109
+ _cursor = 0;
1110
+ state = "initial";
1111
+ error = "";
1112
+ value;
1113
+ userInput = "";
1114
+ constructor(t3, e2 = true) {
1115
+ const { input: i3 = stdin, output: n4 = stdout, render: s2, signal: r3, ...o2 } = t3;
1116
+ this.opts = o2, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s2.bind(this), this._track = e2, this._abortSignal = r3, this.input = i3, this.output = n4;
1117
+ }
1118
+ /**
1119
+ * Unsubscribe all listeners
1120
+ */
1121
+ unsubscribe() {
1122
+ this._subscribers.clear();
1123
+ }
1124
+ /**
1125
+ * Set a subscriber with opts
1126
+ * @param event - The event name
1127
+ */
1128
+ setSubscriber(t3, e2) {
1129
+ const i3 = this._subscribers.get(t3) ?? [];
1130
+ i3.push(e2), this._subscribers.set(t3, i3);
1131
+ }
1132
+ /**
1133
+ * Subscribe to an event
1134
+ * @param event - The event name
1135
+ * @param cb - The callback
1136
+ */
1137
+ on(t3, e2) {
1138
+ this.setSubscriber(t3, { cb: e2 });
1139
+ }
1140
+ /**
1141
+ * Subscribe to an event once
1142
+ * @param event - The event name
1143
+ * @param cb - The callback
1144
+ */
1145
+ once(t3, e2) {
1146
+ this.setSubscriber(t3, { cb: e2, once: true });
1147
+ }
1148
+ /**
1149
+ * Emit an event with data
1150
+ * @param event - The event name
1151
+ * @param data - The data to pass to the callback
1152
+ */
1153
+ emit(t3, ...e2) {
1154
+ const i3 = this._subscribers.get(t3) ?? [], n4 = [];
1155
+ for (const s2 of i3)
1156
+ s2.cb(...e2), s2.once && n4.push(() => i3.splice(i3.indexOf(s2), 1));
1157
+ for (const s2 of n4)
1158
+ s2();
1159
+ }
1160
+ prompt() {
1161
+ return new Promise((t3) => {
1162
+ if (this._abortSignal) {
1163
+ if (this._abortSignal.aborted)
1164
+ return this.state = "cancel", this.close(), t3(CANCEL_SYMBOL);
1165
+ this._abortSignal.addEventListener(
1166
+ "abort",
1167
+ () => {
1168
+ this.state = "cancel", this.close();
1169
+ },
1170
+ { once: true }
1171
+ );
1531
1172
  }
1532
- }
1533
- if (typeof cmd.run === "function") result = await cmd.run(context);
1534
- } catch (error) {
1535
- runError = error;
1173
+ this.rl = l__default.createInterface({
1174
+ input: this.input,
1175
+ tabSize: 2,
1176
+ prompt: "",
1177
+ escapeCodeTimeout: 50,
1178
+ terminal: true
1179
+ }), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
1180
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t3(this.value);
1181
+ }), this.once("cancel", () => {
1182
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t3(CANCEL_SYMBOL);
1183
+ });
1184
+ });
1536
1185
  }
1537
- const cleanupErrors = [];
1538
- if (typeof cmd.cleanup === "function") try {
1539
- await cmd.cleanup(context);
1540
- } catch (error) {
1541
- cleanupErrors.push(error);
1186
+ _isActionKey(t3, e2) {
1187
+ return t3 === " ";
1542
1188
  }
1543
- for (const plugin of [...plugins].reverse()) try {
1544
- await plugin.cleanup?.(context);
1545
- } catch (error) {
1546
- cleanupErrors.push(error);
1189
+ _shouldSubmit(t3, e2) {
1190
+ return true;
1547
1191
  }
1548
- if (runError) throw runError;
1549
- if (cleanupErrors.length === 1) throw cleanupErrors[0];
1550
- if (cleanupErrors.length > 1) throw new Error("Multiple cleanup errors", { cause: cleanupErrors });
1551
- return { result };
1552
- }
1553
- async function resolveSubCommand(cmd, rawArgs, parent) {
1554
- const subCommands = await resolveValue(cmd.subCommands);
1555
- if (subCommands && Object.keys(subCommands).length > 0) {
1556
- const subCommandArgIndex = findSubCommandIndex(rawArgs, await resolveValue(cmd.args || {}));
1557
- const subCommandName = rawArgs[subCommandArgIndex];
1558
- const subCommand = await _findSubCommand(subCommands, subCommandName);
1559
- if (subCommand) return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
1192
+ _setValue(t3) {
1193
+ this.value = t3, this.emit("value", this.value);
1560
1194
  }
1561
- return [cmd, parent];
1562
- }
1563
- async function _findSubCommand(subCommands, name) {
1564
- if (name in subCommands) return resolveValue(subCommands[name]);
1565
- for (const sub of Object.values(subCommands)) {
1566
- const resolved = await resolveValue(sub);
1567
- const meta = await resolveValue(resolved?.meta);
1568
- if (meta?.alias) {
1569
- if (toArray(meta.alias).includes(name)) return resolved;
1570
- }
1195
+ _setUserInput(t3, e2) {
1196
+ this.userInput = t3 ?? "", this.emit("userInput", this.userInput), e2 && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
1571
1197
  }
1572
- }
1573
- function findSubCommandIndex(rawArgs, argsDef) {
1574
- for (let i3 = 0; i3 < rawArgs.length; i3++) {
1575
- const arg = rawArgs[i3];
1576
- if (arg === "--") return -1;
1577
- if (arg.startsWith("-")) {
1578
- if (!arg.includes("=") && _isValueFlag(arg, argsDef)) i3++;
1579
- continue;
1198
+ _clearUserInput() {
1199
+ this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
1200
+ }
1201
+ onKeypress(t3, e2) {
1202
+ if (this._track && e2.name !== "return" && (e2.name && this._isActionKey(t3, e2) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e2?.name && (!this._track && settings.aliases.has(e2.name) && this.emit("cursor", settings.aliases.get(e2.name)), settings.actions.has(e2.name) && this.emit("cursor", e2.name)), t3 && (t3.toLowerCase() === "y" || t3.toLowerCase() === "n") && this.emit("confirm", t3.toLowerCase() === "y"), this.emit("key", t3, e2), e2?.name === "return" && this._shouldSubmit(t3, e2)) {
1203
+ if (this.opts.validate) {
1204
+ const i3 = runValidation(this.opts.validate, this.value);
1205
+ i3 && (this.error = i3 instanceof Error ? i3.message : i3, this.state = "error", this.rl?.write(this.userInput));
1206
+ }
1207
+ this.state !== "error" && (this.state = "submit");
1580
1208
  }
1581
- return i3;
1209
+ isActionKey([t3, e2?.name, e2?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
1582
1210
  }
1583
- return -1;
1584
- }
1585
- function _isValueFlag(flag, argsDef) {
1586
- const name = flag.replace(/^-{1,2}/, "");
1587
- const normalized = camelCase(name);
1588
- for (const [key, def] of Object.entries(argsDef)) {
1589
- if (def.type !== "string" && def.type !== "enum") continue;
1590
- if (normalized === camelCase(key)) return true;
1591
- if ((Array.isArray(def.alias) ? def.alias : def.alias ? [def.alias] : []).includes(name)) return true;
1211
+ close() {
1212
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
1213
+ `), setRawMode(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
1592
1214
  }
1593
- return false;
1594
- }
1595
- async function showUsage(cmd, parent) {
1596
- try {
1597
- console.log(await renderUsage(cmd, parent) + "\n");
1598
- } catch (error) {
1599
- console.error(error);
1215
+ restoreCursor() {
1216
+ const t3 = wrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split(`
1217
+ `).length - 1;
1218
+ this.output.write(import_sisteransi.cursor.move(-999, t3 * -1));
1600
1219
  }
1601
- }
1602
- var negativePrefixRe = /^no[-A-Z]/;
1603
- async function renderUsage(cmd, parent) {
1604
- const cmdMeta = await resolveValue(cmd.meta || {});
1605
- const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
1606
- const parentMeta = await resolveValue(parent?.meta || {});
1607
- const commandName = `${parentMeta.name ? `${parentMeta.name} ` : ""}` + (cmdMeta.name || process.argv[1]);
1608
- const argLines = [];
1609
- const posLines = [];
1610
- const commandsLines = [];
1611
- const usageLine = [];
1612
- for (const arg of cmdArgs) if (arg.type === "positional") {
1613
- const name = arg.name.toUpperCase();
1614
- const isRequired = arg.required !== false && arg.default === void 0;
1615
- posLines.push([cyan(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
1616
- usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
1617
- } else {
1618
- const isRequired = arg.required === true && arg.default === void 0;
1619
- const argStr = [...(arg.alias || []).map((a3) => `-${a3}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
1620
- argLines.push([cyan(argStr), renderDescription(arg, isRequired)]);
1621
- if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
1622
- const negativeArgStr = [...(arg.alias || []).map((a3) => `--no-${a3}`), `--no-${arg.name}`].join(", ");
1623
- argLines.push([cyan(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
1220
+ render() {
1221
+ const t3 = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
1222
+ hard: true,
1223
+ trim: false
1224
+ });
1225
+ if (t3 !== this._prevFrame) {
1226
+ if (this.state === "initial")
1227
+ this.output.write(import_sisteransi.cursor.hide);
1228
+ else {
1229
+ const e2 = diffLines(this._prevFrame, t3), i3 = getRows(this.output);
1230
+ if (this.restoreCursor(), e2) {
1231
+ const n4 = Math.max(0, e2.numLinesAfter - i3), s2 = Math.max(0, e2.numLinesBefore - i3);
1232
+ let r3 = e2.lines.find((o2) => o2 >= n4);
1233
+ if (r3 === void 0) {
1234
+ this._prevFrame = t3;
1235
+ return;
1236
+ }
1237
+ if (e2.lines.length === 1) {
1238
+ this.output.write(import_sisteransi.cursor.move(0, r3 - s2)), this.output.write(import_sisteransi.erase.lines(1));
1239
+ const o2 = t3.split(`
1240
+ `);
1241
+ this.output.write(o2[r3]), this._prevFrame = t3, this.output.write(import_sisteransi.cursor.move(0, o2.length - r3 - 1));
1242
+ return;
1243
+ } else if (e2.lines.length > 1) {
1244
+ if (n4 < s2)
1245
+ r3 = n4;
1246
+ else {
1247
+ const h3 = r3 - s2;
1248
+ h3 > 0 && this.output.write(import_sisteransi.cursor.move(0, h3));
1249
+ }
1250
+ this.output.write(import_sisteransi.erase.down());
1251
+ const f2 = t3.split(`
1252
+ `).slice(r3);
1253
+ this.output.write(f2.join(`
1254
+ `)), this._prevFrame = t3;
1255
+ return;
1256
+ }
1257
+ }
1258
+ this.output.write(import_sisteransi.erase.down());
1259
+ }
1260
+ this.output.write(t3), this.state === "initial" && (this.state = "active"), this._prevFrame = t3;
1624
1261
  }
1625
- if (isRequired) usageLine.push(`--${arg.name}` + renderValueHint(arg));
1626
1262
  }
1627
- if (cmd.subCommands) {
1628
- const commandNames = [];
1629
- const subCommands = await resolveValue(cmd.subCommands);
1630
- for (const [name, sub] of Object.entries(subCommands)) {
1631
- const meta = await resolveValue((await resolveValue(sub))?.meta);
1632
- if (meta?.hidden) continue;
1633
- const aliases = toArray(meta?.alias);
1634
- const label = [name, ...aliases].join(", ");
1635
- commandsLines.push([cyan(label), meta?.description || ""]);
1636
- commandNames.push(name, ...aliases);
1637
- }
1638
- usageLine.push(commandNames.join("|"));
1263
+ };
1264
+ var r = class extends V {
1265
+ get cursor() {
1266
+ return this.value ? 0 : 1;
1267
+ }
1268
+ get _value() {
1269
+ return this.cursor === 0;
1270
+ }
1271
+ constructor(t3) {
1272
+ super(t3, false), this.value = !!t3.initialValue, this.on("userInput", () => {
1273
+ this.value = this._value;
1274
+ }), this.on("confirm", (i3) => {
1275
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = i3, this.state = "submit", this.close();
1276
+ }), this.on("cursor", () => {
1277
+ this.value = !this.value;
1278
+ });
1279
+ }
1280
+ };
1281
+ var n$1 = class n extends V {
1282
+ options;
1283
+ cursor = 0;
1284
+ get _selectedValue() {
1285
+ return this.options[this.cursor];
1286
+ }
1287
+ changeValue() {
1288
+ const e2 = this._selectedValue;
1289
+ this.value = e2 === void 0 ? void 0 : e2.value;
1290
+ }
1291
+ constructor(e2) {
1292
+ super(e2, false), this.options = e2.options;
1293
+ const o2 = this.options.findIndex(({ value: s2 }) => s2 === e2.initialValue), t3 = o2 === -1 ? 0 : o2;
1294
+ this.cursor = this.options[t3]?.disabled ? findCursor(t3, 1, this.options) : t3, this.changeValue(), this.on("cursor", (s2) => {
1295
+ switch (s2) {
1296
+ case "left":
1297
+ case "up":
1298
+ this.cursor = findCursor(this.cursor, -1, this.options);
1299
+ break;
1300
+ case "down":
1301
+ case "right":
1302
+ this.cursor = findCursor(this.cursor, 1, this.options);
1303
+ break;
1304
+ }
1305
+ this.changeValue();
1306
+ });
1307
+ }
1308
+ };
1309
+ var n2 = class extends V {
1310
+ get userInputWithCursor() {
1311
+ if (this.state === "submit")
1312
+ return this.userInput;
1313
+ const t3 = this.userInput;
1314
+ if (this.cursor >= t3.length)
1315
+ return `${this.userInput}\u2588`;
1316
+ const r3 = t3.slice(0, this.cursor), s2 = t3.slice(this.cursor, this.cursor + 1), e2 = t3.slice(this.cursor + 1);
1317
+ return `${r3}${styleText("inverse", s2)}${e2}`;
1639
1318
  }
1640
- const usageLines = [];
1641
- const version = cmdMeta.version || parentMeta.version;
1642
- usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
1643
- const hasOptions = argLines.length > 0 || posLines.length > 0;
1644
- usageLines.push(`${underline(bold("USAGE"))} ${cyan(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
1645
- if (posLines.length > 0) {
1646
- usageLines.push(underline(bold("ARGUMENTS")), "");
1647
- usageLines.push(formatLineColumns(posLines, " "));
1648
- usageLines.push("");
1319
+ get cursor() {
1320
+ return this._cursor;
1649
1321
  }
1650
- if (argLines.length > 0) {
1651
- usageLines.push(underline(bold("OPTIONS")), "");
1652
- usageLines.push(formatLineColumns(argLines, " "));
1653
- usageLines.push("");
1322
+ constructor(t3) {
1323
+ super({
1324
+ ...t3,
1325
+ initialUserInput: t3.initialUserInput ?? t3.initialValue
1326
+ }), this.on("userInput", (r3) => {
1327
+ this._setValue(r3);
1328
+ }), this.on("finalize", () => {
1329
+ this.value || (this.value = t3.defaultValue), this.value === void 0 && (this.value = "");
1330
+ });
1654
1331
  }
1655
- if (commandsLines.length > 0) {
1656
- usageLines.push(underline(bold("COMMANDS")), "");
1657
- usageLines.push(formatLineColumns(commandsLines, " "));
1658
- usageLines.push("", `Use ${cyan(`${commandName} <command> --help`)} for more information about a command.`);
1332
+ };
1333
+
1334
+ // node_modules/@clack/prompts/dist/index.mjs
1335
+ import { styleText as styleText2, stripVTControlCharacters } from "node:util";
1336
+ import process$1 from "node:process";
1337
+ var import_sisteransi2 = __toESM(require_src(), 1);
1338
+ function isUnicodeSupported() {
1339
+ if (process$1.platform !== "win32") {
1340
+ return process$1.env.TERM !== "linux";
1659
1341
  }
1660
- return usageLines.filter((l3) => typeof l3 === "string").join("\n");
1661
- }
1662
- function renderValueHint(arg) {
1663
- const valueHint = arg.valueHint ? `=<${arg.valueHint}>` : "";
1664
- const fallbackValueHint = valueHint || `=<${snakeCase(arg.name)}>`;
1665
- if (!arg.type || arg.type === "positional" || arg.type === "boolean") return valueHint;
1666
- if (arg.type === "enum" && arg.options?.length) return `=<${arg.options.join("|")}>`;
1667
- return fallbackValueHint;
1668
- }
1669
- function renderDescription(arg, required) {
1670
- const requiredHint = required ? gray("(Required)") : "";
1671
- const defaultHint = arg.default === void 0 ? "" : gray(`(Default: ${arg.default})`);
1672
- return [
1673
- arg.description,
1674
- requiredHint,
1675
- defaultHint
1676
- ].filter(Boolean).join(" ");
1342
+ return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
1677
1343
  }
1678
- async function runMain(cmd, opts = {}) {
1679
- const rawArgs = opts.rawArgs || process.argv.slice(2);
1680
- const showUsage$1 = opts.showUsage || showUsage;
1681
- try {
1682
- const builtinFlags = await _resolveBuiltinFlags(cmd);
1683
- if (builtinFlags.help.length > 0 && rawArgs.some((arg) => builtinFlags.help.includes(arg))) {
1684
- await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1685
- process.exit(0);
1686
- } else if (rawArgs.length === 1 && builtinFlags.version.includes(rawArgs[0])) {
1687
- const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
1688
- if (!meta?.version) throw new CLIError("No version specified", "E_NO_VERSION");
1689
- console.log(meta.version);
1690
- } else await runCommand(cmd, { rawArgs });
1691
- } catch (error) {
1692
- if (error instanceof CLIError) {
1693
- await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1694
- console.error(error.message);
1695
- } else console.error(error, "\n");
1696
- process.exit(1);
1344
+ var unicode = isUnicodeSupported();
1345
+ var isCI = () => process.env.CI === "true";
1346
+ var unicodeOr = (o2, e2) => unicode ? o2 : e2;
1347
+ var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
1348
+ var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
1349
+ var S_STEP_ERROR = unicodeOr("\u25B2", "x");
1350
+ var S_STEP_SUBMIT = unicodeOr("\u25C7", "o");
1351
+ var S_BAR_START = unicodeOr("\u250C", "T");
1352
+ var S_BAR = unicodeOr("\u2502", "|");
1353
+ var S_BAR_END = unicodeOr("\u2514", "\u2014");
1354
+ var S_BAR_START_RIGHT = unicodeOr("\u2510", "T");
1355
+ var S_BAR_END_RIGHT = unicodeOr("\u2518", "\u2014");
1356
+ var S_RADIO_ACTIVE = unicodeOr("\u25CF", ">");
1357
+ var S_RADIO_INACTIVE = unicodeOr("\u25CB", " ");
1358
+ var S_CHECKBOX_ACTIVE = unicodeOr("\u25FB", "[\u2022]");
1359
+ var S_CHECKBOX_SELECTED = unicodeOr("\u25FC", "[+]");
1360
+ var S_CHECKBOX_INACTIVE = unicodeOr("\u25FB", "[ ]");
1361
+ var S_PASSWORD_MASK = unicodeOr("\u25AA", "\u2022");
1362
+ var S_BAR_H = unicodeOr("\u2500", "-");
1363
+ var S_CORNER_TOP_RIGHT = unicodeOr("\u256E", "+");
1364
+ var S_CONNECT_LEFT = unicodeOr("\u251C", "+");
1365
+ var S_CORNER_BOTTOM_RIGHT = unicodeOr("\u256F", "+");
1366
+ var S_CORNER_BOTTOM_LEFT = unicodeOr("\u2570", "+");
1367
+ var S_CORNER_TOP_LEFT = unicodeOr("\u256D", "+");
1368
+ var S_INFO = unicodeOr("\u25CF", "\u2022");
1369
+ var S_SUCCESS = unicodeOr("\u25C6", "*");
1370
+ var S_WARN = unicodeOr("\u25B2", "!");
1371
+ var S_ERROR = unicodeOr("\u25A0", "x");
1372
+ var symbol = (o2) => {
1373
+ switch (o2) {
1374
+ case "initial":
1375
+ case "active":
1376
+ return styleText2("cyan", S_STEP_ACTIVE);
1377
+ case "cancel":
1378
+ return styleText2("red", S_STEP_CANCEL);
1379
+ case "error":
1380
+ return styleText2("yellow", S_STEP_ERROR);
1381
+ case "submit":
1382
+ return styleText2("green", S_STEP_SUBMIT);
1697
1383
  }
1698
- }
1699
- async function _resolveBuiltinFlags(cmd) {
1700
- const argsDef = await resolveValue(cmd.args || {});
1701
- const userNames = /* @__PURE__ */ new Set();
1702
- const userAliases = /* @__PURE__ */ new Set();
1703
- for (const [name, def] of Object.entries(argsDef)) {
1704
- userNames.add(name);
1705
- for (const alias of toArray(def.alias)) userAliases.add(alias);
1384
+ };
1385
+ var symbolBar = (o2) => {
1386
+ switch (o2) {
1387
+ case "initial":
1388
+ case "active":
1389
+ return styleText2("cyan", S_BAR);
1390
+ case "cancel":
1391
+ return styleText2("red", S_BAR);
1392
+ case "error":
1393
+ return styleText2("yellow", S_BAR);
1394
+ case "submit":
1395
+ return styleText2("green", S_BAR);
1706
1396
  }
1707
- return {
1708
- help: _getBuiltinFlags("help", "h", userNames, userAliases),
1709
- version: _getBuiltinFlags("version", "v", userNames, userAliases)
1710
- };
1711
- }
1712
- function _getBuiltinFlags(long, short, userNames, userAliases) {
1713
- if (userNames.has(long) || userAliases.has(long)) return [];
1714
- if (userNames.has(short) || userAliases.has(short)) return [`--${long}`];
1715
- return [`--${long}`, `-${short}`];
1397
+ };
1398
+ function formatInstructionFooter(o2, e2) {
1399
+ const r3 = [`${e2 ? `${styleText2("cyan", S_BAR)} ` : ""}${o2.join(" \u2022 ")}`];
1400
+ return e2 && r3.push(styleText2("cyan", S_BAR_END)), r3;
1716
1401
  }
1717
-
1718
- // package.json
1719
- var package_default = {
1720
- name: "zapdev",
1721
- version: "0.11.0",
1722
- description: "Fast, performant and lightweight git chores and dev tools using your terminal and your own local LLM.",
1723
- type: "module",
1724
- bin: {
1725
- zapdev: "./dist/index.js"
1402
+ var I = (l3, e2, w2, p2, b2, C2 = false) => {
1403
+ let r3 = e2, O2 = 0;
1404
+ if (C2)
1405
+ for (let i3 = p2 - 1; i3 >= w2; i3--) {
1406
+ const m2 = l3[i3];
1407
+ if (m2 && (r3 -= m2.length), O2++, r3 <= b2) break;
1408
+ }
1409
+ else
1410
+ for (let i3 = w2; i3 < p2; i3++) {
1411
+ const m2 = l3[i3];
1412
+ if (m2 && (r3 -= m2.length), O2++, r3 <= b2) break;
1413
+ }
1414
+ return { lineCount: r3, removals: O2 };
1415
+ };
1416
+ var limitOptions = ({
1417
+ cursor: l3,
1418
+ options: e2,
1419
+ style: w2,
1420
+ output: p2 = process.stdout,
1421
+ maxItems: b2 = Number.POSITIVE_INFINITY,
1422
+ columnPadding: C2 = 0,
1423
+ rowPadding: r3 = 4
1424
+ }) => {
1425
+ const i3 = getColumns(p2) - C2, m2 = getRows(p2), M = styleText2("dim", "..."), v2 = Math.max(m2 - r3, 0), a3 = Math.max(Math.min(b2, v2), 5);
1426
+ let f2 = 0;
1427
+ l3 >= a3 - 3 && (f2 = Math.max(
1428
+ Math.min(l3 - a3 + 3, e2.length - a3),
1429
+ 0
1430
+ ));
1431
+ let d2 = a3 < e2.length && f2 > 0, c3 = a3 < e2.length && f2 + a3 < e2.length;
1432
+ const W2 = Math.min(
1433
+ f2 + a3,
1434
+ e2.length
1435
+ ), s2 = [];
1436
+ let g2 = 0;
1437
+ d2 && g2++, c3 && g2++;
1438
+ const T2 = f2 + (d2 ? 1 : 0), y2 = W2 - (c3 ? 1 : 0);
1439
+ for (let t3 = T2; t3 < y2; t3++) {
1440
+ const n4 = e2[t3], o2 = n4 ? w2(n4, t3 === l3) : "", h3 = wrapAnsi(o2, i3, {
1441
+ hard: true,
1442
+ trim: false
1443
+ }).split(`
1444
+ `);
1445
+ s2.push(h3), g2 += h3.length;
1446
+ }
1447
+ if (g2 > v2) {
1448
+ let t3 = 0, n4 = 0, o2 = g2;
1449
+ const h3 = l3 - T2;
1450
+ let u4 = v2;
1451
+ const L = () => I(s2, o2, 0, h3, u4), E2 = () => I(
1452
+ s2,
1453
+ o2,
1454
+ h3 + 1,
1455
+ s2.length,
1456
+ u4,
1457
+ true
1458
+ );
1459
+ d2 ? ({ lineCount: o2, removals: t3 } = L(), o2 > u4 && (c3 || (u4 -= 1), { lineCount: o2, removals: n4 } = E2())) : (c3 || (u4 -= 1), { lineCount: o2, removals: n4 } = E2(), o2 > u4 && (u4 -= 1, { lineCount: o2, removals: t3 } = L())), t3 > 0 && (d2 = true, s2.splice(0, t3)), n4 > 0 && (c3 = true, s2.splice(s2.length - n4, n4));
1460
+ }
1461
+ const x2 = [];
1462
+ d2 && x2.push(M);
1463
+ for (const t3 of s2)
1464
+ for (const n4 of t3)
1465
+ x2.push(n4);
1466
+ return c3 && x2.push(M), x2;
1467
+ };
1468
+ var confirm = (i3) => {
1469
+ const a3 = i3.active ?? "Yes", s2 = i3.inactive ?? "No";
1470
+ return new r({
1471
+ active: a3,
1472
+ inactive: s2,
1473
+ signal: i3.signal,
1474
+ input: i3.input,
1475
+ output: i3.output,
1476
+ initialValue: i3.initialValue ?? true,
1477
+ render() {
1478
+ const e2 = i3.withGuide ?? settings.withGuide, u4 = `${symbol(this.state)} `, l3 = e2 ? `${styleText2("gray", S_BAR)} ` : "", f2 = wrapTextWithPrefix(
1479
+ i3.output,
1480
+ i3.message,
1481
+ l3,
1482
+ u4
1483
+ ), o2 = `${e2 ? `${styleText2("gray", S_BAR)}
1484
+ ` : ""}${f2}
1485
+ `, c3 = this.value ? a3 : s2;
1486
+ switch (this.state) {
1487
+ case "submit": {
1488
+ const r3 = e2 ? `${styleText2("gray", S_BAR)} ` : "";
1489
+ return `${o2}${r3}${styleText2("dim", c3)}`;
1490
+ }
1491
+ case "cancel": {
1492
+ const r3 = e2 ? `${styleText2("gray", S_BAR)} ` : "";
1493
+ return `${o2}${r3}${styleText2(["strikethrough", "dim"], c3)}${e2 ? `
1494
+ ${styleText2("gray", S_BAR)}` : ""}`;
1495
+ }
1496
+ default: {
1497
+ const r3 = e2 ? `${styleText2("cyan", S_BAR)} ` : "", g2 = e2 ? styleText2("cyan", S_BAR_END) : "";
1498
+ return `${o2}${r3}${this.value ? `${styleText2("green", S_RADIO_ACTIVE)} ${a3}` : `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", a3)}`}${i3.vertical ? e2 ? `
1499
+ ${styleText2("cyan", S_BAR)} ` : `
1500
+ ` : ` ${styleText2("dim", "/")} `}${this.value ? `${styleText2("dim", S_RADIO_INACTIVE)} ${styleText2("dim", s2)}` : `${styleText2("green", S_RADIO_ACTIVE)} ${s2}`}
1501
+ ${g2}
1502
+ `;
1503
+ }
1504
+ }
1505
+ }
1506
+ }).prompt();
1507
+ };
1508
+ var MULTISELECT_INSTRUCTIONS = [
1509
+ `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1510
+ `${styleText2("dim", "Space:")} select`,
1511
+ `${styleText2("dim", "Enter:")} confirm`
1512
+ ];
1513
+ var log = {
1514
+ message: (s2 = [], {
1515
+ symbol: e2 = styleText2("gray", S_BAR),
1516
+ secondarySymbol: r3 = styleText2("gray", S_BAR),
1517
+ output: m2 = process.stdout,
1518
+ spacing: l3 = 1,
1519
+ withGuide: c3
1520
+ } = {}) => {
1521
+ const t3 = [], o2 = c3 ?? settings.withGuide, f2 = o2 ? r3 : "", O2 = o2 ? `${e2} ` : "", u4 = o2 ? `${r3} ` : "";
1522
+ for (let i3 = 0; i3 < l3; i3++)
1523
+ t3.push(f2);
1524
+ const g2 = Array.isArray(s2) ? s2 : s2.split(`
1525
+ `);
1526
+ if (g2.length > 0) {
1527
+ const [i3, ...y2] = g2;
1528
+ i3.length > 0 ? t3.push(`${O2}${i3}`) : t3.push(o2 ? e2 : "");
1529
+ for (const p2 of y2)
1530
+ p2.length > 0 ? t3.push(`${u4}${p2}`) : t3.push(o2 ? r3 : "");
1531
+ }
1532
+ m2.write(`${t3.join(`
1533
+ `)}
1534
+ `);
1726
1535
  },
1727
- files: [
1728
- "dist"
1729
- ],
1730
- engines: {
1731
- node: ">=20"
1536
+ info: (s2, e2) => {
1537
+ log.message(s2, { ...e2, symbol: styleText2("blue", S_INFO) });
1732
1538
  },
1733
- keywords: [
1734
- "git",
1735
- "cli",
1736
- "commit",
1737
- "conventional-commits",
1738
- "ollama",
1739
- "llm",
1740
- "ai"
1741
- ],
1742
- author: "Matthieu Vagnon <hi@mvagnon.dev>",
1743
- license: "MIT",
1744
- repository: {
1745
- type: "git",
1746
- url: "git+https://github.com/mvagnon/zapdev.git"
1539
+ success: (s2, e2) => {
1540
+ log.message(s2, { ...e2, symbol: styleText2("green", S_SUCCESS) });
1747
1541
  },
1748
- homepage: "https://github.com/mvagnon/zapdev#readme",
1749
- bugs: {
1750
- url: "https://github.com/mvagnon/zapdev/issues"
1542
+ step: (s2, e2) => {
1543
+ log.message(s2, { ...e2, symbol: styleText2("green", S_STEP_SUBMIT) });
1751
1544
  },
1752
- publishConfig: {
1753
- access: "public"
1545
+ warn: (s2, e2) => {
1546
+ log.message(s2, { ...e2, symbol: styleText2("yellow", S_WARN) });
1754
1547
  },
1755
- scripts: {
1756
- zapdev: "npm run build && node dist/index.js",
1757
- build: "esbuild src/cli.ts --bundle --platform=node --format=esm --target=node20 --loader:.md=text --outfile=dist/cli.js && esbuild src/index.ts --platform=node --format=esm --target=node20 --outfile=dist/index.js",
1758
- lint: "eslint .",
1759
- typecheck: "tsc --noEmit",
1760
- test: "vitest run",
1761
- prepack: "npm run build"
1548
+ /** alias for `log.warn()`. */
1549
+ warning: (s2, e2) => {
1550
+ log.warn(s2, e2);
1762
1551
  },
1763
- devDependencies: {
1764
- "@clack/prompts": "^1.6.0",
1765
- "@eslint/js": "^10.0.1",
1766
- "@eslint/json": "^2.0.0",
1767
- "@eslint/markdown": "^8.0.2",
1768
- "@types/node": "^26.1.1",
1769
- citty: "^0.2.2",
1770
- esbuild: "^0.28.1",
1771
- eslint: "^10.6.0",
1772
- jiti: "^2.7.0",
1773
- tinyexec: "^1.2.4",
1774
- typescript: "^6.0.3",
1775
- "typescript-eslint": "^8.62.1",
1776
- vitest: "^4.1.9"
1552
+ error: (s2, e2) => {
1553
+ log.message(s2, { ...e2, symbol: styleText2("red", S_ERROR) });
1777
1554
  }
1778
1555
  };
1556
+ var cancel = (o2 = "", t3) => {
1557
+ const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_END)} ` : "";
1558
+ i3.write(`${e2}${styleText2("red", o2)}
1559
+
1560
+ `);
1561
+ };
1562
+ var intro = (o2 = "", t3) => {
1563
+ const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR_START)} ` : "";
1564
+ i3.write(`${e2}${o2}
1565
+ `);
1566
+ };
1567
+ var outro = (o2 = "", t3) => {
1568
+ const i3 = t3?.output ?? process.stdout, e2 = t3?.withGuide ?? settings.withGuide ? `${styleText2("gray", S_BAR)}
1569
+ ${styleText2("gray", S_BAR_END)} ` : "";
1570
+ i3.write(`${e2}${o2}
1571
+
1572
+ `);
1573
+ };
1574
+ var W = (l3) => styleText2("magenta", l3);
1575
+ var spinner = ({
1576
+ indicator: l3 = "dots",
1577
+ onCancel: h3,
1578
+ output: n4 = process.stdout,
1579
+ cancelMessage: G,
1580
+ errorMessage: O2,
1581
+ frames: E2 = unicode ? ["\u25D2", "\u25D0", "\u25D3", "\u25D1"] : ["\u2022", "o", "O", "0"],
1582
+ delay: F2 = unicode ? 80 : 120,
1583
+ signal: m2,
1584
+ ...I3
1585
+ } = {}) => {
1586
+ const u4 = isCI();
1587
+ let M, T2, d2 = false, S2 = false, s2 = "", p2, w2 = performance.now();
1588
+ const x2 = getColumns(n4), k2 = I3?.styleFrame ?? W, g2 = (e2) => {
1589
+ const r3 = e2 > 1 ? O2 ?? settings.messages.error : G ?? settings.messages.cancel;
1590
+ S2 = e2 === 1, d2 && (a3(r3, e2), S2 && typeof h3 == "function" && h3());
1591
+ }, f2 = () => g2(2), i3 = () => g2(1), A = () => {
1592
+ process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i3), process.on("SIGTERM", i3), process.on("exit", g2), m2 && m2.addEventListener("abort", i3);
1593
+ }, H = () => {
1594
+ process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i3), process.removeListener("SIGTERM", i3), process.removeListener("exit", g2), m2 && m2.removeEventListener("abort", i3);
1595
+ }, y2 = () => {
1596
+ if (p2 === void 0) return;
1597
+ u4 && n4.write(`
1598
+ `);
1599
+ const r3 = wrapAnsi(p2, x2, {
1600
+ hard: true,
1601
+ trim: false
1602
+ }).split(`
1603
+ `);
1604
+ r3.length > 1 && n4.write(import_sisteransi2.cursor.up(r3.length - 1)), n4.write(import_sisteransi2.cursor.to(0)), n4.write(import_sisteransi2.erase.down());
1605
+ }, C2 = (e2) => e2.replace(/\.+$/, ""), _2 = (e2) => {
1606
+ const r3 = (performance.now() - e2) / 1e3, t3 = Math.floor(r3 / 60), o2 = Math.floor(r3 % 60);
1607
+ return t3 > 0 ? `[${t3}m ${o2}s]` : `[${o2}s]`;
1608
+ }, N2 = I3.withGuide ?? settings.withGuide, P2 = (e2 = "") => {
1609
+ d2 = true, M = block({ output: n4 }), s2 = C2(e2), w2 = performance.now(), N2 && n4.write(`${styleText2("gray", S_BAR)}
1610
+ `);
1611
+ let r3 = 0, t3 = 0;
1612
+ A(), T2 = setInterval(() => {
1613
+ if (u4 && s2 === p2)
1614
+ return;
1615
+ y2(), p2 = s2;
1616
+ const o2 = k2(E2[r3]);
1617
+ let v2;
1618
+ if (u4)
1619
+ v2 = `${o2} ${s2}...`;
1620
+ else if (l3 === "timer")
1621
+ v2 = `${o2} ${s2} ${_2(w2)}`;
1622
+ else {
1623
+ const B = ".".repeat(Math.floor(t3)).slice(0, 3);
1624
+ v2 = `${o2} ${s2}${B}`;
1625
+ }
1626
+ const j2 = wrapAnsi(v2, x2, {
1627
+ hard: true,
1628
+ trim: false
1629
+ });
1630
+ n4.write(j2), r3 = r3 + 1 < E2.length ? r3 + 1 : 0, t3 = t3 < 4 ? t3 + 0.125 : 0;
1631
+ }, F2);
1632
+ }, a3 = (e2 = "", r3 = 0, t3 = false) => {
1633
+ if (!d2) return;
1634
+ d2 = false, clearInterval(T2), y2();
1635
+ const o2 = r3 === 0 ? styleText2("green", S_STEP_SUBMIT) : r3 === 1 ? styleText2("red", S_STEP_CANCEL) : styleText2("red", S_STEP_ERROR);
1636
+ s2 = e2 ?? s2, t3 || (l3 === "timer" ? n4.write(`${o2} ${s2} ${_2(w2)}
1637
+ `) : n4.write(`${o2} ${s2}
1638
+ `)), H(), M();
1639
+ };
1640
+ return {
1641
+ start: P2,
1642
+ stop: (e2 = "") => a3(e2, 0),
1643
+ message: (e2 = "") => {
1644
+ s2 = C2(e2 ?? s2);
1645
+ },
1646
+ cancel: (e2 = "") => a3(e2, 1),
1647
+ error: (e2 = "") => a3(e2, 2),
1648
+ clear: () => a3("", 0, true),
1649
+ get isCancelled() {
1650
+ return S2;
1651
+ }
1652
+ };
1653
+ };
1654
+ var u2 = {
1655
+ light: unicodeOr("\u2500", "-"),
1656
+ heavy: unicodeOr("\u2501", "="),
1657
+ block: unicodeOr("\u2588", "#")
1658
+ };
1659
+ var SELECT_INSTRUCTIONS = [
1660
+ `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1661
+ `${styleText2("dim", "Enter:")} confirm`
1662
+ ];
1663
+ var c = (t3, o2) => t3.includes(`
1664
+ `) ? t3.split(`
1665
+ `).map((d2) => o2(d2)).join(`
1666
+ `) : o2(t3);
1667
+ var select = (t3) => {
1668
+ const o2 = (n4, m2) => {
1669
+ if (n4 === void 0)
1670
+ return "";
1671
+ const s2 = n4.label ?? String(n4.value);
1672
+ switch (m2) {
1673
+ case "disabled":
1674
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("gray", i3))}${n4.hint ? ` ${styleText2("dim", `(${n4.hint ?? "disabled"})`)}` : ""}`;
1675
+ case "selected":
1676
+ return `${c(s2, (i3) => styleText2("dim", i3))}`;
1677
+ case "active":
1678
+ return `${styleText2("green", S_RADIO_ACTIVE)} ${s2}${n4.hint ? ` ${styleText2("dim", `(${n4.hint})`)}` : ""}`;
1679
+ case "cancelled":
1680
+ return `${c(s2, (i3) => styleText2(["strikethrough", "dim"], i3))}`;
1681
+ default:
1682
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("dim", i3))}`;
1683
+ }
1684
+ }, d2 = t3.showInstructions ?? true;
1685
+ return new n$1({
1686
+ options: t3.options,
1687
+ signal: t3.signal,
1688
+ input: t3.input,
1689
+ output: t3.output,
1690
+ initialValue: t3.initialValue,
1691
+ render() {
1692
+ const n4 = t3.withGuide ?? settings.withGuide, m2 = `${symbol(this.state)} `, s2 = `${symbolBar(this.state)} `, i3 = wrapTextWithPrefix(
1693
+ t3.output,
1694
+ t3.message,
1695
+ s2,
1696
+ m2
1697
+ ), u4 = `${n4 ? `${styleText2("gray", S_BAR)}
1698
+ ` : ""}${i3}
1699
+ `;
1700
+ switch (this.state) {
1701
+ case "submit": {
1702
+ const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1703
+ t3.output,
1704
+ o2(this.options[this.cursor], "selected"),
1705
+ r3
1706
+ );
1707
+ return `${u4}${a3}`;
1708
+ }
1709
+ case "cancel": {
1710
+ const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1711
+ t3.output,
1712
+ o2(this.options[this.cursor], "cancelled"),
1713
+ r3
1714
+ );
1715
+ return `${u4}${a3}${n4 ? `
1716
+ ${styleText2("gray", S_BAR)}` : ""}`;
1717
+ }
1718
+ default: {
1719
+ const r3 = n4 ? `${styleText2("cyan", S_BAR)} ` : "", a3 = u4.split(`
1720
+ `).length, p2 = d2 ? formatInstructionFooter(SELECT_INSTRUCTIONS, n4) : n4 ? [styleText2("cyan", S_BAR_END)] : [], b2 = p2.join(`
1721
+ `), f2 = p2.length + 1;
1722
+ return `${u4}${r3}${limitOptions({
1723
+ output: t3.output,
1724
+ cursor: this.cursor,
1725
+ options: this.options,
1726
+ maxItems: t3.maxItems,
1727
+ columnPadding: r3.length,
1728
+ rowPadding: a3 + f2,
1729
+ style: (g2, x2) => o2(g2, g2.disabled ? "disabled" : x2 ? "active" : "inactive")
1730
+ }).join(`
1731
+ ${r3}`)}
1732
+ ${b2}
1733
+ `;
1734
+ }
1735
+ }
1736
+ }
1737
+ }).prompt();
1738
+ };
1739
+ var i = `${styleText2("gray", S_BAR)} `;
1740
+ var text = (e2) => new n2({
1741
+ validate: e2.validate,
1742
+ placeholder: e2.placeholder,
1743
+ defaultValue: e2.defaultValue,
1744
+ initialValue: e2.initialValue,
1745
+ output: e2.output,
1746
+ signal: e2.signal,
1747
+ input: e2.input,
1748
+ render() {
1749
+ const i3 = e2?.withGuide ?? settings.withGuide, s2 = `${`${i3 ? `${styleText2("gray", S_BAR)}
1750
+ ` : ""}${symbol(this.state)} `}${e2.message}
1751
+ `, c3 = e2.placeholder && e2.placeholder.length > 0 ? (
1752
+ // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
1753
+ styleText2("inverse", e2.placeholder[0]) + styleText2("dim", e2.placeholder.slice(1))
1754
+ ) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, l3 = this.value ?? "";
1755
+ switch (this.state) {
1756
+ case "error": {
1757
+ const n4 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r3 = i3 ? `${styleText2("yellow", S_BAR)} ` : "", d2 = i3 ? styleText2("yellow", S_BAR_END) : "";
1758
+ return `${s2.trim()}
1759
+ ${r3}${o2}
1760
+ ${d2}${n4}
1761
+ `;
1762
+ }
1763
+ case "submit": {
1764
+ const n4 = l3 ? ` ${styleText2("dim", l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1765
+ return `${s2}${r3}${n4}`;
1766
+ }
1767
+ case "cancel": {
1768
+ const n4 = l3 ? ` ${styleText2(["strikethrough", "dim"], l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1769
+ return `${s2}${r3}${n4}${l3.trim() ? `
1770
+ ${r3}` : ""}`;
1771
+ }
1772
+ default: {
1773
+ const n4 = i3 ? `${styleText2("cyan", S_BAR)} ` : "", r3 = i3 ? styleText2("cyan", S_BAR_END) : "";
1774
+ return `${s2}${n4}${o2}
1775
+ ${r3}
1776
+ `;
1777
+ }
1778
+ }
1779
+ }
1780
+ }).prompt();
1779
1781
 
1780
1782
  // src/types/commit.ts
1781
1783
  var COMMIT_TYPES = [
@@ -1812,23 +1814,25 @@ function sanitizeCommitMessage(raw) {
1812
1814
  }
1813
1815
 
1814
1816
  // src/lib/config.ts
1815
- var DEFAULT_OLLAMA_URL = "http://localhost:11434";
1816
- var DEFAULT_MODEL = "deepseek-v4-flash:cloud";
1817
- var DEFAULT_EFFORT = "low";
1818
1817
  function resolveConfig(env = process.env, overrides = {}) {
1819
- return {
1820
- ollamaUrl: normalizeBaseUrl(overrides.ollamaUrl ?? env.OLLAMA_URL ?? DEFAULT_OLLAMA_URL),
1821
- model: overrides.model ?? env.OLLAMA_MODEL ?? DEFAULT_MODEL,
1822
- backupModel: overrides.backupModel ?? optionalValue(env.OLLAMA_BACKUP_MODEL),
1823
- effort: overrides.effort ?? optionalValue(env.OLLAMA_EFFORT) ?? DEFAULT_EFFORT
1818
+ const config = {
1819
+ url: (overrides.url ?? env.ZD_URL)?.trim() ?? "",
1820
+ model: (overrides.model ?? env.ZD_MODEL)?.trim() ?? "",
1821
+ effort: (overrides.effort ?? env.ZD_EFFORT)?.trim() ?? ""
1824
1822
  };
1825
- }
1826
- function optionalValue(value) {
1827
- return value?.trim() || void 0;
1828
- }
1829
- function normalizeBaseUrl(raw) {
1830
- const trimmed = raw.trim().replace(/\/+$/, "");
1831
- return /^https?:\/\//.test(trimmed) ? trimmed : `http://${trimmed}`;
1823
+ for (const [key, value] of Object.entries(config)) {
1824
+ if (!value) throw new Error(`Set ZD_${key.toUpperCase()} or --${key} before generating a commit message.`);
1825
+ }
1826
+ let url;
1827
+ try {
1828
+ url = new URL(config.url);
1829
+ } catch {
1830
+ throw new Error("URL must be a complete HTTP(S) Chat Completions endpoint.");
1831
+ }
1832
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
1833
+ throw new Error("URL must be a complete HTTP(S) Chat Completions endpoint.");
1834
+ }
1835
+ return config;
1832
1836
  }
1833
1837
 
1834
1838
  // src/lib/git.ts
@@ -2161,40 +2165,8 @@ var R2 = (e2, t3, n4) => {
2161
2165
  };
2162
2166
  var z = R2;
2163
2167
 
2164
- // src/lib/branches.ts
2165
- function parseDefaultBranch(originHead) {
2166
- const trimmed = originHead.trim();
2167
- if (!trimmed) return null;
2168
- return trimmed.replace(/^origin\//, "");
2169
- }
2170
- function parseBranches(raw) {
2171
- return raw.split("\n").map((branch) => branch.trim()).filter(Boolean);
2172
- }
2173
- function deletableBranches(all, protectedBranches) {
2174
- const kept = new Set(protectedBranches.filter(Boolean));
2175
- return all.filter((branch) => !kept.has(branch));
2176
- }
2177
-
2178
- // src/lib/worktrees.ts
2179
- var WORKTREE_PREFIX = "worktree ";
2180
- var BRANCH_PREFIX = "branch ";
2181
- function parseWorktrees(porcelain) {
2182
- const worktrees = [];
2183
- let current = null;
2184
- for (const line of porcelain.split("\n")) {
2185
- if (line.startsWith(WORKTREE_PREFIX)) {
2186
- current = { path: line.slice(WORKTREE_PREFIX.length).trim(), branch: null };
2187
- worktrees.push(current);
2188
- } else if (current && line.startsWith(BRANCH_PREFIX)) {
2189
- current.branch = line.slice(BRANCH_PREFIX.length).trim().replace(/^refs\/heads\//, "");
2190
- }
2191
- }
2192
- return worktrees;
2193
- }
2194
-
2195
2168
  // src/lib/git.ts
2196
2169
  var UPSTREAM_REF = "@{upstream}";
2197
- var BRANCH_FORMAT = "%(refname:short)";
2198
2170
  async function git(args, cwd) {
2199
2171
  const result = await R2("git", args, { nodeOptions: { cwd } });
2200
2172
  if (result.exitCode !== 0) {
@@ -2206,98 +2178,52 @@ async function tryGit(args, cwd) {
2206
2178
  const result = await R2("git", args, { nodeOptions: { cwd } });
2207
2179
  return result.exitCode === 0 ? result.stdout : null;
2208
2180
  }
2209
- async function stageAll() {
2210
- await git(["add", "-A"]);
2181
+ async function stageAll(repo) {
2182
+ await git(["add", "-A"], repo);
2211
2183
  }
2212
- async function getStagedDiff() {
2213
- return git(["diff", "--cached"]);
2184
+ async function getStagedDiff(repo) {
2185
+ return git(["diff", "--cached"], repo);
2214
2186
  }
2215
- async function commit(message) {
2216
- await git(["commit", "-m", message]);
2187
+ async function commit(repo, message) {
2188
+ await git(["commit", "-m", message], repo);
2217
2189
  }
2218
- async function currentBranch() {
2219
- return (await git(["symbolic-ref", "--short", "HEAD"])).trim();
2190
+ async function currentBranch(repo) {
2191
+ return (await git(["symbolic-ref", "--short", "HEAD"], repo)).trim();
2220
2192
  }
2221
- async function hasUpstream() {
2222
- const result = await tryGit(["rev-parse", "--abbrev-ref", "--symbolic-full-name", UPSTREAM_REF]);
2193
+ async function hasUpstream(repo) {
2194
+ const result = await tryGit(["rev-parse", "--abbrev-ref", "--symbolic-full-name", UPSTREAM_REF], repo);
2223
2195
  return result !== null;
2224
2196
  }
2225
- async function push() {
2226
- await git(["push"]);
2197
+ async function push(repo) {
2198
+ await git(["push"], repo);
2227
2199
  }
2228
- async function pushSetUpstream(branch) {
2229
- await git(["push", "-u", "origin", branch]);
2200
+ async function pushSetUpstream(repo, branch) {
2201
+ await git(["push", "-u", "origin", branch], repo);
2230
2202
  }
2231
- async function pullRebase() {
2232
- await git(["pull", "--rebase"]);
2203
+ async function pullRebase(repo) {
2204
+ await git(["pull", "--rebase"], repo);
2233
2205
  }
2234
- async function pullMerge() {
2235
- await git(["pull", "--no-rebase", "--no-edit"]);
2206
+ async function pullMerge(repo) {
2207
+ await git(["pull", "--no-rebase", "--no-edit"], repo);
2236
2208
  }
2237
- async function fetchRemote() {
2238
- await git(["fetch"]);
2209
+ async function fetchRemote(repo) {
2210
+ await git(["fetch"], repo);
2239
2211
  }
2240
- async function behindCount() {
2241
- const out = await tryGit(["rev-list", "--count", `HEAD..${UPSTREAM_REF}`]);
2212
+ async function behindCount(repo) {
2213
+ const out = await tryGit(["rev-list", "--count", `HEAD..${UPSTREAM_REF}`], repo);
2242
2214
  return out === null ? 0 : Number(out.trim()) || 0;
2243
2215
  }
2244
2216
  async function findRepos(path) {
2245
- if (await isGitRepo(path)) return [path];
2217
+ const root = await repoRoot(path);
2218
+ if (root) return [root];
2246
2219
  const entries = await readdir(path, { withFileTypes: true }).catch(() => null);
2247
2220
  if (!entries) return [];
2248
2221
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules");
2249
- const repos = await Promise.all(
2250
- dirs.map(async (entry) => {
2251
- const dir = join(path, entry.name);
2252
- return await isGitRepo(dir) ? dir : null;
2253
- })
2254
- );
2222
+ const repos = await Promise.all(dirs.map((entry) => repoRoot(join(path, entry.name))));
2255
2223
  return repos.filter((dir) => dir !== null).sort();
2256
2224
  }
2257
- async function isGitRepo(dir) {
2258
- const entries = await readdir(dir, { withFileTypes: true }).catch(() => null);
2259
- return entries?.some((entry) => entry.name === ".git" && entry.isDirectory()) ?? false;
2260
- }
2261
- async function fetchPrune(repo) {
2262
- await git(["fetch", "--prune"], repo);
2263
- }
2264
- async function defaultBranch(repo) {
2265
- const output = await tryGit(
2266
- ["symbolic-ref", "--quiet", "--short", "refs/remotes/origin/HEAD"],
2267
- repo
2268
- );
2269
- return output === null ? null : parseDefaultBranch(output);
2270
- }
2271
- async function currentBranchAt(repo) {
2272
- const output = await tryGit(["symbolic-ref", "--quiet", "--short", "HEAD"], repo);
2273
- return output === null ? null : output.trim();
2274
- }
2275
- async function localBranches(repo) {
2276
- return parseBranches(await git(["branch", `--format=${BRANCH_FORMAT}`], repo));
2277
- }
2278
- async function branchExists(repo, branch) {
2279
- const local = await tryGit(["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], repo);
2280
- if (local !== null) return true;
2281
- const remote = await tryGit(
2282
- ["show-ref", "--verify", "--quiet", `refs/remotes/origin/${branch}`],
2283
- repo
2284
- );
2285
- return remote !== null;
2286
- }
2287
- async function listWorktrees(repo) {
2288
- return parseWorktrees(await git(["worktree", "list", "--porcelain"], repo));
2289
- }
2290
- async function removeWorktree(repo, path) {
2291
- await git(["worktree", "remove", "--force", path], repo);
2292
- }
2293
- async function switchBranch(repo, branch) {
2294
- await git(["switch", branch], repo);
2295
- }
2296
- async function deleteBranch(repo, branch) {
2297
- await git(["branch", "-D", branch], repo);
2298
- }
2299
- async function pull(repo) {
2300
- await git(["pull"], repo);
2225
+ async function repoRoot(dir) {
2226
+ return (await tryGit(["rev-parse", "--show-toplevel"], dir))?.trim() ?? null;
2301
2227
  }
2302
2228
 
2303
2229
  // src/lib/errors.ts
@@ -2317,8 +2243,11 @@ async function hasGitleaks() {
2317
2243
  throw error;
2318
2244
  }
2319
2245
  }
2320
- async function scanStagedChanges() {
2321
- const result = await R2("gitleaks", ["git", "--staged"], { nodePath: false });
2246
+ async function scanStagedChanges(repo) {
2247
+ const result = await R2("gitleaks", ["git", "--staged"], {
2248
+ nodePath: false,
2249
+ nodeOptions: { cwd: repo }
2250
+ });
2322
2251
  if (result.exitCode === 0) return;
2323
2252
  const output = result.stderr.trim() || result.stdout.trim();
2324
2253
  throw new Error(output || "gitleaks git --staged failed");
@@ -2330,65 +2259,49 @@ var commit_message_default = "You are zapdev, a CLI tool that creates commits qu
2330
2259
  // src/prompts/index.ts
2331
2260
  var COMMIT_SYSTEM_PROMPT = commit_message_default.trim();
2332
2261
 
2333
- // src/lib/ollama.ts
2262
+ // src/lib/llm.ts
2334
2263
  var REQUEST_TIMEOUT_MS = 25e3;
2335
- var KEEP_ALIVE = "30m";
2336
2264
  async function generateCommitMessage(diff, config, type) {
2337
2265
  const systemPrompt = type ? applyCommitType(COMMIT_SYSTEM_PROMPT, type) : COMMIT_SYSTEM_PROMPT;
2338
2266
  const messages = [
2339
2267
  { role: "system", content: systemPrompt },
2340
2268
  { role: "user", content: truncateDiff(diff) }
2341
2269
  ];
2342
- let content;
2343
- try {
2344
- content = await chat(config, config.model, messages);
2345
- } catch (error) {
2346
- if (!config.backupModel || config.backupModel === config.model) throw error;
2347
- try {
2348
- content = await chat(config, config.backupModel, messages);
2349
- } catch (backupError) {
2350
- throw new AggregateError(
2351
- [error, backupError],
2352
- `Primary model failed: ${errorMessage(error)} Backup model failed: ${errorMessage(backupError)}`,
2353
- { cause: backupError }
2354
- );
2355
- }
2356
- }
2357
- return sanitizeCommitMessage(content);
2358
- }
2359
- async function chat(config, model, messages) {
2360
- const url = `${config.ollamaUrl}/api/chat`;
2361
2270
  let response;
2271
+ let body;
2362
2272
  try {
2363
- response = await fetch(url, {
2273
+ response = await fetch(config.url, {
2364
2274
  method: "POST",
2365
2275
  headers: { "content-type": "application/json" },
2366
2276
  body: JSON.stringify({
2367
- model,
2277
+ model: config.model,
2368
2278
  stream: false,
2369
- keep_alive: KEEP_ALIVE,
2370
- think: config.effort,
2371
- options: { temperature: 0.2 },
2279
+ reasoning_effort: config.effort,
2372
2280
  messages
2373
2281
  }),
2374
2282
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
2375
2283
  });
2284
+ const text2 = await response.text();
2285
+ try {
2286
+ body = JSON.parse(text2);
2287
+ } catch {
2288
+ body = null;
2289
+ }
2376
2290
  } catch (error) {
2377
- throw new Error(describeRequestError(error, url), { cause: error });
2291
+ throw new Error(describeRequestError(error), { cause: error });
2378
2292
  }
2379
- const body = await response.json().catch(() => null);
2380
2293
  if (!response.ok) {
2381
- throw new Error(`Ollama error: ${serverError(body) ?? `HTTP ${response.status}`}`);
2294
+ throw new Error(`LLM error: ${serverError(body) ?? `HTTP ${response.status}`}`);
2382
2295
  }
2383
2296
  const content = messageContent(body);
2384
- if (content === null) throw new Error("Ollama returned an unexpected response shape.");
2385
- return content;
2297
+ if (content === null) throw new Error("LLM returned an unexpected response shape.");
2298
+ return sanitizeCommitMessage(content);
2386
2299
  }
2387
- function describeRequestError(error, url) {
2300
+ function describeRequestError(error) {
2388
2301
  if (errorName(error) === "TimeoutError") {
2389
- return `Ollama did not answer within ${REQUEST_TIMEOUT_MS / 1e3}s (${url}).`;
2302
+ return `LLM did not answer within ${REQUEST_TIMEOUT_MS / 1e3}s.`;
2390
2303
  }
2391
- return `Could not reach Ollama at ${url}. Is it running?`;
2304
+ return "Could not complete the LLM request. Check URL and endpoint availability.";
2392
2305
  }
2393
2306
  function errorName(error) {
2394
2307
  if (error && typeof error === "object" && "name" in error && typeof error.name === "string") {
@@ -2397,14 +2310,18 @@ function errorName(error) {
2397
2310
  return null;
2398
2311
  }
2399
2312
  function serverError(body) {
2400
- if (body && typeof body === "object" && "error" in body && typeof body.error === "string") {
2401
- return body.error;
2313
+ if (!body || typeof body !== "object" || !("error" in body)) return null;
2314
+ const error = body.error;
2315
+ if (error && typeof error === "object" && "message" in error && typeof error.message === "string") {
2316
+ return error.message;
2402
2317
  }
2403
2318
  return null;
2404
2319
  }
2405
2320
  function messageContent(body) {
2406
- if (!body || typeof body !== "object" || !("message" in body)) return null;
2407
- const message = body.message;
2321
+ if (!body || typeof body !== "object" || !("choices" in body) || !Array.isArray(body.choices)) return null;
2322
+ const choice = body.choices[0];
2323
+ if (!choice || typeof choice !== "object" || !("message" in choice)) return null;
2324
+ const message = choice.message;
2408
2325
  if (!message || typeof message !== "object" || !("content" in message)) return null;
2409
2326
  return typeof message.content === "string" ? message.content : null;
2410
2327
  }
@@ -2413,12 +2330,20 @@ function messageContent(body) {
2413
2330
  var commitCommand = defineCommand({
2414
2331
  meta: {
2415
2332
  name: "commit",
2416
- description: "Stage all changes and commit with an LLM-generated Conventional Commits message."
2333
+ description: "Generate and review commit messages for the current repo or direct child repos."
2417
2334
  },
2418
2335
  args: {
2336
+ url: {
2337
+ type: "string",
2338
+ description: "Override $ZD_URL, the complete Chat Completions endpoint."
2339
+ },
2419
2340
  model: {
2420
2341
  type: "string",
2421
- description: "Override the Ollama model (defaults to $OLLAMA_MODEL)."
2342
+ description: "Override the model configured with $ZD_MODEL."
2343
+ },
2344
+ effort: {
2345
+ type: "string",
2346
+ description: "Override $ZD_EFFORT, sent as reasoning_effort."
2422
2347
  },
2423
2348
  type: {
2424
2349
  type: "string",
@@ -2453,10 +2378,6 @@ var commitCommand = defineCommand({
2453
2378
  },
2454
2379
  async run({ args }) {
2455
2380
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
2456
- const config = resolveConfig(
2457
- process.env,
2458
- args.model ? { model: args.model } : {}
2459
- );
2460
2381
  if (args.rebase && args.merge) {
2461
2382
  log.error("Choose either --rebase or --merge, not both.");
2462
2383
  process.exitCode = 1;
@@ -2471,145 +2392,178 @@ var commitCommand = defineCommand({
2471
2392
  process.exitCode = 1;
2472
2393
  return;
2473
2394
  }
2395
+ let config;
2396
+ try {
2397
+ config = resolveConfig(process.env, {
2398
+ url: args.url,
2399
+ model: args.model,
2400
+ effort: args.effort
2401
+ });
2402
+ } catch (error) {
2403
+ log.error(errorMessage(error));
2404
+ process.exitCode = 1;
2405
+ return;
2406
+ }
2474
2407
  if (interactive) intro("zapdev commit");
2475
- if (!args.staged) await stageAll();
2476
- const diff = await getStagedDiff();
2477
- if (!diff.trim()) {
2478
- log.warn("Nothing to commit.");
2408
+ const repos = await findRepos(process.cwd());
2409
+ if (repos.length === 0) {
2410
+ log.warn("No git repository found here or in direct children.");
2479
2411
  if (interactive) outro("Nothing to do.");
2480
2412
  return;
2481
2413
  }
2414
+ let scan;
2482
2415
  try {
2483
- if (await hasGitleaks()) {
2484
- const scanLoader = interactive ? spinner() : void 0;
2485
- scanLoader?.start("Scanning staged changes with Gitleaks");
2486
- try {
2487
- await scanStagedChanges();
2488
- scanLoader?.stop("No leaks found");
2489
- } catch (error) {
2490
- scanLoader?.error("Gitleaks check failed");
2491
- throw error;
2492
- }
2493
- } else {
2494
- log.info("Gitleaks not found, skipping secret scan.");
2495
- }
2416
+ scan = await hasGitleaks();
2496
2417
  } catch (error) {
2497
2418
  log.error(`Gitleaks check failed: ${errorMessage(error)}`);
2498
2419
  process.exitCode = 1;
2499
2420
  return;
2500
2421
  }
2422
+ if (!scan) log.info("Gitleaks not found, skipping secret scan.");
2501
2423
  const loader = interactive ? spinner() : void 0;
2502
- loader?.start("Generating commit message");
2503
- let message;
2504
- try {
2505
- message = await generateCommitMessage(diff, config, type);
2506
- } catch (error) {
2507
- loader?.error("Generation failed");
2508
- log.error(`Generation failed: ${errorMessage(error)}`);
2509
- process.exitCode = 1;
2424
+ loader?.start("Preparing repositories and generating commit messages in parallel");
2425
+ const results = await Promise.allSettled(repos.map(async (repo) => {
2426
+ if (!args.staged) await stageAll(repo);
2427
+ const diff = await getStagedDiff(repo);
2428
+ if (!diff.trim()) return null;
2429
+ if (scan) await scanStagedChanges(repo);
2430
+ const message = await generateCommitMessage(diff, config, type);
2431
+ if (!message) throw new Error("The model returned an empty message.");
2432
+ return { repo, message };
2433
+ }));
2434
+ loader?.stop("Repositories prepared");
2435
+ const drafts = [];
2436
+ for (const [index, result] of results.entries()) {
2437
+ if (result.status === "rejected") {
2438
+ log.error(`${basename(repos[index])}: ${errorMessage(result.reason)}`);
2439
+ process.exitCode = 1;
2440
+ } else if (result.value) {
2441
+ drafts.push(result.value);
2442
+ } else {
2443
+ log.info(`${basename(repos[index])}: nothing to commit.`);
2444
+ }
2445
+ }
2446
+ if (drafts.length === 0) {
2447
+ if (interactive) outro("No commits prepared.");
2510
2448
  return;
2511
2449
  }
2512
- if (!message) {
2513
- loader?.error("Generation failed");
2514
- log.error("Generation failed: the model returned an empty message.");
2515
- process.exitCode = 1;
2450
+ const selected = await reviewMessages(drafts, interactive && !args.yes);
2451
+ if (!selected) {
2452
+ cancel("Cancelled (changes left staged).");
2516
2453
  return;
2517
2454
  }
2518
- if (loader) loader.stop(message);
2519
- else log.message(message);
2520
- let finalMessage = message;
2521
- if (interactive && !args.yes) {
2522
- const action = await select({
2523
- message: "Action",
2524
- initialValue: "commit",
2525
- options: [
2526
- { value: "commit", label: "Commit" },
2527
- { value: "edit", label: "Edit message" },
2528
- { value: "cancel", label: "Cancel" }
2529
- ]
2530
- });
2531
- if (isCancel(action) || action === "cancel") {
2532
- cancel("Cancelled (changes left staged).");
2533
- return;
2534
- }
2535
- if (action === "edit") {
2536
- const edited = await text({
2537
- message: "Edit message",
2538
- initialValue: message
2539
- });
2540
- if (isCancel(edited)) {
2541
- cancel("Cancelled (changes left staged).");
2542
- return;
2543
- }
2544
- finalMessage = edited.trim();
2545
- if (!finalMessage) {
2546
- cancel("Empty message, cancelled.");
2547
- return;
2548
- }
2455
+ const committed = [];
2456
+ for (const draft of selected) {
2457
+ try {
2458
+ await commit(draft.repo, draft.message);
2459
+ committed.push(draft);
2460
+ log.success(`${basename(draft.repo)}: committed ${draft.message}`);
2461
+ } catch (error) {
2462
+ log.error(`${basename(draft.repo)}: commit failed: ${errorMessage(error)}`);
2463
+ process.exitCode = 1;
2549
2464
  }
2550
2465
  }
2551
- await commit(finalMessage);
2552
- if (interactive) log.success(`Committed: ${finalMessage}`);
2466
+ if (committed.length === 0) return;
2553
2467
  let shouldPush = Boolean(args.push);
2554
2468
  if (!shouldPush && interactive && !args.yes) {
2555
- const answer = await confirm({ message: "Push?", initialValue: false });
2469
+ const answer = await confirm({
2470
+ message: `Push ${committed.map(({ repo }) => basename(repo)).join(", ")}?`,
2471
+ initialValue: false
2472
+ });
2556
2473
  if (isCancel(answer)) {
2557
- if (interactive) outro("Committed. Not pushed.");
2474
+ outro("Committed. Not pushed.");
2558
2475
  return;
2559
2476
  }
2560
2477
  shouldPush = answer;
2561
2478
  }
2562
2479
  if (shouldPush) {
2563
- const pushed = await pushOptimistic(
2564
- interactive,
2565
- interactive && !args.yes,
2566
- syncStrategy
2567
- );
2568
- if (!pushed) {
2569
- process.exitCode = 1;
2570
- return;
2480
+ for (const { repo } of committed) {
2481
+ try {
2482
+ const pushed = await pushOptimistic(
2483
+ repo,
2484
+ interactive,
2485
+ interactive && !args.yes,
2486
+ syncStrategy
2487
+ );
2488
+ if (!pushed) process.exitCode = 1;
2489
+ } catch (error) {
2490
+ log.error(`${basename(repo)}: push failed: ${errorMessage(error)}`);
2491
+ process.exitCode = 1;
2492
+ }
2571
2493
  }
2572
2494
  }
2573
- if (interactive) outro("Done.");
2495
+ if (interactive) outro(process.exitCode ? "Finished with errors." : "Done.");
2574
2496
  }
2575
2497
  });
2576
- async function syncWithUpstream(strategy, interactive) {
2498
+ async function reviewMessages(drafts, canPrompt) {
2499
+ while (true) {
2500
+ for (const draft of drafts) log.message(`${basename(draft.repo)}: ${draft.message}`);
2501
+ if (!canPrompt) return drafts;
2502
+ const action = await select({
2503
+ message: "Action",
2504
+ initialValue: "all",
2505
+ options: [
2506
+ { value: "all", label: drafts.length > 1 ? "Commit all" : "Commit" },
2507
+ ...drafts.length > 1 ? drafts.map((draft) => ({
2508
+ value: { action: "commit", draft },
2509
+ label: `Commit only "${basename(draft.repo)}"`
2510
+ })) : [],
2511
+ ...drafts.map((draft) => ({
2512
+ value: { action: "edit", draft },
2513
+ label: `Edit message for "${basename(draft.repo)}"`
2514
+ })),
2515
+ { value: "cancel", label: "Cancel" }
2516
+ ]
2517
+ });
2518
+ if (isCancel(action) || action === "cancel") return null;
2519
+ if (action === "all") return drafts;
2520
+ if (action.action === "commit") return [action.draft];
2521
+ const edited = await text({
2522
+ message: `Edit message for "${basename(action.draft.repo)}"`,
2523
+ initialValue: action.draft.message,
2524
+ validate: (value) => value?.trim() ? void 0 : "Message cannot be empty."
2525
+ });
2526
+ if (isCancel(edited)) return null;
2527
+ action.draft.message = edited.trim();
2528
+ }
2529
+ }
2530
+ async function syncWithUpstream(repo, strategy, interactive) {
2577
2531
  const loader = interactive ? spinner() : void 0;
2578
2532
  const label = strategy === "rebase" ? "Rebase" : "Merge";
2579
- loader?.start(`Pulling --${strategy === "rebase" ? "rebase" : "no-rebase"}`);
2533
+ loader?.start(`${basename(repo)}: pulling --${strategy === "rebase" ? "rebase" : "no-rebase"}`);
2580
2534
  try {
2581
- await (strategy === "rebase" ? pullRebase() : pullMerge());
2535
+ await (strategy === "rebase" ? pullRebase(repo) : pullMerge(repo));
2582
2536
  loader?.stop(strategy === "rebase" ? "\u2713 Rebased on upstream" : "\u2713 Merged upstream");
2583
2537
  return true;
2584
2538
  } catch (error) {
2585
2539
  loader?.error(`${label} failed`);
2586
- log.error(`${label} failed (resolve conflicts, then push): ${errorMessage(error)}`);
2540
+ log.error(`${basename(repo)}: ${label} failed (resolve conflicts, then push): ${errorMessage(error)}`);
2587
2541
  return false;
2588
2542
  }
2589
2543
  }
2590
- async function pushOptimistic(interactive, canPrompt, strategy) {
2591
- const [upstream, branch] = await Promise.all([hasUpstream(), currentBranch()]);
2592
- const doPush = () => upstream ? push() : pushSetUpstream(branch);
2593
- const first = await tryPush(interactive, doPush);
2544
+ async function pushOptimistic(repo, interactive, canPrompt, strategy) {
2545
+ const [upstream, branch] = await Promise.all([hasUpstream(repo), currentBranch(repo)]);
2546
+ const doPush = () => upstream ? push(repo) : pushSetUpstream(repo, branch);
2547
+ const first = await tryPush(repo, interactive, doPush);
2594
2548
  if (first.ok) return true;
2595
- if (upstream && await isBehind(interactive)) {
2596
- const syncStrategy = strategy ?? await chooseSyncStrategy(canPrompt);
2597
- if (!syncStrategy || !await syncWithUpstream(syncStrategy, interactive)) return false;
2598
- const retry = await tryPush(interactive, doPush);
2549
+ if (upstream && await isBehind(repo, interactive)) {
2550
+ const syncStrategy = strategy ?? await chooseSyncStrategy(repo, canPrompt);
2551
+ if (!syncStrategy || !await syncWithUpstream(repo, syncStrategy, interactive)) return false;
2552
+ const retry = await tryPush(repo, interactive, doPush);
2599
2553
  if (retry.ok) return true;
2600
- log.error(`Push failed: ${errorMessage(retry.error)}`);
2554
+ log.error(`${basename(repo)}: push failed: ${errorMessage(retry.error)}`);
2601
2555
  return false;
2602
2556
  }
2603
- log.error(`Push failed: ${errorMessage(first.error)}`);
2557
+ log.error(`${basename(repo)}: push failed: ${errorMessage(first.error)}`);
2604
2558
  return false;
2605
2559
  }
2606
- async function chooseSyncStrategy(interactive) {
2560
+ async function chooseSyncStrategy(repo, interactive) {
2607
2561
  if (!interactive) {
2608
- log.error("Branch is behind upstream. Re-run with --rebase or --merge.");
2562
+ log.error(`${basename(repo)}: branch is behind upstream. Re-run with --rebase or --merge.`);
2609
2563
  return null;
2610
2564
  }
2611
2565
  const action = await select({
2612
- message: "Branch is behind upstream. How should zapdev sync it?",
2566
+ message: `${basename(repo)}: branch is behind upstream. How should zapdev sync it?`,
2613
2567
  options: [
2614
2568
  { value: "rebase", label: "Rebase" },
2615
2569
  { value: "merge", label: "Merge" },
@@ -2622,9 +2576,9 @@ async function chooseSyncStrategy(interactive) {
2622
2576
  }
2623
2577
  return action;
2624
2578
  }
2625
- async function tryPush(interactive, doPush) {
2579
+ async function tryPush(repo, interactive, doPush) {
2626
2580
  const loader = interactive ? spinner() : void 0;
2627
- loader?.start("Pushing");
2581
+ loader?.start(`${basename(repo)}: pushing`);
2628
2582
  try {
2629
2583
  await doPush();
2630
2584
  loader?.stop("\u2713 Pushed");
@@ -2634,252 +2588,32 @@ async function tryPush(interactive, doPush) {
2634
2588
  return { ok: false, error };
2635
2589
  }
2636
2590
  }
2637
- async function isBehind(interactive) {
2591
+ async function isBehind(repo, interactive) {
2638
2592
  const loader = interactive ? spinner() : void 0;
2639
- loader?.start("Checking upstream");
2593
+ loader?.start(`${basename(repo)}: checking upstream`);
2640
2594
  try {
2641
- await fetchRemote();
2642
- const behind = await behindCount();
2595
+ await fetchRemote(repo);
2596
+ const behind = await behindCount(repo);
2643
2597
  loader?.stop(
2644
2598
  behind > 0 ? `Behind upstream by ${behind} commit${behind > 1 ? "s" : ""}` : "Up to date with upstream"
2645
2599
  );
2646
2600
  return behind > 0;
2647
2601
  } catch (error) {
2648
2602
  loader?.error("Could not check upstream");
2649
- log.warn(`Could not check upstream: ${errorMessage(error)}`);
2650
- return false;
2651
- }
2652
- }
2653
-
2654
- // src/commands/reset.ts
2655
- var CANCEL = /* @__PURE__ */ Symbol("cancel");
2656
- var resetCommand = defineCommand({
2657
- meta: {
2658
- name: "reset",
2659
- description: "Switch each repo to a branch, then delete all other local branches and worktrees."
2660
- },
2661
- args: {
2662
- path: {
2663
- type: "positional",
2664
- required: false,
2665
- default: ".",
2666
- description: "A git repo to reset, or a directory whose direct child repos are reset."
2667
- },
2668
- principal: {
2669
- type: "boolean",
2670
- alias: "p",
2671
- description: "Switch every repo to its resolved principal branch (origin/HEAD)."
2672
- },
2673
- target: {
2674
- type: "string",
2675
- alias: "t",
2676
- description: "Switch every repo to this branch, falling back to the principal one."
2677
- },
2678
- pull: {
2679
- type: "boolean",
2680
- description: "Pull the checked-out branch after reset without asking."
2681
- },
2682
- yes: {
2683
- type: "boolean",
2684
- alias: "y",
2685
- description: "Non-interactive: switch and delete without confirmation."
2686
- }
2687
- },
2688
- async run({ args }) {
2689
- const assumeYes = Boolean(args.yes);
2690
- const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !assumeYes;
2691
- const options = {
2692
- principal: Boolean(args.principal),
2693
- target: typeof args.target === "string" ? args.target.trim() : "",
2694
- pull: Boolean(args.pull)
2695
- };
2696
- const path = args.path || ".";
2697
- if (interactive) intro("zapdev reset");
2698
- const repos = await findRepos(path);
2699
- if (repos.length === 0) {
2700
- log.warn(`No git repository found at or under ${path}.`);
2701
- if (interactive) outro("Nothing to do.");
2702
- return;
2703
- }
2704
- for (const repo of repos) {
2705
- try {
2706
- const cancelled = await resetRepo(repo, options, interactive, assumeYes);
2707
- if (cancelled) {
2708
- cancel("Cancelled.");
2709
- return;
2710
- }
2711
- } catch (error) {
2712
- log.error(`Skipped ${repo}: ${errorMessage(error)}`);
2713
- }
2714
- }
2715
- if (interactive) outro(`Done (${repos.length} repo${repos.length > 1 ? "s" : ""}).`);
2716
- }
2717
- });
2718
- async function resetRepo(repo, options, interactive, assumeYes) {
2719
- log.step(`Resetting ${repo}`);
2720
- const fetchLoader = interactive ? spinner() : void 0;
2721
- fetchLoader?.start("Fetching + pruning\u2026");
2722
- try {
2723
- await fetchPrune(repo);
2724
- fetchLoader?.stop("Fetched + pruned");
2725
- } catch (error) {
2726
- fetchLoader?.error("Fetch failed");
2727
- log.warn(` Fetch failed, continuing: ${errorMessage(error)}`);
2728
- }
2729
- const [principal, current] = await Promise.all([defaultBranch(repo), currentBranchAt(repo)]);
2730
- const endBranch = await resolveEndBranch(repo, principal, current, options, interactive);
2731
- if (endBranch === CANCEL) return true;
2732
- if (endBranch === null) return false;
2733
- const [branches, worktrees] = await Promise.all([localBranches(repo), listWorktrees(repo)]);
2734
- const branchesToDelete = deletableBranches(branches, [principal ?? "", endBranch]);
2735
- const worktreesToRemove = worktrees.slice(1);
2736
- if (branchesToDelete.length > 0 || worktreesToRemove.length > 0) {
2737
- if (!assumeYes) {
2738
- if (!interactive) {
2739
- log.warn(" Refusing to delete non-interactively; pass --yes.");
2740
- return false;
2741
- }
2742
- announcePlan(endBranch, branchesToDelete, worktreesToRemove);
2743
- const ok = await confirm({ message: "Delete permanently?", initialValue: false });
2744
- if (isCancel(ok)) return true;
2745
- if (!ok) {
2746
- log.info(" Skipped.");
2747
- return false;
2748
- }
2749
- }
2750
- await removeWorktrees(repo, worktreesToRemove);
2751
- }
2752
- if (!await switchTo(repo, current, endBranch)) return false;
2753
- if (branchesToDelete.length > 0) await deleteBranches(repo, branchesToDelete);
2754
- return maybePull(repo, endBranch, options, interactive);
2755
- }
2756
- async function resolveEndBranch(repo, principal, current, options, interactive) {
2757
- if (options.target) {
2758
- if (await branchExists(repo, options.target)) return options.target;
2759
- if (principal) return principal;
2760
- log.warn(` Target "${options.target}" not found and no origin/HEAD; skipped.`);
2761
- return null;
2762
- }
2763
- if (options.principal || !interactive) {
2764
- if (principal) return principal;
2765
- log.warn(" No origin/HEAD to resolve the principal branch; skipped.");
2766
- return null;
2767
- }
2768
- const branches = await localBranches(repo);
2769
- if (branches.length === 0) return principal;
2770
- const choice = await select({
2771
- message: "Switch to:",
2772
- initialValue: principal ?? current ?? branches[0],
2773
- options: branches.map((branch) => ({
2774
- value: branch,
2775
- label: branch === principal ? `${branch} (principal)` : branch
2776
- }))
2777
- });
2778
- if (isCancel(choice)) return CANCEL;
2779
- return choice;
2780
- }
2781
- function announcePlan(endBranch, branches, worktrees) {
2782
- log.info(` Switch to ${endBranch}`);
2783
- if (branches.length > 0) {
2784
- const label = branches.length > 1 ? "branches" : "branch";
2785
- log.warn(` Delete ${branches.length} ${label}: ${branches.join(", ")}`);
2786
- }
2787
- if (worktrees.length > 0) {
2788
- const label = worktrees.length > 1 ? "worktrees" : "worktree";
2789
- const paths = worktrees.map((worktree) => worktree.path).join(", ");
2790
- log.warn(` Remove ${worktrees.length} ${label}: ${paths}`);
2791
- }
2792
- }
2793
- async function removeWorktrees(repo, worktrees) {
2794
- let removed = 0;
2795
- for (const worktree of worktrees) {
2796
- try {
2797
- await removeWorktree(repo, worktree.path);
2798
- removed += 1;
2799
- } catch (error) {
2800
- log.error(` Could not remove worktree ${worktree.path}: ${errorMessage(error)}`);
2801
- }
2802
- }
2803
- if (removed > 0) log.success(` Removed ${removed} worktree${removed > 1 ? "s" : ""}.`);
2804
- }
2805
- async function switchTo(repo, current, endBranch) {
2806
- if (current === endBranch) return true;
2807
- try {
2808
- await switchBranch(repo, endBranch);
2809
- return true;
2810
- } catch (error) {
2811
- log.error(` Could not switch to ${endBranch}: ${errorMessage(error)}`);
2603
+ log.warn(`${basename(repo)}: could not check upstream: ${errorMessage(error)}`);
2812
2604
  return false;
2813
2605
  }
2814
2606
  }
2815
- async function deleteBranches(repo, branches) {
2816
- let deleted = 0;
2817
- for (const branch of branches) {
2818
- try {
2819
- await deleteBranch(repo, branch);
2820
- deleted += 1;
2821
- } catch (error) {
2822
- log.error(` Could not delete ${branch}: ${errorMessage(error)}`);
2823
- }
2824
- }
2825
- if (deleted > 0) log.success(` Deleted ${deleted} branch${deleted > 1 ? "es" : ""}.`);
2826
- }
2827
- async function maybePull(repo, endBranch, options, interactive) {
2828
- let shouldPull = options.pull;
2829
- if (!shouldPull && interactive) {
2830
- const answer = await confirm({ message: `Pull ${endBranch}?`, initialValue: false });
2831
- if (isCancel(answer)) return true;
2832
- shouldPull = answer;
2833
- }
2834
- if (shouldPull) {
2835
- const loader = interactive ? spinner() : void 0;
2836
- loader?.start(`Pulling ${endBranch}\u2026`);
2837
- try {
2838
- await pull(repo);
2839
- loader?.stop(`\u2713 Pulled ${endBranch}`);
2840
- } catch (error) {
2841
- loader?.error("Pull failed");
2842
- log.error(` Pull failed: ${errorMessage(error)}`);
2843
- }
2844
- }
2845
- return false;
2846
- }
2847
2607
 
2848
2608
  // src/cli.ts
2849
- var commands = {
2850
- commit: commitCommand,
2851
- reset: resetCommand
2852
- };
2853
- var MENU = {
2854
- commit: "Stage all changes and commit with an AI-generated message",
2855
- reset: "Switch repos to a branch and delete the other branches and worktrees"
2856
- };
2857
- var menuOptions = Object.keys(MENU).map((value) => ({
2858
- value,
2859
- label: value,
2860
- hint: MENU[value]
2861
- }));
2862
2609
  var main = defineCommand({
2863
2610
  meta: {
2864
2611
  name: "zapdev",
2865
2612
  version: package_default.version,
2866
2613
  description: "Fast, precise git chores from your terminal."
2867
2614
  },
2868
- subCommands: commands,
2869
- // citty runs this after a matched subcommand too, so bail out when one already ran.
2870
- async run({ args, cmd }) {
2871
- const selected = args._[0];
2872
- if (selected && selected in commands) return;
2873
- if (!(process.stdin.isTTY && process.stdout.isTTY)) {
2874
- await showUsage(cmd);
2875
- return;
2876
- }
2877
- const choice = await select({ message: "Which command?", options: menuOptions });
2878
- if (isCancel(choice)) {
2879
- cancel("Cancelled.");
2880
- return;
2881
- }
2882
- await runCommand(commands[choice], { rawArgs: [] });
2883
- }
2615
+ args: commitCommand.args,
2616
+ subCommands: { commit: commitCommand },
2617
+ default: "commit"
2884
2618
  });
2885
2619
  await runMain(main);