@kyubiware/commit-mint 0.8.1 → 0.8.3

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.
package/dist/cli.mjs CHANGED
@@ -10,12 +10,16 @@ import { execa } from "execa";
10
10
  import picomatch from "picomatch";
11
11
  import ini from "ini";
12
12
  import { createHash } from "node:crypto";
13
- import * as p from "@clack/prompts";
14
- import { intro, isCancel, log, outro, spinner } from "@clack/prompts";
13
+ import * as p$1 from "@clack/prompts";
14
+ import { S_BAR, S_BAR_END, S_RADIO_ACTIVE, S_RADIO_INACTIVE, intro, isCancel, limitOptions, log, outro, spinner, symbol } from "@clack/prompts";
15
15
  import { spawn } from "node:child_process";
16
16
  import semver from "semver";
17
+ import { styleText } from "node:util";
18
+ import { stdin, stdout } from "node:process";
19
+ import E from "node:readline";
17
20
  //#region \0rolldown/runtime.js
18
21
  var __defProp = Object.defineProperty;
22
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
19
23
  var __exportAll = (all, no_symbols) => {
20
24
  let target = {};
21
25
  for (var name in all) __defProp(target, name, {
@@ -29,7 +33,7 @@ var __exportAll = (all, no_symbols) => {
29
33
  //#region package.json
30
34
  var package_default = {
31
35
  name: "@kyubiware/commit-mint",
32
- version: "0.8.1",
36
+ version: "0.8.3",
33
37
  description: "🌿 AI-powered git commit tool — auto-group changed files, generate messages, run pre-commit checks",
34
38
  type: "module",
35
39
  bin: { "cmint": "./dist/cli.mjs" },
@@ -267,7 +271,7 @@ function buildStatSummary(diff) {
267
271
  return lines.join("\n");
268
272
  }
269
273
  function buildSystemPrompt(type) {
270
- let prompt = "You are a commit message generator. Follow the Conventional Commits specification.\nValid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\nFormat: type(scope): description\nUse imperative mood, lowercase, no trailing period.\nOutput ONLY the commit message, no markdown fences, no explanation.";
274
+ let prompt = "You are a commit message generator. Follow the Conventional Commits specification.\nValid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\nFormat: type(scope): description\nUse imperative mood, lowercase, no trailing period.\nOutput a SINGLE commit message, one line only. No markdown fences, no explanation.";
271
275
  if (type && type.trim().length > 0) prompt += `\nYou MUST use type: ${type}`;
272
276
  return prompt;
273
277
  }
@@ -354,7 +358,7 @@ async function generateCommitMessage(diff, options) {
354
358
  debug("Validation: message=%s, isValid=%s", message.slice(0, 100), isValidConventionalCommit(message));
355
359
  if (!isValidConventionalCommit(message)) {
356
360
  debug("Initial message failed conventional commit validation, retrying with strict prompt (elapsed: %d ms)", Date.now() - totalStart);
357
- const retryMessage = await callAI("You MUST output ONLY a valid conventional commit message. Format: type(scope): description. If you output anything else your response will be rejected.\nValid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.");
361
+ const retryMessage = await callAI("You MUST output ONLY a valid conventional commit message. Format: type(scope): description. If you output anything else your response will be rejected.\nOutput a SINGLE commit message, one line only.\nValid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.");
358
362
  debug("Retry validation: message=%s, isValid=%s", retryMessage.slice(0, 100), isValidConventionalCommit(retryMessage));
359
363
  if (isValidConventionalCommit(retryMessage)) {
360
364
  debug("Retry produced valid conventional commit");
@@ -1629,6 +1633,35 @@ async function loadCachedCommit(repoPath) {
1629
1633
  }
1630
1634
  }
1631
1635
  //#endregion
1636
+ //#region src/services/auto-accept.ts
1637
+ /** Parse a stored `auto-accept` INI value into a boolean.
1638
+ * Accepts true variants ("true", "1", "yes" — case-insensitive).
1639
+ * Handles boolean values from ini.parse (which converts unquoted
1640
+ * `true`/`false` to actual booleans).
1641
+ * Everything else (including undefined) returns false. */
1642
+ function parseAutoAcceptValue(value) {
1643
+ if (typeof value === "boolean") return value;
1644
+ if (typeof value !== "string" || !value) return false;
1645
+ return [
1646
+ "true",
1647
+ "1",
1648
+ "yes"
1649
+ ].includes(value.toLowerCase());
1650
+ }
1651
+ /** Read the persisted auto-accept preference from `~/.commit-mint`. */
1652
+ async function getAutoAccept() {
1653
+ const raw = (await readConfig())["auto-accept"];
1654
+ const enabled = parseAutoAcceptValue(raw);
1655
+ debug("getAutoAccept: raw=%s enabled=%s", raw, enabled);
1656
+ return enabled;
1657
+ }
1658
+ /** Persist the auto-accept preference to `~/.commit-mint`. */
1659
+ async function setAutoAccept(enabled) {
1660
+ const value = enabled ? "true" : "false";
1661
+ debug("setAutoAccept: %s", value);
1662
+ await writeConfig({ "auto-accept": value });
1663
+ }
1664
+ //#endregion
1632
1665
  //#region src/ui/grouping.ts
1633
1666
  async function showGroupingConfirmation(groups, excluded) {
1634
1667
  debug("showGroupingConfirmation: %d groups, %d excluded", groups.length, excluded.length);
@@ -1644,8 +1677,8 @@ async function showGroupingConfirmation(groups, excluded) {
1644
1677
  lines.push(dim(`Excluded: ${excluded.length} file${excluded.length !== 1 ? "s" : ""}`));
1645
1678
  for (const file of excluded) lines.push(` ${dim("•")} ${dim(file)}`);
1646
1679
  }
1647
- p.note(lines.join("\n"), "Proposed commit groups");
1648
- const choice = await p.select({
1680
+ p$1.note(lines.join("\n"), "Proposed commit groups");
1681
+ const choice = await p$1.select({
1649
1682
  message: "Proceed with these groupings?",
1650
1683
  options: [{
1651
1684
  label: "Yes, commit all groups",
@@ -1655,7 +1688,7 @@ async function showGroupingConfirmation(groups, excluded) {
1655
1688
  value: "no"
1656
1689
  }]
1657
1690
  });
1658
- if (p.isCancel(choice) || choice === "no") {
1691
+ if (p$1.isCancel(choice) || choice === "no") {
1659
1692
  debug("showGroupingConfirmation: user cancelled");
1660
1693
  return false;
1661
1694
  }
@@ -1663,7 +1696,7 @@ async function showGroupingConfirmation(groups, excluded) {
1663
1696
  return true;
1664
1697
  }
1665
1698
  function showGroupProgress(current, total, groupName) {
1666
- p.log.info(`Commit group ${current} of ${total}: ${cyan(`"${groupName}"`)}`);
1699
+ p$1.log.info(`Commit group ${current} of ${total}: ${cyan(`"${groupName}"`)}`);
1667
1700
  }
1668
1701
  const statusLabel = (status) => {
1669
1702
  switch (status) {
@@ -1688,7 +1721,7 @@ function showGroupedFiles(groups, changedFiles) {
1688
1721
  }
1689
1722
  if (i < groups.length - 1) lines.push("");
1690
1723
  }
1691
- p.note(lines.join("\n"), "Commit groups");
1724
+ p$1.note(lines.join("\n"), "Commit groups");
1692
1725
  }
1693
1726
  //#endregion
1694
1727
  //#region src/services/clipboard.ts
@@ -1776,10 +1809,10 @@ async function showRecoveryMenu(errors, onRetry, onSkipHooks, onRestage, message
1776
1809
  let showNote = true;
1777
1810
  while (true) {
1778
1811
  if (showNote) {
1779
- p.note(errors.map((e) => ` ${red("•")} [${e.tool}] ${e.message}`).join("\n"), red(bold("Pre-commit hook failed")));
1812
+ p$1.note(errors.map((e) => ` ${red("•")} [${e.tool}] ${e.message}`).join("\n"), red(bold("Pre-commit hook failed")));
1780
1813
  showNote = false;
1781
1814
  }
1782
- const choice = await p.select({
1815
+ const choice = await p$1.select({
1783
1816
  message: "What do you want to do?",
1784
1817
  options: [
1785
1818
  {
@@ -1813,9 +1846,9 @@ async function showRecoveryMenu(errors, onRetry, onSkipHooks, onRestage, message
1813
1846
  }
1814
1847
  ]
1815
1848
  });
1816
- if (p.isCancel(choice)) {
1849
+ if (p$1.isCancel(choice)) {
1817
1850
  debug("showRecoveryMenu: user cancelled");
1818
- p.outro(yellow("Cancelled. Message cached for --retry."));
1851
+ p$1.outro(yellow("Cancelled. Message cached for --retry."));
1819
1852
  return "cancelled";
1820
1853
  }
1821
1854
  debug("showRecoveryMenu: user chose %s", choice);
@@ -1823,50 +1856,50 @@ async function showRecoveryMenu(errors, onRetry, onSkipHooks, onRestage, message
1823
1856
  case "clipboard":
1824
1857
  if (await copyToClipboard(rawStderr)) {
1825
1858
  clipboardCopied = true;
1826
- p.log.step(green("Copied to clipboard."));
1827
- } else p.log.warn(red("No clipboard tool found. Install xclip, wl-copy, or xsel."));
1859
+ p$1.log.step(green("Copied to clipboard."));
1860
+ } else p$1.log.warn(red("No clipboard tool found. Install xclip, wl-copy, or xsel."));
1828
1861
  continue;
1829
1862
  case "view":
1830
- p.note(rawStderr.trim() || "(no raw output)", "Full error output");
1863
+ p$1.note(rawStderr.trim() || "(no raw output)", "Full error output");
1831
1864
  showNote = true;
1832
1865
  continue;
1833
1866
  case "skip":
1834
- p.log.info(yellow("Committing with --no-verify..."));
1867
+ p$1.log.info(yellow("Committing with --no-verify..."));
1835
1868
  if (await onSkipHooks(message)) {
1836
- p.outro(green("Committed (hooks skipped)."));
1869
+ p$1.outro(green("Committed (hooks skipped)."));
1837
1870
  return "committed";
1838
1871
  } else {
1839
- p.outro(red("Commit failed even with --no-verify."));
1872
+ p$1.outro(red("Commit failed even with --no-verify."));
1840
1873
  return "failed";
1841
1874
  }
1842
1875
  case "restage":
1843
- p.log.info(cyan("Re-staging and retrying..."));
1876
+ p$1.log.info(cyan("Re-staging and retrying..."));
1844
1877
  if (await onRestage()) {
1845
- p.outro(green("Committed successfully."));
1878
+ p$1.outro(green("Committed successfully."));
1846
1879
  return "committed";
1847
1880
  }
1848
1881
  showNote = true;
1849
1882
  continue;
1850
1883
  case "edit": {
1851
- const edited = await p.text({
1884
+ const edited = await p$1.text({
1852
1885
  message: "Edit commit message:",
1853
1886
  initialValue: message,
1854
1887
  validate: (v) => v?.trim() ? void 0 : "Message cannot be empty"
1855
1888
  });
1856
- if (p.isCancel(edited)) {
1857
- p.outro(yellow("Cancelled. Message cached for --retry."));
1889
+ if (p$1.isCancel(edited)) {
1890
+ p$1.outro(yellow("Cancelled. Message cached for --retry."));
1858
1891
  return "cancelled";
1859
1892
  }
1860
1893
  if (await onRetry()) {
1861
- p.outro(green("Committed successfully."));
1894
+ p$1.outro(green("Committed successfully."));
1862
1895
  return "committed";
1863
1896
  } else {
1864
- p.outro(red("Commit failed again."));
1897
+ p$1.outro(red("Commit failed again."));
1865
1898
  return "failed";
1866
1899
  }
1867
1900
  }
1868
1901
  case "cancel":
1869
- p.outro(dim("Message cached for --retry."));
1902
+ p$1.outro(dim("Message cached for --retry."));
1870
1903
  return "cancelled";
1871
1904
  }
1872
1905
  }
@@ -2075,9 +2108,9 @@ function truncate(message, maxLength) {
2075
2108
  async function showCheckFailureMenu(errors, rawStderr, onRetry) {
2076
2109
  debug("showCheckFailureMenu: %d errors", errors.length);
2077
2110
  let clipboardCopied = false;
2078
- p.note(formatCheckFailureSummary(errors), red("Pre-commit check failed"));
2111
+ p$1.note(formatCheckFailureSummary(errors), red("Pre-commit check failed"));
2079
2112
  while (true) {
2080
- const choice = await p.select({
2113
+ const choice = await p$1.select({
2081
2114
  message: "What do you want to do?",
2082
2115
  options: [
2083
2116
  {
@@ -2104,7 +2137,7 @@ async function showCheckFailureMenu(errors, rawStderr, onRetry) {
2104
2137
  }
2105
2138
  ]
2106
2139
  });
2107
- if (p.isCancel(choice)) {
2140
+ if (p$1.isCancel(choice)) {
2108
2141
  debug("showCheckFailureMenu: user cancelled");
2109
2142
  return "cancelled";
2110
2143
  }
@@ -2113,20 +2146,20 @@ async function showCheckFailureMenu(errors, rawStderr, onRetry) {
2113
2146
  case "copy":
2114
2147
  if (await copyToClipboard(rawStderr)) {
2115
2148
  clipboardCopied = true;
2116
- p.log.step(green("Copied to clipboard."));
2117
- } else p.log.warn(red("No clipboard tool found. Install xclip, wl-copy, or xsel."));
2149
+ p$1.log.step(green("Copied to clipboard."));
2150
+ } else p$1.log.warn(red("No clipboard tool found. Install xclip, wl-copy, or xsel."));
2118
2151
  continue;
2119
2152
  case "view":
2120
- p.note(rawStderr.trim() || "(no raw output)", "Full error output");
2153
+ p$1.note(rawStderr.trim() || "(no raw output)", "Full error output");
2121
2154
  continue;
2122
2155
  case "retry":
2123
2156
  if (onRetry) return "retried";
2124
2157
  return "retried";
2125
2158
  case "skip":
2126
- p.log.info("Skipping checks and proceeding with commit...");
2159
+ p$1.log.info("Skipping checks and proceeding with commit...");
2127
2160
  return "skipped";
2128
2161
  case "cancel":
2129
- p.outro(dim("Cancelled."));
2162
+ p$1.outro(dim("Cancelled."));
2130
2163
  return "cancelled";
2131
2164
  }
2132
2165
  }
@@ -2256,7 +2289,9 @@ async function runAutoGroupFlow(changedFiles, flags) {
2256
2289
  const validatedGroups = validateGroups((await generateGroups(included, await getProviderApiKey(provider), getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel), config.timeout ? parseInt(config.timeout, 10) : void 0, provider, config.proxy)).groups, included);
2257
2290
  s.stop("Files analyzed");
2258
2291
  showGroupedFiles(validatedGroups, included);
2259
- if (flags.auto) debug("Auto mode: skipping grouping confirmation");
2292
+ const autoAccept = await getAutoAccept();
2293
+ const skipPrompts = flags.auto || autoAccept;
2294
+ if (skipPrompts) debug("Skipping grouping confirmation (auto=%s autoAccept=%s)", flags.auto, autoAccept);
2260
2295
  else if (!await showGroupingConfirmation(validatedGroups, excluded)) {
2261
2296
  outro(dim("Cancelled."));
2262
2297
  return "cancelled";
@@ -2282,7 +2317,7 @@ async function runAutoGroupFlow(changedFiles, flags) {
2282
2317
  }
2283
2318
  s.stop("Message generated");
2284
2319
  log.info(dim(message));
2285
- if (flags.auto) debug("Auto mode: accepting generated message");
2320
+ if (skipPrompts) debug("Accepting generated message (auto=%s autoAccept=%s)", flags.auto, autoAccept);
2286
2321
  else {
2287
2322
  const reviewed = await reviewCommitMessage(message, { regenerate: async (hint) => {
2288
2323
  const combinedHint = flags.hint ? `${flags.hint}\n${hint}` : hint;
@@ -3067,30 +3102,30 @@ function formatDetection(tools) {
3067
3102
  async function setupCmintrcCommand(cwd = process.cwd()) {
3068
3103
  debug("setupCmintrcCommand: starting in %s", cwd);
3069
3104
  const tools = await detectTools(cwd);
3070
- p.log.info(`Detected tools in ${bold(cwd)}:`);
3071
- p.log.message(formatDetection(tools));
3072
- if (!Object.values(tools).some(Boolean)) p.log.warn("No recognized tools found. Writing an empty config to fill in manually.");
3073
- else if (tools.biome && tools.eslint) p.log.warn(yellow("Both biome and eslint detected — using biome (remove this line to switch)."));
3105
+ p$1.log.info(`Detected tools in ${bold(cwd)}:`);
3106
+ p$1.log.message(formatDetection(tools));
3107
+ if (!Object.values(tools).some(Boolean)) p$1.log.warn("No recognized tools found. Writing an empty config to fill in manually.");
3108
+ else if (tools.biome && tools.eslint) p$1.log.warn(yellow("Both biome and eslint detected — using biome (remove this line to switch)."));
3074
3109
  const fileName = pickFileName(tools);
3075
3110
  const filePath = join(cwd, fileName);
3076
3111
  if (await exists(filePath)) {
3077
- const overwrite = await p.confirm({ message: `${fileName} already exists. Overwrite?` });
3078
- if (p.isCancel(overwrite) || !overwrite) {
3079
- p.log.info(dim("Cancelled — existing file left untouched."));
3112
+ const overwrite = await p$1.confirm({ message: `${fileName} already exists. Overwrite?` });
3113
+ if (p$1.isCancel(overwrite) || !overwrite) {
3114
+ p$1.log.info(dim("Cancelled — existing file left untouched."));
3080
3115
  return;
3081
3116
  }
3082
3117
  }
3083
3118
  const content = buildCmintrcContent(tools);
3084
- p.log.info(dim(`\nPreview of ${fileName}:`));
3085
- p.log.message(dim(content));
3086
- const confirm = await p.confirm({ message: `Write ${fileName}?` });
3087
- if (p.isCancel(confirm) || !confirm) {
3088
- p.log.info(dim("Cancelled."));
3119
+ p$1.log.info(dim(`\nPreview of ${fileName}:`));
3120
+ p$1.log.message(dim(content));
3121
+ const confirm = await p$1.confirm({ message: `Write ${fileName}?` });
3122
+ if (p$1.isCancel(confirm) || !confirm) {
3123
+ p$1.log.info(dim("Cancelled."));
3089
3124
  return;
3090
3125
  }
3091
3126
  await writeFile(filePath, content, "utf-8");
3092
3127
  debug("setupCmintrcCommand: wrote %s", filePath);
3093
- p.log.success(green(`Wrote ${fileName}`));
3128
+ p$1.log.success(green(`Wrote ${fileName}`));
3094
3129
  }
3095
3130
  /** Project-local marker file that suppresses the preflight prompt forever. */
3096
3131
  const SKIP_SETUP_MARKER = ".cmint-skip-setup";
@@ -3131,7 +3166,7 @@ async function runPreflightSetupPrompt(cwd) {
3131
3166
  debug("preflight: project not auto-configurable, skipping prompt");
3132
3167
  return;
3133
3168
  }
3134
- const choice = await p.select({
3169
+ const choice = await p$1.select({
3135
3170
  message: "No .cmintrc found. Run setup to create one from detected tools?",
3136
3171
  options: [
3137
3172
  {
@@ -3148,23 +3183,698 @@ async function runPreflightSetupPrompt(cwd) {
3148
3183
  }
3149
3184
  ]
3150
3185
  });
3151
- if (p.isCancel(choice)) {
3186
+ if (p$1.isCancel(choice)) {
3152
3187
  debug("preflight: user cancelled prompt");
3153
3188
  return;
3154
3189
  }
3155
3190
  if (choice === "never") {
3156
3191
  await writeSkipSetupMarker(cwd);
3157
- p.log.info(dim(`Won't ask again. Delete ${SKIP_SETUP_MARKER} to re-enable.`));
3192
+ p$1.log.info(dim(`Won't ask again. Delete ${SKIP_SETUP_MARKER} to re-enable.`));
3158
3193
  return;
3159
3194
  }
3160
3195
  if (choice === "no") {
3161
- p.log.info(dim("Skipping .cmintrc setup."));
3196
+ p$1.log.info(dim("Skipping .cmintrc setup."));
3162
3197
  return;
3163
3198
  }
3164
3199
  debug("preflight: user chose yes, running setup");
3165
3200
  await setupCmintrcCommand(cwd);
3166
3201
  }
3167
3202
  //#endregion
3203
+ //#region node_modules/fast-string-truncated-width/dist/utils.js
3204
+ const getCodePointsLength = (() => {
3205
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
3206
+ return (input) => {
3207
+ let surrogatePairsNr = 0;
3208
+ SURROGATE_PAIR_RE.lastIndex = 0;
3209
+ while (SURROGATE_PAIR_RE.test(input)) surrogatePairsNr += 1;
3210
+ return input.length - surrogatePairsNr;
3211
+ };
3212
+ })();
3213
+ const isFullWidth = (x) => {
3214
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
3215
+ };
3216
+ const isWideNotCJKTNotEmoji = (x) => {
3217
+ return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
3218
+ };
3219
+ //#endregion
3220
+ //#region node_modules/fast-string-truncated-width/dist/index.js
3221
+ const ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
3222
+ const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
3223
+ const CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/uy;
3224
+ const TAB_RE = /\t{1,1000}/y;
3225
+ const EMOJI_RE = /[\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?))*/uy;
3226
+ const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
3227
+ const MODIFIER_RE = /\p{M}+/gu;
3228
+ const NO_TRUNCATION$1 = {
3229
+ limit: Infinity,
3230
+ ellipsis: ""
3231
+ };
3232
+ const getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
3233
+ const LIMIT = truncationOptions.limit ?? Infinity;
3234
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
3235
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION$1, widthOptions).width : 0);
3236
+ const ANSI_WIDTH = 0;
3237
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
3238
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
3239
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
3240
+ const FULL_WIDTH_WIDTH = 2;
3241
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
3242
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
3243
+ const PARSE_BLOCKS = [
3244
+ [LATIN_RE, REGULAR_WIDTH],
3245
+ [ANSI_RE, ANSI_WIDTH],
3246
+ [CONTROL_RE, CONTROL_WIDTH],
3247
+ [TAB_RE, TAB_WIDTH],
3248
+ [EMOJI_RE, EMOJI_WIDTH],
3249
+ [CJKT_WIDE_RE, WIDE_WIDTH]
3250
+ ];
3251
+ let indexPrev = 0;
3252
+ let index = 0;
3253
+ let length = input.length;
3254
+ let lengthExtra = 0;
3255
+ let truncationEnabled = false;
3256
+ let truncationIndex = length;
3257
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
3258
+ let unmatchedStart = 0;
3259
+ let unmatchedEnd = 0;
3260
+ let width = 0;
3261
+ let widthExtra = 0;
3262
+ outer: while (true) {
3263
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
3264
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
3265
+ lengthExtra = 0;
3266
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
3267
+ const codePoint = char.codePointAt(0) || 0;
3268
+ if (isFullWidth(codePoint)) widthExtra = FULL_WIDTH_WIDTH;
3269
+ else if (isWideNotCJKTNotEmoji(codePoint)) widthExtra = WIDE_WIDTH;
3270
+ else widthExtra = REGULAR_WIDTH;
3271
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
3272
+ if (width + widthExtra > LIMIT) {
3273
+ truncationEnabled = true;
3274
+ break outer;
3275
+ }
3276
+ lengthExtra += char.length;
3277
+ width += widthExtra;
3278
+ }
3279
+ unmatchedStart = unmatchedEnd = 0;
3280
+ }
3281
+ if (index >= length) break outer;
3282
+ for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {
3283
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
3284
+ BLOCK_RE.lastIndex = index;
3285
+ if (BLOCK_RE.test(input)) {
3286
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
3287
+ widthExtra = lengthExtra * BLOCK_WIDTH;
3288
+ if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
3289
+ if (width + widthExtra > LIMIT) {
3290
+ truncationEnabled = true;
3291
+ break outer;
3292
+ }
3293
+ width += widthExtra;
3294
+ unmatchedStart = indexPrev;
3295
+ unmatchedEnd = index;
3296
+ index = indexPrev = BLOCK_RE.lastIndex;
3297
+ continue outer;
3298
+ }
3299
+ }
3300
+ index += 1;
3301
+ }
3302
+ return {
3303
+ width: truncationEnabled ? truncationLimit : width,
3304
+ index: truncationEnabled ? truncationIndex : length,
3305
+ truncated: truncationEnabled,
3306
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
3307
+ };
3308
+ };
3309
+ //#endregion
3310
+ //#region node_modules/fast-string-width/dist/index.js
3311
+ const NO_TRUNCATION = {
3312
+ limit: Infinity,
3313
+ ellipsis: "",
3314
+ ellipsisWidth: 0
3315
+ };
3316
+ const fastStringWidth = (input, options = {}) => {
3317
+ return getStringTruncatedWidth(input, NO_TRUNCATION, options).width;
3318
+ };
3319
+ //#endregion
3320
+ //#region node_modules/fast-wrap-ansi/lib/main.js
3321
+ const ESC = "\x1B";
3322
+ const CSI = "›";
3323
+ const END_CODE = 39;
3324
+ const ANSI_ESCAPE_BELL = "\x07";
3325
+ const ANSI_CSI = "[";
3326
+ const ANSI_OSC = "]";
3327
+ const ANSI_SGR_TERMINATOR = "m";
3328
+ const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
3329
+ const GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
3330
+ const getClosingCode = (openingCode) => {
3331
+ if (openingCode >= 30 && openingCode <= 37) return 39;
3332
+ if (openingCode >= 90 && openingCode <= 97) return 39;
3333
+ if (openingCode >= 40 && openingCode <= 47) return 49;
3334
+ if (openingCode >= 100 && openingCode <= 107) return 49;
3335
+ if (openingCode === 1 || openingCode === 2) return 22;
3336
+ if (openingCode === 3) return 23;
3337
+ if (openingCode === 4) return 24;
3338
+ if (openingCode === 7) return 27;
3339
+ if (openingCode === 8) return 28;
3340
+ if (openingCode === 9) return 29;
3341
+ if (openingCode === 0) return 0;
3342
+ };
3343
+ const wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
3344
+ const wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
3345
+ const wrapWord = (rows, word, columns) => {
3346
+ const characters = word[Symbol.iterator]();
3347
+ let isInsideEscape = false;
3348
+ let isInsideLinkEscape = false;
3349
+ let lastRow = rows.at(-1);
3350
+ let visible = lastRow === void 0 ? 0 : fastStringWidth(lastRow);
3351
+ let currentCharacter = characters.next();
3352
+ let nextCharacter = characters.next();
3353
+ let rawCharacterIndex = 0;
3354
+ while (!currentCharacter.done) {
3355
+ const character = currentCharacter.value;
3356
+ const characterLength = fastStringWidth(character);
3357
+ if (visible + characterLength <= columns) rows[rows.length - 1] += character;
3358
+ else {
3359
+ rows.push(character);
3360
+ visible = 0;
3361
+ }
3362
+ if (character === ESC || character === CSI) {
3363
+ isInsideEscape = true;
3364
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
3365
+ }
3366
+ if (isInsideEscape) {
3367
+ if (isInsideLinkEscape) {
3368
+ if (character === ANSI_ESCAPE_BELL) {
3369
+ isInsideEscape = false;
3370
+ isInsideLinkEscape = false;
3371
+ }
3372
+ } else if (character === ANSI_SGR_TERMINATOR) isInsideEscape = false;
3373
+ } else {
3374
+ visible += characterLength;
3375
+ if (visible === columns && !nextCharacter.done) {
3376
+ rows.push("");
3377
+ visible = 0;
3378
+ }
3379
+ }
3380
+ currentCharacter = nextCharacter;
3381
+ nextCharacter = characters.next();
3382
+ rawCharacterIndex += character.length;
3383
+ }
3384
+ lastRow = rows.at(-1);
3385
+ if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) rows[rows.length - 2] += rows.pop();
3386
+ };
3387
+ const stringVisibleTrimSpacesRight = (string) => {
3388
+ const words = string.split(" ");
3389
+ let last = words.length;
3390
+ while (last) {
3391
+ if (fastStringWidth(words[last - 1])) break;
3392
+ last--;
3393
+ }
3394
+ if (last === words.length) return string;
3395
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
3396
+ };
3397
+ const exec = (string, columns, options = {}) => {
3398
+ if (options.trim !== false && string.trim() === "") return "";
3399
+ let returnValue = "";
3400
+ let escapeCode;
3401
+ let escapeUrl;
3402
+ const words = string.split(" ");
3403
+ let rows = [""];
3404
+ let rowLength = 0;
3405
+ for (let index = 0; index < words.length; index++) {
3406
+ const word = words[index];
3407
+ if (options.trim !== false) {
3408
+ const row = rows.at(-1) ?? "";
3409
+ const trimmed = row.trimStart();
3410
+ if (row.length !== trimmed.length) {
3411
+ rows[rows.length - 1] = trimmed;
3412
+ rowLength = fastStringWidth(trimmed);
3413
+ }
3414
+ }
3415
+ if (index !== 0) {
3416
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
3417
+ rows.push("");
3418
+ rowLength = 0;
3419
+ }
3420
+ if (rowLength || options.trim === false) {
3421
+ rows[rows.length - 1] += " ";
3422
+ rowLength++;
3423
+ }
3424
+ }
3425
+ const wordLength = fastStringWidth(word);
3426
+ if (options.hard && wordLength > columns) {
3427
+ const remainingColumns = columns - rowLength;
3428
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
3429
+ if (Math.floor((wordLength - 1) / columns) < breaksStartingThisLine) rows.push("");
3430
+ wrapWord(rows, word, columns);
3431
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3432
+ continue;
3433
+ }
3434
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
3435
+ if (options.wordWrap === false && rowLength < columns) {
3436
+ wrapWord(rows, word, columns);
3437
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3438
+ continue;
3439
+ }
3440
+ rows.push("");
3441
+ rowLength = 0;
3442
+ }
3443
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
3444
+ wrapWord(rows, word, columns);
3445
+ rowLength = fastStringWidth(rows.at(-1) ?? "");
3446
+ continue;
3447
+ }
3448
+ rows[rows.length - 1] += word;
3449
+ rowLength += wordLength;
3450
+ }
3451
+ if (options.trim !== false) rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
3452
+ const preString = rows.join("\n");
3453
+ let inSurrogate = false;
3454
+ for (let i = 0; i < preString.length; i++) {
3455
+ const character = preString[i];
3456
+ returnValue += character;
3457
+ if (!inSurrogate) {
3458
+ inSurrogate = character >= "\ud800" && character <= "\udbff";
3459
+ if (inSurrogate) continue;
3460
+ } else inSurrogate = false;
3461
+ if (character === ESC || character === CSI) {
3462
+ GROUP_REGEX.lastIndex = i + 1;
3463
+ const groups = GROUP_REGEX.exec(preString)?.groups;
3464
+ if (groups?.code !== void 0) {
3465
+ const code = Number.parseFloat(groups.code);
3466
+ escapeCode = code === END_CODE ? void 0 : code;
3467
+ } else if (groups?.uri !== void 0) escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
3468
+ }
3469
+ if (preString[i + 1] === "\n") {
3470
+ if (escapeUrl) returnValue += wrapAnsiHyperlink("");
3471
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
3472
+ if (escapeCode && closingCode) returnValue += wrapAnsiCode(closingCode);
3473
+ } else if (character === "\n") {
3474
+ if (escapeCode && getClosingCode(escapeCode)) returnValue += wrapAnsiCode(escapeCode);
3475
+ if (escapeUrl) returnValue += wrapAnsiHyperlink(escapeUrl);
3476
+ }
3477
+ }
3478
+ return returnValue;
3479
+ };
3480
+ const CRLF_OR_LF = /\r?\n/;
3481
+ function wrapAnsi(string, columns, options) {
3482
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
3483
+ }
3484
+ //#endregion
3485
+ //#region node_modules/@clack/core/dist/index.mjs
3486
+ var import_src = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
3487
+ const ESC = "\x1B";
3488
+ const CSI = `${ESC}[`;
3489
+ const beep = "\x07";
3490
+ const cursor = {
3491
+ to(x, y) {
3492
+ if (!y) return `${CSI}${x + 1}G`;
3493
+ return `${CSI}${y + 1};${x + 1}H`;
3494
+ },
3495
+ move(x, y) {
3496
+ let ret = "";
3497
+ if (x < 0) ret += `${CSI}${-x}D`;
3498
+ else if (x > 0) ret += `${CSI}${x}C`;
3499
+ if (y < 0) ret += `${CSI}${-y}A`;
3500
+ else if (y > 0) ret += `${CSI}${y}B`;
3501
+ return ret;
3502
+ },
3503
+ up: (count = 1) => `${CSI}${count}A`,
3504
+ down: (count = 1) => `${CSI}${count}B`,
3505
+ forward: (count = 1) => `${CSI}${count}C`,
3506
+ backward: (count = 1) => `${CSI}${count}D`,
3507
+ nextLine: (count = 1) => `${CSI}E`.repeat(count),
3508
+ prevLine: (count = 1) => `${CSI}F`.repeat(count),
3509
+ left: `${CSI}G`,
3510
+ hide: `${CSI}?25l`,
3511
+ show: `${CSI}?25h`,
3512
+ save: `${ESC}7`,
3513
+ restore: `${ESC}8`
3514
+ };
3515
+ module.exports = {
3516
+ cursor,
3517
+ scroll: {
3518
+ up: (count = 1) => `${CSI}S`.repeat(count),
3519
+ down: (count = 1) => `${CSI}T`.repeat(count)
3520
+ },
3521
+ erase: {
3522
+ screen: `${CSI}2J`,
3523
+ up: (count = 1) => `${CSI}1J`.repeat(count),
3524
+ down: (count = 1) => `${CSI}J`.repeat(count),
3525
+ line: `${CSI}2K`,
3526
+ lineEnd: `${CSI}K`,
3527
+ lineStart: `${CSI}1K`,
3528
+ lines(count) {
3529
+ let clear = "";
3530
+ for (let i = 0; i < count; i++) clear += this.line + (i < count - 1 ? cursor.up() : "");
3531
+ if (count) clear += cursor.left;
3532
+ return clear;
3533
+ }
3534
+ },
3535
+ beep
3536
+ };
3537
+ })))();
3538
+ function f(r, t, s) {
3539
+ if (!s.some((o) => !o.disabled)) return r;
3540
+ const e = r + t, i = Math.max(s.length - 1, 0), n = e < 0 ? i : e > i ? 0 : e;
3541
+ return s[n].disabled ? f(n, t < 0 ? -1 : 1, s) : n;
3542
+ }
3543
+ const h = {
3544
+ actions: new Set([
3545
+ "up",
3546
+ "down",
3547
+ "left",
3548
+ "right",
3549
+ "space",
3550
+ "enter",
3551
+ "cancel"
3552
+ ]),
3553
+ aliases: new Map([
3554
+ ["k", "up"],
3555
+ ["j", "down"],
3556
+ ["h", "left"],
3557
+ ["l", "right"],
3558
+ ["", "cancel"],
3559
+ ["escape", "cancel"]
3560
+ ]),
3561
+ messages: {
3562
+ cancel: "Canceled",
3563
+ error: "Something went wrong"
3564
+ },
3565
+ withGuide: !0,
3566
+ date: {
3567
+ monthNames: [...[
3568
+ "January",
3569
+ "February",
3570
+ "March",
3571
+ "April",
3572
+ "May",
3573
+ "June",
3574
+ "July",
3575
+ "August",
3576
+ "September",
3577
+ "October",
3578
+ "November",
3579
+ "December"
3580
+ ]],
3581
+ messages: {
3582
+ required: "Please enter a valid date",
3583
+ invalidMonth: "There are only 12 months in a year",
3584
+ invalidDay: (r, t) => `There are only ${r} days in ${t}`,
3585
+ afterMin: (r) => `Date must be on or after ${r.toISOString().slice(0, 10)}`,
3586
+ beforeMax: (r) => `Date must be on or before ${r.toISOString().slice(0, 10)}`
3587
+ }
3588
+ }
3589
+ };
3590
+ function C(r, t) {
3591
+ if (typeof r == "string") return h.aliases.get(r) === t;
3592
+ for (const s of r) if (s !== void 0 && C(s, t)) return !0;
3593
+ return !1;
3594
+ }
3595
+ function z(r, t) {
3596
+ if (r === t) return;
3597
+ const s = r.split(`
3598
+ `), e = t.split(`
3599
+ `), i = Math.max(s.length, e.length), n = [];
3600
+ for (let o = 0; o < i; o++) s[o] !== e[o] && n.push(o);
3601
+ return {
3602
+ lines: n,
3603
+ numLinesBefore: s.length,
3604
+ numLinesAfter: e.length,
3605
+ numLines: i
3606
+ };
3607
+ }
3608
+ globalThis.process.platform.startsWith("win");
3609
+ const k = Symbol("clack:cancel");
3610
+ function q(r) {
3611
+ return r === k;
3612
+ }
3613
+ function w(r, t) {
3614
+ const s = r;
3615
+ s.isTTY && s.setRawMode(t);
3616
+ }
3617
+ const L = (r) => "rows" in r && typeof r.rows == "number" ? r.rows : 20;
3618
+ let m = class {
3619
+ input;
3620
+ output;
3621
+ _abortSignal;
3622
+ rl;
3623
+ opts;
3624
+ _render;
3625
+ _track = !1;
3626
+ _prevFrame = "";
3627
+ _subscribers = /* @__PURE__ */ new Map();
3628
+ _cursor = 0;
3629
+ state = "initial";
3630
+ error = "";
3631
+ value;
3632
+ userInput = "";
3633
+ constructor(t, s = !0) {
3634
+ const { input: e = stdin, output: i = stdout, render: n, signal: o, ...u } = t;
3635
+ this.opts = u, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = n.bind(this), this._track = s, this._abortSignal = o, this.input = e, this.output = i;
3636
+ }
3637
+ unsubscribe() {
3638
+ this._subscribers.clear();
3639
+ }
3640
+ setSubscriber(t, s) {
3641
+ const e = this._subscribers.get(t) ?? [];
3642
+ e.push(s), this._subscribers.set(t, e);
3643
+ }
3644
+ on(t, s) {
3645
+ this.setSubscriber(t, { cb: s });
3646
+ }
3647
+ once(t, s) {
3648
+ this.setSubscriber(t, {
3649
+ cb: s,
3650
+ once: !0
3651
+ });
3652
+ }
3653
+ emit(t, ...s) {
3654
+ const e = this._subscribers.get(t) ?? [], i = [];
3655
+ for (const n of e) n.cb(...s), n.once && i.push(() => e.splice(e.indexOf(n), 1));
3656
+ for (const n of i) n();
3657
+ }
3658
+ prompt() {
3659
+ return new Promise((t) => {
3660
+ if (this._abortSignal) {
3661
+ if (this._abortSignal.aborted) return this.state = "cancel", this.close(), t(k);
3662
+ this._abortSignal.addEventListener("abort", () => {
3663
+ this.state = "cancel", this.close();
3664
+ }, { once: !0 });
3665
+ }
3666
+ this.rl = E.createInterface({
3667
+ input: this.input,
3668
+ tabSize: 2,
3669
+ prompt: "",
3670
+ escapeCodeTimeout: 50,
3671
+ terminal: !0
3672
+ }), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, !0), this.input.on("keypress", this.onKeypress), w(this.input, !0), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
3673
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), w(this.input, !1), t(this.value);
3674
+ }), this.once("cancel", () => {
3675
+ this.output.write(import_src.cursor.show), this.output.off("resize", this.render), w(this.input, !1), t(k);
3676
+ });
3677
+ });
3678
+ }
3679
+ _isActionKey(t, s) {
3680
+ return t === " ";
3681
+ }
3682
+ _shouldSubmit(t, s) {
3683
+ return !0;
3684
+ }
3685
+ _setValue(t) {
3686
+ this.value = t, this.emit("value", this.value);
3687
+ }
3688
+ _setUserInput(t, s) {
3689
+ this.userInput = t ?? "", this.emit("userInput", this.userInput), s && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
3690
+ }
3691
+ _clearUserInput() {
3692
+ this.rl?.write(null, {
3693
+ ctrl: !0,
3694
+ name: "u"
3695
+ }), this._setUserInput("");
3696
+ }
3697
+ onKeypress(t, s) {
3698
+ if (this._track && s.name !== "return" && (s.name && this._isActionKey(t, s) && this.rl?.write(null, {
3699
+ ctrl: !0,
3700
+ name: "h"
3701
+ }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), s?.name && (!this._track && h.aliases.has(s.name) && this.emit("cursor", h.aliases.get(s.name)), h.actions.has(s.name) && this.emit("cursor", s.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t?.toLowerCase(), s), s?.name === "return" && this._shouldSubmit(t, s)) {
3702
+ if (this.opts.validate) {
3703
+ const e = this.opts.validate(this.value);
3704
+ e && (this.error = e instanceof Error ? e.message : e, this.state = "error", this.rl?.write(this.userInput));
3705
+ }
3706
+ this.state !== "error" && (this.state = "submit");
3707
+ }
3708
+ C([
3709
+ t,
3710
+ s?.name,
3711
+ s?.sequence
3712
+ ], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
3713
+ }
3714
+ close() {
3715
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
3716
+ `), w(this.input, !1), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
3717
+ }
3718
+ restoreCursor() {
3719
+ const t = wrapAnsi(this._prevFrame, process.stdout.columns, {
3720
+ hard: !0,
3721
+ trim: !1
3722
+ }).split(`
3723
+ `).length - 1;
3724
+ this.output.write(import_src.cursor.move(-999, t * -1));
3725
+ }
3726
+ render() {
3727
+ const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
3728
+ hard: !0,
3729
+ trim: !1
3730
+ });
3731
+ if (t !== this._prevFrame) {
3732
+ if (this.state === "initial") this.output.write(import_src.cursor.hide);
3733
+ else {
3734
+ const s = z(this._prevFrame, t), e = L(this.output);
3735
+ if (this.restoreCursor(), s) {
3736
+ const i = Math.max(0, s.numLinesAfter - e), n = Math.max(0, s.numLinesBefore - e);
3737
+ let o = s.lines.find((u) => u >= i);
3738
+ if (o === void 0) {
3739
+ this._prevFrame = t;
3740
+ return;
3741
+ }
3742
+ if (s.lines.length === 1) {
3743
+ this.output.write(import_src.cursor.move(0, o - n)), this.output.write(import_src.erase.lines(1));
3744
+ const u = t.split(`
3745
+ `);
3746
+ this.output.write(u[o]), this._prevFrame = t, this.output.write(import_src.cursor.move(0, u.length - o - 1));
3747
+ return;
3748
+ } else if (s.lines.length > 1) {
3749
+ if (i < n) o = i;
3750
+ else {
3751
+ const a = o - n;
3752
+ a > 0 && this.output.write(import_src.cursor.move(0, a));
3753
+ }
3754
+ this.output.write(import_src.erase.down());
3755
+ const u = t.split(`
3756
+ `).slice(o);
3757
+ this.output.write(u.join(`
3758
+ `)), this._prevFrame = t;
3759
+ return;
3760
+ }
3761
+ }
3762
+ this.output.write(import_src.erase.down());
3763
+ }
3764
+ this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
3765
+ }
3766
+ }
3767
+ };
3768
+ var ut = class extends m {
3769
+ options;
3770
+ cursor = 0;
3771
+ get _selectedValue() {
3772
+ return this.options[this.cursor];
3773
+ }
3774
+ changeValue() {
3775
+ this.value = this._selectedValue.value;
3776
+ }
3777
+ constructor(t) {
3778
+ super(t, !1), this.options = t.options;
3779
+ const s = this.options.findIndex(({ value: i }) => i === t.initialValue), e = s === -1 ? 0 : s;
3780
+ this.cursor = this.options[e].disabled ? f(e, 1, this.options) : e, this.changeValue(), this.on("cursor", (i) => {
3781
+ switch (i) {
3782
+ case "left":
3783
+ case "up":
3784
+ this.cursor = f(this.cursor, -1, this.options);
3785
+ break;
3786
+ case "down":
3787
+ case "right":
3788
+ this.cursor = f(this.cursor, 1, this.options);
3789
+ break;
3790
+ }
3791
+ this.changeValue();
3792
+ });
3793
+ }
3794
+ };
3795
+ //#endregion
3796
+ //#region src/ui/auto-accept-select.ts
3797
+ const ON_LABEL = styleText("green", "ON");
3798
+ const OFF_LABEL = styleText("dim", "OFF");
3799
+ const HOTKEY_HINT = dim("(press `a` to toggle)");
3800
+ function renderStatus(autoAccept) {
3801
+ const label = autoAccept ? ON_LABEL : OFF_LABEL;
3802
+ return `${dim("⚡ Auto-accept:")} ${label} ${HOTKEY_HINT}`;
3803
+ }
3804
+ /** Render a single select option line. */
3805
+ function renderOption(opt, active) {
3806
+ const text = opt.label ?? String(opt.value);
3807
+ if (opt.disabled) return `${dim(S_RADIO_INACTIVE)} ${styleText(["strikethrough", "dim"], text)}`;
3808
+ if (active) {
3809
+ const hint = opt.hint ? ` ${dim(`(${opt.hint})`)}` : "";
3810
+ return `${green(S_RADIO_ACTIVE)} ${text}${hint}`;
3811
+ }
3812
+ return `${dim(S_RADIO_INACTIVE)} ${dim(text)}`;
3813
+ }
3814
+ /**
3815
+ * Select prompt with an inline `a`-hotkey toggle for auto-accept mode.
3816
+ *
3817
+ * Renders a normal select list plus a status line showing the current
3818
+ * auto-accept state. Pressing `a` flips the state in-place (the menu
3819
+ * re-renders) and fires `onToggle` so callers can persist the change.
3820
+ *
3821
+ * Returns `{ value, autoAccept }` on submit, or the clack cancel symbol
3822
+ * on cancel.
3823
+ */
3824
+ async function selectWithAutoAccept(opts) {
3825
+ let autoAccept = opts.initialAutoAccept;
3826
+ const prompt = new ut({
3827
+ options: opts.options,
3828
+ input: opts.input,
3829
+ output: opts.output,
3830
+ render() {
3831
+ const sym = symbol(this.state);
3832
+ const statusLine = renderStatus(autoAccept);
3833
+ const header = `${sym} ${opts.message}\n${dim(S_BAR)} ${statusLine}`;
3834
+ switch (this.state) {
3835
+ case "submit": {
3836
+ const selected = this.options[this.cursor];
3837
+ const text = selected.label ?? String(selected.value);
3838
+ return `${header}\n${dim(S_BAR)} ${dim(text)}`;
3839
+ }
3840
+ case "cancel": {
3841
+ const selected = this.options[this.cursor];
3842
+ const text = selected.label ?? String(selected.value);
3843
+ return `${header}\n${dim(S_BAR)} ${styleText(["strikethrough", "dim"], text)}\n${dim(S_BAR_END)}`;
3844
+ }
3845
+ default: return [
3846
+ header,
3847
+ ...limitOptions({
3848
+ cursor: this.cursor,
3849
+ options: this.options,
3850
+ style: (opt, active) => renderOption(opt, active),
3851
+ maxItems: 7,
3852
+ output: opts.output ?? process.stdout
3853
+ }).map((line) => `${dim(S_BAR)} ${line}`),
3854
+ `${dim(S_BAR_END)} ${dim("↑/↓ navigate • Enter confirm • `a` toggle auto-accept")}`
3855
+ ].join("\n");
3856
+ }
3857
+ }
3858
+ });
3859
+ prompt.on("key", async (char) => {
3860
+ if (char === "a") {
3861
+ autoAccept = !autoAccept;
3862
+ debug("auto-accept toggled to %s", autoAccept);
3863
+ try {
3864
+ await opts.onToggle?.(autoAccept);
3865
+ } catch (err) {
3866
+ debug("onToggle threw (ignored): %s", err instanceof Error ? err.message : String(err));
3867
+ }
3868
+ }
3869
+ });
3870
+ const result = await prompt.prompt();
3871
+ if (q(result)) return result;
3872
+ return {
3873
+ value: result,
3874
+ autoAccept
3875
+ };
3876
+ }
3877
+ //#endregion
3168
3878
  //#region src/ui/staging-menu.ts
3169
3879
  async function showStagingMenu(files, hasChecks) {
3170
3880
  debug("showStagingMenu: %d files", files.length);
@@ -3190,9 +3900,15 @@ async function showStagingMenu(files, hasChecks) {
3190
3900
  if (lines.length > 0) lines.push("");
3191
3901
  lines.push(yellow(bold("Changed:")), ...unstagedFiles.map((f) => ` ${statusLabel(f.status)} ${f.path}`));
3192
3902
  }
3193
- p.note(lines.join("\n"), `${files.length} file${files.length !== 1 ? "s" : ""}`);
3194
- const choice = await p.select({
3903
+ p$1.note(lines.join("\n"), `${files.length} file${files.length !== 1 ? "s" : ""}`);
3904
+ const initialAutoAccept = await getAutoAccept();
3905
+ debug("showStagingMenu: initial auto-accept=%s", initialAutoAccept);
3906
+ const selectResult = await selectWithAutoAccept({
3195
3907
  message: "Stage files for commit:",
3908
+ initialAutoAccept,
3909
+ onToggle: async (next) => {
3910
+ await setAutoAccept(next);
3911
+ },
3196
3912
  options: [
3197
3913
  {
3198
3914
  label: "Auto-group into commits",
@@ -3214,17 +3930,23 @@ async function showStagingMenu(files, hasChecks) {
3214
3930
  value: "checks",
3215
3931
  hint: "Pre-flight checks from cmint config"
3216
3932
  }] : [],
3217
- {
3933
+ ...files.length > 1 ? [{
3218
3934
  label: "Select files...",
3219
3935
  value: "select"
3220
- },
3936
+ }] : [],
3221
3937
  {
3222
3938
  label: "Cancel",
3223
3939
  value: "cancel"
3224
3940
  }
3225
3941
  ]
3226
3942
  });
3227
- if (p.isCancel(choice) || choice === "cancel") return null;
3943
+ if (typeof selectResult === "symbol") {
3944
+ debug("showStagingMenu: user cancelled (clack cancel symbol)");
3945
+ return null;
3946
+ }
3947
+ const choice = selectResult.value;
3948
+ debug("showStagingMenu: choice=%s autoAccept=%s", choice, selectResult.autoAccept);
3949
+ if (p$1.isCancel(choice) || choice === "cancel") return null;
3228
3950
  if (choice === "autogroup") return "autogroup";
3229
3951
  if (choice === "checks") return "checks";
3230
3952
  if (choice === "staged") return "staged";
@@ -3232,7 +3954,7 @@ async function showStagingMenu(files, hasChecks) {
3232
3954
  files: files.map((f) => f.path),
3233
3955
  all: true
3234
3956
  };
3235
- const selected = await p.multiselect({
3957
+ const selected = await p$1.multiselect({
3236
3958
  message: "Select files to stage:",
3237
3959
  options: sorted.map((f) => ({
3238
3960
  label: `${statusLabel(f.status)} ${f.path}`,
@@ -3240,7 +3962,7 @@ async function showStagingMenu(files, hasChecks) {
3240
3962
  })),
3241
3963
  required: true
3242
3964
  });
3243
- if (p.isCancel(selected)) return null;
3965
+ if (p$1.isCancel(selected)) return null;
3244
3966
  return {
3245
3967
  files: selected,
3246
3968
  all: false
@@ -3358,10 +4080,6 @@ async function commitCommand(flags, version) {
3358
4080
  }
3359
4081
  if (await runAutoGroupFlow(changedFiles, flags) !== "committed") process.exit(1);
3360
4082
  return;
3361
- } else if (changedFiles.length === 1) {
3362
- s.start(`Staging ${changedFiles[0].path}...`);
3363
- await stageFiles([changedFiles[0].path]);
3364
- s.stop("File staged");
3365
4083
  } else {
3366
4084
  const result = await handleStaging(changedFiles, flags);
3367
4085
  if (!result) return;
@@ -3439,24 +4157,29 @@ async function commitCommand(flags, version) {
3439
4157
  }
3440
4158
  s.stop("Message generated");
3441
4159
  }
3442
- const reviewed = await reviewCommitMessage(message, { regenerate: async (hint) => {
3443
- const combinedHint = flags.hint ? `${flags.hint}\n${hint}` : hint;
3444
- debug("Regenerating with combined hint:", combinedHint);
3445
- s.start("Regenerating commit message...");
3446
- try {
3447
- const newMessage = await generateMessage(diffResult.diff, combinedHint);
3448
- s.stop("Message regenerated");
3449
- return newMessage;
3450
- } catch (err) {
3451
- s.stop(red("Regeneration failed"));
3452
- throw err;
4160
+ if (await getAutoAccept()) {
4161
+ debug("Auto-accept ON: skipping review step");
4162
+ log.info(message);
4163
+ } else {
4164
+ const reviewed = await reviewCommitMessage(message, { regenerate: async (hint) => {
4165
+ const combinedHint = flags.hint ? `${flags.hint}\n${hint}` : hint;
4166
+ debug("Regenerating with combined hint:", combinedHint);
4167
+ s.start("Regenerating commit message...");
4168
+ try {
4169
+ const newMessage = await generateMessage(diffResult.diff, combinedHint);
4170
+ s.stop("Message regenerated");
4171
+ return newMessage;
4172
+ } catch (err) {
4173
+ s.stop(red("Regeneration failed"));
4174
+ throw err;
4175
+ }
4176
+ } });
4177
+ if (reviewed === null) {
4178
+ outro(dim("Cancelled."));
4179
+ return;
3453
4180
  }
3454
- } });
3455
- if (reviewed === null) {
3456
- outro(dim("Cancelled."));
3457
- return;
4181
+ message = reviewed;
3458
4182
  }
3459
- message = reviewed;
3460
4183
  await saveCachedCommit(repoRoot, message);
3461
4184
  debug("Message cached for repo:", repoRoot);
3462
4185
  s.start("Running pre-commit hooks...");
@@ -3496,7 +4219,7 @@ function getProvider(config) {
3496
4219
  return isValidProvider(config.provider ?? "groq") ? config.provider : "groq";
3497
4220
  }
3498
4221
  async function promptProvider() {
3499
- return p.select({
4222
+ return p$1.select({
3500
4223
  message: "Select LLM provider:",
3501
4224
  options: [
3502
4225
  {
@@ -3519,24 +4242,24 @@ async function promptProvider() {
3519
4242
  }
3520
4243
  async function promptApiKey(provider) {
3521
4244
  const keyName = PROVIDER_ENV_KEYS[provider];
3522
- const result = await p.text({
4245
+ const result = await p$1.text({
3523
4246
  message: `${formatProviderName(provider)} API key:`,
3524
4247
  placeholder: "Paste your API key",
3525
4248
  validate: (v) => !v?.trim() ? "API key cannot be empty" : void 0
3526
4249
  });
3527
- if (p.isCancel(result)) return result;
4250
+ if (p$1.isCancel(result)) return result;
3528
4251
  await writeConfig({ [keyName]: result.toString().trim() });
3529
4252
  debug("config: %s set", keyName);
3530
4253
  return result;
3531
4254
  }
3532
4255
  async function promptTextSetting(label, configKey, currentValue, validate) {
3533
- const result = await p.text({
4256
+ const result = await p$1.text({
3534
4257
  message: label,
3535
4258
  placeholder: currentValue ?? "",
3536
4259
  initialValue: currentValue ?? "",
3537
4260
  validate
3538
4261
  });
3539
- if (p.isCancel(result)) return result;
4262
+ if (p$1.isCancel(result)) return result;
3540
4263
  await writeConfig({ [configKey]: result.toString().trim() });
3541
4264
  debug("config: %s set to %s", configKey, result);
3542
4265
  return result;
@@ -3550,7 +4273,7 @@ function getSettingHandlers(config) {
3550
4273
  return {
3551
4274
  provider: async () => {
3552
4275
  const result = await promptProvider();
3553
- if (p.isCancel(result)) return result;
4276
+ if (p$1.isCancel(result)) return result;
3554
4277
  const newProvider = result;
3555
4278
  const newDefaultModel = PROVIDER_CONFIGS[newProvider].defaultModel;
3556
4279
  await writeConfig({
@@ -3561,7 +4284,7 @@ function getSettingHandlers(config) {
3561
4284
  const keyName = PROVIDER_ENV_KEYS[newProvider];
3562
4285
  if (!(await readConfig())[keyName]) {
3563
4286
  const keyResult = await promptApiKey(newProvider);
3564
- if (p.isCancel(keyResult)) return keyResult;
4287
+ if (p$1.isCancel(keyResult)) return keyResult;
3565
4288
  }
3566
4289
  },
3567
4290
  apikey: async () => promptApiKey(provider),
@@ -3579,7 +4302,7 @@ async function handleEditSetting(setting, config) {
3579
4302
  const handler = getSettingHandlers(config)[setting];
3580
4303
  if (!handler) return false;
3581
4304
  const result = await handler();
3582
- return !p.isCancel(result);
4305
+ return !p$1.isCancel(result);
3583
4306
  }
3584
4307
  async function editSettingsLoop(initialConfig) {
3585
4308
  let config = initialConfig;
@@ -3587,7 +4310,7 @@ async function editSettingsLoop(initialConfig) {
3587
4310
  config = await readConfig();
3588
4311
  const provider = getProvider(config);
3589
4312
  const effectiveModel = getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel);
3590
- const setting = await p.select({
4313
+ const setting = await p$1.select({
3591
4314
  message: "Select a setting to edit:",
3592
4315
  options: [
3593
4316
  {
@@ -3628,17 +4351,17 @@ async function editSettingsLoop(initialConfig) {
3628
4351
  }
3629
4352
  ]
3630
4353
  });
3631
- if (p.isCancel(setting) || setting === "done") break;
3632
- if (await handleEditSetting(setting, config)) p.log.success(green("Updated."));
4354
+ if (p$1.isCancel(setting) || setting === "done") break;
4355
+ if (await handleEditSetting(setting, config)) p$1.log.success(green("Updated."));
3633
4356
  }
3634
4357
  }
3635
4358
  async function configCommand() {
3636
4359
  debug("configCommand: starting");
3637
- p.intro(bold("🌿 commit-mint config"));
4360
+ p$1.intro(bold("🌿 commit-mint config"));
3638
4361
  while (true) {
3639
4362
  const config = await readConfig();
3640
- p.note(buildConfigDisplay(config), "commit-mint config");
3641
- const action = await p.select({
4363
+ p$1.note(buildConfigDisplay(config), "commit-mint config");
4364
+ const action = await p$1.select({
3642
4365
  message: "What would you like to do?",
3643
4366
  options: [
3644
4367
  {
@@ -3655,14 +4378,14 @@ async function configCommand() {
3655
4378
  }
3656
4379
  ]
3657
4380
  });
3658
- if (p.isCancel(action)) {
4381
+ if (p$1.isCancel(action)) {
3659
4382
  debug("configCommand: cancelled at main menu");
3660
- p.outro(dim("Cancelled."));
4383
+ p$1.outro(dim("Cancelled."));
3661
4384
  return;
3662
4385
  }
3663
4386
  if (action === "done") {
3664
4387
  debug("configCommand: done");
3665
- p.outro("Config saved.");
4388
+ p$1.outro("Config saved.");
3666
4389
  return;
3667
4390
  }
3668
4391
  if (action === "setup") {
@@ -3816,43 +4539,53 @@ async function runUpdate(pm, packageName = PACKAGE_NAME) {
3816
4539
  * resolve normally so the CLI exits cleanly.
3817
4540
  */
3818
4541
  async function updateCommand(currentVersion, flags) {
3819
- p.intro("cmint update");
4542
+ p$1.intro("cmint update");
3820
4543
  const pm = detectPackageManager(process.env.npm_config_user_agent);
3821
- p.log.info(`Package manager: ${pm}`);
3822
- p.log.message("Checking latest version...");
4544
+ p$1.log.info(`Package manager: ${pm}`);
4545
+ p$1.log.message("Checking latest version...");
3823
4546
  const latest = await fetchLatestVersion();
3824
4547
  if (latest === null) {
3825
- p.outro(red("Could not reach the npm registry. Check your connection and try again."));
4548
+ p$1.outro(red("Could not reach the npm registry. Check your connection and try again."));
3826
4549
  process.exit(1);
3827
4550
  return;
3828
4551
  }
3829
4552
  if (!isUpdateAvailable(currentVersion, latest)) {
3830
- p.outro(`Already up-to-date: v${currentVersion}`);
4553
+ p$1.outro(`Already up-to-date: v${currentVersion}`);
3831
4554
  return;
3832
4555
  }
3833
- p.log.step(`${dim(currentVersion)} → ${green(latest)}`);
4556
+ p$1.log.step(`${dim(currentVersion)} → ${green(latest)}`);
3834
4557
  const cmd = buildUpdateCommand(pm);
3835
4558
  if (flags?.yes !== true) {
3836
- const confirmed = await p.confirm({
4559
+ const confirmed = await p$1.confirm({
3837
4560
  message: `Run \`${cmd}\`?`,
3838
4561
  initialValue: true
3839
4562
  });
3840
- if (p.isCancel(confirmed) || !confirmed) {
3841
- p.outro("Update cancelled.");
4563
+ if (p$1.isCancel(confirmed) || !confirmed) {
4564
+ p$1.outro("Update cancelled.");
3842
4565
  return;
3843
4566
  }
3844
4567
  }
3845
- p.log.message(`Running ${cyan(cmd)}...`);
4568
+ p$1.log.message(`Running ${cyan(cmd)}...`);
3846
4569
  if (await runUpdate(pm)) {
3847
- p.outro(green(`Updated to v${latest}`));
4570
+ p$1.outro(green(`Updated to v${latest}`));
3848
4571
  return;
3849
4572
  }
3850
- p.outro(red("Update failed. See output above."));
4573
+ p$1.outro(red("Update failed. See output above."));
3851
4574
  process.exit(1);
3852
4575
  }
3853
4576
  //#endregion
3854
4577
  //#region src/cli.ts
3855
4578
  const { version } = package_default;
4579
+ /** `cmint auto` subcommand handler — equivalent to `cmint --auto`. */
4580
+ async function handleAutoSubcommand(version) {
4581
+ writeSessionHeader();
4582
+ setDebug(false);
4583
+ commitCommand({
4584
+ auto: true,
4585
+ retry: false,
4586
+ agent: false
4587
+ }, version);
4588
+ }
3856
4589
  cli({
3857
4590
  name: "cmint",
3858
4591
  version,
@@ -3910,6 +4643,12 @@ cli({
3910
4643
  }, async (argv) => {
3911
4644
  await logsCommand(argv.flags);
3912
4645
  }),
4646
+ command({
4647
+ name: "auto",
4648
+ description: "Auto-group files into logical commits (alias for --auto)"
4649
+ }, async () => {
4650
+ await handleAutoSubcommand(version);
4651
+ }),
3913
4652
  command({ name: "config" }, async () => {
3914
4653
  await configCommand();
3915
4654
  }),
@@ -3933,6 +4672,6 @@ cli({
3933
4672
  else commitCommand(argv.flags, version);
3934
4673
  });
3935
4674
  //#endregion
3936
- export {};
4675
+ export { handleAutoSubcommand };
3937
4676
 
3938
4677
  //# sourceMappingURL=cli.mjs.map