@byh3071/vhk 1.6.3 → 1.6.5

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.
@@ -2980,6 +2980,7 @@ export {
2980
2980
  require_ignore,
2981
2981
  printSecurityWarnings,
2982
2982
  filterTrackedPaths,
2983
+ stripBom,
2983
2984
  readJsonFile,
2984
2985
  NETWORK_EXEC_TIMEOUT_MS,
2985
2986
  safeExecFile,
package/dist/index.js CHANGED
@@ -35,9 +35,10 @@ import {
35
35
  safeExecFile,
36
36
  scanProjectForSecrets,
37
37
  startMcpServer,
38
+ stripBom,
38
39
  sync,
39
40
  t
40
- } from "./chunk-53RJHPP6.js";
41
+ } from "./chunk-EJTVXWUZ.js";
41
42
 
42
43
  // src/index.ts
43
44
  import { Command, Help } from "commander";
@@ -504,7 +505,32 @@ import inquirer12 from "inquirer";
504
505
 
505
506
  // src/commands/gate.ts
506
507
  import inquirer from "inquirer";
508
+ import chalk2 from "chalk";
509
+
510
+ // src/lib/interactive.ts
507
511
  import chalk from "chalk";
512
+ function isInteractive(opts) {
513
+ if (opts?.yes) return false;
514
+ if (process.env.VHK_FORCE_INTERACTIVE === "1") return true;
515
+ return !!process.stdin.isTTY;
516
+ }
517
+ async function promptOrDefault(ask, fallback, opts) {
518
+ if (!isInteractive(opts)) return fallback;
519
+ return await ask();
520
+ }
521
+ function ensureInteractive(hint = "") {
522
+ if (isInteractive()) return true;
523
+ 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."));
524
+ if (hint) console.error(chalk.dim(` ${hint}`));
525
+ process.exitCode = 1;
526
+ return false;
527
+ }
528
+ function isPromptAbortError(err) {
529
+ const msg = err instanceof Error ? err.message : String(err);
530
+ return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
531
+ }
532
+
533
+ // src/commands/gate.ts
508
534
  var GATE_QUESTIONS = [
509
535
  { id: 1, stage: "\uBB38\uC81C \uC815\uC758", question: "\uC774 \uC544\uC774\uB514\uC5B4\uAC00 \uD574\uACB0\uD558\uB294 \uBB38\uC81C\uB97C \uD55C \uBB38\uC7A5\uC73C\uB85C \uB9D0\uD574\uBCF4\uC138\uC694.", failIf: "\uD55C \uBB38\uC7A5 \uBD88\uAC00 \u2192 \uBBF8\uC131\uC219", quick: true },
510
536
  { id: 2, stage: "\uD575\uC2EC \uAE30\uB2A5", question: "\uB531 1\uAC1C \uAE30\uB2A5\uB9CC \uACE0\uB974\uBA74?", failIf: "2\uAC1C \uC774\uC0C1 \u2192 \uBC94\uC704 \uCD08\uACFC", quick: true },
@@ -526,7 +552,8 @@ function judgeGate(failCount, holdCount) {
526
552
  return "DROP";
527
553
  }
528
554
  async function gate() {
529
- console.log(chalk.bold(`
555
+ if (!ensureInteractive("\uC544\uC774\uB514\uC5B4 \uAC80\uC99D\uC740 \uB300\uD654\uD615 \uC9C8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110(PowerShell \uB4F1)\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694. Git Bash \uBA74 VHK_FORCE_INTERACTIVE=1.")) return;
556
+ console.log(chalk2.bold(`
530
557
  ${ko.gate.title}
531
558
  `));
532
559
  const { mode: mode2 } = await inquirer.prompt([{
@@ -545,33 +572,33 @@ ${ko.gate.title}
545
572
  name: "source",
546
573
  message: ko.gate.skipSourcePrompt
547
574
  }]);
548
- console.log(chalk.green.bold(`
575
+ console.log(chalk2.green.bold(`
549
576
  ${ko.gate.skipGo}`));
550
- console.log(chalk.dim(ko.gate.skipSourceLabel(source)));
577
+ console.log(chalk2.dim(ko.gate.skipSourceLabel(source)));
551
578
  return;
552
579
  }
553
580
  const questions = mode2 === "quick" ? GATE_QUESTIONS.filter((q) => q.quick) : GATE_QUESTIONS;
554
581
  const total = questions.length;
555
582
  const header = mode2 === "quick" ? ko.gate.quickHeader : ko.gate.fullHeader;
556
- console.log(chalk.dim(`
583
+ console.log(chalk2.dim(`
557
584
  ${header} ${ko.gate.modeCountSuffix(total)}
558
585
  `));
559
- console.log(chalk.dim(`
586
+ console.log(chalk2.dim(`
560
587
  ${ko.gate.welcome}
561
588
  `));
562
- console.log(chalk.dim(` ${ko.gate.ideaHint}`));
589
+ console.log(chalk2.dim(` ${ko.gate.ideaHint}`));
563
590
  const { idea } = await inquirer.prompt([
564
591
  { type: "input", name: "idea", message: ko.gate.idea }
565
592
  ]);
566
- console.log(chalk.dim(` ${ko.gate.painPointHint}`));
593
+ console.log(chalk2.dim(` ${ko.gate.painPointHint}`));
567
594
  const { painPoint } = await inquirer.prompt([
568
595
  { type: "input", name: "painPoint", message: ko.gate.painPoint }
569
596
  ]);
570
- console.log(chalk.dim(` ${ko.gate.edgeHint}`));
597
+ console.log(chalk2.dim(` ${ko.gate.edgeHint}`));
571
598
  const { edge } = await inquirer.prompt([
572
599
  { type: "input", name: "edge", message: ko.gate.edge }
573
600
  ]);
574
- console.log(chalk.dim(`
601
+ console.log(chalk2.dim(`
575
602
  ${ko.gate.checklistStart}
576
603
  `));
577
604
  let failCount = 0;
@@ -579,7 +606,7 @@ ${ko.gate.checklistStart}
579
606
  const results = [];
580
607
  for (let i = 0; i < questions.length; i++) {
581
608
  const q = questions[i];
582
- if (q.hint) console.log(chalk.dim(`${ko.gate.hintPrefix} ${q.hint}`));
609
+ if (q.hint) console.log(chalk2.dim(`${ko.gate.hintPrefix} ${q.hint}`));
583
610
  const { answer } = await inquirer.prompt([{
584
611
  type: "input",
585
612
  name: "answer",
@@ -598,22 +625,22 @@ ${ko.gate.checklistStart}
598
625
  if (status2 === "fail") failCount++;
599
626
  if (status2 === "hold") holdCount++;
600
627
  results.push({ id: q.id, stage: q.stage, status: status2, answer });
601
- const icon = status2 === "pass" ? chalk.green(ko.gate.statusPassLine) : status2 === "hold" ? chalk.yellow(ko.gate.statusHoldLine) : chalk.red(ko.gate.statusFailLine);
628
+ const icon = status2 === "pass" ? chalk2.green(ko.gate.statusPassLine) : status2 === "hold" ? chalk2.yellow(ko.gate.statusHoldLine) : chalk2.red(ko.gate.statusFailLine);
602
629
  console.log(icon);
603
630
  }
604
- console.log(chalk.bold(`
631
+ console.log(chalk2.bold(`
605
632
  ${ko.gate.verdictTitle}
606
633
  `));
607
- console.log(`${ko.gate.ideaLabel} ${chalk.cyan(idea)}`);
634
+ console.log(`${ko.gate.ideaLabel} ${chalk2.cyan(idea)}`);
608
635
  console.log(`${ko.gate.painPointLabel} ${painPoint}`);
609
636
  console.log(`${ko.gate.edgeLabel} ${edge}`);
610
637
  console.log(`${ko.gate.countLine(failCount, holdCount, total)}
611
638
  `);
612
639
  const verdict = judgeGate(failCount, holdCount);
613
640
  if (verdict === "GO") {
614
- console.log(chalk.green.bold(ko.gate.go));
641
+ console.log(chalk2.green.bold(ko.gate.go));
615
642
  if (holdCount > 0) {
616
- console.log(chalk.yellow(ko.gate.holdRemainHint));
643
+ console.log(chalk2.yellow(ko.gate.holdRemainHint));
617
644
  }
618
645
  printNextStep({
619
646
  message: "\uC544\uC774\uB514\uC5B4 \uD1B5\uACFC! \uC774\uC81C \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E4\uC5B4\uBCF4\uC138\uC694.",
@@ -621,20 +648,20 @@ ${ko.gate.verdictTitle}
621
648
  cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9CC\uB4E4\uC5B4\uC918"
622
649
  });
623
650
  } else if (verdict === "REFINE") {
624
- console.log(chalk.yellow.bold(ko.gate.refine));
651
+ console.log(chalk2.yellow.bold(ko.gate.refine));
625
652
  printNextStep({
626
653
  message: "\uC870\uAE08 \uB354 \uB2E4\uB4EC\uC740 \uD6C4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uBCF4\uC138\uC694.",
627
654
  command: "vhk \uAC80\uC99D",
628
655
  cursorHint: "\uC544\uC774\uB514\uC5B4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uC918"
629
656
  });
630
657
  } else {
631
- console.log(chalk.red.bold(ko.gate.drop));
658
+ console.log(chalk2.red.bold(ko.gate.drop));
632
659
  }
633
660
  }
634
661
 
635
662
  // src/commands/init.ts
636
663
  import inquirer2 from "inquirer";
637
- import chalk3 from "chalk";
664
+ import chalk4 from "chalk";
638
665
  import fs2 from "fs";
639
666
  import path2 from "path";
640
667
 
@@ -956,13 +983,13 @@ function VHK_CONTEXT_SEED(name, type, stack) {
956
983
  }
957
984
 
958
985
  // src/utils/logger.ts
959
- import chalk2 from "chalk";
986
+ import chalk3 from "chalk";
960
987
  var log = {
961
- success: (msg) => console.log(chalk2.green(`\u2705 ${msg}`)),
962
- error: (msg) => console.log(chalk2.red(`\u274C ${msg}`)),
963
- warn: (msg) => console.log(chalk2.yellow(`\u26A0\uFE0F ${msg}`)),
964
- info: (msg) => console.log(chalk2.blue(`\u2139\uFE0F ${msg}`)),
965
- step: (msg) => console.log(chalk2.bold(`
988
+ success: (msg) => console.log(chalk3.green(`\u2705 ${msg}`)),
989
+ error: (msg) => console.log(chalk3.red(`\u274C ${msg}`)),
990
+ warn: (msg) => console.log(chalk3.yellow(`\u26A0\uFE0F ${msg}`)),
991
+ info: (msg) => console.log(chalk3.blue(`\u2139\uFE0F ${msg}`)),
992
+ step: (msg) => console.log(chalk3.bold(`
966
993
  \u25B8 ${msg}`))
967
994
  };
968
995
 
@@ -1180,12 +1207,9 @@ function resolveType(type) {
1180
1207
  }
1181
1208
  return type;
1182
1209
  }
1183
- function isNonInteractive(options) {
1184
- return Boolean(options.yes) || !process.stdin.isTTY || !process.stdout.isTTY;
1185
- }
1186
1210
  var DEFAULT_TYPE = PROJECT_TYPES[0].value;
1187
1211
  async function collectAnswers(options, defaults = {}) {
1188
- const noninteractive = isNonInteractive(options);
1212
+ const noninteractive = !isInteractive(options);
1189
1213
  const prompts = [];
1190
1214
  if (!noninteractive) {
1191
1215
  if (!options.name && !defaults.name) {
@@ -1208,11 +1232,11 @@ async function collectAnswers(options, defaults = {}) {
1208
1232
  async function init(options = {}) {
1209
1233
  const skipGate = Boolean(options.skipGate || options.fromNotion);
1210
1234
  if (skipGate) {
1211
- console.log(chalk3.dim(`
1235
+ console.log(chalk4.dim(`
1212
1236
  ${ko.init.skipGate}
1213
1237
  `));
1214
1238
  }
1215
- console.log(chalk3.bold(`
1239
+ console.log(chalk4.bold(`
1216
1240
  ${ko.init.title}
1217
1241
  `));
1218
1242
  printSecurityWarnings();
@@ -1238,11 +1262,11 @@ ${ko.init.title}
1238
1262
  }
1239
1263
  const detected = detectProjectStack(process.cwd());
1240
1264
  const stack = detected ?? STACK_PRESETS[answers.type];
1241
- if (detected) console.log(chalk3.dim(" \u{1F50E} package.json \uC758\uC874\uC131\uC5D0\uC11C \uC2E4\uC81C \uC2A4\uD0DD \uAC10\uC9C0"));
1242
- console.log(chalk3.dim(`
1265
+ if (detected) console.log(chalk4.dim(" \u{1F50E} package.json \uC758\uC874\uC131\uC5D0\uC11C \uC2E4\uC81C \uC2A4\uD0DD \uAC10\uC9C0"));
1266
+ console.log(chalk4.dim(`
1243
1267
  ${ko.init.recommendedStack} ${stack.join(" + ")}
1244
1268
  `));
1245
- if (!isNonInteractive(options)) {
1269
+ if (isInteractive(options)) {
1246
1270
  const { confirmStack } = await inquirer2.prompt([{
1247
1271
  type: "confirm",
1248
1272
  name: "confirmStack",
@@ -1256,7 +1280,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
1256
1280
  }
1257
1281
  const cwd = process.cwd();
1258
1282
  let adoptedRules = null;
1259
- if (!isNonInteractive(options) && !options.fromNotion) {
1283
+ if (isInteractive(options) && !options.fromNotion) {
1260
1284
  const existingRules = detectExistingRuleFiles(cwd);
1261
1285
  if (existingRules.length > 0) {
1262
1286
  const { adopt } = await inquirer2.prompt([{
@@ -1270,7 +1294,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
1270
1294
  }]);
1271
1295
  if (adopt) {
1272
1296
  adoptedRules = buildAdoptedRules(existingRules, answers.name);
1273
- console.log(chalk3.dim(` ${ko.init.adoptPreview(existingRules.length)}`));
1297
+ console.log(chalk4.dim(` ${ko.init.adoptPreview(existingRules.length)}`));
1274
1298
  }
1275
1299
  }
1276
1300
  }
@@ -1280,7 +1304,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
1280
1304
  for (const [filePath, content] of Object.entries(files)) {
1281
1305
  const fullPath = path2.join(cwd, filePath);
1282
1306
  if (fileExists(fullPath)) {
1283
- const overwrite = isNonInteractive(options) ? false : (await inquirer2.prompt([{
1307
+ const overwrite = !isInteractive(options) ? false : (await inquirer2.prompt([{
1284
1308
  type: "confirm",
1285
1309
  name: "overwrite",
1286
1310
  message: ko.init.overwrite(filePath),
@@ -1294,22 +1318,22 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
1294
1318
  writeFile(fullPath, content);
1295
1319
  log.success(filePath);
1296
1320
  }
1297
- await writeInitExtras(cwd, isNonInteractive(options));
1298
- console.log(chalk3.bold.green(`
1321
+ await writeInitExtras(cwd, !isInteractive(options));
1322
+ console.log(chalk4.bold.green(`
1299
1323
  ${ko.init.done}`));
1300
- console.log(chalk3.dim(`
1324
+ console.log(chalk4.dim(`
1301
1325
  ${ko.init.nextSteps}`));
1302
1326
  if (options.fromNotion) {
1303
1327
  console.log(` 1. ${ko.init.notionReviewHint}`);
1304
1328
  console.log(` 2. ${ko.init.gitHintLabel}`);
1305
- console.log(` ${chalk3.cyan(ko.init.gitHintCommand)}`);
1329
+ console.log(` ${chalk4.cyan(ko.init.gitHintCommand)}`);
1306
1330
  console.log(` 3. ${ko.init.startDev}
1307
1331
  `);
1308
1332
  } else {
1309
1333
  console.log(` 1. ${ko.init.fillHint}`);
1310
1334
  console.log(` 2. ${ko.init.prdHint}`);
1311
1335
  console.log(` 3. ${ko.init.gitHintLabel}`);
1312
- console.log(` ${chalk3.cyan(ko.init.gitHintCommand)}`);
1336
+ console.log(` ${chalk4.cyan(ko.init.gitHintCommand)}`);
1313
1337
  console.log(` 4. ${ko.init.startDev}
1314
1338
  `);
1315
1339
  }
@@ -1626,20 +1650,6 @@ function createAdrFile(cwd, title, context2, decision, consequences) {
1626
1650
  return filePath;
1627
1651
  }
1628
1652
 
1629
- // src/lib/interactive.ts
1630
- import chalk4 from "chalk";
1631
- function ensureInteractive(hint = "") {
1632
- if (process.stdin.isTTY) return true;
1633
- console.error(chalk4.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."));
1634
- if (hint) console.error(chalk4.dim(` ${hint}`));
1635
- process.exitCode = 1;
1636
- return false;
1637
- }
1638
- function isPromptAbortError(err) {
1639
- const msg = err instanceof Error ? err.message : String(err);
1640
- return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
1641
- }
1642
-
1643
1653
  // src/lib/hard-stop-guard.ts
1644
1654
  import chalk5 from "chalk";
1645
1655
 
@@ -2178,8 +2188,9 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync,
2178
2188
  import { join as join3 } from "path";
2179
2189
  var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
2180
2190
  function parseFrontmatter(content) {
2181
- const m = content.match(FRONTMATTER_RE);
2182
- if (!m) return { frontmatter: {}, body: content };
2191
+ const normalized = stripBom(content);
2192
+ const m = normalized.match(FRONTMATTER_RE);
2193
+ if (!m) return { frontmatter: {}, body: normalized };
2183
2194
  const fm = parseSimpleYaml(m[1]);
2184
2195
  const body = (m[2] ?? "").replace(/^\r?\n+/, "");
2185
2196
  return { frontmatter: fm, body };
@@ -3236,12 +3247,16 @@ async function save() {
3236
3247
  if (severe.length > 5) {
3237
3248
  console.log(chalk12.dim(` ... \uC678 ${severe.length - 5}\uAC74 (vhk \uBCF4\uC548 scan)`));
3238
3249
  }
3239
- const { proceed } = await inquirer5.prompt([{
3240
- type: "confirm",
3241
- name: "proceed",
3242
- message: t("save.secretsConfirm"),
3243
- default: false
3244
- }]);
3250
+ const proceed = await promptOrDefault(
3251
+ async () => (await inquirer5.prompt([{
3252
+ type: "confirm",
3253
+ name: "proceed",
3254
+ message: t("save.secretsConfirm"),
3255
+ default: false
3256
+ }])).proceed,
3257
+ false
3258
+ // 비대화형 = 시크릿 커밋 안 함 (안전)
3259
+ );
3245
3260
  if (!proceed) {
3246
3261
  console.log(chalk12.gray(t("save.cancelled")));
3247
3262
  return;
@@ -3259,12 +3274,15 @@ async function save() {
3259
3274
  const name = line.substring(3);
3260
3275
  console.log(` ${statusIcon(code)} ${name}`);
3261
3276
  });
3262
- const { message } = await inquirer5.prompt([{
3263
- type: "input",
3264
- name: "message",
3265
- message: t("save.commitMessage"),
3266
- default: formatDefaultCommitMessage()
3267
- }]);
3277
+ const message = await promptOrDefault(
3278
+ async () => (await inquirer5.prompt([{
3279
+ type: "input",
3280
+ name: "message",
3281
+ message: t("save.commitMessage"),
3282
+ default: formatDefaultCommitMessage()
3283
+ }])).message,
3284
+ "chore: vhk save"
3285
+ );
3268
3286
  const spinner = ora(t("save.saving")).start();
3269
3287
  let didAdd = false;
3270
3288
  try {
@@ -5393,7 +5411,8 @@ var HIGH_RISK_ACTIONS = [
5393
5411
  "cloud-pull",
5394
5412
  "resume",
5395
5413
  "env-write",
5396
- "delete"
5414
+ "delete",
5415
+ "restore"
5397
5416
  ];
5398
5417
  var STRICT_EXTRA_ACTIONS = /* @__PURE__ */ new Set(["save", "sync"]);
5399
5418
  var NL_GUARDED_ACTIONS = {
@@ -5404,7 +5423,8 @@ var NL_GUARDED_ACTIONS = {
5404
5423
  "cloud-pull": "cloud-pull",
5405
5424
  env: "env-write",
5406
5425
  save: "save",
5407
- sync: "sync"
5426
+ sync: "sync",
5427
+ restore: "restore"
5408
5428
  };
5409
5429
  function isHighRisk(action) {
5410
5430
  return HIGH_RISK_ACTIONS.includes(action);
@@ -5426,6 +5446,11 @@ async function runGuarded(action, deps, run) {
5426
5446
  return { outcome: { ran: true, guard, reason: "low-risk" }, result: await run() };
5427
5447
  }
5428
5448
  if (guard === "warn") {
5449
+ const canConfirm = deps.isTTY ?? !!process.stdin.isTTY;
5450
+ if (!deps.approved && !canConfirm) {
5451
+ log2(`\u26A0\uFE0F \uC704\uD5D8 \uC791\uC5C5(${action}) \u2014 lite \uC9C0\uB9CC \uBE44\uB300\uD654\uD615+\uBBF8\uC2B9\uC778 \u2192 \uC911\uB2E8. (--yes \uB85C \uC2B9\uC778)`);
5452
+ return { outcome: { ran: false, guard, reason: "lite-noninteractive-block" } };
5453
+ }
5429
5454
  log2(`\u26A0\uFE0F \uC704\uD5D8 \uC791\uC5C5(${action}) \u2014 lite \uBAA8\uB4DC: \uACBD\uACE0\uB9CC \uD558\uACE0 \uC9C4\uD589\uD569\uB2C8\uB2E4.`);
5430
5455
  return { outcome: { ran: true, guard, reason: "lite-warn" }, result: await run() };
5431
5456
  }
@@ -5433,7 +5458,7 @@ async function runGuarded(action, deps, run) {
5433
5458
  if (deps.approved === true) {
5434
5459
  return { outcome: { ran: true, guard, reason: "approved" }, result: await run() };
5435
5460
  }
5436
- const tty = deps.isTTY ?? !!process.stdout.isTTY;
5461
+ const tty = deps.isTTY ?? !!process.stdin.isTTY;
5437
5462
  if (tty && deps.confirm) {
5438
5463
  const ok = await deps.confirm();
5439
5464
  if (ok) return { outcome: { ran: true, guard, reason: "confirmed" }, result: await run() };
@@ -5789,8 +5814,8 @@ program.command("save").alias("\uC800\uC7A5").option("--yes", "\uD655\uC778 \uC5
5789
5814
  program.command("undo").alias("\uB418\uB3CC\uB9AC\uAE30").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC2E4\uD589 (\uC704\uD5D8 \uC791\uC5C5 \uBA85\uC2DC \uC2B9\uC778)").description("\uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30").action(async (opts) => {
5790
5815
  await guardCliDefer("undo", opts?.yes === true, () => undo());
5791
5816
  });
5792
- program.command("restore").alias("\uBCF5\uC6D0").argument("[id]", "\uBCF5\uC6D0\uD560 \uBC31\uC5C5 id (\uC0DD\uB7B5 \uC2DC \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD)").description("sync \uBC31\uC5C5 \uBCF5\uC6D0 (.vhk/backups/ \u2014 \uC5B8\uCEE4\uBC0B \uB36E\uC5B4\uC4F0\uAE30 \uBCF5\uAD6C)").action(async (id) => {
5793
- await restore(id);
5817
+ program.command("restore").alias("\uBCF5\uC6D0").argument("[id]", "\uBCF5\uC6D0\uD560 \uBC31\uC5C5 id (\uC0DD\uB7B5 \uC2DC \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD)").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC2E4\uD589 (\uC704\uD5D8 \uC791\uC5C5 \uBA85\uC2DC \uC2B9\uC778)").description("sync \uBC31\uC5C5 \uBCF5\uC6D0 (.vhk/backups/ \u2014 \uC5B8\uCEE4\uBC0B \uB36E\uC5B4\uC4F0\uAE30 \uBCF5\uAD6C)").action(async (id, opts) => {
5818
+ await guardCli("restore", opts?.yes === true, () => restore(id));
5794
5819
  });
5795
5820
  program.command("status").alias("\uC0C1\uD0DC").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uB300\uC2DC\uBCF4\uB4DC").action(async () => {
5796
5821
  await status();
package/dist/mcp/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  resolveVhkCliInvocation,
4
4
  startMcpServer
5
- } from "../chunk-53RJHPP6.js";
5
+ } from "../chunk-EJTVXWUZ.js";
6
6
 
7
7
  // src/mcp/index.ts
8
8
  var cli = resolveVhkCliInvocation();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byh3071/vhk",
3
- "version": "1.6.3",
3
+ "version": "1.6.5",
4
4
  "description": "Vibe Harness Kit — AI 코딩 도구·기기를 바꿔도 규칙·맥락이 따라가는 포터빌리티 CLI (sync: Cursor·Claude·Windsurf·Copilot·Antigravity / cloud 백업)",
5
5
  "bin": {
6
6
  "vhk": "dist/index.js",