@byh3071/vhk 1.6.5 → 1.7.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.
@@ -483,8 +483,31 @@ var require_ignore = __commonJS({
483
483
  }
484
484
  });
485
485
 
486
+ // src/lib/interactive.ts
487
+ import chalk from "chalk";
488
+ function isInteractive(opts) {
489
+ if (opts?.yes) return false;
490
+ if (process.env.VHK_FORCE_INTERACTIVE === "1") return true;
491
+ return !!process.stdin.isTTY;
492
+ }
493
+ async function promptOrDefault(ask, fallback, opts) {
494
+ if (!isInteractive(opts)) return fallback;
495
+ return await ask();
496
+ }
497
+ function ensureInteractive(hint = "") {
498
+ if (isInteractive()) return true;
499
+ console.error(chalk.yellow(" \u26A0\uFE0F \uC774 \uBA85\uB839\uC740 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uBE44-TTY/\uD30C\uC774\uD504 \uD658\uACBD\uC5D0\uC11C\uB294 \uC2E4\uD589\uD560 \uC218 \uC5C6\uC5B4\uC694."));
500
+ if (hint) console.error(chalk.dim(` ${hint}`));
501
+ process.exitCode = 1;
502
+ return false;
503
+ }
504
+ function isPromptAbortError(err) {
505
+ const msg = err instanceof Error ? err.message : String(err);
506
+ return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
507
+ }
508
+
486
509
  // src/commands/sync.ts
487
- import chalk2 from "chalk";
510
+ import chalk3 from "chalk";
488
511
  import fs4 from "fs";
489
512
  import path4 from "path";
490
513
  import inquirer from "inquirer";
@@ -911,7 +934,7 @@ function t(key, ...args) {
911
934
  // src/lib/next-step.ts
912
935
  import fs2 from "fs";
913
936
  import path2 from "path";
914
- import chalk from "chalk";
937
+ import chalk2 from "chalk";
915
938
 
916
939
  // src/lib/drift.ts
917
940
  import fs from "fs";
@@ -1029,39 +1052,39 @@ function checkContextDrift(rootDir) {
1029
1052
  // src/lib/next-step.ts
1030
1053
  function printNextStep(step) {
1031
1054
  console.log("");
1032
- console.log(chalk.cyan.bold("\u2501\u2501\u2501 \uB2E4\uC74C\uC5D0 \uC774\uAC83\uB9CC \uD558\uC138\uC694 \u2501\u2501\u2501"));
1055
+ console.log(chalk2.cyan.bold("\u2501\u2501\u2501 \uB2E4\uC74C\uC5D0 \uC774\uAC83\uB9CC \uD558\uC138\uC694 \u2501\u2501\u2501"));
1033
1056
  console.log("");
1034
1057
  console.log(` ${step.message}`);
1035
1058
  if (step.command) {
1036
1059
  console.log("");
1037
- console.log(chalk.white.bgGray(" \uD130\uBBF8\uB110\uC5D0 \uBCF5\uBD99 "));
1038
- console.log(chalk.green(` ${step.command}`));
1060
+ console.log(chalk2.white.bgGray(" \uD130\uBBF8\uB110\uC5D0 \uBCF5\uBD99 "));
1061
+ console.log(chalk2.green(` ${step.command}`));
1039
1062
  }
1040
1063
  if (step.cursorHint) {
1041
1064
  console.log("");
1042
- console.log(chalk.white.bgBlue(" Cursor\uC5D0\uAC8C \uB9D0\uD558\uAE30 "));
1043
- console.log(chalk.blue(` "${step.cursorHint}"`));
1065
+ console.log(chalk2.white.bgBlue(" Cursor\uC5D0\uAC8C \uB9D0\uD558\uAE30 "));
1066
+ console.log(chalk2.blue(` "${step.cursorHint}"`));
1044
1067
  }
1045
1068
  if (step.alternative) {
1046
1069
  console.log("");
1047
- console.log(chalk.dim(` \uB610\uB294: ${step.alternative}`));
1070
+ console.log(chalk2.dim(` \uB610\uB294: ${step.alternative}`));
1048
1071
  }
1049
1072
  console.log("");
1050
- console.log(chalk.cyan.bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
1073
+ console.log(chalk2.cyan.bold("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
1051
1074
  console.log("");
1052
1075
  }
1053
1076
  function printContextResumeHint(cwd = process.cwd()) {
1054
1077
  const ctxPath = path2.join(cwd, ".vhk", "context.md");
1055
1078
  if (!fs2.existsSync(ctxPath)) {
1056
- console.log(chalk.dim(` ${t("context.resumeMissing")}`));
1079
+ console.log(chalk2.dim(` ${t("context.resumeMissing")}`));
1057
1080
  return;
1058
1081
  }
1059
1082
  const drift = checkContextDrift(cwd);
1060
1083
  if (drift.checked && drift.stale) {
1061
- console.log(chalk.dim(` ${t("context.resumeStale")}`));
1084
+ console.log(chalk2.dim(` ${t("context.resumeStale")}`));
1062
1085
  return;
1063
1086
  }
1064
- console.log(chalk.dim(` ${t("context.resumeExists")}`));
1087
+ console.log(chalk2.dim(` ${t("context.resumeExists")}`));
1065
1088
  }
1066
1089
 
1067
1090
  // src/lib/backup.ts
@@ -1467,85 +1490,88 @@ async function syncCore(rootDir, opts, confirmOverwrite) {
1467
1490
  return { dryRun: false, firstSync, backupId, backedUp, written, skipped, truncated, plan, unmapped };
1468
1491
  }
1469
1492
  async function sync(opts = {}) {
1470
- console.log(chalk2.bold(`
1493
+ console.log(chalk3.bold(`
1471
1494
  ${ko.sync.title}
1472
1495
  `));
1473
1496
  const cwd = process.cwd();
1474
1497
  const rulesPath = path4.join(cwd, "RULES.md");
1475
1498
  if (!fs4.existsSync(rulesPath)) {
1476
- console.log(chalk2.yellow(ko.sync.noRules));
1477
- console.log(chalk2.dim(" RULES.md\uB294 \uD504\uB85C\uC81D\uD2B8 \uADDC\uCE59\uC758 Single Source of Truth\uC785\uB2C8\uB2E4."));
1478
- console.log(chalk2.dim(" \uC0DD\uC131\uD558\uB824\uBA74: vhk init \uC2E4\uD589 \uD6C4 RULES.md\uB97C \uC791\uC131\uD558\uC138\uC694."));
1499
+ console.log(chalk3.yellow(ko.sync.noRules));
1500
+ console.log(chalk3.dim(" RULES.md\uB294 \uD504\uB85C\uC81D\uD2B8 \uADDC\uCE59\uC758 Single Source of Truth\uC785\uB2C8\uB2E4."));
1501
+ console.log(chalk3.dim(" \uC0DD\uC131\uD558\uB824\uBA74: vhk init \uC2E4\uD589 \uD6C4 RULES.md\uB97C \uC791\uC131\uD558\uC138\uC694."));
1479
1502
  console.log("");
1480
- console.log(chalk2.dim(" RULES.md \uAE30\uBCF8 \uAD6C\uC870:"));
1481
- console.log(chalk2.dim(" ## \uD504\uB85C\uC81D\uD2B8 \uC815\uCCB4\uC131"));
1482
- console.log(chalk2.dim(" ## \uAE30\uC220 \uC2A4\uD0DD"));
1483
- console.log(chalk2.dim(" ## \uCF54\uB529 \uADDC\uCE59"));
1484
- console.log(chalk2.dim(" ## \uAE30\uB85D \uADDC\uCE59"));
1485
- console.log(chalk2.dim(" ## \uCEE4\uBC0B \uCEE8\uBCA4\uC158"));
1503
+ console.log(chalk3.dim(" RULES.md \uAE30\uBCF8 \uAD6C\uC870:"));
1504
+ console.log(chalk3.dim(" ## \uD504\uB85C\uC81D\uD2B8 \uC815\uCCB4\uC131"));
1505
+ console.log(chalk3.dim(" ## \uAE30\uC220 \uC2A4\uD0DD"));
1506
+ console.log(chalk3.dim(" ## \uCF54\uB529 \uADDC\uCE59"));
1507
+ console.log(chalk3.dim(" ## \uAE30\uB85D \uADDC\uCE59"));
1508
+ console.log(chalk3.dim(" ## \uCEE4\uBC0B \uCEE8\uBCA4\uC158"));
1486
1509
  return;
1487
1510
  }
1488
1511
  const sections = parseRulesMd(fs4.readFileSync(rulesPath, "utf-8"));
1489
- console.log(chalk2.dim(` \u{1F4C4} RULES.md \uD30C\uC2F1 \uC644\uB8CC \u2014 ${sections.length}\uAC1C \uC139\uC158`));
1490
- const interactive = !!process.stdout.isTTY && !opts.yes;
1491
- const confirmOverwrite = async (drifted) => {
1492
- if (!interactive) return true;
1493
- for (const d of drifted) console.log(chalk2.yellow(` ${ko.sync.driftWarn(d.path)}`));
1494
- const { confirm } = await inquirer.prompt([
1495
- {
1496
- type: "confirm",
1497
- name: "confirm",
1498
- message: ko.sync.driftConfirm(drifted.length),
1499
- default: false
1500
- }
1501
- ]);
1502
- return confirm;
1503
- };
1512
+ console.log(chalk3.dim(` \u{1F4C4} RULES.md \uD30C\uC2F1 \uC644\uB8CC \u2014 ${sections.length}\uAC1C \uC139\uC158`));
1513
+ const confirmOverwrite = async (drifted) => promptOrDefault(
1514
+ async () => {
1515
+ for (const d of drifted) console.log(chalk3.yellow(` ${ko.sync.driftWarn(d.path)}`));
1516
+ const { confirm } = await inquirer.prompt([
1517
+ {
1518
+ type: "confirm",
1519
+ name: "confirm",
1520
+ message: ko.sync.driftConfirm(drifted.length),
1521
+ default: false
1522
+ }
1523
+ ]);
1524
+ return confirm;
1525
+ },
1526
+ true,
1527
+ // 비대화형/--yes → 자동 덮어쓰기(백업이 먼저라 손실 0, 멱등)
1528
+ { yes: opts.yes }
1529
+ );
1504
1530
  const result = await syncCore(cwd, opts, confirmOverwrite);
1505
1531
  if (result.unmapped.length) {
1506
1532
  console.error(
1507
- chalk2.yellow(
1533
+ chalk3.yellow(
1508
1534
  ` \u26A0\uFE0F ${result.unmapped.length}\uAC1C \uC139\uC158\uC774 \uC5B4\uB290 \uD0C0\uAE43\uC5D0\uB3C4 \uB9E4\uD551 \uC548 \uB3FC \uC0B0\uCD9C\uBB3C\uC5D0\uC11C \uC81C\uC678\uB428: ${result.unmapped.join(", ")}
1509
1535
  (\uCF54\uB529 \uADDC\uCE59/\uAE30\uC220 \uC2A4\uD0DD/\uCEE4\uBC0B/\uAE30\uB85D \uB4F1 \uD45C\uC900 \uC81C\uBAA9\uC744 \uC4F0\uAC70\uB098, \uC774 \uC139\uC158\uC740 RULES.md \uC5D0\uB9CC \uBCF4\uC874\uB429\uB2C8\uB2E4.)`
1510
1536
  )
1511
1537
  );
1512
1538
  }
1513
1539
  if (result.dryRun) {
1514
- console.log(chalk2.cyan(`
1540
+ console.log(chalk3.cyan(`
1515
1541
  ${ko.sync.dryRunHeader}`));
1516
1542
  for (const item of result.plan) {
1517
1543
  console.log(ko.sync.dryRunWouldWrite(item.path, item.exists && item.drift));
1518
1544
  }
1519
1545
  const wouldBackup = result.plan.filter((p) => p.exists && (p.drift || result.firstSync)).map((p) => p.path);
1520
1546
  if (wouldBackup.length) {
1521
- console.log(chalk2.dim(`
1547
+ console.log(chalk3.dim(`
1522
1548
  \uBC31\uC5C5 \uC608\uC815(${wouldBackup.length}): ${wouldBackup.join(", ")}`));
1523
1549
  }
1524
1550
  return;
1525
1551
  }
1526
1552
  if (result.backupId) {
1527
- if (result.firstSync) console.log(chalk2.cyan(` ${ko.sync.firstSync}`));
1528
- if (!process.stdout.isTTY) {
1529
- console.log(chalk2.yellow(` ${ko.sync.nonTtyAuto(result.backedUp.length, result.backupId)}`));
1553
+ if (result.firstSync) console.log(chalk3.cyan(` ${ko.sync.firstSync}`));
1554
+ if (!isInteractive(opts)) {
1555
+ console.log(chalk3.yellow(` ${ko.sync.nonTtyAuto(result.backedUp.length, result.backupId)}`));
1530
1556
  } else {
1531
- console.log(chalk2.cyan(` ${ko.sync.backupSaved(result.backedUp.length, result.backupId)}`));
1557
+ console.log(chalk3.cyan(` ${ko.sync.backupSaved(result.backedUp.length, result.backupId)}`));
1532
1558
  }
1533
1559
  }
1534
1560
  for (const p of result.written) {
1535
1561
  const item = result.plan.find((i) => i.path === p);
1536
- if (item) console.log(chalk2.green(` ${item.doneMessage}`));
1562
+ if (item) console.log(chalk3.green(` ${item.doneMessage}`));
1537
1563
  }
1538
1564
  for (const _ of result.truncated) {
1539
- console.log(chalk2.yellow(` \u26A0\uFE0F ${ko.sync.antigravityTruncated}`));
1565
+ console.log(chalk3.yellow(` \u26A0\uFE0F ${ko.sync.antigravityTruncated}`));
1540
1566
  }
1541
1567
  for (const p of result.skipped) {
1542
- console.log(chalk2.gray(` ${ko.sync.skipped(p)}`));
1568
+ console.log(chalk3.gray(` ${ko.sync.skipped(p)}`));
1543
1569
  }
1544
- console.log(chalk2.bold.green(`
1570
+ console.log(chalk3.bold.green(`
1545
1571
  ${ko.sync.done}`));
1546
- console.log(chalk2.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md + .windsurfrules"));
1547
- console.log(chalk2.dim(" + .github/copilot-instructions.md + .agents/rules/vhk-rules.md (\uC790\uB3D9 \uC0DD\uC131)"));
1548
- console.log(chalk2.dim(" \uADDC\uCE59 \uBCC0\uACBD\uC740 \uD56D\uC0C1 RULES.md\uC5D0\uC11C\uB9CC \uD558\uC138\uC694."));
1572
+ console.log(chalk3.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md + .windsurfrules"));
1573
+ console.log(chalk3.dim(" + .github/copilot-instructions.md + .agents/rules/vhk-rules.md (\uC790\uB3D9 \uC0DD\uC131)"));
1574
+ console.log(chalk3.dim(" \uADDC\uCE59 \uBCC0\uACBD\uC740 \uD56D\uC0C1 RULES.md\uC5D0\uC11C\uB9CC \uD558\uC138\uC694."));
1549
1575
  printNextStep({
1550
1576
  message: "\uADDC\uCE59 \uB3D9\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C Cursor\uAC00 \uC0C8 \uADDC\uCE59\uC744 \uB530\uB985\uB2C8\uB2E4.",
1551
1577
  command: "vhk \uC810\uAC80",
@@ -1555,7 +1581,7 @@ ${ko.sync.done}`));
1555
1581
 
1556
1582
  // src/commands/deploy.ts
1557
1583
  import { existsSync as existsSync2 } from "fs";
1558
- import chalk3 from "chalk";
1584
+ import chalk4 from "chalk";
1559
1585
  import inquirer2 from "inquirer";
1560
1586
 
1561
1587
  // src/lib/exec.ts
@@ -1664,11 +1690,11 @@ function isCLIAvailable(cmd, checkArgs) {
1664
1690
  return safeExecFile(cmd, checkArgs).ok;
1665
1691
  }
1666
1692
  async function deploy() {
1667
- console.log(chalk3.bold("\n\u{1F680} " + t("deploy.title")));
1668
- console.log(chalk3.gray("\u2500".repeat(40)));
1693
+ console.log(chalk4.bold("\n\u{1F680} " + t("deploy.title")));
1694
+ console.log(chalk4.gray("\u2500".repeat(40)));
1669
1695
  let platform = detectPlatform();
1670
1696
  if (platform) {
1671
- console.log(chalk3.cyan(`
1697
+ console.log(chalk4.cyan(`
1672
1698
  \u{1F50D} \uAC10\uC9C0\uB41C \uD50C\uB7AB\uD3FC: ${PLATFORMS[platform].name}`));
1673
1699
  } else {
1674
1700
  const { selected } = await inquirer2.prompt([
@@ -1687,9 +1713,9 @@ async function deploy() {
1687
1713
  }
1688
1714
  const config = PLATFORMS[platform];
1689
1715
  if (!isCLIAvailable(config.command, config.checkArgs)) {
1690
- console.log(chalk3.red(`
1716
+ console.log(chalk4.red(`
1691
1717
  \u274C ${config.name} CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`));
1692
- console.log(chalk3.yellow(` \u2192 ${config.installHint}`));
1718
+ console.log(chalk4.yellow(` \u2192 ${config.installHint}`));
1693
1719
  return;
1694
1720
  }
1695
1721
  const { confirm } = await inquirer2.prompt([
@@ -1701,15 +1727,15 @@ async function deploy() {
1701
1727
  }
1702
1728
  ]);
1703
1729
  if (!confirm) {
1704
- console.log(chalk3.gray("\uCDE8\uC18C\uB428"));
1730
+ console.log(chalk4.gray("\uCDE8\uC18C\uB428"));
1705
1731
  return;
1706
1732
  }
1707
- console.log(chalk3.cyan(`
1733
+ console.log(chalk4.cyan(`
1708
1734
  ${t("deploy.deploying")}
1709
1735
  `));
1710
1736
  const result = safeExecFileStream(config.command, config.commandArgs);
1711
1737
  if (result.ok) {
1712
- console.log(chalk3.green(`
1738
+ console.log(chalk4.green(`
1713
1739
  \u2705 ${t("deploy.success")}`));
1714
1740
  printNextStep({
1715
1741
  message: "\uBC30\uD3EC \uC644\uB8CC! \uC0AC\uC774\uD2B8\uB97C \uD655\uC778\uD558\uC138\uC694.",
@@ -1717,16 +1743,16 @@ ${t("deploy.deploying")}
1717
1743
  cursorHint: "\uC0C1\uD0DC \uD655\uC778\uD574\uC918"
1718
1744
  });
1719
1745
  } else {
1720
- console.log(chalk3.red(`
1746
+ console.log(chalk4.red(`
1721
1747
  \u274C ${t("deploy.failed")}`));
1722
- console.log(chalk3.red(result.err));
1748
+ console.log(chalk4.red(result.err));
1723
1749
  }
1724
1750
  }
1725
1751
 
1726
1752
  // src/commands/env.ts
1727
1753
  import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync, appendFileSync, readdirSync } from "fs";
1728
1754
  import { join as join2 } from "path";
1729
- import chalk4 from "chalk";
1755
+ import chalk5 from "chalk";
1730
1756
  function parseEnvKeys(content) {
1731
1757
  return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split("=")[0].trim()).filter(Boolean);
1732
1758
  }
@@ -1754,32 +1780,32 @@ function ensureGitignore() {
1754
1780
  const content = readFileSync2(gitignorePath, "utf-8");
1755
1781
  if (!content.split("\n").some((l) => l.trim() === ".env")) {
1756
1782
  appendFileSync(gitignorePath, "\n.env\n");
1757
- console.log(chalk4.green("\n\u{1F512} .gitignore\uC5D0 .env \uCD94\uAC00\uB428"));
1783
+ console.log(chalk5.green("\n\u{1F512} .gitignore\uC5D0 .env \uCD94\uAC00\uB428"));
1758
1784
  }
1759
1785
  } else {
1760
1786
  writeFileSync(gitignorePath, ".env\nnode_modules/\ndist/\n");
1761
- console.log(chalk4.green("\n\u{1F512} .gitignore \uC0DD\uC131 (.env \uD3EC\uD568)"));
1787
+ console.log(chalk5.green("\n\u{1F512} .gitignore \uC0DD\uC131 (.env \uD3EC\uD568)"));
1762
1788
  }
1763
1789
  }
1764
1790
  async function env() {
1765
- console.log(chalk4.bold("\n\u{1F510} " + t("env.title")));
1766
- console.log(chalk4.gray("\u2500".repeat(40)));
1791
+ console.log(chalk5.bold("\n\u{1F510} " + t("env.title")));
1792
+ console.log(chalk5.gray("\u2500".repeat(40)));
1767
1793
  if (!existsSync3(".env")) {
1768
- console.log(chalk4.yellow("\n\u26A0\uFE0F .env \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
1769
- console.log(chalk4.gray(" .env \uD30C\uC77C\uC744 \uBA3C\uC800 \uB9CC\uB4E4\uC5B4\uC8FC\uC138\uC694."));
1794
+ console.log(chalk5.yellow("\n\u26A0\uFE0F .env \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
1795
+ console.log(chalk5.gray(" .env \uD30C\uC77C\uC744 \uBA3C\uC800 \uB9CC\uB4E4\uC5B4\uC8FC\uC138\uC694."));
1770
1796
  return;
1771
1797
  }
1772
1798
  const envContent = readFileSync2(".env", "utf-8");
1773
1799
  const keys = parseEnvKeys(envContent);
1774
1800
  if (keys.length === 0) {
1775
- console.log(chalk4.yellow("\n\u{1F4ED} .env\uC5D0 \uD658\uACBD\uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
1801
+ console.log(chalk5.yellow("\n\u{1F4ED} .env\uC5D0 \uD658\uACBD\uBCC0\uC218\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
1776
1802
  return;
1777
1803
  }
1778
1804
  const exampleContent = keys.map((k) => `${k}=`).join("\n") + "\n";
1779
1805
  writeFileSync(".env.example", exampleContent, "utf-8");
1780
- console.log(chalk4.green(`
1806
+ console.log(chalk5.green(`
1781
1807
  \u2705 .env.example \uC0DD\uC131 (${keys.length}\uAC1C \uD0A4)`));
1782
- keys.forEach((k) => console.log(chalk4.gray(` ${k}`)));
1808
+ keys.forEach((k) => console.log(chalk5.gray(` ${k}`)));
1783
1809
  ensureGitignore();
1784
1810
  printNextStep({
1785
1811
  message: ".env.example \uC0DD\uC131 \uC644\uB8CC!",
@@ -1788,37 +1814,37 @@ async function env() {
1788
1814
  });
1789
1815
  }
1790
1816
  async function envCheck() {
1791
- console.log(chalk4.bold("\n\u{1F50D} " + t("env.checkTitle")));
1792
- console.log(chalk4.gray("\u2500".repeat(40)));
1817
+ console.log(chalk5.bold("\n\u{1F50D} " + t("env.checkTitle")));
1818
+ console.log(chalk5.gray("\u2500".repeat(40)));
1793
1819
  if (!existsSync3(".env.example")) {
1794
- console.log(chalk4.yellow("\n\u26A0\uFE0F .env.example\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 vhk env\uB97C \uC2E4\uD589\uD558\uC138\uC694."));
1820
+ console.log(chalk5.yellow("\n\u26A0\uFE0F .env.example\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 vhk env\uB97C \uC2E4\uD589\uD558\uC138\uC694."));
1795
1821
  return;
1796
1822
  }
1797
1823
  const requiredKeys = parseEnvKeys(readFileSync2(".env.example", "utf-8"));
1798
1824
  const currentKeys = loadDefinedEnvKeys();
1799
1825
  const missing = requiredKeys.filter((k) => !currentKeys.includes(k));
1800
1826
  const extra = currentKeys.filter((k) => !requiredKeys.includes(k));
1801
- console.log(chalk4.cyan(`
1827
+ console.log(chalk5.cyan(`
1802
1828
  \u{1F4CB} \uD544\uC218 \uD658\uACBD\uBCC0\uC218: ${requiredKeys.length}\uAC1C`));
1803
1829
  if (missing.length === 0) {
1804
- console.log(chalk4.green("\n\u2705 \uBAA8\uB4E0 \uD544\uC218 \uD658\uACBD\uBCC0\uC218\uAC00 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4!"));
1830
+ console.log(chalk5.green("\n\u2705 \uBAA8\uB4E0 \uD544\uC218 \uD658\uACBD\uBCC0\uC218\uAC00 \uC124\uC815\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4!"));
1805
1831
  } else {
1806
- console.log(chalk4.red(`
1832
+ console.log(chalk5.red(`
1807
1833
  \u274C \uB204\uB77D\uB41C \uD658\uACBD\uBCC0\uC218 (${missing.length}\uAC1C):`));
1808
- missing.forEach((k) => console.log(chalk4.red(` \u2022 ${k}`)));
1834
+ missing.forEach((k) => console.log(chalk5.red(` \u2022 ${k}`)));
1809
1835
  process.exitCode = 1;
1810
1836
  }
1811
1837
  if (extra.length > 0) {
1812
- console.log(chalk4.yellow(`
1838
+ console.log(chalk5.yellow(`
1813
1839
  \u{1F4A1} .env.example\uC5D0 \uC5C6\uB294 \uCD94\uAC00 \uBCC0\uC218 (${extra.length}\uAC1C):`));
1814
- extra.forEach((k) => console.log(chalk4.yellow(` \u2022 ${k}`)));
1840
+ extra.forEach((k) => console.log(chalk5.yellow(` \u2022 ${k}`)));
1815
1841
  }
1816
1842
  ensureGitignore();
1817
1843
  }
1818
1844
 
1819
1845
  // src/commands/publish.ts
1820
1846
  import { existsSync as existsSync4, writeFileSync as writeFileSync2 } from "fs";
1821
- import chalk5 from "chalk";
1847
+ import chalk6 from "chalk";
1822
1848
  import inquirer3 from "inquirer";
1823
1849
  import ora from "ora";
1824
1850
 
@@ -1887,21 +1913,21 @@ function gitPostRelease(newVersion) {
1887
1913
  };
1888
1914
  }
1889
1915
  async function publish() {
1890
- console.log(chalk5.bold("\n\u{1F4E6} " + t("publish.title")));
1891
- console.log(chalk5.gray("\u2500".repeat(40)));
1916
+ console.log(chalk6.bold("\n\u{1F4E6} " + t("publish.title")));
1917
+ console.log(chalk6.gray("\u2500".repeat(40)));
1892
1918
  if (!existsSync4("package.json")) {
1893
- console.log(chalk5.red("\u274C package.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
1919
+ console.log(chalk6.red("\u274C package.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
1894
1920
  return;
1895
1921
  }
1896
1922
  let pkg;
1897
1923
  try {
1898
1924
  pkg = readJsonFile("package.json");
1899
1925
  } catch {
1900
- console.log(chalk5.red("\u274C package.json \uD30C\uC2F1 \uC2E4\uD328"));
1926
+ console.log(chalk6.red("\u274C package.json \uD30C\uC2F1 \uC2E4\uD328"));
1901
1927
  return;
1902
1928
  }
1903
1929
  const currentVersion = pkg.version || "0.0.0";
1904
- console.log(chalk5.cyan(`
1930
+ console.log(chalk6.cyan(`
1905
1931
  \u{1F4CC} \uD604\uC7AC \uBC84\uC804: v${currentVersion}`));
1906
1932
  const { bumpType } = await inquirer3.prompt([
1907
1933
  {
@@ -1916,16 +1942,16 @@ async function publish() {
1916
1942
  }
1917
1943
  ]);
1918
1944
  const newVersion = bumpVersion(currentVersion, bumpType);
1919
- console.log(chalk5.cyan(`
1945
+ console.log(chalk6.cyan(`
1920
1946
  \u{1F195} \uC0C8 \uBC84\uC804: v${newVersion}`));
1921
1947
  pkg.version = newVersion;
1922
1948
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
1923
- console.log(chalk5.green("\u2705 package.json \uBC84\uC804 \uC5C5\uB370\uC774\uD2B8"));
1949
+ console.log(chalk6.green("\u2705 package.json \uBC84\uC804 \uC5C5\uB370\uC774\uD2B8"));
1924
1950
  const buildSpinner = ora(t("publish.building")).start();
1925
1951
  const buildResult = safeExecFile("pnpm", ["build"]);
1926
1952
  if (!buildResult.ok) {
1927
1953
  buildSpinner.fail(t("publish.buildFailed"));
1928
- console.log(chalk5.red(buildResult.err.slice(0, 500)));
1954
+ console.log(chalk6.red(buildResult.err.slice(0, 500)));
1929
1955
  pkg.version = currentVersion;
1930
1956
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
1931
1957
  return;
@@ -1935,7 +1961,7 @@ async function publish() {
1935
1961
  const testResult = safeExecFile("pnpm", ["test", "--run"]);
1936
1962
  if (!testResult.ok) {
1937
1963
  testSpinner.fail(t("publish.testFailed"));
1938
- console.log(chalk5.red(testResult.err.slice(0, 500)));
1964
+ console.log(chalk6.red(testResult.err.slice(0, 500)));
1939
1965
  pkg.version = currentVersion;
1940
1966
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
1941
1967
  return;
@@ -1952,37 +1978,37 @@ async function publish() {
1952
1978
  if (!confirm) {
1953
1979
  pkg.version = currentVersion;
1954
1980
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
1955
- console.log(chalk5.gray("\uCDE8\uC18C\uB428. \uBC84\uC804\uC774 \uC6D0\uB798\uB300\uB85C \uBCF5\uAD6C\uB429\uB2C8\uB2E4."));
1981
+ console.log(chalk6.gray("\uCDE8\uC18C\uB428. \uBC84\uC804\uC774 \uC6D0\uB798\uB300\uB85C \uBCF5\uAD6C\uB429\uB2C8\uB2E4."));
1956
1982
  return;
1957
1983
  }
1958
- console.log(chalk5.cyan(`
1984
+ console.log(chalk6.cyan(`
1959
1985
  \u{1F4E4} ${t("publish.publishing")}`));
1960
- console.log(chalk5.gray(" 2FA \uD65C\uC131\uD654 \uC2DC: OTP 6\uC790\uB9AC \uC785\uB825 \uB610\uB294 \uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D URL \uD074\uB9AD (Windows Hello / PIN \uC9C0\uC6D0)"));
1986
+ console.log(chalk6.gray(" 2FA \uD65C\uC131\uD654 \uC2DC: OTP 6\uC790\uB9AC \uC785\uB825 \uB610\uB294 \uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D URL \uD074\uB9AD (Windows Hello / PIN \uC9C0\uC6D0)"));
1961
1987
  const pubResult = safeExecFileStream("npm", ["publish", "--access", "public"]);
1962
1988
  if (!pubResult.ok) {
1963
- console.log(chalk5.red(`
1989
+ console.log(chalk6.red(`
1964
1990
  \u2716 ${t("publish.publishFailed")}`));
1965
- console.log(chalk5.red(pubResult.err.slice(0, 500)));
1991
+ console.log(chalk6.red(pubResult.err.slice(0, 500)));
1966
1992
  pkg.version = currentVersion;
1967
1993
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
1968
- console.log(chalk5.gray(`\u{1F4E6} package.json \uBC84\uC804\uC744 v${currentVersion}\uB85C \uBCF5\uAD6C\uD588\uC2B5\uB2C8\uB2E4.`));
1994
+ console.log(chalk6.gray(`\u{1F4E6} package.json \uBC84\uC804\uC744 v${currentVersion}\uB85C \uBCF5\uAD6C\uD588\uC2B5\uB2C8\uB2E4.`));
1969
1995
  return;
1970
1996
  }
1971
- console.log(chalk5.green(`
1997
+ console.log(chalk6.green(`
1972
1998
  \u2714 ${t("publish.publishSuccess")}`));
1973
1999
  const git = gitPostRelease(newVersion);
1974
2000
  if (git.warning) {
1975
- console.log(chalk5.yellow(`
2001
+ console.log(chalk6.yellow(`
1976
2002
  \u26A0\uFE0F ${git.warning}`));
1977
- console.log(chalk5.dim(` npm \uBC30\uD3EC\uB294 \uC774\uBBF8 \uC131\uACF5\uD588\uC2B5\uB2C8\uB2E4 (v${newVersion}).`));
2003
+ console.log(chalk6.dim(` npm \uBC30\uD3EC\uB294 \uC774\uBBF8 \uC131\uACF5\uD588\uC2B5\uB2C8\uB2E4 (v${newVersion}).`));
1978
2004
  } else if (git.tagged && git.pushed) {
1979
- console.log(chalk5.green(`
2005
+ console.log(chalk6.green(`
1980
2006
  \u{1F3F7}\uFE0F git tag v${newVersion} \uC0DD\uC131 + push \uC644\uB8CC`));
1981
2007
  } else if (git.tagged) {
1982
- console.log(chalk5.yellow(`
2008
+ console.log(chalk6.yellow(`
1983
2009
  \u{1F3F7}\uFE0F git tag v${newVersion} \uC0DD\uC131\uB428 (push\uB294 \uC218\uB3D9\uC73C\uB85C)`));
1984
2010
  }
1985
- console.log(chalk5.green.bold(`
2011
+ console.log(chalk6.green.bold(`
1986
2012
  \u{1F389} v${newVersion} \uBC30\uD3EC \uC644\uB8CC!`));
1987
2013
  printNextStep({
1988
2014
  message: "npm \uBC30\uD3EC \uC644\uB8CC!",
@@ -1993,7 +2019,7 @@ async function publish() {
1993
2019
 
1994
2020
  // src/commands/audit.ts
1995
2021
  import { existsSync as existsSync5 } from "fs";
1996
- import chalk6 from "chalk";
2022
+ import chalk7 from "chalk";
1997
2023
  import inquirer4 from "inquirer";
1998
2024
  import ora2 from "ora";
1999
2025
  function detectCurrentPM() {
@@ -2038,24 +2064,24 @@ function runAuditFix(pm) {
2038
2064
  return result.ok ? { ok: true } : { ok: false, err: result.err };
2039
2065
  }
2040
2066
  async function audit(autoFix = false) {
2041
- console.log(chalk6.bold("\n\u{1F6E1}\uFE0F " + t("audit.title")));
2042
- console.log(chalk6.gray("\u2500".repeat(40)));
2067
+ console.log(chalk7.bold("\n\u{1F6E1}\uFE0F " + t("audit.title")));
2068
+ console.log(chalk7.gray("\u2500".repeat(40)));
2043
2069
  const pm = detectCurrentPM();
2044
- console.log(chalk6.cyan(`\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${pm}`));
2070
+ console.log(chalk7.cyan(`\u{1F4E6} \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${pm}`));
2045
2071
  const spinner = ora2("\uBCF4\uC548 \uAC10\uC0AC \uC2E4\uD589 \uC911...").start();
2046
2072
  const output = runAuditJson(pm);
2047
2073
  spinner.stop();
2048
2074
  const summary = parseAuditOutput(output, pm);
2049
2075
  if (summary.total === 0) {
2050
- console.log(chalk6.green.bold("\n\u{1F389} \uCDE8\uC57D\uC810\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4!"));
2076
+ console.log(chalk7.green.bold("\n\u{1F389} \uCDE8\uC57D\uC810\uC774 \uBC1C\uACAC\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4!"));
2051
2077
  return;
2052
2078
  }
2053
- console.log(chalk6.bold("\n\u{1F4CA} \uCDE8\uC57D\uC810 \uC694\uC57D:"));
2054
- if (summary.critical > 0) console.log(chalk6.red(` \u{1F534} Critical: ${summary.critical}`));
2055
- if (summary.high > 0) console.log(chalk6.red(` \u{1F7E0} High: ${summary.high}`));
2056
- if (summary.moderate > 0) console.log(chalk6.yellow(` \u{1F7E1} Moderate: ${summary.moderate}`));
2057
- if (summary.low > 0) console.log(chalk6.gray(` \u26AA Low: ${summary.low}`));
2058
- console.log(chalk6.bold(`
2079
+ console.log(chalk7.bold("\n\u{1F4CA} \uCDE8\uC57D\uC810 \uC694\uC57D:"));
2080
+ if (summary.critical > 0) console.log(chalk7.red(` \u{1F534} Critical: ${summary.critical}`));
2081
+ if (summary.high > 0) console.log(chalk7.red(` \u{1F7E0} High: ${summary.high}`));
2082
+ if (summary.moderate > 0) console.log(chalk7.yellow(` \u{1F7E1} Moderate: ${summary.moderate}`));
2083
+ if (summary.low > 0) console.log(chalk7.gray(` \u26AA Low: ${summary.low}`));
2084
+ console.log(chalk7.bold(`
2059
2085
  \uCD1D ${summary.total}\uAC1C\uC758 \uCDE8\uC57D\uC810`));
2060
2086
  const shouldRunFix = autoFix ? true : summary.critical > 0 || summary.high > 0 ? (await inquirer4.prompt([
2061
2087
  {
@@ -2205,7 +2231,7 @@ import path6 from "path";
2205
2231
  var import_ignore = __toESM(require_ignore(), 1);
2206
2232
  import fs5 from "fs";
2207
2233
  import path5 from "path";
2208
- import chalk7 from "chalk";
2234
+ import chalk8 from "chalk";
2209
2235
  function loadGitignore(rootDir) {
2210
2236
  const ig = (0, import_ignore.default)();
2211
2237
  const gitignorePath = path5.join(rootDir, ".gitignore");
@@ -2279,7 +2305,7 @@ function printSecurityWarnings(rootDir = process.cwd()) {
2279
2305
  const result = checkProjectSecurity(rootDir);
2280
2306
  if (result.ok) return true;
2281
2307
  for (const w of result.warnings) {
2282
- console.log(chalk7.yellow(` \u26A0\uFE0F ${w}`));
2308
+ console.log(chalk8.yellow(` \u26A0\uFE0F ${w}`));
2283
2309
  }
2284
2310
  return false;
2285
2311
  }
@@ -2961,10 +2987,15 @@ export {
2961
2987
  ko,
2962
2988
  t,
2963
2989
  localDate,
2990
+ ensureVhkIgnored,
2964
2991
  listBackups,
2965
2992
  restoreBackup,
2966
2993
  detectExistingRuleFiles,
2967
2994
  buildAdoptedRules,
2995
+ isInteractive,
2996
+ promptOrDefault,
2997
+ ensureInteractive,
2998
+ isPromptAbortError,
2968
2999
  sync,
2969
3000
  getGitRoot,
2970
3001
  gitOut,