zapdev 1.10.0 → 1.12.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 +24 -74
  2. package/dist/cli.js +1278 -1381
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -84,1079 +84,565 @@ var require_src = __commonJS({
84
84
  }
85
85
  });
86
86
 
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;
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;
113
101
  }
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;
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;
121
173
  }
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;
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;
128
197
  }
129
198
  }
130
- buff += char;
131
- previousUpper = isUpper;
132
- previousSplitter = isSplitter;
199
+ index += 1;
133
200
  }
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
- }
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;
155
209
 
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;
176
- }
210
+ // node_modules/fast-string-width/dist/index.js
211
+ var NO_TRUNCATION2 = {
212
+ limit: Infinity,
213
+ ellipsis: "",
214
+ ellipsisWidth: 0
177
215
  };
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
- }
195
- }
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";
202
- }
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;
208
- }
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;
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;
228
275
  }
229
- if (arg.startsWith("--no-")) {
230
- const flagName = arg.slice(5);
231
- negatedFlags[flagName] = true;
232
- continue;
276
+ if (character === ESC || character === CSI) {
277
+ isInsideEscape = true;
278
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
233
279
  }
234
- processedArgs.push(arg);
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;
235
299
  }
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
243
- });
244
- } catch {
245
- parsed = {
246
- values: {},
247
- positionals: processedArgs
248
- };
300
+ lastRow = rows.at(-1);
301
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
302
+ rows[rows.length - 2] += rows.pop();
249
303
  }
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;
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--;
257
313
  }
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;
314
+ if (last === words.length) {
315
+ return string;
264
316
  }
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];
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 "";
269
322
  }
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;
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
+ }
302
338
  }
303
- }
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;
320
- }
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");
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++;
367
347
  }
368
348
  }
369
- if (typeof cmd.run === "function") result = await cmd.run(context);
370
- } catch (error) {
371
- runError = error;
372
- }
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);
396
- }
397
- return [cmd, parent];
398
- }
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;
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;
406
360
  }
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++;
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) ?? "");
415
373
  continue;
416
374
  }
417
- return i3;
375
+ rows[rows.length - 1] += word;
376
+ rowLength += wordLength;
418
377
  }
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;
378
+ if (options.trim !== false) {
379
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
428
380
  }
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);
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
+ }
436
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");
437
427
  }
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(" ")]);
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)}`
460
478
  }
461
- if (isRequired) usageLine.push(`--${arg.name}` + renderValueHint(arg));
462
479
  }
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);
480
+ };
481
+ function updateSettings(n4) {
482
+ if (n4.aliases !== void 0) {
483
+ const e2 = n4.aliases;
484
+ for (const s2 in e2) {
485
+ if (!Object.hasOwn(e2, s2)) continue;
486
+ const i3 = e2[s2];
487
+ i3 === void 0 || !settings.actions.has(i3) || settings.aliases.has(s2) || settings.aliases.set(s2, i3);
473
488
  }
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
489
  }
486
- if (argLines.length > 0) {
487
- usageLines.push(underline(bold("OPTIONS")), "");
488
- usageLines.push(formatLineColumns(argLines, " "));
489
- usageLines.push("");
490
+ if (n4.messages !== void 0) {
491
+ const e2 = n4.messages;
492
+ e2.cancel !== void 0 && (settings.messages.cancel = e2.cancel), e2.error !== void 0 && (settings.messages.error = e2.error);
490
493
  }
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.`);
494
+ if (n4.withGuide !== void 0 && (settings.withGuide = n4.withGuide !== false), n4.date !== void 0) {
495
+ const e2 = n4.date;
496
+ e2.monthNames !== void 0 && (settings.date.monthNames = [...e2.monthNames]), e2.messages !== void 0 && (e2.messages.required !== void 0 && (settings.date.messages.required = e2.messages.required), e2.messages.invalidMonth !== void 0 && (settings.date.messages.invalidMonth = e2.messages.invalidMonth), e2.messages.invalidDay !== void 0 && (settings.date.messages.invalidDay = e2.messages.invalidDay), e2.messages.afterMin !== void 0 && (settings.date.messages.afterMin = e2.messages.afterMin), e2.messages.beforeMax !== void 0 && (settings.date.messages.beforeMax = e2.messages.beforeMax));
495
497
  }
496
- return usageLines.filter((l3) => typeof l3 === "string").join("\n");
497
498
  }
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;
499
+ function isActionKey(n4, e2) {
500
+ if (typeof n4 == "string")
501
+ return settings.aliases.get(n4) === e2;
502
+ for (const s2 of n4)
503
+ if (s2 !== void 0 && isActionKey(s2, e2))
504
+ return true;
505
+ return false;
504
506
  }
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
- }
507
+ function diffLines(i3, s2) {
508
+ if (i3 === s2) return;
509
+ const e2 = i3.split(`
510
+ `), t3 = s2.split(`
511
+ `), r3 = Math.max(e2.length, t3.length), f2 = [];
512
+ for (let n4 = 0; n4 < r3; n4++)
513
+ e2[n4] !== t3[n4] && f2.push(n4);
543
514
  return {
544
- help: _getBuiltinFlags("help", "h", userNames, userAliases),
545
- version: _getBuiltinFlags("version", "v", userNames, userAliases)
515
+ lines: f2,
516
+ numLinesBefore: e2.length,
517
+ numLinesAfter: t3.length,
518
+ numLines: r3
546
519
  };
547
520
  }
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}`];
521
+ var R = globalThis.process.platform.startsWith("win");
522
+ var CANCEL_SYMBOL = /* @__PURE__ */ Symbol("clack:cancel");
523
+ function isCancel(e2) {
524
+ return e2 === CANCEL_SYMBOL;
552
525
  }
553
-
554
- // package.json
555
- var package_default = {
556
- name: "zapdev",
557
- version: "1.10.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"
562
- },
563
- files: [
564
- "dist"
565
- ],
566
- engines: {
567
- node: ">=20"
568
- },
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"
582
- },
583
- homepage: "https://github.com/mvagnon/zapdev#readme",
584
- bugs: {
585
- url: "https://github.com/mvagnon/zapdev/issues"
586
- },
587
- publishConfig: {
588
- access: "public"
589
- },
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"
597
- },
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"
612
- }
613
- };
614
-
615
- // src/commands/commit.ts
616
- import { basename } from "node:path";
617
- import { styleText as styleText4 } from "node:util";
618
-
619
- // node_modules/@clack/core/dist/index.mjs
620
- import { styleText } from "node:util";
621
- import { stdout, stdin } from "node:process";
622
- import * as l from "node:readline";
623
- import l__default from "node:readline";
624
-
625
- // node_modules/fast-string-truncated-width/dist/utils.js
626
- var getCodePointsLength = /* @__PURE__ */ (() => {
627
- const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
628
- return (input) => {
629
- let surrogatePairsNr = 0;
630
- SURROGATE_PAIR_RE.lastIndex = 0;
631
- while (SURROGATE_PAIR_RE.test(input)) {
632
- surrogatePairsNr += 1;
526
+ function setRawMode(e2, r3) {
527
+ const o2 = e2;
528
+ o2.isTTY && o2.setRawMode(r3);
529
+ }
530
+ function block({
531
+ input: e2 = stdin,
532
+ output: r3 = stdout,
533
+ overwrite: o2 = true,
534
+ hideCursor: t3 = true
535
+ } = {}) {
536
+ const s2 = l.createInterface({
537
+ input: e2,
538
+ output: r3,
539
+ prompt: "",
540
+ tabSize: 1
541
+ });
542
+ l.emitKeypressEvents(e2, s2), e2 instanceof ReadStream && e2.isTTY && e2.setRawMode(true);
543
+ const n4 = (f2, { name: a3, sequence: p2 }) => {
544
+ const c3 = String(f2);
545
+ if (isActionKey([c3, a3, p2], "cancel")) {
546
+ t3 && r3.write(import_sisteransi.cursor.show), process.exit(0);
547
+ return;
633
548
  }
634
- return input.length - surrogatePairsNr;
549
+ if (!o2) return;
550
+ const i3 = a3 === "return" ? 0 : -1, m2 = a3 === "return" ? -1 : 0;
551
+ l.moveCursor(r3, i3, m2, () => {
552
+ l.clearLine(r3, 1, () => {
553
+ e2.once("keypress", n4);
554
+ });
555
+ });
635
556
  };
636
- })();
637
- var isFullWidth = (x2) => {
638
- return x2 === 12288 || x2 >= 65281 && x2 <= 65376 || x2 >= 65504 && x2 <= 65510;
639
- };
640
- var isWideNotCJKTNotEmoji = (x2) => {
641
- 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;
642
- };
643
-
644
- // node_modules/fast-string-truncated-width/dist/index.js
645
- var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
646
- var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
647
- 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;
648
- var TAB_RE = /\t{1,1000}/y;
649
- 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");
650
- var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
651
- var MODIFIER_RE = new RegExp("\\p{M}+", "gu");
652
- var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
653
- var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
654
- const LIMIT = truncationOptions.limit ?? Infinity;
655
- const ELLIPSIS = truncationOptions.ellipsis ?? "";
656
- const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
657
- const ANSI_WIDTH = 0;
658
- const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
659
- const TAB_WIDTH = widthOptions.tabWidth ?? 8;
660
- const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
661
- const FULL_WIDTH_WIDTH = 2;
662
- const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
663
- const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
664
- const PARSE_BLOCKS = [
665
- [LATIN_RE, REGULAR_WIDTH],
666
- [ANSI_RE, ANSI_WIDTH],
667
- [CONTROL_RE, CONTROL_WIDTH],
668
- [TAB_RE, TAB_WIDTH],
669
- [EMOJI_RE, EMOJI_WIDTH],
670
- [CJKT_WIDE_RE, WIDE_WIDTH]
671
- ];
672
- let indexPrev = 0;
673
- let index = 0;
674
- let length = input.length;
675
- let lengthExtra = 0;
676
- let truncationEnabled = false;
677
- let truncationIndex = length;
678
- let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
679
- let unmatchedStart = 0;
680
- let unmatchedEnd = 0;
681
- let width = 0;
682
- let widthExtra = 0;
683
- outer: while (true) {
684
- if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
685
- const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
686
- lengthExtra = 0;
687
- for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
688
- const codePoint = char.codePointAt(0) || 0;
689
- if (isFullWidth(codePoint)) {
690
- widthExtra = FULL_WIDTH_WIDTH;
691
- } else if (isWideNotCJKTNotEmoji(codePoint)) {
692
- widthExtra = WIDE_WIDTH;
693
- } else {
694
- widthExtra = REGULAR_WIDTH;
695
- }
696
- if (width + widthExtra > truncationLimit) {
697
- truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
698
- }
699
- if (width + widthExtra > LIMIT) {
700
- truncationEnabled = true;
701
- break outer;
702
- }
703
- lengthExtra += char.length;
704
- width += widthExtra;
705
- }
706
- unmatchedStart = unmatchedEnd = 0;
707
- }
708
- if (index >= length) {
709
- break outer;
710
- }
711
- for (let i3 = 0, l3 = PARSE_BLOCKS.length; i3 < l3; i3++) {
712
- const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i3];
713
- BLOCK_RE.lastIndex = index;
714
- if (BLOCK_RE.test(input)) {
715
- lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
716
- widthExtra = lengthExtra * BLOCK_WIDTH;
717
- if (width + widthExtra > truncationLimit) {
718
- truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
719
- }
720
- if (width + widthExtra > LIMIT) {
721
- truncationEnabled = true;
722
- break outer;
723
- }
724
- width += widthExtra;
725
- unmatchedStart = indexPrev;
726
- unmatchedEnd = index;
727
- index = indexPrev = BLOCK_RE.lastIndex;
728
- continue outer;
729
- }
730
- }
731
- index += 1;
732
- }
733
- return {
734
- width: truncationEnabled ? truncationLimit : width,
735
- index: truncationEnabled ? truncationIndex : length,
736
- truncated: truncationEnabled,
737
- ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
557
+ return t3 && r3.write(import_sisteransi.cursor.hide), e2.once("keypress", n4), () => {
558
+ 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();
738
559
  };
739
- };
740
- var dist_default = getStringTruncatedWidth;
741
-
742
- // node_modules/fast-string-width/dist/index.js
743
- var NO_TRUNCATION2 = {
744
- limit: Infinity,
745
- ellipsis: "",
746
- ellipsisWidth: 0
747
- };
748
- var fastStringWidth = (input, options = {}) => {
749
- return dist_default(input, NO_TRUNCATION2, options).width;
750
- };
751
- var dist_default2 = fastStringWidth;
752
-
753
- // node_modules/fast-wrap-ansi/lib/main.js
754
- var ESC = "\x1B";
755
- var CSI = "\x9B";
756
- var END_CODE = 39;
757
- var ANSI_ESCAPE_BELL = "\x07";
758
- var ANSI_CSI = "[";
759
- var ANSI_OSC = "]";
760
- var ANSI_SGR_TERMINATOR = "m";
761
- var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
762
- var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
763
- var getClosingCode = (openingCode) => {
764
- if (openingCode >= 30 && openingCode <= 37)
765
- return 39;
766
- if (openingCode >= 90 && openingCode <= 97)
767
- return 39;
768
- if (openingCode >= 40 && openingCode <= 47)
769
- return 49;
770
- if (openingCode >= 100 && openingCode <= 107)
771
- return 49;
772
- if (openingCode === 1 || openingCode === 2)
773
- return 22;
774
- if (openingCode === 3)
775
- return 23;
776
- if (openingCode === 4)
777
- return 24;
778
- if (openingCode === 7)
779
- return 27;
780
- if (openingCode === 8)
781
- return 28;
782
- if (openingCode === 9)
783
- return 29;
784
- if (openingCode === 0)
785
- return 0;
786
- return void 0;
787
- };
788
- var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
789
- var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
790
- var wrapWord = (rows, word, columns) => {
791
- const characters = word[Symbol.iterator]();
792
- let isInsideEscape = false;
793
- let isInsideLinkEscape = false;
794
- let lastRow = rows.at(-1);
795
- let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
796
- let currentCharacter = characters.next();
797
- let nextCharacter = characters.next();
798
- let rawCharacterIndex = 0;
799
- while (!currentCharacter.done) {
800
- const character = currentCharacter.value;
801
- const characterLength = dist_default2(character);
802
- if (visible + characterLength <= columns) {
803
- rows[rows.length - 1] += character;
804
- } else {
805
- rows.push(character);
806
- visible = 0;
807
- }
808
- if (character === ESC || character === CSI) {
809
- isInsideEscape = true;
810
- isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
811
- }
812
- if (isInsideEscape) {
813
- if (isInsideLinkEscape) {
814
- if (character === ANSI_ESCAPE_BELL) {
815
- isInsideEscape = false;
816
- isInsideLinkEscape = false;
817
- }
818
- } else if (character === ANSI_SGR_TERMINATOR) {
819
- isInsideEscape = false;
820
- }
821
- } else {
822
- visible += characterLength;
823
- if (visible === columns && !nextCharacter.done) {
824
- rows.push("");
825
- visible = 0;
826
- }
827
- }
828
- currentCharacter = nextCharacter;
829
- nextCharacter = characters.next();
830
- rawCharacterIndex += character.length;
560
+ }
561
+ var getColumns = (e2) => "columns" in e2 && typeof e2.columns == "number" ? e2.columns : 80;
562
+ var getRows = (e2) => "rows" in e2 && typeof e2.rows == "number" ? e2.rows : 20;
563
+ function wrapTextWithPrefix(e2, r3, o2, t3 = o2, s2 = o2, n4) {
564
+ const f2 = getColumns(e2 ?? stdout);
565
+ return wrapAnsi(r3, f2 - o2.length, {
566
+ hard: true,
567
+ trim: false
568
+ }).split(`
569
+ `).map((c3, i3, m2) => {
570
+ const d2 = n4 ? n4(c3, i3) : c3;
571
+ return i3 === 0 ? `${t3}${d2}` : i3 === m2.length - 1 ? `${s2}${d2}` : `${o2}${d2}`;
572
+ }).join(`
573
+ `);
574
+ }
575
+ function runValidation(e2, n4) {
576
+ if ("~standard" in e2) {
577
+ const a3 = e2["~standard"].validate(n4);
578
+ if (a3 instanceof Promise)
579
+ throw new TypeError(
580
+ "Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic."
581
+ );
582
+ return a3.issues?.at(0)?.message;
831
583
  }
832
- lastRow = rows.at(-1);
833
- if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
834
- rows[rows.length - 2] += rows.pop();
584
+ return e2(n4);
585
+ }
586
+ var V = class {
587
+ input;
588
+ output;
589
+ _abortSignal;
590
+ rl;
591
+ opts;
592
+ _render;
593
+ _track = false;
594
+ _prevFrame = "";
595
+ _subscribers = /* @__PURE__ */ new Map();
596
+ _cursor = 0;
597
+ state = "initial";
598
+ error = "";
599
+ value;
600
+ userInput = "";
601
+ constructor(t3, e2 = true) {
602
+ const { input: i3 = stdin, output: n4 = stdout, render: s2, signal: r3, ...o2 } = t3;
603
+ 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;
835
604
  }
836
- };
837
- var stringVisibleTrimSpacesRight = (string) => {
838
- const words = string.split(" ");
839
- let last = words.length;
840
- while (last) {
841
- if (dist_default2(words[last - 1])) {
842
- break;
843
- }
844
- last--;
605
+ /**
606
+ * Unsubscribe all listeners
607
+ */
608
+ unsubscribe() {
609
+ this._subscribers.clear();
845
610
  }
846
- if (last === words.length) {
847
- return string;
611
+ /**
612
+ * Set a subscriber with opts
613
+ * @param event - The event name
614
+ */
615
+ setSubscriber(t3, e2) {
616
+ const i3 = this._subscribers.get(t3) ?? [];
617
+ i3.push(e2), this._subscribers.set(t3, i3);
848
618
  }
849
- return words.slice(0, last).join(" ") + words.slice(last).join("");
850
- };
851
- var exec = (string, columns, options = {}) => {
852
- if (options.trim !== false && string.trim() === "") {
853
- return "";
619
+ /**
620
+ * Subscribe to an event
621
+ * @param event - The event name
622
+ * @param cb - The callback
623
+ */
624
+ on(t3, e2) {
625
+ this.setSubscriber(t3, { cb: e2 });
854
626
  }
855
- let returnValue = "";
856
- let escapeCode;
857
- let escapeUrl;
858
- const words = string.split(" ");
859
- let rows = [""];
860
- let rowLength = 0;
861
- for (let index = 0; index < words.length; index++) {
862
- const word = words[index];
863
- if (options.trim !== false) {
864
- const row = rows.at(-1) ?? "";
865
- const trimmed = row.trimStart();
866
- if (row.length !== trimmed.length) {
867
- rows[rows.length - 1] = trimmed;
868
- rowLength = dist_default2(trimmed);
869
- }
870
- }
871
- if (index !== 0) {
872
- if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
873
- rows.push("");
874
- rowLength = 0;
875
- }
876
- if (rowLength || options.trim === false) {
877
- rows[rows.length - 1] += " ";
878
- rowLength++;
879
- }
880
- }
881
- const wordLength = dist_default2(word);
882
- if (options.hard && wordLength > columns) {
883
- const remainingColumns = columns - rowLength;
884
- const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
885
- const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
886
- if (breaksStartingNextLine < breaksStartingThisLine) {
887
- rows.push("");
888
- }
889
- wrapWord(rows, word, columns);
890
- rowLength = dist_default2(rows.at(-1) ?? "");
891
- continue;
892
- }
893
- if (rowLength + wordLength > columns && rowLength && wordLength) {
894
- if (options.wordWrap === false && rowLength < columns) {
895
- wrapWord(rows, word, columns);
896
- rowLength = dist_default2(rows.at(-1) ?? "");
897
- continue;
898
- }
899
- rows.push("");
900
- rowLength = 0;
901
- }
902
- if (rowLength + wordLength > columns && options.wordWrap === false) {
903
- wrapWord(rows, word, columns);
904
- rowLength = dist_default2(rows.at(-1) ?? "");
905
- continue;
906
- }
907
- rows[rows.length - 1] += word;
908
- rowLength += wordLength;
627
+ /**
628
+ * Subscribe to an event once
629
+ * @param event - The event name
630
+ * @param cb - The callback
631
+ */
632
+ once(t3, e2) {
633
+ this.setSubscriber(t3, { cb: e2, once: true });
909
634
  }
910
- if (options.trim !== false) {
911
- rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
912
- }
913
- const preString = rows.join("\n");
914
- let inSurrogate = false;
915
- for (let i3 = 0; i3 < preString.length; i3++) {
916
- const character = preString[i3];
917
- returnValue += character;
918
- if (!inSurrogate) {
919
- inSurrogate = character >= "\uD800" && character <= "\uDBFF";
920
- if (inSurrogate) {
921
- continue;
922
- }
923
- } else {
924
- inSurrogate = false;
925
- }
926
- if (character === ESC || character === CSI) {
927
- GROUP_REGEX.lastIndex = i3 + 1;
928
- const groupsResult = GROUP_REGEX.exec(preString);
929
- const groups = groupsResult?.groups;
930
- if (groups?.code !== void 0) {
931
- const code = Number.parseFloat(groups.code);
932
- escapeCode = code === END_CODE ? void 0 : code;
933
- } else if (groups?.uri !== void 0) {
934
- escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
935
- }
936
- }
937
- if (preString[i3 + 1] === "\n") {
938
- if (escapeUrl) {
939
- returnValue += wrapAnsiHyperlink("");
940
- }
941
- const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
942
- if (escapeCode && closingCode) {
943
- returnValue += wrapAnsiCode(closingCode);
944
- }
945
- } else if (character === "\n") {
946
- if (escapeCode && getClosingCode(escapeCode)) {
947
- returnValue += wrapAnsiCode(escapeCode);
948
- }
949
- if (escapeUrl) {
950
- returnValue += wrapAnsiHyperlink(escapeUrl);
951
- }
952
- }
953
- }
954
- return returnValue;
955
- };
956
- var CRLF_OR_LF = /\r?\n/;
957
- function wrapAnsi(string, columns, options) {
958
- return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
959
- }
960
-
961
- // node_modules/@clack/core/dist/index.mjs
962
- var import_sisteransi = __toESM(require_src(), 1);
963
- import { ReadStream } from "node:tty";
964
- function findCursor(s2, o2, l3) {
965
- if (!l3.some((r3) => !r3.disabled))
966
- return s2;
967
- const t3 = s2 + o2, n4 = Math.max(l3.length - 1, 0), e2 = t3 < 0 ? n4 : t3 > n4 ? 0 : t3;
968
- return l3[e2]?.disabled ? findCursor(e2, o2 < 0 ? -1 : 1, l3) : e2;
969
- }
970
- var a$1 = ["up", "down", "left", "right", "space", "enter", "cancel"];
971
- var t = [
972
- "January",
973
- "February",
974
- "March",
975
- "April",
976
- "May",
977
- "June",
978
- "July",
979
- "August",
980
- "September",
981
- "October",
982
- "November",
983
- "December"
984
- ];
985
- var settings = {
986
- actions: new Set(a$1),
987
- aliases: /* @__PURE__ */ new Map([
988
- // vim support
989
- ["k", "up"],
990
- ["j", "down"],
991
- ["h", "left"],
992
- ["l", "right"],
993
- ["", "cancel"],
994
- // opinionated defaults!
995
- ["escape", "cancel"]
996
- ]),
997
- messages: {
998
- cancel: "Canceled",
999
- error: "Something went wrong"
1000
- },
1001
- withGuide: true,
1002
- date: {
1003
- monthNames: [...t],
1004
- messages: {
1005
- required: "Please enter a valid date",
1006
- invalidMonth: "There are only 12 months in a year",
1007
- invalidDay: (n4, e2) => `There are only ${n4} days in ${e2}`,
1008
- afterMin: (n4) => `Date must be on or after ${n4.toISOString().slice(0, 10)}`,
1009
- beforeMax: (n4) => `Date must be on or before ${n4.toISOString().slice(0, 10)}`
1010
- }
1011
- }
1012
- };
1013
- function isActionKey(n4, e2) {
1014
- if (typeof n4 == "string")
1015
- return settings.aliases.get(n4) === e2;
1016
- for (const s2 of n4)
1017
- if (s2 !== void 0 && isActionKey(s2, e2))
1018
- return true;
1019
- return false;
1020
- }
1021
- function diffLines(i3, s2) {
1022
- if (i3 === s2) return;
1023
- const e2 = i3.split(`
1024
- `), t3 = s2.split(`
1025
- `), r3 = Math.max(e2.length, t3.length), f2 = [];
1026
- for (let n4 = 0; n4 < r3; n4++)
1027
- e2[n4] !== t3[n4] && f2.push(n4);
1028
- return {
1029
- lines: f2,
1030
- numLinesBefore: e2.length,
1031
- numLinesAfter: t3.length,
1032
- numLines: r3
1033
- };
1034
- }
1035
- var R = globalThis.process.platform.startsWith("win");
1036
- var CANCEL_SYMBOL = /* @__PURE__ */ Symbol("clack:cancel");
1037
- function isCancel(e2) {
1038
- return e2 === CANCEL_SYMBOL;
1039
- }
1040
- function setRawMode(e2, r3) {
1041
- const o2 = e2;
1042
- o2.isTTY && o2.setRawMode(r3);
1043
- }
1044
- function block({
1045
- input: e2 = stdin,
1046
- output: r3 = stdout,
1047
- overwrite: o2 = true,
1048
- hideCursor: t3 = true
1049
- } = {}) {
1050
- const s2 = l.createInterface({
1051
- input: e2,
1052
- output: r3,
1053
- prompt: "",
1054
- tabSize: 1
1055
- });
1056
- l.emitKeypressEvents(e2, s2), e2 instanceof ReadStream && e2.isTTY && e2.setRawMode(true);
1057
- const n4 = (f2, { name: a3, sequence: p2 }) => {
1058
- const c3 = String(f2);
1059
- if (isActionKey([c3, a3, p2], "cancel")) {
1060
- t3 && r3.write(import_sisteransi.cursor.show), process.exit(0);
1061
- return;
1062
- }
1063
- if (!o2) return;
1064
- const i3 = a3 === "return" ? 0 : -1, m2 = a3 === "return" ? -1 : 0;
1065
- l.moveCursor(r3, i3, m2, () => {
1066
- l.clearLine(r3, 1, () => {
1067
- e2.once("keypress", n4);
1068
- });
1069
- });
1070
- };
1071
- return t3 && r3.write(import_sisteransi.cursor.hide), e2.once("keypress", n4), () => {
1072
- 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();
1073
- };
1074
- }
1075
- var getColumns = (e2) => "columns" in e2 && typeof e2.columns == "number" ? e2.columns : 80;
1076
- var getRows = (e2) => "rows" in e2 && typeof e2.rows == "number" ? e2.rows : 20;
1077
- function wrapTextWithPrefix(e2, r3, o2, t3 = o2, s2 = o2, n4) {
1078
- const f2 = getColumns(e2 ?? stdout);
1079
- return wrapAnsi(r3, f2 - o2.length, {
1080
- hard: true,
1081
- trim: false
1082
- }).split(`
1083
- `).map((c3, i3, m2) => {
1084
- const d2 = n4 ? n4(c3, i3) : c3;
1085
- return i3 === 0 ? `${t3}${d2}` : i3 === m2.length - 1 ? `${s2}${d2}` : `${o2}${d2}`;
1086
- }).join(`
1087
- `);
1088
- }
1089
- function runValidation(e2, n4) {
1090
- if ("~standard" in e2) {
1091
- const a3 = e2["~standard"].validate(n4);
1092
- if (a3 instanceof Promise)
1093
- throw new TypeError(
1094
- "Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic."
1095
- );
1096
- return a3.issues?.at(0)?.message;
1097
- }
1098
- return e2(n4);
1099
- }
1100
- var V = class {
1101
- input;
1102
- output;
1103
- _abortSignal;
1104
- rl;
1105
- opts;
1106
- _render;
1107
- _track = false;
1108
- _prevFrame = "";
1109
- _subscribers = /* @__PURE__ */ new Map();
1110
- _cursor = 0;
1111
- state = "initial";
1112
- error = "";
1113
- value;
1114
- userInput = "";
1115
- constructor(t3, e2 = true) {
1116
- const { input: i3 = stdin, output: n4 = stdout, render: s2, signal: r3, ...o2 } = t3;
1117
- 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;
1118
- }
1119
- /**
1120
- * Unsubscribe all listeners
1121
- */
1122
- unsubscribe() {
1123
- this._subscribers.clear();
1124
- }
1125
- /**
1126
- * Set a subscriber with opts
1127
- * @param event - The event name
1128
- */
1129
- setSubscriber(t3, e2) {
1130
- const i3 = this._subscribers.get(t3) ?? [];
1131
- i3.push(e2), this._subscribers.set(t3, i3);
1132
- }
1133
- /**
1134
- * Subscribe to an event
1135
- * @param event - The event name
1136
- * @param cb - The callback
1137
- */
1138
- on(t3, e2) {
1139
- this.setSubscriber(t3, { cb: e2 });
1140
- }
1141
- /**
1142
- * Subscribe to an event once
1143
- * @param event - The event name
1144
- * @param cb - The callback
1145
- */
1146
- once(t3, e2) {
1147
- this.setSubscriber(t3, { cb: e2, once: true });
1148
- }
1149
- /**
1150
- * Emit an event with data
1151
- * @param event - The event name
1152
- * @param data - The data to pass to the callback
1153
- */
1154
- emit(t3, ...e2) {
1155
- const i3 = this._subscribers.get(t3) ?? [], n4 = [];
1156
- for (const s2 of i3)
1157
- s2.cb(...e2), s2.once && n4.push(() => i3.splice(i3.indexOf(s2), 1));
1158
- for (const s2 of n4)
1159
- s2();
635
+ /**
636
+ * Emit an event with data
637
+ * @param event - The event name
638
+ * @param data - The data to pass to the callback
639
+ */
640
+ emit(t3, ...e2) {
641
+ const i3 = this._subscribers.get(t3) ?? [], n4 = [];
642
+ for (const s2 of i3)
643
+ s2.cb(...e2), s2.once && n4.push(() => i3.splice(i3.indexOf(s2), 1));
644
+ for (const s2 of n4)
645
+ s2();
1160
646
  }
1161
647
  prompt() {
1162
648
  return new Promise((t3) => {
@@ -1651,191 +1137,668 @@ var spinner = ({
1651
1137
  return S2;
1652
1138
  }
1653
1139
  };
1654
- };
1655
- var u2 = {
1656
- light: unicodeOr("\u2500", "-"),
1657
- heavy: unicodeOr("\u2501", "="),
1658
- block: unicodeOr("\u2588", "#")
1659
- };
1660
- var SELECT_INSTRUCTIONS = [
1661
- `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1662
- `${styleText2("dim", "Enter:")} confirm`
1663
- ];
1664
- var c = (t3, o2) => t3.includes(`
1665
- `) ? t3.split(`
1666
- `).map((d2) => o2(d2)).join(`
1667
- `) : o2(t3);
1668
- var select = (t3) => {
1669
- const o2 = (n4, m2) => {
1670
- if (n4 === void 0)
1671
- return "";
1672
- const s2 = n4.label ?? String(n4.value);
1673
- switch (m2) {
1674
- case "disabled":
1675
- return `${styleText2("gray", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("gray", i3))}${n4.hint ? ` ${styleText2("dim", `(${n4.hint ?? "disabled"})`)}` : ""}`;
1676
- case "selected":
1677
- return `${c(s2, (i3) => styleText2("dim", i3))}`;
1678
- case "active":
1679
- return `${styleText2("green", S_RADIO_ACTIVE)} ${s2}${n4.hint ? ` ${styleText2("dim", `(${n4.hint})`)}` : ""}`;
1680
- case "cancelled":
1681
- return `${c(s2, (i3) => styleText2(["strikethrough", "dim"], i3))}`;
1682
- default:
1683
- return `${styleText2("dim", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("dim", i3))}`;
1684
- }
1685
- }, d2 = t3.showInstructions ?? true;
1686
- return new n$1({
1687
- options: t3.options,
1688
- signal: t3.signal,
1689
- input: t3.input,
1690
- output: t3.output,
1691
- initialValue: t3.initialValue,
1692
- render() {
1693
- const n4 = t3.withGuide ?? settings.withGuide, m2 = `${symbol(this.state)} `, s2 = `${symbolBar(this.state)} `, i3 = wrapTextWithPrefix(
1694
- t3.output,
1695
- t3.message,
1696
- s2,
1697
- m2
1698
- ), u4 = `${n4 ? `${styleText2("gray", S_BAR)}
1699
- ` : ""}${i3}
1700
- `;
1701
- switch (this.state) {
1702
- case "submit": {
1703
- const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1704
- t3.output,
1705
- o2(this.options[this.cursor], "selected"),
1706
- r3
1707
- );
1708
- return `${u4}${a3}`;
1709
- }
1710
- case "cancel": {
1711
- const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1712
- t3.output,
1713
- o2(this.options[this.cursor], "cancelled"),
1714
- r3
1715
- );
1716
- return `${u4}${a3}${n4 ? `
1717
- ${styleText2("gray", S_BAR)}` : ""}`;
1718
- }
1719
- default: {
1720
- const r3 = n4 ? `${styleText2("cyan", S_BAR)} ` : "", a3 = u4.split(`
1721
- `).length, p2 = d2 ? formatInstructionFooter(SELECT_INSTRUCTIONS, n4) : n4 ? [styleText2("cyan", S_BAR_END)] : [], b2 = p2.join(`
1722
- `), f2 = p2.length + 1;
1723
- return `${u4}${r3}${limitOptions({
1724
- output: t3.output,
1725
- cursor: this.cursor,
1726
- options: this.options,
1727
- maxItems: t3.maxItems,
1728
- columnPadding: r3.length,
1729
- rowPadding: a3 + f2,
1730
- style: (g2, x2) => o2(g2, g2.disabled ? "disabled" : x2 ? "active" : "inactive")
1731
- }).join(`
1732
- ${r3}`)}
1733
- ${b2}
1734
- `;
1735
- }
1140
+ };
1141
+ var u2 = {
1142
+ light: unicodeOr("\u2500", "-"),
1143
+ heavy: unicodeOr("\u2501", "="),
1144
+ block: unicodeOr("\u2588", "#")
1145
+ };
1146
+ var SELECT_INSTRUCTIONS = [
1147
+ `${styleText2("dim", "\u2191/\u2193")} to navigate`,
1148
+ `${styleText2("dim", "Enter:")} confirm`
1149
+ ];
1150
+ var c = (t3, o2) => t3.includes(`
1151
+ `) ? t3.split(`
1152
+ `).map((d2) => o2(d2)).join(`
1153
+ `) : o2(t3);
1154
+ var select = (t3) => {
1155
+ const o2 = (n4, m2) => {
1156
+ if (n4 === void 0)
1157
+ return "";
1158
+ const s2 = n4.label ?? String(n4.value);
1159
+ switch (m2) {
1160
+ case "disabled":
1161
+ return `${styleText2("gray", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("gray", i3))}${n4.hint ? ` ${styleText2("dim", `(${n4.hint ?? "disabled"})`)}` : ""}`;
1162
+ case "selected":
1163
+ return `${c(s2, (i3) => styleText2("dim", i3))}`;
1164
+ case "active":
1165
+ return `${styleText2("green", S_RADIO_ACTIVE)} ${s2}${n4.hint ? ` ${styleText2("dim", `(${n4.hint})`)}` : ""}`;
1166
+ case "cancelled":
1167
+ return `${c(s2, (i3) => styleText2(["strikethrough", "dim"], i3))}`;
1168
+ default:
1169
+ return `${styleText2("dim", S_RADIO_INACTIVE)} ${c(s2, (i3) => styleText2("dim", i3))}`;
1170
+ }
1171
+ }, d2 = t3.showInstructions ?? true;
1172
+ return new n$1({
1173
+ options: t3.options,
1174
+ signal: t3.signal,
1175
+ input: t3.input,
1176
+ output: t3.output,
1177
+ initialValue: t3.initialValue,
1178
+ render() {
1179
+ const n4 = t3.withGuide ?? settings.withGuide, m2 = `${symbol(this.state)} `, s2 = `${symbolBar(this.state)} `, i3 = wrapTextWithPrefix(
1180
+ t3.output,
1181
+ t3.message,
1182
+ s2,
1183
+ m2
1184
+ ), u4 = `${n4 ? `${styleText2("gray", S_BAR)}
1185
+ ` : ""}${i3}
1186
+ `;
1187
+ switch (this.state) {
1188
+ case "submit": {
1189
+ const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1190
+ t3.output,
1191
+ o2(this.options[this.cursor], "selected"),
1192
+ r3
1193
+ );
1194
+ return `${u4}${a3}`;
1195
+ }
1196
+ case "cancel": {
1197
+ const r3 = n4 ? `${styleText2("gray", S_BAR)} ` : "", a3 = wrapTextWithPrefix(
1198
+ t3.output,
1199
+ o2(this.options[this.cursor], "cancelled"),
1200
+ r3
1201
+ );
1202
+ return `${u4}${a3}${n4 ? `
1203
+ ${styleText2("gray", S_BAR)}` : ""}`;
1204
+ }
1205
+ default: {
1206
+ const r3 = n4 ? `${styleText2("cyan", S_BAR)} ` : "", a3 = u4.split(`
1207
+ `).length, p2 = d2 ? formatInstructionFooter(SELECT_INSTRUCTIONS, n4) : n4 ? [styleText2("cyan", S_BAR_END)] : [], b2 = p2.join(`
1208
+ `), f2 = p2.length + 1;
1209
+ return `${u4}${r3}${limitOptions({
1210
+ output: t3.output,
1211
+ cursor: this.cursor,
1212
+ options: this.options,
1213
+ maxItems: t3.maxItems,
1214
+ columnPadding: r3.length,
1215
+ rowPadding: a3 + f2,
1216
+ style: (g2, x2) => o2(g2, g2.disabled ? "disabled" : x2 ? "active" : "inactive")
1217
+ }).join(`
1218
+ ${r3}`)}
1219
+ ${b2}
1220
+ `;
1221
+ }
1222
+ }
1223
+ }
1224
+ }).prompt();
1225
+ };
1226
+ var i = `${styleText2("gray", S_BAR)} `;
1227
+ var text = (e2) => new n2({
1228
+ validate: e2.validate,
1229
+ placeholder: e2.placeholder,
1230
+ defaultValue: e2.defaultValue,
1231
+ initialValue: e2.initialValue,
1232
+ output: e2.output,
1233
+ signal: e2.signal,
1234
+ input: e2.input,
1235
+ render() {
1236
+ const i3 = e2?.withGuide ?? settings.withGuide, s2 = `${`${i3 ? `${styleText2("gray", S_BAR)}
1237
+ ` : ""}${symbol(this.state)} `}${e2.message}
1238
+ `, c3 = e2.placeholder && e2.placeholder.length > 0 ? (
1239
+ // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
1240
+ styleText2("inverse", e2.placeholder[0]) + styleText2("dim", e2.placeholder.slice(1))
1241
+ ) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, l3 = this.value ?? "";
1242
+ switch (this.state) {
1243
+ case "error": {
1244
+ const n4 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r3 = i3 ? `${styleText2("yellow", S_BAR)} ` : "", d2 = i3 ? styleText2("yellow", S_BAR_END) : "";
1245
+ return `${s2.trim()}
1246
+ ${r3}${o2}
1247
+ ${d2}${n4}
1248
+ `;
1249
+ }
1250
+ case "submit": {
1251
+ const n4 = l3 ? ` ${styleText2("dim", l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1252
+ return `${s2}${r3}${n4}`;
1253
+ }
1254
+ case "cancel": {
1255
+ const n4 = l3 ? ` ${styleText2(["strikethrough", "dim"], l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1256
+ return `${s2}${r3}${n4}${l3.trim() ? `
1257
+ ${r3}` : ""}`;
1258
+ }
1259
+ default: {
1260
+ const n4 = i3 ? `${styleText2("cyan", S_BAR)} ` : "", r3 = i3 ? styleText2("cyan", S_BAR_END) : "";
1261
+ return `${s2}${n4}${o2}
1262
+ ${r3}
1263
+ `;
1264
+ }
1265
+ }
1266
+ }
1267
+ }).prompt();
1268
+
1269
+ // node_modules/citty/dist/_chunks/libs/scule.mjs
1270
+ var NUMBER_CHAR_RE = /\d/;
1271
+ var STR_SPLITTERS = [
1272
+ "-",
1273
+ "_",
1274
+ "/",
1275
+ "."
1276
+ ];
1277
+ function isUppercase(char = "") {
1278
+ if (NUMBER_CHAR_RE.test(char)) return;
1279
+ return char !== char.toLowerCase();
1280
+ }
1281
+ function splitByCase(str, separators) {
1282
+ const splitters = separators ?? STR_SPLITTERS;
1283
+ const parts = [];
1284
+ if (!str || typeof str !== "string") return parts;
1285
+ let buff = "";
1286
+ let previousUpper;
1287
+ let previousSplitter;
1288
+ for (const char of str) {
1289
+ const isSplitter = splitters.includes(char);
1290
+ if (isSplitter === true) {
1291
+ parts.push(buff);
1292
+ buff = "";
1293
+ previousUpper = void 0;
1294
+ continue;
1295
+ }
1296
+ const isUpper = isUppercase(char);
1297
+ if (previousSplitter === false) {
1298
+ if (previousUpper === false && isUpper === true) {
1299
+ parts.push(buff);
1300
+ buff = char;
1301
+ previousUpper = isUpper;
1302
+ continue;
1303
+ }
1304
+ if (previousUpper === true && isUpper === false && buff.length > 1) {
1305
+ const lastChar = buff.at(-1);
1306
+ parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
1307
+ buff = lastChar + char;
1308
+ previousUpper = isUpper;
1309
+ continue;
1310
+ }
1311
+ }
1312
+ buff += char;
1313
+ previousUpper = isUpper;
1314
+ previousSplitter = isSplitter;
1315
+ }
1316
+ parts.push(buff);
1317
+ return parts;
1318
+ }
1319
+ function upperFirst(str) {
1320
+ return str ? str[0].toUpperCase() + str.slice(1) : "";
1321
+ }
1322
+ function lowerFirst(str) {
1323
+ return str ? str[0].toLowerCase() + str.slice(1) : "";
1324
+ }
1325
+ function pascalCase(str, opts) {
1326
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => upperFirst(opts?.normalize ? p2.toLowerCase() : p2)).join("") : "";
1327
+ }
1328
+ function camelCase(str, opts) {
1329
+ return lowerFirst(pascalCase(str || "", opts));
1330
+ }
1331
+ function kebabCase(str, joiner) {
1332
+ return str ? (Array.isArray(str) ? str : splitByCase(str)).map((p2) => p2.toLowerCase()).join(joiner ?? "-") : "";
1333
+ }
1334
+ function snakeCase(str) {
1335
+ return kebabCase(str || "", "_");
1336
+ }
1337
+
1338
+ // node_modules/citty/dist/index.mjs
1339
+ import { parseArgs as parseArgs$1 } from "node:util";
1340
+ function toArray(val) {
1341
+ if (Array.isArray(val)) return val;
1342
+ return val === void 0 ? [] : [val];
1343
+ }
1344
+ function formatLineColumns(lines, linePrefix = "") {
1345
+ const maxLength = [];
1346
+ for (const line of lines) for (const [i3, element] of line.entries()) maxLength[i3] = Math.max(maxLength[i3] || 0, element.length);
1347
+ return lines.map((l3) => l3.map((c3, i3) => linePrefix + c3[i3 === 0 ? "padStart" : "padEnd"](maxLength[i3])).join(" ")).join("\n");
1348
+ }
1349
+ function resolveValue(input) {
1350
+ return typeof input === "function" ? input() : input;
1351
+ }
1352
+ var CLIError = class extends Error {
1353
+ code;
1354
+ constructor(message, code) {
1355
+ super(message);
1356
+ this.name = "CLIError";
1357
+ this.code = code;
1358
+ }
1359
+ };
1360
+ function parseRawArgs(args = [], opts = {}) {
1361
+ const booleans = new Set(opts.boolean || []);
1362
+ const strings = new Set(opts.string || []);
1363
+ const aliasMap = opts.alias || {};
1364
+ const defaults = opts.default || {};
1365
+ const aliasToMain = /* @__PURE__ */ new Map();
1366
+ const mainToAliases = /* @__PURE__ */ new Map();
1367
+ for (const [key, value] of Object.entries(aliasMap)) {
1368
+ const targets = value;
1369
+ for (const target of targets) {
1370
+ aliasToMain.set(key, target);
1371
+ if (!mainToAliases.has(target)) mainToAliases.set(target, []);
1372
+ mainToAliases.get(target).push(key);
1373
+ aliasToMain.set(target, key);
1374
+ if (!mainToAliases.has(key)) mainToAliases.set(key, []);
1375
+ mainToAliases.get(key).push(target);
1376
+ }
1377
+ }
1378
+ const options = {};
1379
+ function getType(name) {
1380
+ if (booleans.has(name)) return "boolean";
1381
+ const aliases = mainToAliases.get(name) || [];
1382
+ for (const alias of aliases) if (booleans.has(alias)) return "boolean";
1383
+ return "string";
1384
+ }
1385
+ function isStringType(name) {
1386
+ if (strings.has(name)) return true;
1387
+ const aliases = mainToAliases.get(name) || [];
1388
+ for (const alias of aliases) if (strings.has(alias)) return true;
1389
+ return false;
1390
+ }
1391
+ const allOptions = /* @__PURE__ */ new Set([
1392
+ ...booleans,
1393
+ ...strings,
1394
+ ...Object.keys(aliasMap),
1395
+ ...Object.values(aliasMap).flat(),
1396
+ ...Object.keys(defaults)
1397
+ ]);
1398
+ for (const name of allOptions) if (!options[name]) options[name] = {
1399
+ type: getType(name),
1400
+ default: defaults[name]
1401
+ };
1402
+ for (const [alias, main2] of aliasToMain.entries()) if (alias.length === 1 && options[main2] && !options[main2].short) options[main2].short = alias;
1403
+ const processedArgs = [];
1404
+ const negatedFlags = {};
1405
+ for (let i3 = 0; i3 < args.length; i3++) {
1406
+ const arg = args[i3];
1407
+ if (arg === "--") {
1408
+ processedArgs.push(...args.slice(i3));
1409
+ break;
1410
+ }
1411
+ if (arg.startsWith("--no-")) {
1412
+ const flagName = arg.slice(5);
1413
+ negatedFlags[flagName] = true;
1414
+ continue;
1415
+ }
1416
+ processedArgs.push(arg);
1417
+ }
1418
+ let parsed;
1419
+ try {
1420
+ parsed = parseArgs$1({
1421
+ args: processedArgs,
1422
+ options: Object.keys(options).length > 0 ? options : void 0,
1423
+ allowPositionals: true,
1424
+ strict: false
1425
+ });
1426
+ } catch {
1427
+ parsed = {
1428
+ values: {},
1429
+ positionals: processedArgs
1430
+ };
1431
+ }
1432
+ const out = { _: [] };
1433
+ out._ = parsed.positionals;
1434
+ for (const [key, value] of Object.entries(parsed.values)) {
1435
+ let coerced = value;
1436
+ if (getType(key) === "boolean" && typeof value === "string") coerced = value !== "false";
1437
+ else if (isStringType(key) && typeof value === "boolean") coerced = "";
1438
+ out[key] = coerced;
1439
+ }
1440
+ for (const [name] of Object.entries(negatedFlags)) {
1441
+ out[name] = false;
1442
+ const mainName = aliasToMain.get(name);
1443
+ if (mainName) out[mainName] = false;
1444
+ const aliases = mainToAliases.get(name);
1445
+ if (aliases) for (const alias of aliases) out[alias] = false;
1446
+ }
1447
+ for (const [alias, main2] of aliasToMain.entries()) {
1448
+ if (out[alias] !== void 0 && out[main2] === void 0) out[main2] = out[alias];
1449
+ if (out[main2] !== void 0 && out[alias] === void 0) out[alias] = out[main2];
1450
+ if (out[alias] !== out[main2] && defaults[main2] === out[main2]) out[main2] = out[alias];
1451
+ }
1452
+ return out;
1453
+ }
1454
+ var noColor = /* @__PURE__ */ (() => {
1455
+ const env = globalThis.process?.env ?? {};
1456
+ return env.NO_COLOR === "1" || env.TERM === "dumb" || env.TEST || env.CI;
1457
+ })();
1458
+ var _c = (c3, r3 = 39) => (t3) => noColor ? t3 : `\x1B[${c3}m${t3}\x1B[${r3}m`;
1459
+ var bold = /* @__PURE__ */ _c(1, 22);
1460
+ var cyan = /* @__PURE__ */ _c(36);
1461
+ var gray = /* @__PURE__ */ _c(90);
1462
+ var underline = /* @__PURE__ */ _c(4, 24);
1463
+ function parseArgs(rawArgs, argsDef) {
1464
+ const parseOptions = {
1465
+ boolean: [],
1466
+ string: [],
1467
+ alias: {},
1468
+ default: {}
1469
+ };
1470
+ const args = resolveArgs(argsDef);
1471
+ for (const arg of args) {
1472
+ if (arg.type === "positional") continue;
1473
+ if (arg.type === "string" || arg.type === "enum") parseOptions.string.push(arg.name);
1474
+ else if (arg.type === "boolean") parseOptions.boolean.push(arg.name);
1475
+ if (arg.default !== void 0) parseOptions.default[arg.name] = arg.default;
1476
+ if (arg.alias) parseOptions.alias[arg.name] = arg.alias;
1477
+ const camelName = camelCase(arg.name);
1478
+ const kebabName = kebabCase(arg.name);
1479
+ if (camelName !== arg.name || kebabName !== arg.name) {
1480
+ const existingAliases = toArray(parseOptions.alias[arg.name] || []);
1481
+ if (camelName !== arg.name && !existingAliases.includes(camelName)) existingAliases.push(camelName);
1482
+ if (kebabName !== arg.name && !existingAliases.includes(kebabName)) existingAliases.push(kebabName);
1483
+ if (existingAliases.length > 0) parseOptions.alias[arg.name] = existingAliases;
1484
+ }
1485
+ }
1486
+ const parsed = parseRawArgs(rawArgs, parseOptions);
1487
+ const [...positionalArguments] = parsed._;
1488
+ const parsedArgsProxy = new Proxy(parsed, { get(target, prop) {
1489
+ return target[prop] ?? target[camelCase(prop)] ?? target[kebabCase(prop)];
1490
+ } });
1491
+ for (const [, arg] of args.entries()) if (arg.type === "positional") {
1492
+ const nextPositionalArgument = positionalArguments.shift();
1493
+ if (nextPositionalArgument !== void 0) parsedArgsProxy[arg.name] = nextPositionalArgument;
1494
+ else if (arg.default === void 0 && arg.required !== false) throw new CLIError(`Missing required positional argument: ${arg.name.toUpperCase()}`, "EARG");
1495
+ else parsedArgsProxy[arg.name] = arg.default;
1496
+ } else if (arg.type === "enum") {
1497
+ const argument = parsedArgsProxy[arg.name];
1498
+ const options = arg.options || [];
1499
+ 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");
1500
+ } else if (arg.required && parsedArgsProxy[arg.name] === void 0) throw new CLIError(`Missing required argument: --${arg.name}`, "EARG");
1501
+ return parsedArgsProxy;
1502
+ }
1503
+ function resolveArgs(argsDef) {
1504
+ const args = [];
1505
+ for (const [name, argDef] of Object.entries(argsDef || {})) args.push({
1506
+ ...argDef,
1507
+ name,
1508
+ alias: toArray(argDef.alias)
1509
+ });
1510
+ return args;
1511
+ }
1512
+ async function resolvePlugins(plugins) {
1513
+ return Promise.all(plugins.map((p2) => resolveValue(p2)));
1514
+ }
1515
+ function defineCommand(def) {
1516
+ return def;
1517
+ }
1518
+ async function runCommand(cmd, opts) {
1519
+ const cmdArgs = await resolveValue(cmd.args || {});
1520
+ const parsedArgs = parseArgs(opts.rawArgs, cmdArgs);
1521
+ const context = {
1522
+ rawArgs: opts.rawArgs,
1523
+ args: parsedArgs,
1524
+ data: opts.data,
1525
+ cmd
1526
+ };
1527
+ const plugins = await resolvePlugins(cmd.plugins ?? []);
1528
+ let result;
1529
+ let runError;
1530
+ try {
1531
+ for (const plugin of plugins) await plugin.setup?.(context);
1532
+ if (typeof cmd.setup === "function") await cmd.setup(context);
1533
+ const subCommands = await resolveValue(cmd.subCommands);
1534
+ if (subCommands && Object.keys(subCommands).length > 0) {
1535
+ const subCommandArgIndex = findSubCommandIndex(opts.rawArgs, cmdArgs);
1536
+ const explicitName = opts.rawArgs[subCommandArgIndex];
1537
+ if (explicitName) {
1538
+ const subCommand = await _findSubCommand(subCommands, explicitName);
1539
+ if (!subCommand) throw new CLIError(`Unknown command ${cyan(explicitName)}`, "E_UNKNOWN_COMMAND");
1540
+ await runCommand(subCommand, { rawArgs: opts.rawArgs.slice(subCommandArgIndex + 1) });
1541
+ } else {
1542
+ const defaultSubCommand = await resolveValue(cmd.default);
1543
+ if (defaultSubCommand) {
1544
+ if (cmd.run) throw new CLIError(`Cannot specify both 'run' and 'default' on the same command.`, "E_DEFAULT_CONFLICT");
1545
+ const subCommand = await _findSubCommand(subCommands, defaultSubCommand);
1546
+ if (!subCommand) throw new CLIError(`Default sub command ${cyan(defaultSubCommand)} not found in subCommands.`, "E_UNKNOWN_COMMAND");
1547
+ await runCommand(subCommand, { rawArgs: opts.rawArgs });
1548
+ } else if (!cmd.run) throw new CLIError(`No command specified.`, "E_NO_COMMAND");
1736
1549
  }
1737
1550
  }
1738
- }).prompt();
1739
- };
1740
- var i = `${styleText2("gray", S_BAR)} `;
1741
- var text = (e2) => new n2({
1742
- validate: e2.validate,
1743
- placeholder: e2.placeholder,
1744
- defaultValue: e2.defaultValue,
1745
- initialValue: e2.initialValue,
1746
- output: e2.output,
1747
- signal: e2.signal,
1748
- input: e2.input,
1749
- render() {
1750
- const i3 = e2?.withGuide ?? settings.withGuide, s2 = `${`${i3 ? `${styleText2("gray", S_BAR)}
1751
- ` : ""}${symbol(this.state)} `}${e2.message}
1752
- `, c3 = e2.placeholder && e2.placeholder.length > 0 ? (
1753
- // biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
1754
- styleText2("inverse", e2.placeholder[0]) + styleText2("dim", e2.placeholder.slice(1))
1755
- ) : styleText2(["inverse", "hidden"], "_"), o2 = this.userInput ? this.userInputWithCursor : c3, l3 = this.value ?? "";
1756
- switch (this.state) {
1757
- case "error": {
1758
- const n4 = this.error ? ` ${styleText2("yellow", this.error)}` : "", r3 = i3 ? `${styleText2("yellow", S_BAR)} ` : "", d2 = i3 ? styleText2("yellow", S_BAR_END) : "";
1759
- return `${s2.trim()}
1760
- ${r3}${o2}
1761
- ${d2}${n4}
1762
- `;
1763
- }
1764
- case "submit": {
1765
- const n4 = l3 ? ` ${styleText2("dim", l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1766
- return `${s2}${r3}${n4}`;
1767
- }
1768
- case "cancel": {
1769
- const n4 = l3 ? ` ${styleText2(["strikethrough", "dim"], l3)}` : "", r3 = i3 ? styleText2("gray", S_BAR) : "";
1770
- return `${s2}${r3}${n4}${l3.trim() ? `
1771
- ${r3}` : ""}`;
1772
- }
1773
- default: {
1774
- const n4 = i3 ? `${styleText2("cyan", S_BAR)} ` : "", r3 = i3 ? styleText2("cyan", S_BAR_END) : "";
1775
- return `${s2}${n4}${o2}
1776
- ${r3}
1777
- `;
1778
- }
1551
+ if (typeof cmd.run === "function") result = await cmd.run(context);
1552
+ } catch (error) {
1553
+ runError = error;
1554
+ }
1555
+ const cleanupErrors = [];
1556
+ if (typeof cmd.cleanup === "function") try {
1557
+ await cmd.cleanup(context);
1558
+ } catch (error) {
1559
+ cleanupErrors.push(error);
1560
+ }
1561
+ for (const plugin of [...plugins].reverse()) try {
1562
+ await plugin.cleanup?.(context);
1563
+ } catch (error) {
1564
+ cleanupErrors.push(error);
1565
+ }
1566
+ if (runError) throw runError;
1567
+ if (cleanupErrors.length === 1) throw cleanupErrors[0];
1568
+ if (cleanupErrors.length > 1) throw new Error("Multiple cleanup errors", { cause: cleanupErrors });
1569
+ return { result };
1570
+ }
1571
+ async function resolveSubCommand(cmd, rawArgs, parent) {
1572
+ const subCommands = await resolveValue(cmd.subCommands);
1573
+ if (subCommands && Object.keys(subCommands).length > 0) {
1574
+ const subCommandArgIndex = findSubCommandIndex(rawArgs, await resolveValue(cmd.args || {}));
1575
+ const subCommandName = rawArgs[subCommandArgIndex];
1576
+ const subCommand = await _findSubCommand(subCommands, subCommandName);
1577
+ if (subCommand) return resolveSubCommand(subCommand, rawArgs.slice(subCommandArgIndex + 1), cmd);
1578
+ }
1579
+ return [cmd, parent];
1580
+ }
1581
+ async function _findSubCommand(subCommands, name) {
1582
+ if (name in subCommands) return resolveValue(subCommands[name]);
1583
+ for (const sub of Object.values(subCommands)) {
1584
+ const resolved = await resolveValue(sub);
1585
+ const meta = await resolveValue(resolved?.meta);
1586
+ if (meta?.alias) {
1587
+ if (toArray(meta.alias).includes(name)) return resolved;
1779
1588
  }
1780
1589
  }
1781
- }).prompt();
1782
-
1783
- // src/lib/config.ts
1784
- import { readFile } from "node:fs/promises";
1785
- import { isAbsolute, join } from "node:path";
1786
-
1787
- // src/lib/errors.ts
1788
- var GitOutputError = class extends Error {
1789
- constructor(message, hookFailureReported = false) {
1790
- super(message);
1791
- this.hookFailureReported = hookFailureReported;
1590
+ }
1591
+ function findSubCommandIndex(rawArgs, argsDef) {
1592
+ for (let i3 = 0; i3 < rawArgs.length; i3++) {
1593
+ const arg = rawArgs[i3];
1594
+ if (arg === "--") return -1;
1595
+ if (arg.startsWith("-")) {
1596
+ if (!arg.includes("=") && _isValueFlag(arg, argsDef)) i3++;
1597
+ continue;
1598
+ }
1599
+ return i3;
1792
1600
  }
1793
- hookFailureReported;
1794
- };
1795
- function errorMessage(error) {
1796
- return error instanceof Error ? error.message : String(error);
1601
+ return -1;
1602
+ }
1603
+ function _isValueFlag(flag, argsDef) {
1604
+ const name = flag.replace(/^-{1,2}/, "");
1605
+ const normalized = camelCase(name);
1606
+ for (const [key, def] of Object.entries(argsDef)) {
1607
+ if (def.type !== "string" && def.type !== "enum") continue;
1608
+ if (normalized === camelCase(key)) return true;
1609
+ if ((Array.isArray(def.alias) ? def.alias : def.alias ? [def.alias] : []).includes(name)) return true;
1610
+ }
1611
+ return false;
1797
1612
  }
1798
-
1799
- // src/lib/config.ts
1800
- async function readProjectConfig(directory) {
1801
- let content;
1613
+ async function showUsage(cmd, parent) {
1802
1614
  try {
1803
- content = await readFile(join(directory, "zapdev.json"), "utf8");
1615
+ console.log(await renderUsage(cmd, parent) + "\n");
1804
1616
  } catch (error) {
1805
- if (error.code === "ENOENT") return {};
1806
- throw new Error(`Unable to read zapdev.json: ${errorMessage(error)}`, { cause: error });
1617
+ console.error(error);
1807
1618
  }
1808
- let config;
1809
- try {
1810
- config = JSON.parse(content);
1811
- } catch (error) {
1812
- throw new Error("zapdev.json must contain valid JSON.", { cause: error });
1619
+ }
1620
+ var negativePrefixRe = /^no[-A-Z]/;
1621
+ async function renderUsage(cmd, parent) {
1622
+ const cmdMeta = await resolveValue(cmd.meta || {});
1623
+ const cmdArgs = resolveArgs(await resolveValue(cmd.args || {}));
1624
+ const parentMeta = await resolveValue(parent?.meta || {});
1625
+ const commandName = `${parentMeta.name ? `${parentMeta.name} ` : ""}` + (cmdMeta.name || process.argv[1]);
1626
+ const argLines = [];
1627
+ const posLines = [];
1628
+ const commandsLines = [];
1629
+ const usageLine = [];
1630
+ for (const arg of cmdArgs) if (arg.type === "positional") {
1631
+ const name = arg.name.toUpperCase();
1632
+ const isRequired = arg.required !== false && arg.default === void 0;
1633
+ posLines.push([cyan(name + renderValueHint(arg)), renderDescription(arg, isRequired)]);
1634
+ usageLine.push(isRequired ? `<${name}>` : `[${name}]`);
1635
+ } else {
1636
+ const isRequired = arg.required === true && arg.default === void 0;
1637
+ const argStr = [...(arg.alias || []).map((a3) => `-${a3}`), `--${arg.name}`].join(", ") + renderValueHint(arg);
1638
+ argLines.push([cyan(argStr), renderDescription(arg, isRequired)]);
1639
+ if (arg.type === "boolean" && (arg.default === true || arg.negativeDescription) && !negativePrefixRe.test(arg.name)) {
1640
+ const negativeArgStr = [...(arg.alias || []).map((a3) => `--no-${a3}`), `--no-${arg.name}`].join(", ");
1641
+ argLines.push([cyan(negativeArgStr), [arg.negativeDescription, isRequired ? gray("(Required)") : ""].filter(Boolean).join(" ")]);
1642
+ }
1643
+ if (isRequired) usageLine.push(`--${arg.name}` + renderValueHint(arg));
1813
1644
  }
1814
- if (typeof config !== "object" || config === null || Array.isArray(config)) {
1815
- throw new Error("zapdev.json must contain an object.");
1645
+ if (cmd.subCommands) {
1646
+ const commandNames = [];
1647
+ const subCommands = await resolveValue(cmd.subCommands);
1648
+ for (const [name, sub] of Object.entries(subCommands)) {
1649
+ const meta = await resolveValue((await resolveValue(sub))?.meta);
1650
+ if (meta?.hidden) continue;
1651
+ const aliases = toArray(meta?.alias);
1652
+ const label = [name, ...aliases].join(", ");
1653
+ commandsLines.push([cyan(label), meta?.description || ""]);
1654
+ commandNames.push(name, ...aliases);
1655
+ }
1656
+ usageLine.push(commandNames.join("|"));
1816
1657
  }
1817
- const settings2 = config;
1818
- if (settings2.isSubtree !== void 0) {
1819
- throw new Error("zapdev.json isSubtree is no longer supported; use a subtrees folder-to-remote mapping.");
1658
+ const usageLines = [];
1659
+ const version = cmdMeta.version || parentMeta.version;
1660
+ usageLines.push(gray(`${cmdMeta.description} (${commandName + (version ? ` v${version}` : "")})`), "");
1661
+ const hasOptions = argLines.length > 0 || posLines.length > 0;
1662
+ usageLines.push(`${underline(bold("USAGE"))} ${cyan(`${commandName}${hasOptions ? " [OPTIONS]" : ""} ${usageLine.join(" ")}`)}`, "");
1663
+ if (posLines.length > 0) {
1664
+ usageLines.push(underline(bold("ARGUMENTS")), "");
1665
+ usageLines.push(formatLineColumns(posLines, " "));
1666
+ usageLines.push("");
1820
1667
  }
1821
- const subtrees = settings2.subtrees;
1822
- if (subtrees === void 0) return settings2;
1823
- if (typeof subtrees !== "object" || subtrees === null || Array.isArray(subtrees)) {
1824
- throw new Error("zapdev.json subtrees must be a folder-to-remote object.");
1668
+ if (argLines.length > 0) {
1669
+ usageLines.push(underline(bold("OPTIONS")), "");
1670
+ usageLines.push(formatLineColumns(argLines, " "));
1671
+ usageLines.push("");
1825
1672
  }
1826
- for (const [prefix, remote] of Object.entries(subtrees)) {
1827
- if (prefix !== prefix.trim() || isAbsolute(prefix) || prefix.includes("\\") || prefix.split("/").some((part) => ["", ".", "..", ".git"].includes(part))) {
1828
- throw new Error(`zapdev.json subtree folder "${prefix}" must be a repository-relative directory.`);
1829
- }
1830
- if (typeof remote !== "string" || !remote || /\s/.test(remote) || remote.startsWith("-")) {
1831
- throw new Error(`zapdev.json subtree "${prefix}" must map to a nonempty Git remote name.`);
1832
- }
1673
+ if (commandsLines.length > 0) {
1674
+ usageLines.push(underline(bold("COMMANDS")), "");
1675
+ usageLines.push(formatLineColumns(commandsLines, " "));
1676
+ usageLines.push("", `Use ${cyan(`${commandName} <command> --help`)} for more information about a command.`);
1833
1677
  }
1834
- return settings2;
1678
+ return usageLines.filter((l3) => typeof l3 === "string").join("\n");
1679
+ }
1680
+ function renderValueHint(arg) {
1681
+ const valueHint = arg.valueHint ? `=<${arg.valueHint}>` : "";
1682
+ const fallbackValueHint = valueHint || `=<${snakeCase(arg.name)}>`;
1683
+ if (!arg.type || arg.type === "positional" || arg.type === "boolean") return valueHint;
1684
+ if (arg.type === "enum" && arg.options?.length) return `=<${arg.options.join("|")}>`;
1685
+ return fallbackValueHint;
1686
+ }
1687
+ function renderDescription(arg, required) {
1688
+ const requiredHint = required ? gray("(Required)") : "";
1689
+ const defaultHint = arg.default === void 0 ? "" : gray(`(Default: ${arg.default})`);
1690
+ return [
1691
+ arg.description,
1692
+ requiredHint,
1693
+ defaultHint
1694
+ ].filter(Boolean).join(" ");
1695
+ }
1696
+ async function runMain(cmd, opts = {}) {
1697
+ const rawArgs = opts.rawArgs || process.argv.slice(2);
1698
+ const showUsage$1 = opts.showUsage || showUsage;
1699
+ try {
1700
+ const builtinFlags = await _resolveBuiltinFlags(cmd);
1701
+ if (builtinFlags.help.length > 0 && rawArgs.some((arg) => builtinFlags.help.includes(arg))) {
1702
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1703
+ process.exit(0);
1704
+ } else if (rawArgs.length === 1 && builtinFlags.version.includes(rawArgs[0])) {
1705
+ const meta = typeof cmd.meta === "function" ? await cmd.meta() : await cmd.meta;
1706
+ if (!meta?.version) throw new CLIError("No version specified", "E_NO_VERSION");
1707
+ console.log(meta.version);
1708
+ } else await runCommand(cmd, { rawArgs });
1709
+ } catch (error) {
1710
+ if (error instanceof CLIError) {
1711
+ await showUsage$1(...await resolveSubCommand(cmd, rawArgs));
1712
+ console.error(error.message);
1713
+ } else console.error(error, "\n");
1714
+ process.exit(1);
1715
+ }
1716
+ }
1717
+ async function _resolveBuiltinFlags(cmd) {
1718
+ const argsDef = await resolveValue(cmd.args || {});
1719
+ const userNames = /* @__PURE__ */ new Set();
1720
+ const userAliases = /* @__PURE__ */ new Set();
1721
+ for (const [name, def] of Object.entries(argsDef)) {
1722
+ userNames.add(name);
1723
+ for (const alias of toArray(def.alias)) userAliases.add(alias);
1724
+ }
1725
+ return {
1726
+ help: _getBuiltinFlags("help", "h", userNames, userAliases),
1727
+ version: _getBuiltinFlags("version", "v", userNames, userAliases)
1728
+ };
1835
1729
  }
1836
- async function resolveSubtrees(directory) {
1837
- return (await readProjectConfig(directory)).subtrees ?? {};
1730
+ function _getBuiltinFlags(long, short, userNames, userAliases) {
1731
+ if (userNames.has(long) || userAliases.has(long)) return [];
1732
+ if (userNames.has(short) || userAliases.has(short)) return [`--${long}`];
1733
+ return [`--${long}`, `-${short}`];
1838
1734
  }
1735
+
1736
+ // package.json
1737
+ var package_default = {
1738
+ name: "zapdev",
1739
+ version: "1.12.0",
1740
+ description: "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
1741
+ type: "module",
1742
+ bin: {
1743
+ zapdev: "./dist/index.js"
1744
+ },
1745
+ files: [
1746
+ "dist"
1747
+ ],
1748
+ engines: {
1749
+ node: ">=20"
1750
+ },
1751
+ keywords: [
1752
+ "git",
1753
+ "cli",
1754
+ "commit",
1755
+ "conventional-commits",
1756
+ "llm",
1757
+ "ai"
1758
+ ],
1759
+ author: "Matthieu Vagnon <hi@mvagnon.dev>",
1760
+ license: "MIT",
1761
+ repository: {
1762
+ type: "git",
1763
+ url: "git+https://github.com/mvagnon/zapdev.git"
1764
+ },
1765
+ homepage: "https://github.com/mvagnon/zapdev#readme",
1766
+ bugs: {
1767
+ url: "https://github.com/mvagnon/zapdev/issues"
1768
+ },
1769
+ publishConfig: {
1770
+ access: "public"
1771
+ },
1772
+ scripts: {
1773
+ zapdev: "npm run build && node dist/index.js",
1774
+ 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",
1775
+ lint: "eslint .",
1776
+ typecheck: "tsc --noEmit",
1777
+ test: "vitest run",
1778
+ prepack: "npm run build"
1779
+ },
1780
+ devDependencies: {
1781
+ "@clack/prompts": "^1.6.0",
1782
+ "@eslint/js": "^10.0.1",
1783
+ "@eslint/json": "^2.0.0",
1784
+ "@eslint/markdown": "^8.0.2",
1785
+ "@types/node": "^26.1.1",
1786
+ citty: "^0.2.2",
1787
+ esbuild: "^0.28.1",
1788
+ eslint: "^10.6.0",
1789
+ jiti: "^2.7.0",
1790
+ tinyexec: "^1.2.4",
1791
+ typescript: "^6.0.3",
1792
+ "typescript-eslint": "^8.62.1",
1793
+ vitest: "^4.1.9"
1794
+ }
1795
+ };
1796
+
1797
+ // src/commands/commit.ts
1798
+ import { basename } from "node:path";
1799
+ import { styleText as styleText3 } from "node:util";
1800
+
1801
+ // src/lib/config.ts
1839
1802
  function resolveHookTimeout(env = process.env) {
1840
1803
  const timeout = Number(env.ZD_HOOK_TIMEOUT ?? 60) * 1e3;
1841
1804
  if (!Number.isFinite(timeout) || timeout < 1 || timeout > 2147483647) {
@@ -1867,7 +1830,7 @@ function resolveConfig(env = process.env, overrides = {}) {
1867
1830
  // src/lib/git.ts
1868
1831
  import { execFileSync } from "node:child_process";
1869
1832
  import { readdir } from "node:fs/promises";
1870
- import { join as join2 } from "node:path";
1833
+ import { join } from "node:path";
1871
1834
  import { createInterface as createInterface2 } from "node:readline";
1872
1835
  import { Readable } from "node:stream";
1873
1836
 
@@ -2197,6 +2160,18 @@ var R2 = (e2, t3, n4) => {
2197
2160
  };
2198
2161
  var z = R2;
2199
2162
 
2163
+ // src/lib/errors.ts
2164
+ var GitOutputError = class extends Error {
2165
+ constructor(message, hookFailureReported = false) {
2166
+ super(message);
2167
+ this.hookFailureReported = hookFailureReported;
2168
+ }
2169
+ hookFailureReported;
2170
+ };
2171
+ function errorMessage(error) {
2172
+ return error instanceof Error ? error.message : String(error);
2173
+ }
2174
+
2200
2175
  // src/lib/git-hooks.ts
2201
2176
  function createHookReporter(onHook, onTimeout, timeout) {
2202
2177
  const hooks = /* @__PURE__ */ new Map();
@@ -2233,11 +2208,10 @@ function createHookReporter(onHook, onTimeout, timeout) {
2233
2208
  }
2234
2209
 
2235
2210
  // src/lib/git.ts
2236
- async function git(args, cwd, onHook, onNativeOutput) {
2211
+ async function git(args, cwd, onHook) {
2237
2212
  const timeout = resolveHookTimeout();
2238
- const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY && ["commit", "push", "subtree", "fetch", "ls-remote"].includes(args[0] ?? "") && !(args[0] === "subtree" && args[1] === "split"));
2213
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY && ["commit", "pull", "push", "fetch", "ls-remote"].includes(args[0] ?? ""));
2239
2214
  const terminalState = interactive && process.platform !== "win32" ? execFileSync("stty", ["-g"], { stdio: ["inherit", "pipe", "ignore"], encoding: "utf8" }).trim() : void 0;
2240
- if (interactive) onNativeOutput?.("start");
2241
2215
  const child = R2("git", args, {
2242
2216
  nodeOptions: {
2243
2217
  cwd,
@@ -2280,11 +2254,7 @@ async function git(args, cwd, onHook, onNativeOutput) {
2280
2254
  } finally {
2281
2255
  reader?.close();
2282
2256
  close();
2283
- try {
2284
- if (terminalState) execFileSync("stty", [terminalState], { stdio: ["inherit", "ignore", "ignore"] });
2285
- } finally {
2286
- if (interactive) onNativeOutput?.("exit");
2287
- }
2257
+ if (terminalState) execFileSync("stty", [terminalState], { stdio: ["inherit", "ignore", "ignore"] });
2288
2258
  }
2289
2259
  }
2290
2260
  function killProcessTree(pid) {
@@ -2317,12 +2287,28 @@ async function stageAll(repo) {
2317
2287
  async function getStagedDiff(repo) {
2318
2288
  return git(["diff", "--cached"], repo);
2319
2289
  }
2320
- async function commit(repo, message, onHook, onNativeOutput) {
2321
- await git(["commit", "--quiet", "-m", message], repo, onHook, onNativeOutput);
2290
+ async function getStagedDiffStats(repo) {
2291
+ const output = await git(["diff", "--cached", "--numstat"], repo);
2292
+ const stats = { additions: 0, deletions: 0 };
2293
+ for (const line of output.trim().split("\n")) {
2294
+ const [additions, deletions] = line.split(" ");
2295
+ stats.additions += Number(additions) || 0;
2296
+ stats.deletions += Number(deletions) || 0;
2297
+ }
2298
+ return stats;
2299
+ }
2300
+ async function commit(repo, message, onHook) {
2301
+ await git(["commit", "--quiet", "-m", message], repo, onHook);
2322
2302
  }
2323
2303
  async function currentBranch(repo) {
2324
2304
  return (await git(["symbolic-ref", "--short", "HEAD"], repo)).trim();
2325
2305
  }
2306
+ async function switchBranch(repo, branch) {
2307
+ await git(["check-ref-format", "--branch", branch], repo);
2308
+ await git(["check-ref-format", `refs/heads/${branch}`], repo);
2309
+ const exists = await tryGit(["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], repo) !== null;
2310
+ await git(exists ? ["switch", "--no-guess", "--", branch] : ["switch", "--no-track", "-c", branch], repo);
2311
+ }
2326
2312
  async function getRepoStatus(repo) {
2327
2313
  const lines = (await git(["status", "--porcelain=v2", "--branch", "--untracked-files=normal"], repo)).trim().split("\n");
2328
2314
  const branch = lines.find((line) => line.startsWith("# branch.head "))?.slice(14) ?? "HEAD";
@@ -2337,20 +2323,19 @@ async function getPushRemote(repo, branch) {
2337
2323
  if (upstream) return remotes.includes(upstream) ? upstream : null;
2338
2324
  return remotes.length === 1 ? remotes[0] : null;
2339
2325
  }
2340
- async function push(repo, remote, branch, onHook, prefix, onNativeOutput) {
2326
+ async function push(repo, remote, branch, onHook) {
2341
2327
  await git(["check-ref-format", "--branch", branch], repo);
2342
- await git(prefix ? ["subtree", "push", `--prefix=${prefix}`, remote, branch] : ["push", "--", remote, `HEAD:refs/heads/${branch}`], repo, onHook, onNativeOutput);
2328
+ await git(["push", "--", remote, `HEAD:refs/heads/${branch}`], repo, onHook);
2343
2329
  }
2344
- async function hasUnpushedCommits(repo, remote, branch, onHook, prefix, onNativeOutput) {
2330
+ async function hasUnpushedCommits(repo, remote, branch, onHook) {
2345
2331
  if (await tryGit(["rev-parse", "--verify", "HEAD"], repo) === null) return false;
2346
2332
  await git(["check-ref-format", "--branch", branch], repo);
2347
- const source = prefix ? (await git(["subtree", "split", `--prefix=${prefix}`, "--quiet", "HEAD"], repo)).trim() : "HEAD";
2348
2333
  const ref = `refs/heads/${branch}`;
2349
- const refs = new Set((await git(["ls-remote", "--", remote, ref, "HEAD"], repo, onHook, onNativeOutput)).trim().split("\n").map((line) => line.split(" ")[1]));
2334
+ const refs = new Set((await git(["ls-remote", "--", remote, ref, "HEAD"], repo, onHook)).trim().split("\n").map((line) => line.split(" ")[1]));
2350
2335
  const target = refs.has(ref) ? ref : refs.has("HEAD") ? "HEAD" : null;
2351
2336
  if (!target) return true;
2352
- await git(["fetch", "--quiet", "--", remote, target], repo, onHook, onNativeOutput);
2353
- return Boolean((await git(["rev-list", "--max-count=1", `FETCH_HEAD..${source}`], repo)).trim());
2337
+ await git(["fetch", "--quiet", "--", remote, target], repo, onHook);
2338
+ return Boolean((await git(["rev-list", "--max-count=1", "FETCH_HEAD..HEAD"], repo)).trim());
2354
2339
  }
2355
2340
  async function findRepos(path) {
2356
2341
  const root = await repoRoot(path);
@@ -2358,7 +2343,7 @@ async function findRepos(path) {
2358
2343
  const entries = await readdir(path, { withFileTypes: true }).catch(() => null);
2359
2344
  if (!entries) return [];
2360
2345
  const dirs = entries.filter((entry) => entry.isDirectory() && entry.name !== "node_modules");
2361
- const repos = await Promise.all(dirs.map((entry) => repoRoot(join2(path, entry.name))));
2346
+ const repos = await Promise.all(dirs.map((entry) => repoRoot(join(path, entry.name))));
2362
2347
  return repos.filter((dir) => dir !== null).sort();
2363
2348
  }
2364
2349
  async function repoRoot(dir) {
@@ -2484,13 +2469,6 @@ var COMMIT_TYPES = [
2484
2469
  "revert"
2485
2470
  ];
2486
2471
 
2487
- // src/commands/native-output.ts
2488
- import { styleText as styleText3 } from "node:util";
2489
- var reportNativeOutput = (phase) => {
2490
- const symbol2 = styleText3("gray", phase === "start" ? S_BAR_END : S_BAR_START);
2491
- log.message(phase === "start" ? symbol2 : ["", symbol2], { withGuide: false, spacing: 0 });
2492
- };
2493
-
2494
2472
  // src/commands/commit.ts
2495
2473
  var commitCommand = defineCommand({
2496
2474
  meta: {
@@ -2520,7 +2498,11 @@ var commitCommand = defineCommand({
2520
2498
  push: {
2521
2499
  type: "boolean",
2522
2500
  alias: "p",
2523
- description: "Skip push confirmation; still ask for each destination branch."
2501
+ description: "Skip push confirmation and push the current branch."
2502
+ },
2503
+ pull: {
2504
+ type: "boolean",
2505
+ description: "Pull fast-forward updates before staging or generating commit messages."
2524
2506
  },
2525
2507
  staged: {
2526
2508
  type: "boolean",
@@ -2536,7 +2518,6 @@ var commitCommand = defineCommand({
2536
2518
  async run({ args }) {
2537
2519
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
2538
2520
  let config;
2539
- let subtrees;
2540
2521
  try {
2541
2522
  resolveHookTimeout();
2542
2523
  config = resolveConfig(process.env, {
@@ -2544,13 +2525,11 @@ var commitCommand = defineCommand({
2544
2525
  model: args.model,
2545
2526
  effort: args.effort
2546
2527
  });
2547
- subtrees = await resolveSubtrees(process.cwd());
2548
2528
  } catch (error) {
2549
2529
  log.error(errorMessage(error));
2550
2530
  process.exitCode = 1;
2551
2531
  return;
2552
2532
  }
2553
- const publishSubtreeMode = Object.keys(subtrees).length > 0;
2554
2533
  if (interactive) intro("zapdev commit");
2555
2534
  const repos = await findRepos(process.cwd());
2556
2535
  if (repos.length === 0) {
@@ -2558,6 +2537,19 @@ var commitCommand = defineCommand({
2558
2537
  if (interactive) outro("Nothing to do.");
2559
2538
  return;
2560
2539
  }
2540
+ if (args.pull) {
2541
+ for (const repo of repos) {
2542
+ const label = basename(repo);
2543
+ try {
2544
+ log.info(`${label}: pulling`);
2545
+ await git(["pull", "--ff-only", "--no-rebase", "--no-autostash"], repo, reportHooks(label));
2546
+ } catch (error) {
2547
+ reportGitFailure(`${label}: pull failed`, error);
2548
+ process.exitCode = 1;
2549
+ return;
2550
+ }
2551
+ }
2552
+ }
2561
2553
  let scan;
2562
2554
  try {
2563
2555
  scan = await hasGitleaks();
@@ -2574,14 +2566,15 @@ var commitCommand = defineCommand({
2574
2566
  const { repo } = repository;
2575
2567
  const { branch, hasChanges } = await getRepoStatus(repo);
2576
2568
  repository.label = `${basename(repo)} (${branch})`;
2577
- repository.pendingLabel = hasChanges ? styleText4(["bold", "underline"], repository.label) : repository.label;
2569
+ repository.pendingLabel = hasChanges ? styleText3("bold", repository.label) : repository.label;
2578
2570
  if (!args.staged) await stageAll(repo);
2579
2571
  const diff = await getStagedDiff(repo);
2580
2572
  if (!diff.trim()) return null;
2573
+ const stats = await getStagedDiffStats(repo);
2581
2574
  if (scan) await scanStagedChanges(repo);
2582
2575
  const message = await generateCommitMessage(diff, config, args.type);
2583
2576
  if (!message) throw new Error("The model returned an empty message.");
2584
- return { ...repository, message };
2577
+ return { ...repository, message, stats };
2585
2578
  }));
2586
2579
  loader?.stop("Repositories prepared");
2587
2580
  const drafts = [];
@@ -2603,10 +2596,30 @@ var commitCommand = defineCommand({
2603
2596
  return;
2604
2597
  }
2605
2598
  const toSend = [];
2599
+ let previousBranchInput = "";
2606
2600
  for (const draft of selected) {
2607
- log.info(`${draft.label}: committing`);
2608
2601
  try {
2609
- await commit(draft.repo, draft.message, reportHooks(draft.label), reportNativeOutput);
2602
+ const current = await currentBranch(draft.repo);
2603
+ if (/^(main|master|principal|dev|development)$/.test(current)) {
2604
+ if (!interactive) throw new Error("Committing on a protected branch requires a terminal to choose a branch. Changes remain staged.");
2605
+ const answer = await text({
2606
+ message: `${basename(draft.repo)} (${current}): branch to commit to`,
2607
+ initialValue: previousBranchInput
2608
+ });
2609
+ if (isCancel(answer)) {
2610
+ cancel("Committing cancelled. Changes remain staged; earlier commits stay local.");
2611
+ return;
2612
+ }
2613
+ previousBranchInput = answer.trim();
2614
+ const branch = previousBranchInput || current;
2615
+ if (branch !== current) {
2616
+ await switchBranch(draft.repo, branch);
2617
+ draft.label = `${basename(draft.repo)} (${branch})`;
2618
+ draft.pendingLabel = styleText3("bold", draft.label);
2619
+ }
2620
+ }
2621
+ log.info(`${draft.label}: committing`);
2622
+ await commit(draft.repo, draft.message, reportHooks(draft.label));
2610
2623
  toSend.push(draft);
2611
2624
  log.success(`${draft.label}: committed ${draft.message}`);
2612
2625
  } catch (error) {
@@ -2616,55 +2629,45 @@ var commitCommand = defineCommand({
2616
2629
  }
2617
2630
  toSend.push(...unchanged);
2618
2631
  if (toSend.length === 0) return;
2632
+ if (!interactive && !args.push) return;
2633
+ const destinations = [];
2634
+ for (const { repo, label } of toSend) {
2635
+ try {
2636
+ const branch = await currentBranch(repo);
2637
+ const remote = await getPushRemote(repo, branch);
2638
+ if (remote) destinations.push({ repo, label, branch, remote });
2639
+ else log.warn(`${label}: no remote or ambiguous remote choice. Skipping push; commit remains local.`);
2640
+ } catch (error) {
2641
+ reportGitFailure(`${label}: push failed`, error);
2642
+ process.exitCode = 1;
2643
+ return;
2644
+ }
2645
+ }
2619
2646
  let shouldPush = Boolean(args.push);
2620
- if (!shouldPush && interactive) {
2647
+ if (!shouldPush && interactive && destinations.length) {
2621
2648
  const answer = await confirm({
2622
- message: `${publishSubtreeMode ? "Publish subtrees in" : "Push"} ${toSend.map(({ label }) => label).join(", ")}?`,
2649
+ message: `Push ${destinations.map(({ label }) => label).join(", ")}?`,
2623
2650
  initialValue: false
2624
2651
  });
2625
2652
  if (isCancel(answer)) {
2626
- outro(publishSubtreeMode ? "Committed. Not published." : "Committed. Not pushed.");
2653
+ outro("Committed. Not pushed.");
2627
2654
  return;
2628
2655
  }
2629
2656
  shouldPush = answer;
2630
2657
  }
2631
2658
  if (shouldPush) {
2632
- if (!interactive) {
2633
- log.error("Pushing requires a terminal to choose each destination branch. Commits remain local.");
2634
- process.exitCode = 1;
2635
- return;
2636
- }
2637
- let previousBranchInput = "";
2638
- for (const { repo, label } of toSend) {
2659
+ for (const { repo, label, branch, remote } of destinations) {
2639
2660
  try {
2640
- const current = await currentBranch(repo);
2641
- const destinations = publishSubtreeMode ? Object.entries(subtrees) : [["", await getPushRemote(repo, current)]];
2642
- for (const [prefix, remote] of destinations) {
2643
- if (!remote) {
2644
- log.warn(`${label}: no remote or ambiguous remote choice. Skipping push; commit remains local.`);
2645
- continue;
2646
- }
2647
- log.info(`${label}: checking unpublished commits${prefix ? ` in ${prefix}` : ""} (${remote}/${previousBranchInput || current}).`);
2648
- if (!await hasUnpushedCommits(repo, remote, previousBranchInput || current, reportHooks(label), prefix || void 0, reportNativeOutput)) {
2649
- log.info(`${label}: no unpushed commits${prefix ? ` in ${prefix}` : ""}. Skipping.`);
2650
- continue;
2651
- }
2652
- const answer = await text({
2653
- message: `${label}: branch to push ${publishSubtreeMode ? `${prefix} to ` : "to "}${remote}`,
2654
- initialValue: previousBranchInput
2655
- });
2656
- if (isCancel(answer)) {
2657
- outro("Sending cancelled. Remaining commits stay local.");
2658
- return;
2659
- }
2660
- previousBranchInput = answer.trim();
2661
- const branch = previousBranchInput || current;
2662
- log.info(`${label}: pushing ${publishSubtreeMode ? `${prefix} \u2192 ` : ""}${remote}/${branch}`);
2663
- await push(repo, remote, branch, reportHooks(label), prefix || void 0, reportNativeOutput);
2664
- log.success(`${label}: pushed to ${remote}/${branch}`);
2661
+ log.info(`${label}: checking unpublished commits (${remote}/${branch}).`);
2662
+ if (!await hasUnpushedCommits(repo, remote, branch, reportHooks(label))) {
2663
+ log.info(`${label}: no unpushed commits. Skipping.`);
2664
+ continue;
2665
2665
  }
2666
+ log.info(`${label}: pushing ${remote}/${branch}`);
2667
+ await push(repo, remote, branch, reportHooks(label));
2668
+ log.success(`${label}: pushed to ${remote}/${branch}`);
2666
2669
  } catch (error) {
2667
- reportGitFailure(`${label}: ${publishSubtreeMode ? "publication" : "push"} failed`, error);
2670
+ reportGitFailure(`${label}: push failed`, error);
2668
2671
  process.exitCode = 1;
2669
2672
  outro("Sending stopped after a Git failure.");
2670
2673
  return;
@@ -2679,20 +2682,21 @@ function reportGitFailure(message, error) {
2679
2682
  log.error(error instanceof GitOutputError ? message : `${message}: ${errorMessage(error)}`);
2680
2683
  }
2681
2684
  function reportHooks(label) {
2682
- const options = { secondarySymbol: "", withGuide: false };
2683
2685
  return (event) => {
2684
2686
  const hook = `${label}: ${event.name}`;
2685
2687
  if (event.phase === "start") {
2686
- log.step(styleText4("bold", hook), options);
2688
+ log.step(styleText3("bold", hook));
2687
2689
  } else {
2688
- if (event.exitCode === 0) log.success(`${hook}: completed`, options);
2689
- else log.error(`${hook}: failed (exit ${event.exitCode})`, options);
2690
+ if (event.exitCode === 0) log.success(`${hook}: completed`);
2691
+ else log.error(`${hook}: failed (exit ${event.exitCode})`);
2690
2692
  }
2691
2693
  };
2692
2694
  }
2693
2695
  async function reviewMessages(drafts, canPrompt) {
2694
2696
  while (true) {
2695
- for (const draft of drafts) log.message(`${draft.pendingLabel}: ${draft.message}`);
2697
+ for (const { stats, pendingLabel, message } of drafts) {
2698
+ log.message(`(${styleText3("green", `+${stats.additions}`)} ${styleText3("red", `-${stats.deletions}`)}) ${pendingLabel}: ${message}`);
2699
+ }
2696
2700
  if (!canPrompt) return drafts;
2697
2701
  const action = await select({
2698
2702
  message: "Action",
@@ -2723,115 +2727,8 @@ async function reviewMessages(drafts, canPrompt) {
2723
2727
  }
2724
2728
  }
2725
2729
 
2726
- // src/lib/subtree-init.ts
2727
- import { lstat, mkdir, writeFile } from "node:fs/promises";
2728
- import { join as join3, resolve } from "node:path";
2729
- function parseSubtreeSources(entries) {
2730
- if (entries.length === 0) throw new Error("Provide at least one subtree as name=url.");
2731
- const names = /* @__PURE__ */ new Set();
2732
- return entries.map((entry) => {
2733
- const separator = entry.indexOf("=");
2734
- const name = entry.slice(0, separator);
2735
- const url = entry.slice(separator + 1);
2736
- if (separator < 1 || !/^[a-zA-Z0-9_][a-zA-Z0-9_.-]*$/.test(name) || name === "zapdev.json" || name.includes("..") || name.endsWith(".") || name.endsWith(".lock") || !url.trim() || url.startsWith("-") || url.includes("\0")) {
2737
- throw new Error(`Invalid source "${entry}": expected name=url with a simple folder and remote name.`);
2738
- }
2739
- if (names.has(name)) throw new Error(`Duplicate subtree name "${name}".`);
2740
- names.add(name);
2741
- return { name, url };
2742
- });
2743
- }
2744
- async function initializeSubtrees(directory, sources, options = {}) {
2745
- if (!directory.trim()) throw new Error("Directory cannot be empty.");
2746
- if (options.origin !== void 0 && (!options.origin.trim() || options.origin.startsWith("-") || options.origin.includes("\0"))) {
2747
- throw new Error("--origin must be a nonempty repository URL.");
2748
- }
2749
- const repo = resolve(directory);
2750
- await mkdir(repo, { recursive: true });
2751
- if (!await exists(join3(repo, ".git"))) await git(["init", "--quiet", "-b", "main"], repo);
2752
- if ((await getRepoStatus(repo)).hasChanges) {
2753
- throw new Error("Working tree must be clean before adding subtrees (including untracked files).");
2754
- }
2755
- const configPath = join3(repo, "zapdev.json");
2756
- if (await exists(configPath) && (await lstat(configPath)).isSymbolicLink()) {
2757
- throw new Error("Refusing to overwrite zapdev.json through a symbolic link.");
2758
- }
2759
- const settings2 = await readProjectConfig(repo);
2760
- const mapping = new Map(Object.entries(settings2.subtrees ?? {}));
2761
- const remotes = /* @__PURE__ */ new Map();
2762
- if (options.origin !== void 0) remotes.set("origin", options.origin);
2763
- for (const { name, url } of sources) {
2764
- if (await exists(join3(repo, name))) throw new Error(`"${name}" already exists.`);
2765
- const mappedRemote = mapping.get(name);
2766
- if (mappedRemote && mappedRemote !== name) throw new Error(`"${name}" is already mapped to remote "${mappedRemote}".`);
2767
- const plannedURL = remotes.get(name);
2768
- if (plannedURL && plannedURL !== url) throw new Error(`Remote "${name}" was requested with another URL: ${plannedURL}`);
2769
- remotes.set(name, url);
2770
- }
2771
- const missingRemotes = [];
2772
- for (const [name, url] of remotes) {
2773
- const existingURL = await tryGit(["remote", "get-url", name], repo);
2774
- if (existingURL === null) missingRemotes.push([name, url]);
2775
- else if (existingURL.trim() !== url) throw new Error(`Remote "${name}" already exists with another URL: ${existingURL.trim()}`);
2776
- }
2777
- const imports = [];
2778
- for (const source of sources) {
2779
- options.onProgress?.(`Detecting default branch for ${source.name}`);
2780
- const refs = await git(["ls-remote", "--symref", "--", source.url, "HEAD"], repo, void 0, options.onNativeOutput);
2781
- const branch = /^ref: refs\/heads\/(.+)\tHEAD$/m.exec(refs)?.[1];
2782
- if (!branch) options.onWarning?.(`Could not detect default branch for ${source.name}; using main.`);
2783
- imports.push({ ...source, branch: branch ?? "main" });
2784
- }
2785
- const initial = await tryGit(["rev-parse", "--verify", "HEAD"], repo) === null;
2786
- for (const { name } of sources) mapping.set(name, name);
2787
- await writeFile(configPath, `${JSON.stringify({ ...settings2, subtrees: Object.fromEntries(mapping) }, null, 2)}
2788
- `);
2789
- await git(["add", "--", "zapdev.json"], repo);
2790
- if (initial || (await getStagedDiff(repo)).trim()) {
2791
- await commit(repo, initial ? "chore: init" : "chore: configure subtrees", void 0, options.onNativeOutput);
2792
- }
2793
- for (const [name, url] of missingRemotes) await git(["remote", "add", name, url], repo);
2794
- for (const { name, branch } of imports) {
2795
- options.onProgress?.(`Adding ${name} (${branch})`);
2796
- await git(["subtree", "add", `--prefix=${name}`, name, branch, "--squash"], repo, void 0, options.onNativeOutput);
2797
- }
2798
- }
2799
- async function exists(path) {
2800
- return lstat(path).then(() => true, (error) => {
2801
- if (error.code === "ENOENT") return false;
2802
- throw error;
2803
- });
2804
- }
2805
-
2806
- // src/commands/subtree-init.ts
2807
- var subtreeInitCommand = defineCommand({
2808
- meta: { name: "subtree-init", description: "Initialize a repository with squashed subtrees and their named remotes." },
2809
- args: {
2810
- directory: { type: "positional", required: true, description: "Repository directory to create or extend." },
2811
- subtree: { type: "positional", required: true, description: "name=url; add more positional sources for additional subtrees." },
2812
- origin: { type: "string", description: "Optional URL for the parent repository's origin remote." }
2813
- },
2814
- async run({ args }) {
2815
- const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
2816
- try {
2817
- const sources = parseSubtreeSources(args._.slice(1));
2818
- if (interactive) intro("zapdev subtree-init");
2819
- await initializeSubtrees(args.directory, sources, {
2820
- origin: args.origin,
2821
- onProgress: log.info,
2822
- onWarning: log.warn,
2823
- onNativeOutput: reportNativeOutput
2824
- });
2825
- if (interactive) outro("Subtrees ready.");
2826
- else log.info("Subtrees ready.");
2827
- } catch (error) {
2828
- log.error(error instanceof GitOutputError ? "Subtree initialization failed." : errorMessage(error));
2829
- process.exitCode = 1;
2830
- }
2831
- }
2832
- });
2833
-
2834
2730
  // src/cli.ts
2731
+ updateSettings({ withGuide: false });
2835
2732
  var main = defineCommand({
2836
2733
  meta: {
2837
2734
  name: "zapdev",
@@ -2839,7 +2736,7 @@ var main = defineCommand({
2839
2736
  description: "Fast, precise git chores from your terminal."
2840
2737
  },
2841
2738
  args: commitCommand.args,
2842
- subCommands: { commit: commitCommand, "subtree-init": subtreeInitCommand },
2739
+ subCommands: { commit: commitCommand },
2843
2740
  default: "commit"
2844
2741
  });
2845
2742
  await runMain(main);