@byh3071/vhk 2.3.1 → 2.4.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.
package/dist/index.js CHANGED
@@ -43,13 +43,13 @@ import {
43
43
  stripBom,
44
44
  sync,
45
45
  t
46
- } from "./chunk-WQWPM364.js";
46
+ } from "./chunk-MN6LSPN6.js";
47
47
 
48
48
  // src/index.ts
49
49
  import { Command, Help } from "commander";
50
50
  import { fileURLToPath as fileURLToPath4 } from "url";
51
51
  import fs13 from "fs";
52
- import chalk37 from "chalk";
52
+ import chalk38 from "chalk";
53
53
  import inquirer15 from "inquirer";
54
54
 
55
55
  // src/lib/nlp-router.ts
@@ -62,7 +62,8 @@ var NLP_KEYWORDS = {
62
62
  evolve: ["\uC9C4\uD654", "\uB8F0\uD6C4\uBCF4", "\uC9C4\uD654\uD6C4\uBCF4"],
63
63
  undo: ["\uB418\uB3CC\uB824", "\uB418\uB3CC\uB9AC\uAE30", "\uCDE8\uC18C", "\uC6D0\uB798\uB300\uB85C", "\uB864\uBC31", "\uB9AC\uC14B", "reset", "rollback"],
64
64
  status: ["\uC0C1\uD0DC", "\uD604\uD669", "\uC5B4\uB5BB\uAC8C", "\uC5B4\uB54C", "\uC9C0\uAE08"],
65
- diff: ["\uBCC0\uACBD", "\uBC14\uB010", "\uBB50\uBC14\uB01C", "\uBC14\uB00C\uC5C8", "\uCC28\uC774", "\uB2EC\uB77C\uC9C4", "\uC218\uC815\uB41C"]
65
+ diff: ["\uBCC0\uACBD", "\uBC14\uB010", "\uBB50\uBC14\uB01C", "\uBC14\uB00C\uC5C8", "\uCC28\uC774", "\uB2EC\uB77C\uC9C4", "\uC218\uC815\uB41C"],
66
+ work: ["\uC774\uC5B4\uC11C", "\uC774\uC5B4\uD558\uAE30", "work"]
66
67
  };
67
68
  function matchesKeywords(text, command) {
68
69
  const keywords = NLP_KEYWORDS[command];
@@ -372,6 +373,20 @@ var RULES = [
372
373
  confidence: "high",
373
374
  args: ["sync"],
374
375
  test: (t2) => /(게이트|목표).*(스크립트|동기화)|체크\s*스크립트\s*(생성|만들)/.test(t2)
376
+ },
377
+ // work — handoff(인수인계)를 먼저 평가(더 구체적), 그다음 작업 시작/이어하기.
378
+ {
379
+ command: "work",
380
+ explanation: "\uC791\uC5C5 \uC911\uB2E8 \uC815\uB9AC \uD504\uB86C\uD504\uD2B8 (vhk work handoff)",
381
+ confidence: "high",
382
+ args: ["handoff"],
383
+ test: (t2) => /인수인계|핸드오프|handoff|작업\s*(넘기|넘겨|전달|마무리)|중단\s*정리/.test(t2)
384
+ },
385
+ {
386
+ command: "work",
387
+ explanation: "\uC791\uC5C5 \uC2DC\uC791/\uC774\uC5B4\uD558\uAE30 \uD504\uB86C\uD504\uD2B8 (vhk work)",
388
+ confidence: "high",
389
+ test: (t2) => matchesKeywords(t2, "work") || /작업\s*(시작|이어|이어서|계속)|이어서\s*(작업|하자|할래)|^work$/.test(t2)
375
390
  }
376
391
  ];
377
392
  function routeNaturalLanguage(input) {
@@ -406,7 +421,8 @@ var CONTAINER_SUBCOMMANDS = {
406
421
  mode: ["lite", "standard", "strict"],
407
422
  mission: ["set", "check", "clear"],
408
423
  pattern: ["detect", "list", "dismiss"],
409
- evolve: ["suggest", "list", "apply", "reject", "undo"]
424
+ evolve: ["suggest", "list", "apply", "reject", "undo"],
425
+ work: ["handoff"]
410
426
  };
411
427
  var CONTAINER_ALIASES = {
412
428
  \uBAA9\uD45C: "goal",
@@ -419,8 +435,55 @@ var CONTAINER_ALIASES = {
419
435
  \uBAA8\uB4DC: "mode",
420
436
  \uBBF8\uC158: "mission",
421
437
  \uD328\uD134: "pattern",
422
- \uC9C4\uD654: "evolve"
438
+ \uC9C4\uD654: "evolve",
439
+ \uC791\uC5C5: "work"
423
440
  };
441
+ var TOP_LEVEL_COMMANDS = [
442
+ { name: "gate", desc: "\uC544\uC774\uB514\uC5B4 \uAC80\uC99D" },
443
+ { name: "start", desc: "\uC0C8 \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 \uB9C8\uBC95\uC0AC" },
444
+ { name: "init", desc: "\uD558\uB124\uC2A4 \uD30C\uC77C \uC0DD\uC131" },
445
+ { name: "recap", desc: "\uC624\uB298 \uD55C \uC77C \uC815\uB9AC + ADR \uBD84\uB9AC" },
446
+ { name: "sync", desc: "RULES.md \u2192 \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654" },
447
+ { name: "check", desc: "RULES.md \uADDC\uCE59 \uC810\uAC80" },
448
+ { name: "secure", desc: "\uBCF4\uC548 \uC2A4\uCE94 (\uC2DC\uD06C\uB9BF \uC720\uCD9C \uAC80\uC0AC)" },
449
+ { name: "cloud", desc: ".vhk \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5\xB7\uBCF5\uC6D0 (push/pull)" },
450
+ { name: "ship", desc: "\uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 + \uD68C\uACE0" },
451
+ { name: "doctor", desc: "\uAC1C\uBC1C \uD658\uACBD \uC810\uAC80 (+ --strict \uB4DC\uB9AC\uD504\uD2B8 \uAC8C\uC774\uD2B8)" },
452
+ { name: "save", desc: "git \uC800\uC7A5 (add \u2192 commit \u2192 push)" },
453
+ { name: "undo", desc: "\uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30" },
454
+ { name: "restore", desc: "sync \uBC31\uC5C5 \uBCF5\uC6D0" },
455
+ { name: "status", desc: "\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uB300\uC2DC\uBCF4\uB4DC" },
456
+ { name: "diff", desc: "Git \uBCC0\uACBD\uC0AC\uD56D \uD55C\uAD6D\uC5B4 \uC694\uC57D" },
457
+ { name: "mcp", desc: "MCP \uC11C\uBC84 \uC2DC\uC791 (stdio)" },
458
+ { name: "mcp-init", desc: "Cursor\xB7Claude Desktop MCP \uC124\uC815 \uC0DD\uC131" },
459
+ { name: "deploy", desc: "\uD504\uB85C\uB355\uC158 \uBC30\uD3EC (\uC790\uB3D9 \uAC10\uC9C0)" },
460
+ { name: "env", desc: ".env \u2192 .env.example \uB3D9\uAE30\uD654" },
461
+ { name: "env-check", desc: "\uD544\uC218 \uD658\uACBD\uBCC0\uC218 \uB204\uB77D \uAC80\uC0AC" },
462
+ { name: "publish", desc: "npm \uBC30\uD3EC (\uBC84\uC804 \uBC94\uD504 \u2192 \uBE4C\uB4DC \u2192 \uD14C\uC2A4\uD2B8)" },
463
+ { name: "design", desc: "\uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131" },
464
+ { name: "design-palette", desc: "\uCEEC\uB7EC \uD314\uB808\uD2B8 \uD504\uB9AC\uC14B \uC120\uD0DD" },
465
+ { name: "theme", desc: "\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS \uC0DD\uC131" },
466
+ { name: "ref", desc: "\uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC (add/list/open)" },
467
+ { name: "harness", desc: "\uD1B5\uD569 \uD488\uC9C8 \uC810\uAC80 (lint+type+test+build)" },
468
+ { name: "audit", desc: "\uBCF4\uC548 \uCDE8\uC57D\uC810 \uAC10\uC0AC (npm audit)" },
469
+ { name: "migrate", desc: "\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uC804\uD658 (npm/yarn/pnpm)" },
470
+ { name: "update", desc: "VHK CLI \uC140\uD504 \uC5C5\uB370\uC774\uD2B8" },
471
+ { name: "context", desc: "\uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uD30C\uC77C \uC0DD\uC131 (.vhk/context.md)" },
472
+ { name: "mode", desc: "Safety Mode \uC870\uD68C/\uBCC0\uACBD (lite|standard|strict)" },
473
+ { name: "verify", desc: "\uAC80\uC99D \uAC8C\uC774\uD2B8 \uC2E4\uD589 + \uC99D\uAC70 \uAE30\uB85D" },
474
+ { name: "review", desc: "\uC801\uB300\uC801 \uC790\uAE30\uAC80\uC99D (\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC \uD0D0\uC9C0)" },
475
+ { name: "mission", desc: "\uBBF8\uC158 \uACC4\uC57D \u2014 \uC791\uC5C5 \uBAA9\uD45C\xB7\uD5C8\uC6A9/\uAE08\uC9C0 \uBC94\uC704 \uC120\uC5B8\xB7\uAC80\uC99D" },
476
+ { name: "context-show", desc: "\uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C \uB0B4\uC6A9 \uCD9C\uB825" },
477
+ { name: "memory", desc: "\uAE30\uC5B5 \uAD00\uB9AC v2 (decisions/failures/successes)" },
478
+ { name: "brief", desc: "\uD504\uB85C\uC81D\uD2B8 \uC694\uC57D \uBCF4\uACE0\uC11C \uC0DD\uC131" },
479
+ { name: "work", desc: "AI \uC791\uC5C5 \uC2DC\uC791/\uC774\uC5B4\uD558\uAE30 (+ handoff)" },
480
+ { name: "goal", desc: "Goal \uB2E8\uACC4\uBCC4 \uBBF8\uC158 \uAD00\uB9AC" },
481
+ { name: "blocker", desc: "\uBE14\uB85C\uCEE4 \uAE30\uB85D (3\uAC74 \uB204\uC801 \uC2DC HARD_STOP)" },
482
+ { name: "learn", desc: "\uAD50\uD6C8 \uAE30\uB85D \u2192 memory v2 \uB2E8\uC77C SoT" },
483
+ { name: "resume", desc: ".vhk/HARD_STOP \uD574\uC81C (--confirm \uD544\uC694)" },
484
+ { name: "pattern", desc: "\uBC18\uBCF5 \uD328\uD134 \uAC10\uC9C0\xB7\uBAA9\uB85D (avoid/reinforce)" },
485
+ { name: "evolve", desc: "\uD328\uD134 \u2192 \uB8F0 \uD6C4\uBCF4 \uC81C\uC548\xB7\uBC18\uC601\xB7undo" }
486
+ ];
424
487
 
425
488
  // src/lib/cli-args.ts
426
489
  var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
@@ -516,6 +579,12 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
516
579
  "\uAC80\uD1A0",
517
580
  "mission",
518
581
  "\uBBF8\uC158",
582
+ "pattern",
583
+ "\uD328\uD134",
584
+ "evolve",
585
+ "\uC9C4\uD654",
586
+ "work",
587
+ "\uC791\uC5C5",
519
588
  "help"
520
589
  ]);
521
590
  function isOptionToken(token) {
@@ -553,7 +622,7 @@ function detectNaturalLanguageInput(argv) {
553
622
  }
554
623
 
555
624
  // src/lib/nlp-run.ts
556
- import chalk35 from "chalk";
625
+ import chalk36 from "chalk";
557
626
  import inquirer14 from "inquirer";
558
627
 
559
628
  // src/commands/gate.ts
@@ -2953,7 +3022,7 @@ function compareSemver(a, b) {
2953
3022
  if (a2 !== b2) return a2 - b2;
2954
3023
  return a3 - b3;
2955
3024
  }
2956
- async function doctor() {
3025
+ async function doctor(opts = {}) {
2957
3026
  console.log(chalk9.bold(`
2958
3027
  ${ko.doctor.title}
2959
3028
  `));
@@ -3012,14 +3081,15 @@ ${ko.doctor.title}
3012
3081
  }
3013
3082
  }
3014
3083
  } else if (file.name === ".env" && fs8.existsSync(path9.join(cwd, ".env.local"))) {
3015
- console.log(chalk9.green(" \u2705 .env.local") + chalk9.dim(" \u2014 \uB85C\uCEEC env \uC0AC\uC6A9 \uC911 (.env \uC5C6\uC5B4\uB3C4 \uC815\uC0C1)"));
3084
+ console.log(chalk9.green(" \u2705 .env.local") + chalk9.dim(" \u2014 \uB85C\uCEF4 env \uC0AC\uC6A9 \uC911 (.env \uC5C6\uC5B4\uB3C4 \uC815\uC0C1)"));
3016
3085
  } else {
3017
- console.log(chalk9.dim(` \u2B1A ${file.name}`) + chalk9.dim(` \u2014 ${file.hint}`));
3086
+ console.log(chalk9.dim(` \u26AB ${file.name}`) + chalk9.dim(` \u2014 ${file.hint}`));
3018
3087
  }
3019
3088
  }
3020
3089
  console.log("");
3021
3090
  console.log(chalk9.bold(` ${ko.doctor.driftTitle}`));
3022
3091
  const ruleDrift = checkRuleDrift(cwd);
3092
+ let ruleDrifted = false;
3023
3093
  if (!ruleDrift.checked) {
3024
3094
  console.log(chalk9.dim(` ${ko.doctor.driftNoRules}`));
3025
3095
  } else {
@@ -3028,6 +3098,7 @@ ${ko.doctor.title}
3028
3098
  console.log(chalk9.green(` ${ko.doctor.driftRuleClean}`));
3029
3099
  } else {
3030
3100
  console.log(chalk9.yellow(` ${ko.doctor.driftRuleWarn(drifted.map((d) => d.path).join(", "))}`));
3101
+ ruleDrifted = true;
3031
3102
  }
3032
3103
  }
3033
3104
  const ctxDrift = checkContextDrift(cwd);
@@ -3051,6 +3122,11 @@ ${ko.doctor.title}
3051
3122
  });
3052
3123
  process.exitCode = 1;
3053
3124
  }
3125
+ if (opts.strict && ruleDrifted) {
3126
+ console.log("");
3127
+ console.log(chalk9.red.bold(" \u274C --strict: \uADDC\uCE59 \uB4DC\uB9AC\uD504\uD2B8 \uBC1C\uACAC \u2192 \uC2E4\uD328 \uCC98\uB9AC (vhk sync \uB85C \uB3D9\uAE30\uD654 \uD6C4 \uB2E4\uC2DC \uC2E4\uD589)"));
3128
+ process.exitCode = 1;
3129
+ }
3054
3130
  }
3055
3131
 
3056
3132
  // src/commands/ship.ts
@@ -4943,37 +5019,7 @@ function extractTechStack() {
4943
5019
  return stack;
4944
5020
  }
4945
5021
  function getVhkCommands() {
4946
- return [
4947
- "gate \u2014 \uC544\uC774\uB514\uC5B4 \uAC80\uC99D",
4948
- "init \u2014 \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654",
4949
- "recap \u2014 \uC138\uC158 \uC694\uC57D \uC800\uC7A5",
4950
- "sync \u2014 \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654",
4951
- "check \u2014 \uADDC\uCE59 \uC810\uAC80",
4952
- "secure \u2014 \uBCF4\uC548 \uC2A4\uCE94",
4953
- "ship \u2014 \uBC30\uD3EC \uCCB4\uD06C + \uD68C\uACE0",
4954
- "doctor \u2014 \uD658\uACBD \uC9C4\uB2E8",
4955
- "save \u2014 git \uC800\uC7A5 (add+commit+push)",
4956
- "undo \u2014 \uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30",
4957
- "status \u2014 git \uC0C1\uD0DC \uD655\uC778",
4958
- "diff \u2014 git \uBCC0\uACBD \uC0AC\uD56D \uC694\uC57D",
4959
- "deploy \u2014 \uD504\uB85C\uB355\uC158 \uBC30\uD3EC",
4960
- "env \u2014 \uD658\uACBD\uBCC0\uC218 \uAD00\uB9AC",
4961
- "publish \u2014 npm \uBC30\uD3EC \uC790\uB3D9\uD654",
4962
- "design \u2014 \uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131",
4963
- "design-palette \u2014 \uCEEC\uB7EC \uD314\uB808\uD2B8 \uC120\uD0DD",
4964
- "theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC",
4965
- "ref add|list|open \u2014 \uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC",
4966
- "harness \u2014 \uD1B5\uD569 \uD488\uC9C8 \uC810\uAC80",
4967
- "audit \u2014 \uBCF4\uC548 \uCDE8\uC57D\uC810 \uAC10\uC0AC",
4968
- "migrate \u2014 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uC804\uD658",
4969
- "update \u2014 VHK CLI \uC140\uD504 \uC5C5\uB370\uC774\uD2B8",
4970
- "context \u2014 \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uC0DD\uC131",
4971
- "context-show \u2014 \uB9E5\uB77D \uD30C\uC77C \uBCF4\uAE30",
4972
- "memory add|list|remove \u2014 \uACB0\uC815\uC0AC\uD56D \uAE30\uC5B5",
4973
- "brief \u2014 \uD504\uB85C\uC81D\uD2B8 \uC694\uC57D \uBCF4\uACE0\uC11C",
4974
- "mcp \u2014 MCP \uC11C\uBC84 \uC2DC\uC791",
4975
- "mcp-init \u2014 Cursor MCP \uC124\uC815"
4976
- ];
5022
+ return TOP_LEVEL_COMMANDS.map((c) => `${c.name} \u2014 ${c.desc}`);
4977
5023
  }
4978
5024
  async function context(opts = {}) {
4979
5025
  const compact = opts.compact === true;
@@ -4988,6 +5034,16 @@ async function context(opts = {}) {
4988
5034
  lines.push("> \uC774 \uD30C\uC77C\uC740 `vhk context`\uB85C \uC790\uB3D9 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
4989
5035
  lines.push("> AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D\uC744 \uC81C\uACF5\uD569\uB2C8\uB2E4.");
4990
5036
  lines.push("");
5037
+ lines.push("## \uC6D0\uBCF8 \uC9C0\uB3C4 (Source of Truth)");
5038
+ lines.push("");
5039
+ lines.push('> \uBB34\uC5C7\uC744 \uACE0\uCE60 \uB540 "\uC6D0\uBCF8" \uD55C \uACF3\uB9CC \uACE0\uCE58\uC138\uC694. \uB098\uBA38\uC9C0\uB294 \uD30C\uC0DD\uBCF8\uC774\uB77C \uC790\uB3D9 \uC0DD\uC131\uB429\uB2C8\uB2E4.');
5040
+ lines.push("");
5041
+ lines.push("- **\uADDC\uCE59(\uC6D0\uBCF8)**: `RULES.md` \u2014 \uADDC\uCE59\uC740 \uC5EC\uAE30 \uD55C \uACF3\uC5D0\uC11C\uB9CC \uC218\uC815");
5042
+ lines.push("- **\uC791\uC5C5 \uC0C1\uD0DC**: `docs/state/next-task.md`, `docs/state/blockers.md`");
5043
+ lines.push("- **\uBC84\uC804\xB7\uB9B4\uB9AC\uC2A4**: `package.json`, `CHANGELOG.md`");
5044
+ lines.push("- **\uBA85\uB839 \uBAA9\uB85D**: `COMMANDS.md` (+ `vhk help`)");
5045
+ lines.push("- **\uD30C\uC0DD\uBCF8(\uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0)**: `.cursorrules`\xB7`.windsurfrules`\xB7`.github/copilot-instructions.md`\xB7`AGENTS.md`\xB7`GEMINI.md` \uB4F1 7\uC885 + `CLAUDE.md` \uADDC\uCE59 \uC601\uC5ED \u2192 `vhk sync` \uB85C \uC0DD\uC131");
5046
+ lines.push("");
4991
5047
  lines.push("## \uAE30\uC220 \uC2A4\uD0DD");
4992
5048
  lines.push("");
4993
5049
  for (const [key, value] of Object.entries(stack)) {
@@ -5047,9 +5103,10 @@ async function context(opts = {}) {
5047
5103
  if (compact) {
5048
5104
  lines.push("## \uCC38\uC870 \uBB38\uC11C (\uD544\uC694\uC2DC \uC5F4\uB78C)");
5049
5105
  lines.push("");
5106
+ lines.push("- \uADDC\uCE59 \uC6D0\uBCF8(SoT): `RULES.md` \u2014 \uADDC\uCE59\uC740 \uC5EC\uAE30\uC11C\uB9CC \uC218\uC815");
5050
5107
  lines.push("- \uC791\uB3D9 \uADDC\uC57D(\uC694\uC57D): `docs/context/agent-compact.md`");
5051
5108
  lines.push("- \uADDC\uC57D \uC0C1\uC138: `AGENTS.md`");
5052
- lines.push("- \uAE30\uB85D \uADDC\uCE59: `CLAUDE.md`");
5109
+ lines.push("- \uC6B4\uC601 \uC548\uB0B4\xB7\uAE30\uB85D: `CLAUDE.md`");
5053
5110
  lines.push("- \uBA85\uB839 \uC0C1\uC138: `COMMANDS.md`");
5054
5111
  lines.push("- \uAD6C\uC870 \uC0C1\uC138: `docs/ARCHITECTURE.md`");
5055
5112
  lines.push("- \uD604\uC7AC \uC0C1\uD0DC: `docs/state/next-task.md`");
@@ -5209,12 +5266,227 @@ async function brief() {
5209
5266
  });
5210
5267
  }
5211
5268
 
5212
- // src/commands/start.ts
5269
+ // src/commands/work.ts
5270
+ import { existsSync as existsSync14, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10, readFileSync as readFileSync7 } from "fs";
5271
+ import { join as join9 } from "path";
5213
5272
  import chalk26 from "chalk";
5273
+
5274
+ // src/lib/clipboard.ts
5275
+ import { spawnSync } from "child_process";
5276
+ function copyToClipboard(text) {
5277
+ try {
5278
+ if (process.platform === "win32") return copyWin32(text);
5279
+ if (process.platform === "darwin") return runWithInput("pbcopy", [], text);
5280
+ return runWithInput("wl-copy", [], text) || runWithInput("xclip", ["-selection", "clipboard"], text) || runWithInput("xsel", ["--clipboard", "--input"], text);
5281
+ } catch {
5282
+ return false;
5283
+ }
5284
+ }
5285
+ function copyWin32(text) {
5286
+ const b64 = Buffer.from(text, "utf8").toString("base64");
5287
+ const psScript = "$b=[Console]::In.ReadToEnd();$t=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($b));Set-Clipboard -Value $t";
5288
+ const r = spawnSync(
5289
+ "powershell",
5290
+ ["-NoProfile", "-NonInteractive", "-Command", psScript],
5291
+ { input: b64, encoding: "utf8", windowsHide: true }
5292
+ );
5293
+ return r.status === 0 && !r.error;
5294
+ }
5295
+ function runWithInput(cmd, args, input) {
5296
+ const r = spawnSync(cmd, args, { input, encoding: "utf8" });
5297
+ return r.status === 0 && !r.error;
5298
+ }
5299
+
5300
+ // src/commands/work.ts
5301
+ var VHK_DIR2 = ".vhk";
5302
+ function gitShort() {
5303
+ const r = safeExecFile("git", ["status", "--short"]);
5304
+ return r.ok ? r.out.trim() : "";
5305
+ }
5306
+ function ensureVhkProject() {
5307
+ if (existsSync14("CLAUDE.md") || existsSync14(VHK_DIR2) || existsSync14("goals")) return true;
5308
+ console.log(chalk26.yellow(" \u26A0\uFE0F \uC5EC\uAE30\uB294 VHK \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354\uAC00 \uC544\uB2CC \uAC83 \uAC19\uC544\uC694."));
5309
+ console.log(chalk26.dim(" VHK \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354\uC5D0\uC11C \uC2E4\uD589\uD558\uAC70\uB098, vhk start \uB85C \uC0C8\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
5310
+ return false;
5311
+ }
5312
+ function passHardStop() {
5313
+ if (!isHardStopActive()) {
5314
+ console.log(chalk26.green(" \u2705 HARD_STOP \uC5C6\uC74C"));
5315
+ return true;
5316
+ }
5317
+ console.log(chalk26.red.bold("\n\u{1F6D1} HARD STOP \uD65C\uC131 (.vhk/HARD_STOP) \u2014 \uC790\uB3D9\uD654\uB97C \uC911\uB2E8\uD569\uB2C8\uB2E4."));
5318
+ const reason = readHardStopReason();
5319
+ if (reason) console.log(chalk26.red(` \uC0AC\uC720: ${reason.replace(/\s*\n\s*/g, " ")}`));
5320
+ console.log(chalk26.yellow(" \uD574\uC81C\uB294 \uC0AC\uB78C\uC774 \uC9C1\uC811: vhk resume --confirm"));
5321
+ return false;
5322
+ }
5323
+ function activeGoalLine() {
5324
+ const goals = listGoals("goals");
5325
+ if (goals.length === 0) return "\uC815\uC758\uB41C goal \uC5C6\uC74C";
5326
+ const id = selectActiveId(goals);
5327
+ if (id === null) return "\uBAA8\uB4E0 goal \uC644\uB8CC\uB428";
5328
+ const g = goals.find((x) => x.frontmatter.id === id);
5329
+ if (!g) return "\uC815\uC758\uB41C goal \uC5C6\uC74C";
5330
+ return `Goal ${id} \u2014 ${g.frontmatter.title ?? "(untitled)"}`;
5331
+ }
5332
+ function printGit(git3) {
5333
+ if (!git3) {
5334
+ console.log(chalk26.dim(" (\uBCC0\uACBD\uB41C \uD30C\uC77C \uC5C6\uC74C \u2014 \uAE68\uB057\uD55C \uC0C1\uD0DC)"));
5335
+ return;
5336
+ }
5337
+ for (const line of git3.split(/\r?\n/)) console.log(` ${line}`);
5338
+ }
5339
+ function buildStartPrompt(git3, goalLine) {
5340
+ const gitBlock = git3 || "(\uBCC0\uACBD \uC5C6\uC74C)";
5341
+ return [
5342
+ "\uB2F9\uC2E0\uC740 VHK \uD504\uB85C\uC81D\uD2B8\uC758 \uC791\uC5C5 \uD30C\uD2B8\uB108\uC785\uB2C8\uB2E4. \uB098\uB294 \uBE44\uAC1C\uBC1C\uC790\uC785\uB2C8\uB2E4.",
5343
+ "",
5344
+ "[\uADDC\uCE59 \uC6B0\uC120\uC21C\uC704]",
5345
+ "1. CLAUDE.md \uB97C 1\uC21C\uC704 \uADDC\uCE59\uC73C\uB85C \uC77D\uACE0 \uADF8\uB300\uB85C \uB530\uB974\uC138\uC694. (\uCDA9\uB3CC \uC2DC CLAUDE.md \uC6B0\uC120)",
5346
+ "2. AGENTS.md \uB294 Codex/\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uC6A9 \uCC38\uACE0 \uADDC\uCE59\uC785\uB2C8\uB2E4. \uB2F9\uC2E0\uC740 \uCC38\uACE0\uB9CC \uD558\uC138\uC694.",
5347
+ "3. docs/state/next-task.md \uC640 .vhk/context.md \uB97C \uC77D\uACE0 \uADF8 \uAE30\uC900\uC73C\uB85C \uC774\uC5B4\uC11C \uC791\uC5C5\uD558\uC138\uC694.",
5348
+ "",
5349
+ "[\uC791\uC5C5 \uC804 Source of Truth \uCCB4\uD06C]",
5350
+ "1. \uC0C8 \uD0C0\uC785\xB7\uADDC\uCE59\xB7\uC0C1\uC218\xB7\uBA85\uB839\uC5B4\xB7\uD504\uB86C\uD504\uD2B8\uB97C \uB9CC\uB4E4\uAE30 \uC804\uC5D0 \uAE30\uC874 \uC815\uC758\uAC00 \uC788\uB294\uC9C0 \uBA3C\uC800 \uCC3E\uC544\uBCF4\uACE0, \uC788\uC73C\uBA74 \uC7AC\uC0AC\uC6A9(import)\uD558\uC138\uC694.",
5351
+ "2. \uADDC\uCE59\uC740 RULES.md \uD55C \uACF3\uC5D0\uC11C\uB9CC \uACE0\uCE58\uC138\uC694. CLAUDE.md\xB7AGENTS.md\xB7.cursorrules \uB4F1\uC740 vhk sync \uB85C \uB9CC\uB4DC\uB294 \uD30C\uC0DD\uBCF8\uC774\uB77C \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0.",
5352
+ "3. \uC6D0\uBCF8 \uAD6C\uBD84 \u2014 \uADDC\uCE59=RULES.md / \uC791\uC5C5 \uC0C1\uD0DC=docs/state/next-task.md / \uBC84\uC804\xB7\uB9B4\uB9AC\uC2A4=package.json\xB7CHANGELOG.md.",
5353
+ "4. DTO\xB7\uACC4\uCE35 \uBD84\uB9AC\uCC98\uB7FC \uC77C\uBD80\uB7EC \uD0C0\uC785\uC744 \uB098\uB20C \uB550 \uC774\uC720\uB97C \uD55C \uC904 \uC124\uBA85\uD558\uC138\uC694. (\uC758\uBBF8\uAC00 \uAC19\uC740 \uAC78 \uC0C8\uB85C \uB610 \uC815\uC758\uD558\uB294 \uAC83\uB9CC \uAE08\uC9C0)",
5354
+ "",
5355
+ "[\uC9C0\uAE08 \uC0C1\uD0DC \u2014 \uC790\uB3D9 \uC218\uC9D1\uB428]",
5356
+ "- \uBCC0\uACBD\uB41C \uD30C\uC77C (git status --short):",
5357
+ gitBlock,
5358
+ "- \uD604\uC7AC \uBAA9\uD45C (active goal):",
5359
+ goalLine,
5360
+ "",
5361
+ "[\uD574\uC8FC\uC138\uC694]",
5362
+ "1. \uBA3C\uC800 \uD604\uC7AC \uC0C1\uD0DC\uB97C \uBE44\uAC1C\uBC1C\uC790\uAC00 \uC54C\uC544\uB4E3\uAC8C \uC27D\uAC8C \uC694\uC57D\uD574 \uC8FC\uC138\uC694.",
5363
+ "2. \uADF8\uB2E4\uC74C \uD560 \uC77C\uC744 3\uB2E8\uACC4 \uC774\uD558\uB85C \uB9D0\uD558\uACE0 \uC9C4\uD589\uD558\uC138\uC694.",
5364
+ "3. \uD14C\uC2A4\uD2B8\uAC00 \uD1B5\uACFC\uD558\uAE30 \uC804\uC5D0\uB294 \uC644\uB8CC(done) \uCC98\uB9AC\uD558\uC9C0 \uB9C8\uC138\uC694.",
5365
+ "4. \uC790\uB3D9 \uCEE4\uBC0B\uC774\uB098 vhk goal done \uC740 \uB0B4\uAC00 \uC2B9\uC778\uD558\uAE30 \uC804\uC5D0\uB294 \uD558\uC9C0 \uB9C8\uC138\uC694.",
5366
+ "\uBAA8\uB4E0 \uC751\uB2F5\uC740 \uD55C\uAD6D\uC5B4\uB85C."
5367
+ ].join("\n");
5368
+ }
5369
+ function buildHandoffPrompt(git3) {
5370
+ const gitBlock = git3 || "(\uBCC0\uACBD \uC5C6\uC74C)";
5371
+ return [
5372
+ "\uB2F9\uC2E0\uC740 VHK \uD504\uB85C\uC81D\uD2B8\uC758 \uC791\uC5C5 \uD30C\uD2B8\uB108\uC785\uB2C8\uB2E4. \uC624\uB298\uC740 \uC5EC\uAE30\uC11C \uC791\uC5C5\uC744 \uC911\uB2E8\uD558\uACE0 \uCEF4\uD4E8\uD130\uB97C \uAEBC\uC57C \uD569\uB2C8\uB2E4.",
5373
+ "\uB2E4\uC74C \uC138\uC158\uC774 \uC774\uC5B4\uBC1B\uC744 \uC218 \uC788\uAC8C \uC815\uB9AC\uD574 \uC8FC\uC138\uC694.",
5374
+ "",
5375
+ "[\uAC00\uC7A5 \uBA3C\uC800] CLAUDE.md \uB97C 1\uC21C\uC704 \uADDC\uCE59\uC73C\uB85C \uC77D\uC73C\uC138\uC694. AGENTS.md \uB294 Codex/\uBCF4\uC870\uC6A9 \uCC38\uACE0\uB9CC.",
5376
+ "",
5377
+ "[\uC9C0\uAE08 \uC0C1\uD0DC \u2014 \uC790\uB3D9 \uC218\uC9D1\uB428]",
5378
+ "- \uBCC0\uACBD\uB41C \uD30C\uC77C (git status --short):",
5379
+ gitBlock,
5380
+ "",
5381
+ "[\uD574\uC8FC\uC138\uC694 \u2014 \uC815\uB9AC\uB9CC, \uC0C8 \uAC1C\uBC1C \uC2DC\uC791 \uAE08\uC9C0]",
5382
+ "1. \uD604\uC7AC \uBCC0\uACBD\uC0AC\uD56D\uC744 \uD655\uC778\uD558\uACE0, \uC644\uB8CC\uB41C \uC77C / \uBBF8\uC644\uB8CC\uB41C \uC77C\uB85C \uB098\uB220 \uD55C\uAD6D\uC5B4\uB85C \uC815\uB9AC\uD574 \uC8FC\uC138\uC694.",
5383
+ "2. \uD14C\uC2A4\uD2B8\uB97C \uC2E4\uD589\uD588\uB294\uC9C0/\uC548 \uD588\uB294\uC9C0, \uACB0\uACFC\uAC00 \uC5B4\uB560\uB294\uC9C0 \uBA85\uD655\uD788 \uAE30\uB85D\uD574 \uC8FC\uC138\uC694. (\uC548 \uB3CC\uB838\uC73C\uBA74 '\uBBF8\uC2E4\uD589')",
5384
+ "3. docs/state/next-task.md \uB97C \uC9C0\uAE08 \uC0C1\uD0DC\uC5D0 \uB9DE\uAC8C \uC5C5\uB370\uC774\uD2B8\uD574 \uC8FC\uC138\uC694. (\uB2E4\uC74C \uC0AC\uB78C\uC774 \uC774\uC5B4\uBC1B\uC744 \uC9C0\uC810 \uBA85\uD655\uD788)",
5385
+ "4. \uC9C0\uAE08 \uCEE4\uBC0B \uAC00\uB2A5\uD55C \uC0C1\uD0DC\uC778\uC9C0 \uD310\uB2E8\uD574 \uC8FC\uC138\uC694. (\uC774\uC720 \uC124\uBA85)",
5386
+ "5. \uC644\uB8CC(done) \uCC98\uB9AC\uD558\uBA74 \uC548 \uB418\uB294 \uC0C1\uD0DC\uB77C\uBA74 \uC815\uB9AC \uB9E8 \uC704\uC5D0 \uAD75\uAC8C \uD45C\uC2DC\uD574 \uC8FC\uC138\uC694.",
5387
+ "",
5388
+ "[\uAE08\uC9C0] \uC9C1\uC811 git commit / git stash / git reset / vhk goal done \uC2E4\uD589 \uAE08\uC9C0. \uD30C\uC77C \uB418\uB3CC\uB9AC\uAE30\xB7\uC0AD\uC81C \uAE08\uC9C0.",
5389
+ "\uBAA8\uB4E0 \uC751\uB2F5\uC740 \uD55C\uAD6D\uC5B4\uB85C."
5390
+ ].join("\n");
5391
+ }
5392
+ function emitPrompt(prompt, fileName, label) {
5393
+ let savedPath = "";
5394
+ try {
5395
+ mkdirSync10(VHK_DIR2, { recursive: true });
5396
+ savedPath = join9(VHK_DIR2, fileName);
5397
+ writeFileSync10(savedPath, prompt, "utf-8");
5398
+ } catch {
5399
+ savedPath = "";
5400
+ }
5401
+ const copied = copyToClipboard(prompt);
5402
+ if (copied) {
5403
+ console.log(chalk26.green(`
5404
+ \u{1F4CB} Claude\uC5D0\uAC8C \uC904 '${label}'\uC744 \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uD588\uC2B5\uB2C8\uB2E4! \u2705`));
5405
+ if (savedPath) console.log(chalk26.dim(` (\uC0AC\uBCF8 \uC800\uC7A5: ${savedPath})`));
5406
+ } else {
5407
+ console.log(chalk26.yellow(`
5408
+ \u26A0\uFE0F \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC\uC5D0 \uC2E4\uD328\uD588\uC5B4\uC694 \u2014 \uC544\uB798 \uD504\uB86C\uD504\uD2B8\uB97C \uC9C1\uC811 \uBCF5\uC0AC\uD558\uC138\uC694:`));
5409
+ if (savedPath) console.log(chalk26.dim(` (\uD30C\uC77C\uB85C\uB3C4 \uC800\uC7A5\uB428: ${savedPath} \u2014 \uC5F4\uC5B4\uC11C \uBCF5\uC0AC \uAC00\uB2A5)`));
5410
+ console.log(chalk26.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5411
+ console.log(prompt);
5412
+ console.log(chalk26.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5413
+ }
5414
+ }
5415
+ async function refreshContextQuietly() {
5416
+ const origLog = console.log;
5417
+ console.log = () => {
5418
+ };
5419
+ try {
5420
+ await context({ compact: true });
5421
+ return true;
5422
+ } catch {
5423
+ return false;
5424
+ } finally {
5425
+ console.log = origLog;
5426
+ }
5427
+ }
5428
+ async function work() {
5429
+ console.log(chalk26.bold(`
5430
+ ${ko.work.workTitle}`));
5431
+ console.log(chalk26.gray("\u2500".repeat(40)));
5432
+ if (!ensureVhkProject()) return;
5433
+ if (!passHardStop()) return;
5434
+ const git3 = gitShort();
5435
+ console.log("");
5436
+ console.log(chalk26.cyan("\u{1F4CB} \uBCC0\uACBD\uB41C \uD30C\uC77C"));
5437
+ printGit(git3);
5438
+ console.log("");
5439
+ console.log(chalk26.cyan("\u{1F4D6} \uADDC\uCE59"));
5440
+ console.log(" \xB7 CLAUDE.md \uAC00 1\uC21C\uC704 \uADDC\uCE59\uC785\uB2C8\uB2E4.");
5441
+ console.log(chalk26.dim(" \xB7 AGENTS.md \uB294 Codex/\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uC6A9 \uCC38\uACE0 \uADDC\uCE59\uC785\uB2C8\uB2E4."));
5442
+ const goalLine = activeGoalLine();
5443
+ console.log("");
5444
+ console.log(chalk26.cyan(`\u{1F3AF} \uD604\uC7AC \uBAA9\uD45C: ${goalLine}`));
5445
+ const refreshed = await refreshContextQuietly();
5446
+ console.log(chalk26.dim(refreshed ? "\u2699\uFE0F .vhk/context.md \uAC31\uC2E0\uB428" : "\u2699\uFE0F .vhk/context.md \uAC31\uC2E0 \uC0DD\uB7B5(\uAC74\uB108\uB700)"));
5447
+ const nextTaskPath = join9("docs", "state", "next-task.md");
5448
+ if (existsSync14(nextTaskPath)) {
5449
+ try {
5450
+ const lines = readFileSync7(nextTaskPath, "utf-8").split(/\r?\n/).slice(0, 12);
5451
+ console.log("");
5452
+ console.log(chalk26.cyan("\u{1F4DD} \uB2E4\uC74C \uD560 \uC77C (next-task.md)"));
5453
+ for (const l of lines) console.log(chalk26.dim(` ${l}`));
5454
+ } catch {
5455
+ }
5456
+ }
5457
+ const prompt = buildStartPrompt(git3, goalLine);
5458
+ emitPrompt(prompt, "work-prompt.md", "\uC2DC\uC791 \uD504\uB86C\uD504\uD2B8");
5459
+ printNextStep({
5460
+ message: "\uD130\uBBF8\uB110\uC5D0\uC11C claude \uB97C \uC2E4\uD589\uD55C \uB4A4, Ctrl+V \uB85C \uBD99\uC5EC\uB123\uACE0 Enter \uD558\uC138\uC694.",
5461
+ command: "claude"
5462
+ });
5463
+ }
5464
+ async function workHandoff() {
5465
+ console.log(chalk26.bold(`
5466
+ ${ko.work.handoffTitle}`));
5467
+ console.log(chalk26.gray("\u2500".repeat(40)));
5468
+ if (!ensureVhkProject()) return;
5469
+ if (!passHardStop()) return;
5470
+ const git3 = gitShort();
5471
+ console.log("");
5472
+ console.log(chalk26.cyan("\u{1F4CB} \uBC14\uB010 \uD30C\uC77C"));
5473
+ printGit(git3);
5474
+ const prompt = buildHandoffPrompt(git3);
5475
+ emitPrompt(prompt, "handoff-prompt.md", "\uC911\uB2E8 \uC815\uB9AC \uD504\uB86C\uD504\uD2B8");
5476
+ console.log("");
5477
+ console.log(chalk26.dim("\u{1F4A1} \uC774 \uBA85\uB839\uC740 \uCEE4\uBC0B\xB7\uC0AD\uC81C\uB97C \uC808\uB300 \uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC815\uB9AC\xB7\uD310\uB2E8\uC740 Claude \uAC00 \uD569\uB2C8\uB2E4."));
5478
+ printNextStep({
5479
+ message: "\uD130\uBBF8\uB110\uC5D0\uC11C claude \uB97C \uC2E4\uD589\uD55C \uB4A4, Ctrl+V \uB85C \uBD99\uC5EC\uB123\uACE0 Enter \uD558\uC138\uC694.",
5480
+ command: "claude"
5481
+ });
5482
+ }
5483
+
5484
+ // src/commands/start.ts
5485
+ import chalk27 from "chalk";
5214
5486
  import inquirer11 from "inquirer";
5215
5487
  import { simpleGit as simpleGit2 } from "simple-git";
5216
- import { existsSync as existsSync14 } from "fs";
5217
- import { join as join9 } from "path";
5488
+ import { existsSync as existsSync15 } from "fs";
5489
+ import { join as join10 } from "path";
5218
5490
  var VHK_FOOTPRINT_FILES = [
5219
5491
  "CLAUDE.md",
5220
5492
  ".cursorrules",
@@ -5223,7 +5495,7 @@ var VHK_FOOTPRINT_FILES = [
5223
5495
  "docs/PRD.md"
5224
5496
  ];
5225
5497
  function detectExistingFootprint(cwd) {
5226
- return VHK_FOOTPRINT_FILES.filter((rel) => existsSync14(join9(cwd, rel)));
5498
+ return VHK_FOOTPRINT_FILES.filter((rel) => existsSync15(join10(cwd, rel)));
5227
5499
  }
5228
5500
  async function runGitInit(cwd) {
5229
5501
  try {
@@ -5252,21 +5524,21 @@ async function runStep(label, fn) {
5252
5524
  }
5253
5525
  }
5254
5526
  async function start(options = {}) {
5255
- console.log(chalk26.bold(`
5527
+ console.log(chalk27.bold(`
5256
5528
  ${ko.start.title}
5257
5529
  `));
5258
- console.log(chalk26.dim(ko.start.intro));
5259
- console.log(chalk26.dim(` ${ko.start.step1}`));
5260
- console.log(chalk26.dim(` ${ko.start.step2}`));
5261
- console.log(chalk26.dim(` ${ko.start.step3}`));
5262
- console.log(chalk26.dim(` ${ko.start.step4}`));
5530
+ console.log(chalk27.dim(ko.start.intro));
5531
+ console.log(chalk27.dim(` ${ko.start.step1}`));
5532
+ console.log(chalk27.dim(` ${ko.start.step2}`));
5533
+ console.log(chalk27.dim(` ${ko.start.step3}`));
5534
+ console.log(chalk27.dim(` ${ko.start.step4}`));
5263
5535
  console.log();
5264
5536
  const cwd = process.cwd();
5265
5537
  const footprint = detectExistingFootprint(cwd);
5266
5538
  if (footprint.length > 0 && !options.yes) {
5267
- console.log(chalk26.yellow("\u26A0\uFE0F \uC774\uBBF8 VHK \uC124\uCE58 \uD754\uC801\uC774 \uAC10\uC9C0\uB410\uC5B4\uC694:"));
5268
- for (const f of footprint) console.log(chalk26.dim(` - ${f}`));
5269
- console.log(chalk26.dim(" \uACC4\uC18D \uC9C4\uD589\uD558\uBA74 \uC77C\uBD80 \uD30C\uC77C(`.cursor/mcp.json`, `.vhk/context.md`)\uC740 \uAC31\uC2E0\xB7\uB36E\uC5B4\uC4F0\uAE30\uB429\uB2C8\uB2E4."));
5539
+ console.log(chalk27.yellow("\u26A0\uFE0F \uC774\uBBF8 VHK \uC124\uCE58 \uD754\uC801\uC774 \uAC10\uC9C0\uB410\uC5B4\uC694:"));
5540
+ for (const f of footprint) console.log(chalk27.dim(` - ${f}`));
5541
+ console.log(chalk27.dim(" \uACC4\uC18D \uC9C4\uD589\uD558\uBA74 \uC77C\uBD80 \uD30C\uC77C(`.cursor/mcp.json`, `.vhk/context.md`)\uC740 \uAC31\uC2E0\xB7\uB36E\uC5B4\uC4F0\uAE30\uB429\uB2C8\uB2E4."));
5270
5542
  const { proceedExisting } = await inquirer11.prompt([{
5271
5543
  type: "confirm",
5272
5544
  name: "proceedExisting",
@@ -5304,7 +5576,7 @@ ${ko.start.title}
5304
5576
  await runStep("[3/4] vhk mcp-init", () => mcpInit());
5305
5577
  log.step(ko.start.step4Header);
5306
5578
  await runStep("[4/4] vhk context", () => context());
5307
- console.log(chalk26.bold.green(`
5579
+ console.log(chalk27.bold.green(`
5308
5580
  ${ko.start.allDone}
5309
5581
  `));
5310
5582
  printNextStep({
@@ -5317,7 +5589,7 @@ ${ko.start.allDone}
5317
5589
  import fs12 from "fs";
5318
5590
  import os from "os";
5319
5591
  import path13 from "path";
5320
- import chalk27 from "chalk";
5592
+ import chalk28 from "chalk";
5321
5593
 
5322
5594
  // src/lib/vhk-cloud.ts
5323
5595
  var import_ignore = __toESM(require_ignore(), 1);
@@ -5335,7 +5607,7 @@ var DEFAULT_CLOUD_EXCLUDES = [
5335
5607
  ".gitignore"
5336
5608
  // .vhk/ 내부 gitignore
5337
5609
  ];
5338
- var VHK_DIR2 = ".vhk";
5610
+ var VHK_DIR3 = ".vhk";
5339
5611
  var CLOUD_CONFIG_FILE = "cloud.json";
5340
5612
  function loadVhkignore(rootDir) {
5341
5613
  const ig = (0, import_ignore.default)();
@@ -5347,7 +5619,7 @@ function loadVhkignore(rootDir) {
5347
5619
  return ig;
5348
5620
  }
5349
5621
  function collectVhkFiles(rootDir, ig = loadVhkignore(rootDir)) {
5350
- const vhkDir = path12.join(rootDir, VHK_DIR2);
5622
+ const vhkDir = path12.join(rootDir, VHK_DIR3);
5351
5623
  let entries;
5352
5624
  try {
5353
5625
  entries = fs11.readdirSync(vhkDir, { withFileTypes: true });
@@ -5366,7 +5638,7 @@ function partitionGistFiles(gistFiles, ig) {
5366
5638
  return { keep, excluded };
5367
5639
  }
5368
5640
  function readCloudConfig(rootDir) {
5369
- const p = path12.join(rootDir, VHK_DIR2, CLOUD_CONFIG_FILE);
5641
+ const p = path12.join(rootDir, VHK_DIR3, CLOUD_CONFIG_FILE);
5370
5642
  if (!fs11.existsSync(p)) return null;
5371
5643
  try {
5372
5644
  const parsed = readJsonFile(p);
@@ -5379,7 +5651,7 @@ function readCloudConfig(rootDir) {
5379
5651
  }
5380
5652
  }
5381
5653
  function writeCloudConfig(rootDir, config) {
5382
- const vhkDir = path12.join(rootDir, VHK_DIR2);
5654
+ const vhkDir = path12.join(rootDir, VHK_DIR3);
5383
5655
  fs11.mkdirSync(vhkDir, { recursive: true });
5384
5656
  const p = path12.join(vhkDir, CLOUD_CONFIG_FILE);
5385
5657
  fs11.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf-8");
@@ -5409,14 +5681,14 @@ ${CLOUD_CONFIG_FILE}
5409
5681
  function ensureGhReady() {
5410
5682
  const ver = safeExecFile("gh", ["--version"]);
5411
5683
  if (!ver.ok) {
5412
- console.log(chalk27.red(` ${ko.cloud.noGh}`));
5413
- console.log(chalk27.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
5684
+ console.log(chalk28.red(` ${ko.cloud.noGh}`));
5685
+ console.log(chalk28.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
5414
5686
  return false;
5415
5687
  }
5416
5688
  const auth = safeExecFile("gh", ["auth", "status"]);
5417
5689
  if (!auth.ok) {
5418
- console.log(chalk27.red(` ${ko.cloud.noAuth}`));
5419
- console.log(chalk27.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
5690
+ console.log(chalk28.red(` ${ko.cloud.noAuth}`));
5691
+ console.log(chalk28.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
5420
5692
  return false;
5421
5693
  }
5422
5694
  return true;
@@ -5429,26 +5701,26 @@ function parseGistId(output) {
5429
5701
  return null;
5430
5702
  }
5431
5703
  async function cloudPush() {
5432
- console.log(chalk27.bold(`
5704
+ console.log(chalk28.bold(`
5433
5705
  ${ko.cloud.pushTitle}
5434
5706
  `));
5435
5707
  const cwd = process.cwd();
5436
- if (!fs12.existsSync(path13.join(cwd, VHK_DIR2))) {
5437
- console.log(chalk27.yellow(` ${ko.cloud.noVhkDir}`));
5708
+ if (!fs12.existsSync(path13.join(cwd, VHK_DIR3))) {
5709
+ console.log(chalk28.yellow(` ${ko.cloud.noVhkDir}`));
5438
5710
  return;
5439
5711
  }
5440
5712
  const ig = loadVhkignore(cwd);
5441
5713
  const files = collectVhkFiles(cwd, ig);
5442
5714
  if (files.length === 0) {
5443
- console.log(chalk27.yellow(` ${ko.cloud.nothingToSync}`));
5715
+ console.log(chalk28.yellow(` ${ko.cloud.nothingToSync}`));
5444
5716
  return;
5445
5717
  }
5446
5718
  if (!ensureGhReady()) {
5447
5719
  process.exitCode = 1;
5448
5720
  return;
5449
5721
  }
5450
- const filePaths = files.map((f) => path13.join(cwd, VHK_DIR2, f));
5451
- console.log(chalk27.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
5722
+ const filePaths = files.map((f) => path13.join(cwd, VHK_DIR3, f));
5723
+ console.log(chalk28.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
5452
5724
  `));
5453
5725
  const existing = readCloudConfig(cwd);
5454
5726
  const desc = `vhk .vhk backup \u2014 ${path13.basename(cwd)}`;
@@ -5460,8 +5732,8 @@ ${ko.cloud.pushTitle}
5460
5732
  const args = gistFiles.includes(name) ? ["gist", "edit", existing.gistId, "-f", name, src] : ["gist", "edit", existing.gistId, "-a", src];
5461
5733
  const res2 = safeExecFile("gh", args);
5462
5734
  if (!res2.ok) {
5463
- console.log(chalk27.red(` ${ko.cloud.pushFail}: ${name}`));
5464
- console.log(chalk27.dim(` ${res2.err}`));
5735
+ console.log(chalk28.red(` ${ko.cloud.pushFail}: ${name}`));
5736
+ console.log(chalk28.dim(` ${res2.err}`));
5465
5737
  process.exitCode = 1;
5466
5738
  return;
5467
5739
  }
@@ -5476,15 +5748,15 @@ ${ko.cloud.pushTitle}
5476
5748
  if (!purgeFailed.includes(name)) purgeFailed.push(name);
5477
5749
  }
5478
5750
  }
5479
- console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
5480
- console.log(chalk27.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
5751
+ console.log(chalk28.green.bold(` ${ko.cloud.pushDone}`));
5752
+ console.log(chalk28.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
5481
5753
  if (excluded.length > 0) {
5482
5754
  const purged = excluded.filter((n) => !purgeFailed.includes(n));
5483
5755
  if (purged.length > 0) {
5484
- console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${purged.length}\uAC1C gist \uC5D0\uC11C \uC81C\uAC70: ${purged.join(", ")}`));
5756
+ console.log(chalk28.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${purged.length}\uAC1C gist \uC5D0\uC11C \uC81C\uAC70: ${purged.join(", ")}`));
5485
5757
  }
5486
5758
  if (purgeFailed.length > 0) {
5487
- console.log(chalk27.yellow(` \u26A0\uFE0F \uC81C\uC678 \uB300\uC0C1 \uC81C\uAC70 \uC2E4\uD328: ${purgeFailed.join(", ")} (\uC218\uB3D9 \uC81C\uAC70 \uAD8C\uC7A5 \u2014 pull \uC2DC\uC5D4 \uBCF5\uC6D0 \uC548 \uB428)`));
5759
+ console.log(chalk28.yellow(` \u26A0\uFE0F \uC81C\uC678 \uB300\uC0C1 \uC81C\uAC70 \uC2E4\uD328: ${purgeFailed.join(", ")} (\uC218\uB3D9 \uC81C\uAC70 \uAD8C\uC7A5 \u2014 pull \uC2DC\uC5D4 \uBCF5\uC6D0 \uC548 \uB428)`));
5488
5760
  }
5489
5761
  }
5490
5762
  printPushNext();
@@ -5492,32 +5764,32 @@ ${ko.cloud.pushTitle}
5492
5764
  }
5493
5765
  const res = safeExecFile("gh", ["gist", "create", "--desc", desc, ...filePaths]);
5494
5766
  if (!res.ok) {
5495
- console.log(chalk27.red(` ${ko.cloud.pushFail}`));
5496
- console.log(chalk27.dim(` ${res.err || res.out}`));
5767
+ console.log(chalk28.red(` ${ko.cloud.pushFail}`));
5768
+ console.log(chalk28.dim(` ${res.err || res.out}`));
5497
5769
  process.exitCode = 1;
5498
5770
  return;
5499
5771
  }
5500
5772
  const gistId = parseGistId(res.out);
5501
5773
  if (!gistId) {
5502
- console.log(chalk27.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
5503
- console.log(chalk27.dim(` \uCD9C\uB825: ${res.out}`));
5774
+ console.log(chalk28.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
5775
+ console.log(chalk28.dim(` \uCD9C\uB825: ${res.out}`));
5504
5776
  process.exitCode = 1;
5505
5777
  return;
5506
5778
  }
5507
5779
  writeCloudConfig(cwd, { gistId });
5508
- console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
5509
- console.log(chalk27.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
5780
+ console.log(chalk28.green.bold(` ${ko.cloud.pushDone}`));
5781
+ console.log(chalk28.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
5510
5782
  printPushNext();
5511
5783
  }
5512
5784
  async function cloudPull(gistIdArg) {
5513
- console.log(chalk27.bold(`
5785
+ console.log(chalk28.bold(`
5514
5786
  ${ko.cloud.pullTitle}
5515
5787
  `));
5516
5788
  const cwd = process.cwd();
5517
5789
  const gistId = gistIdArg || readCloudConfig(cwd)?.gistId;
5518
5790
  if (!gistId) {
5519
- console.log(chalk27.yellow(` ${ko.cloud.noGistId}`));
5520
- console.log(chalk27.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
5791
+ console.log(chalk28.yellow(` ${ko.cloud.noGistId}`));
5792
+ console.log(chalk28.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
5521
5793
  return;
5522
5794
  }
5523
5795
  if (!ensureGhReady()) {
@@ -5526,34 +5798,34 @@ ${ko.cloud.pullTitle}
5526
5798
  }
5527
5799
  const allNames = listGistFiles(gistId);
5528
5800
  if (allNames.length === 0) {
5529
- console.log(chalk27.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
5801
+ console.log(chalk28.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
5530
5802
  process.exitCode = 1;
5531
5803
  return;
5532
5804
  }
5533
5805
  const { keep: names, excluded: skipped } = partitionGistFiles(allNames, loadVhkignore(cwd));
5534
5806
  if (skipped.length > 0) {
5535
- console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${skipped.length}\uAC1C \uBCF5\uC6D0 \uC2A4\uD0B5: ${skipped.join(", ")}`));
5807
+ console.log(chalk28.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${skipped.length}\uAC1C \uBCF5\uC6D0 \uC2A4\uD0B5: ${skipped.join(", ")}`));
5536
5808
  }
5537
5809
  if (names.length === 0) {
5538
- console.log(chalk27.yellow(` \uBCF5\uC6D0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (gist \uD30C\uC77C\uC774 \uBAA8\uB450 \uC81C\uC678 \uADDC\uCE59\uC5D0 \uD574\uB2F9).`));
5810
+ console.log(chalk28.yellow(` \uBCF5\uC6D0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (gist \uD30C\uC77C\uC774 \uBAA8\uB450 \uC81C\uC678 \uADDC\uCE59\uC5D0 \uD574\uB2F9).`));
5539
5811
  return;
5540
5812
  }
5541
- const vhkDir = path13.join(cwd, VHK_DIR2);
5813
+ const vhkDir = path13.join(cwd, VHK_DIR3);
5542
5814
  fs12.mkdirSync(vhkDir, { recursive: true });
5543
5815
  let restored = 0;
5544
5816
  for (const name of names) {
5545
5817
  const res = safeExecFile("gh", ["gist", "view", gistId, "-f", name, "--raw"]);
5546
5818
  if (!res.ok) {
5547
- console.log(chalk27.red(` ${ko.cloud.pullFail}: ${name}`));
5548
- console.log(chalk27.dim(` ${res.err}`));
5819
+ console.log(chalk28.red(` ${ko.cloud.pullFail}: ${name}`));
5820
+ console.log(chalk28.dim(` ${res.err}`));
5549
5821
  continue;
5550
5822
  }
5551
5823
  fs12.writeFileSync(path13.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
5552
5824
  restored++;
5553
5825
  }
5554
5826
  writeCloudConfig(cwd, { gistId });
5555
- console.log(chalk27.green.bold(` ${ko.cloud.pullDone}`));
5556
- console.log(chalk27.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
5827
+ console.log(chalk28.green.bold(` ${ko.cloud.pullDone}`));
5828
+ console.log(chalk28.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
5557
5829
  printNextStep({
5558
5830
  message: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk/ \uBCF5\uC6D0 \uC644\uB8CC!",
5559
5831
  command: "vhk \uB9E5\uB77D",
@@ -5601,7 +5873,7 @@ function printPushNext() {
5601
5873
  }
5602
5874
 
5603
5875
  // src/commands/help.ts
5604
- import chalk28 from "chalk";
5876
+ import chalk29 from "chalk";
5605
5877
  var QUICK_ACTIONS = [
5606
5878
  { say: "\uC0C1\uD0DC \uC54C\uB824\uC918", does: "vhk status" },
5607
5879
  { say: "\uBB50 \uBC14\uB00C\uC5C8\uC5B4?", does: "vhk diff" },
@@ -5615,21 +5887,21 @@ var QUICK_ACTIONS = [
5615
5887
  { say: "\uC804\uCCB4 \uBA85\uB839\uC5B4 \uBCF4\uAE30", does: "vhk --help" }
5616
5888
  ];
5617
5889
  function quickActions() {
5618
- console.log(chalk28.bold("\n\u{1F9ED} VHK \u2014 \uC774\uB807\uAC8C \uB9D0\uD558\uBA74 \uB429\uB2C8\uB2E4 (quick actions)"));
5619
- console.log(chalk28.gray("\u2500".repeat(40)));
5890
+ console.log(chalk29.bold("\n\u{1F9ED} VHK \u2014 \uC774\uB807\uAC8C \uB9D0\uD558\uBA74 \uB429\uB2C8\uB2E4 (quick actions)"));
5891
+ console.log(chalk29.gray("\u2500".repeat(40)));
5620
5892
  for (const a of QUICK_ACTIONS) {
5621
- console.log(` "${chalk28.cyan(a.say)}" \u2192 ${chalk28.dim(a.does)}`);
5893
+ console.log(` "${chalk29.cyan(a.say)}" \u2192 ${chalk29.dim(a.does)}`);
5622
5894
  }
5623
- console.log(chalk28.gray("\n \uC804\uCCB4 \uBA85\uB839\uC740 `vhk --help` \uB610\uB294 COMMANDS.md \uB97C \uBCF4\uC138\uC694."));
5895
+ console.log(chalk29.gray("\n \uC804\uCCB4 \uBA85\uB839\uC740 `vhk --help` \uB610\uB294 COMMANDS.md \uB97C \uBCF4\uC138\uC694."));
5624
5896
  console.log("");
5625
5897
  }
5626
5898
 
5627
5899
  // src/commands/mode.ts
5628
- import chalk29 from "chalk";
5900
+ import chalk30 from "chalk";
5629
5901
 
5630
5902
  // src/lib/config.ts
5631
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
5632
- import { join as join10 } from "path";
5903
+ import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
5904
+ import { join as join11 } from "path";
5633
5905
 
5634
5906
  // src/lib/safety-mode.ts
5635
5907
  var SAFETY_MODES = ["lite", "standard", "strict"];
@@ -5645,11 +5917,11 @@ function isSafetyMode(value) {
5645
5917
 
5646
5918
  // src/lib/config.ts
5647
5919
  var CONFIG_DIR = ".vhk";
5648
- var CONFIG_PATH = join10(CONFIG_DIR, "config.json");
5920
+ var CONFIG_PATH = join11(CONFIG_DIR, "config.json");
5649
5921
  var DEFAULT_CONFIG = { safetyMode: DEFAULT_SAFETY_MODE };
5650
5922
  function readConfig(rootDir = process.cwd()) {
5651
- const full = join10(rootDir, CONFIG_PATH);
5652
- if (!existsSync15(full)) return { ...DEFAULT_CONFIG };
5923
+ const full = join11(rootDir, CONFIG_PATH);
5924
+ if (!existsSync16(full)) return { ...DEFAULT_CONFIG };
5653
5925
  try {
5654
5926
  const raw = readJsonFile(full);
5655
5927
  return {
@@ -5660,23 +5932,23 @@ function readConfig(rootDir = process.cwd()) {
5660
5932
  }
5661
5933
  }
5662
5934
  function writeConfig(config, rootDir = process.cwd()) {
5663
- mkdirSync10(join10(rootDir, CONFIG_DIR), { recursive: true });
5664
- writeFileSync10(join10(rootDir, CONFIG_PATH), JSON.stringify(config, null, 2) + "\n", "utf-8");
5935
+ mkdirSync11(join11(rootDir, CONFIG_DIR), { recursive: true });
5936
+ writeFileSync11(join11(rootDir, CONFIG_PATH), JSON.stringify(config, null, 2) + "\n", "utf-8");
5665
5937
  }
5666
5938
 
5667
5939
  // src/commands/mode.ts
5668
5940
  async function mode(target) {
5669
- console.log(chalk29.bold("\n\u{1F6E1}\uFE0F Safety Mode"));
5670
- console.log(chalk29.gray("\u2500".repeat(40)));
5941
+ console.log(chalk30.bold("\n\u{1F6E1}\uFE0F Safety Mode"));
5942
+ console.log(chalk30.gray("\u2500".repeat(40)));
5671
5943
  const current = readConfig().safetyMode;
5672
5944
  if (!target) {
5673
- console.log(chalk29.cyan(`
5674
- \uD604\uC7AC \uBAA8\uB4DC: ${chalk29.bold(current)}`));
5675
- console.log(chalk29.dim(` ${SAFETY_MODE_DESC[current]}`));
5945
+ console.log(chalk30.cyan(`
5946
+ \uD604\uC7AC \uBAA8\uB4DC: ${chalk30.bold(current)}`));
5947
+ console.log(chalk30.dim(` ${SAFETY_MODE_DESC[current]}`));
5676
5948
  console.log("");
5677
5949
  for (const m of SAFETY_MODES) {
5678
5950
  const mark = m === current ? "\u25CF" : "\u25CB";
5679
- console.log(` ${mark} ${m.padEnd(9)} ${chalk29.dim(SAFETY_MODE_DESC[m])}`);
5951
+ console.log(` ${mark} ${m.padEnd(9)} ${chalk30.dim(SAFETY_MODE_DESC[m])}`);
5680
5952
  }
5681
5953
  printNextStep({
5682
5954
  message: "\uBAA8\uB4DC\uB97C \uBC14\uAFB8\uB824\uBA74:",
@@ -5686,23 +5958,23 @@ async function mode(target) {
5686
5958
  return;
5687
5959
  }
5688
5960
  if (!isSafetyMode(target)) {
5689
- console.log(chalk29.red(`
5961
+ console.log(chalk30.red(`
5690
5962
  \u274C \uC54C \uC218 \uC5C6\uB294 \uBAA8\uB4DC: ${target}`));
5691
- console.log(chalk29.dim(` \uAC00\uB2A5: ${SAFETY_MODES.join(" | ")}`));
5963
+ console.log(chalk30.dim(` \uAC00\uB2A5: ${SAFETY_MODES.join(" | ")}`));
5692
5964
  process.exitCode = 1;
5693
5965
  return;
5694
5966
  }
5695
5967
  writeConfig({ ...readConfig(), safetyMode: target });
5696
- console.log(chalk29.green(`
5697
- \u2705 Safety Mode \u2192 ${chalk29.bold(target)}`));
5698
- console.log(chalk29.dim(` ${SAFETY_MODE_DESC[target]}`));
5968
+ console.log(chalk30.green(`
5969
+ \u2705 Safety Mode \u2192 ${chalk30.bold(target)}`));
5970
+ console.log(chalk30.dim(` ${SAFETY_MODE_DESC[target]}`));
5699
5971
  }
5700
5972
 
5701
5973
  // src/commands/verify.ts
5702
5974
  import { execFileSync as execFileSync4 } from "child_process";
5703
- import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
5704
- import { join as join11 } from "path";
5705
- import chalk30 from "chalk";
5975
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
5976
+ import { join as join12 } from "path";
5977
+ import chalk31 from "chalk";
5706
5978
 
5707
5979
  // src/commands/verify-report.ts
5708
5980
  function escapeHtml(text) {
@@ -5810,13 +6082,13 @@ ${actions}
5810
6082
 
5811
6083
  // src/commands/verify.ts
5812
6084
  var REPORT_SCHEMA_VERSION = 1;
5813
- var REPORT_DIR_REL = join11(".vhk", "reports");
5814
- var REPORT_PATH_REL = join11(REPORT_DIR_REL, "latest.json");
5815
- var REPORT_HTML_PATH_REL = join11(REPORT_DIR_REL, "latest.html");
6085
+ var REPORT_DIR_REL = join12(".vhk", "reports");
6086
+ var REPORT_PATH_REL = join12(REPORT_DIR_REL, "latest.json");
6087
+ var REPORT_HTML_PATH_REL = join12(REPORT_DIR_REL, "latest.html");
5816
6088
  var SHIM = /* @__PURE__ */ new Set(["pnpm", "npm", "npx", "yarn"]);
5817
6089
  function detectPm(cwd) {
5818
- if (existsSync16(join11(cwd, "pnpm-lock.yaml"))) return "pnpm";
5819
- if (existsSync16(join11(cwd, "yarn.lock"))) return "yarn";
6090
+ if (existsSync17(join12(cwd, "pnpm-lock.yaml"))) return "pnpm";
6091
+ if (existsSync17(join12(cwd, "yarn.lock"))) return "yarn";
5820
6092
  return "npm";
5821
6093
  }
5822
6094
  function execGate(cmd, args, cwd) {
@@ -5859,8 +6131,8 @@ function runScriptGate(id, label, cwd, pm, argvFor) {
5859
6131
  };
5860
6132
  }
5861
6133
  function readPackageScripts(cwd) {
5862
- const pkgPath = join11(cwd, "package.json");
5863
- if (!existsSync16(pkgPath)) return {};
6134
+ const pkgPath = join12(cwd, "package.json");
6135
+ if (!existsSync17(pkgPath)) return {};
5864
6136
  try {
5865
6137
  const pkg = readJsonFile(pkgPath);
5866
6138
  return pkg.scripts ?? {};
@@ -5875,7 +6147,7 @@ function runGates(cwd) {
5875
6147
  gates.push(
5876
6148
  runScriptGate("typecheck", "tsc --noEmit", cwd, pm, () => {
5877
6149
  if (scripts.typecheck) return ["run", "typecheck"];
5878
- if (existsSync16(join11(cwd, "tsconfig.json"))) return pm === "npm" ? ["exec", "--", "tsc", "--noEmit"] : ["exec", "tsc", "--noEmit"];
6150
+ if (existsSync17(join12(cwd, "tsconfig.json"))) return pm === "npm" ? ["exec", "--", "tsc", "--noEmit"] : ["exec", "tsc", "--noEmit"];
5879
6151
  return null;
5880
6152
  })
5881
6153
  );
@@ -5954,10 +6226,10 @@ function buildReport(gates, generatedAt, date) {
5954
6226
  function verifyEvidence(cwd = process.cwd()) {
5955
6227
  const gates = runGates(cwd);
5956
6228
  const report = buildReport(gates, (/* @__PURE__ */ new Date()).toISOString(), localDate());
5957
- const dir = join11(cwd, REPORT_DIR_REL);
5958
- mkdirSync11(dir, { recursive: true });
5959
- const path14 = join11(cwd, REPORT_PATH_REL);
5960
- writeFileSync11(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
6229
+ const dir = join12(cwd, REPORT_DIR_REL);
6230
+ mkdirSync12(dir, { recursive: true });
6231
+ const path14 = join12(cwd, REPORT_PATH_REL);
6232
+ writeFileSync12(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
5961
6233
  try {
5962
6234
  ensureVhkIgnored(cwd, "reports/");
5963
6235
  } catch {
@@ -5965,44 +6237,44 @@ function verifyEvidence(cwd = process.cwd()) {
5965
6237
  return { report, path: REPORT_PATH_REL };
5966
6238
  }
5967
6239
  var STATUS_BADGE = {
5968
- PASS: chalk30.green.bold("PASS"),
5969
- WARN: chalk30.yellow.bold("WARN"),
5970
- FAIL: chalk30.red.bold("FAIL")
6240
+ PASS: chalk31.green.bold("PASS"),
6241
+ WARN: chalk31.yellow.bold("WARN"),
6242
+ FAIL: chalk31.red.bold("FAIL")
5971
6243
  };
5972
6244
  async function renderVerifyReport(cwd, opts) {
5973
- const jsonPath = join11(cwd, REPORT_PATH_REL);
6245
+ const jsonPath = join12(cwd, REPORT_PATH_REL);
5974
6246
  let report;
5975
- if (existsSync16(jsonPath)) {
6247
+ if (existsSync17(jsonPath)) {
5976
6248
  try {
5977
6249
  report = readJsonFile(jsonPath);
5978
6250
  } catch {
5979
- console.log(chalk30.yellow(" \u26A0\uFE0F \uAE30\uC874 latest.json \uC190\uC0C1 \u2014 verify \uC7AC\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB2E4\uC2DC \uB9CC\uB4ED\uB2C8\uB2E4."));
6251
+ console.log(chalk31.yellow(" \u26A0\uFE0F \uAE30\uC874 latest.json \uC190\uC0C1 \u2014 verify \uC7AC\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB2E4\uC2DC \uB9CC\uB4ED\uB2C8\uB2E4."));
5980
6252
  report = verifyEvidence(cwd).report;
5981
6253
  }
5982
6254
  } else {
5983
- console.log(chalk30.dim(" latest.json \uC5C6\uC74C \u2014 verify 1\uD68C \uC120\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB9CC\uB4ED\uB2C8\uB2E4."));
6255
+ console.log(chalk31.dim(" latest.json \uC5C6\uC74C \u2014 verify 1\uD68C \uC120\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB9CC\uB4ED\uB2C8\uB2E4."));
5984
6256
  report = verifyEvidence(cwd).report;
5985
6257
  }
5986
6258
  const html = renderReportHtml(report);
5987
- const htmlPath = join11(cwd, REPORT_HTML_PATH_REL);
6259
+ const htmlPath = join12(cwd, REPORT_HTML_PATH_REL);
5988
6260
  try {
5989
- mkdirSync11(join11(cwd, REPORT_DIR_REL), { recursive: true });
5990
- writeFileSync11(htmlPath, html, "utf-8");
6261
+ mkdirSync12(join12(cwd, REPORT_DIR_REL), { recursive: true });
6262
+ writeFileSync12(htmlPath, html, "utf-8");
5991
6263
  } catch (e) {
5992
6264
  console.error(
5993
- chalk30.red(` \u274C \uB9AC\uD3EC\uD2B8 HTML \uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${REPORT_HTML_PATH_REL}): ${e instanceof Error ? e.message : String(e)}`)
6265
+ chalk31.red(` \u274C \uB9AC\uD3EC\uD2B8 HTML \uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (${REPORT_HTML_PATH_REL}): ${e instanceof Error ? e.message : String(e)}`)
5994
6266
  );
5995
- console.error(chalk30.dim(" \uD574\uB2F9 \uACBD\uB85C\uC758 \uC4F0\uAE30 \uAD8C\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694."));
6267
+ console.error(chalk31.dim(" \uD574\uB2F9 \uACBD\uB85C\uC758 \uC4F0\uAE30 \uAD8C\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694."));
5996
6268
  process.exitCode = 1;
5997
6269
  return;
5998
6270
  }
5999
- console.log(chalk30.bold("\n\u{1F50E} \uAC80\uC99D \uB9AC\uD3EC\uD2B8 (verify --report)"));
6271
+ console.log(chalk31.bold("\n\u{1F50E} \uAC80\uC99D \uB9AC\uD3EC\uD2B8 (verify --report)"));
6000
6272
  console.log(` \uACB0\uACFC: ${STATUS_BADGE[report.status]}`);
6001
- console.log(chalk30.dim(` \u{1F4C4} HTML: ${REPORT_HTML_PATH_REL}`));
6273
+ console.log(chalk31.dim(` \u{1F4C4} HTML: ${REPORT_HTML_PATH_REL}`));
6002
6274
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6003
6275
  if (opts.open) {
6004
6276
  if (isInteractive()) openReportInBrowser(htmlPath);
6005
- else console.log(chalk30.dim(" (\uBE44\uB300\uD654\uD615/CI/MCP \u2014 --open \uC790\uB3D9 \uC2A4\uD0B5)"));
6277
+ else console.log(chalk31.dim(" (\uBE44\uB300\uD654\uD615/CI/MCP \u2014 --open \uC790\uB3D9 \uC2A4\uD0B5)"));
6006
6278
  return;
6007
6279
  }
6008
6280
  printNextStep({
@@ -6020,8 +6292,8 @@ function openReportInBrowser(filePath) {
6020
6292
  } else {
6021
6293
  result = safeExecFile("xdg-open", [filePath]);
6022
6294
  }
6023
- if (result.ok) console.log(chalk30.green(" \u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
6024
- else console.log(chalk30.yellow(" \u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC704 \uD30C\uC77C\uC744 \uC9C1\uC811 \uC5EC\uC138\uC694."));
6295
+ if (result.ok) console.log(chalk31.green(" \u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
6296
+ else console.log(chalk31.yellow(" \u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC704 \uD30C\uC77C\uC744 \uC9C1\uC811 \uC5EC\uC138\uC694."));
6025
6297
  }
6026
6298
  async function verify(opts = {}) {
6027
6299
  if (!ensureNotHardStopped("verify")) return;
@@ -6036,21 +6308,21 @@ async function verify(opts = {}) {
6036
6308
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6037
6309
  return;
6038
6310
  }
6039
- console.log(chalk30.bold("\n\u{1F50E} \uAC80\uC99D \uBB36\uC74C (verify)"));
6040
- console.log(chalk30.gray("\u2500".repeat(40)));
6311
+ console.log(chalk31.bold("\n\u{1F50E} \uAC80\uC99D \uBB36\uC74C (verify)"));
6312
+ console.log(chalk31.gray("\u2500".repeat(40)));
6041
6313
  const mode2 = readConfig().safetyMode;
6042
- console.log(chalk30.dim(` \uD604\uC7AC Safety Mode: ${mode2} \u2014 ${SAFETY_MODE_DESC[mode2]}`));
6043
- const icon = (s2) => s2 === "pass" ? chalk30.green("\u2713") : s2 === "fail" ? chalk30.red("\u2717") : chalk30.yellow("\u2298");
6314
+ console.log(chalk31.dim(` \uD604\uC7AC Safety Mode: ${mode2} \u2014 ${SAFETY_MODE_DESC[mode2]}`));
6315
+ const icon = (s2) => s2 === "pass" ? chalk31.green("\u2713") : s2 === "fail" ? chalk31.red("\u2717") : chalk31.yellow("\u2298");
6044
6316
  for (const g of report.gates) {
6045
- const tail = g.detail ? chalk30.dim(` \u2014 ${g.detail}`) : "";
6317
+ const tail = g.detail ? chalk31.dim(` \u2014 ${g.detail}`) : "";
6046
6318
  console.log(` ${icon(g.status)} ${g.label}${tail}`);
6047
6319
  }
6048
6320
  const s = report.summary;
6049
6321
  console.log(
6050
6322
  `
6051
- \uACB0\uACFC: ${STATUS_BADGE[report.status]} ` + chalk30.dim(`(pass ${s.pass} / fail ${s.fail} / skip ${s.skip}, \uCD1D ${s.total})`)
6323
+ \uACB0\uACFC: ${STATUS_BADGE[report.status]} ` + chalk31.dim(`(pass ${s.pass} / fail ${s.fail} / skip ${s.skip}, \uCD1D ${s.total})`)
6052
6324
  );
6053
- console.log(chalk30.dim(` \u{1F4C4} \uC99D\uAC70: ${path14}`));
6325
+ console.log(chalk31.dim(` \u{1F4C4} \uC99D\uAC70: ${path14}`));
6054
6326
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6055
6327
  if (report.status === "FAIL") {
6056
6328
  printNextStep({
@@ -6069,9 +6341,9 @@ async function verify(opts = {}) {
6069
6341
  }
6070
6342
 
6071
6343
  // src/commands/review.ts
6072
- import { existsSync as existsSync17, writeFileSync as writeFileSync12 } from "fs";
6073
- import { join as join12 } from "path";
6074
- import chalk31 from "chalk";
6344
+ import { existsSync as existsSync18, writeFileSync as writeFileSync13 } from "fs";
6345
+ import { join as join13 } from "path";
6346
+ import chalk32 from "chalk";
6075
6347
  var GOALS_DIR2 = "goals";
6076
6348
  var COVERAGE_MIN = 0.5;
6077
6349
  var STALE_AGE_MS = 6 * 60 * 60 * 1e3;
@@ -6203,22 +6475,22 @@ function resolveGoal(optId, goals) {
6203
6475
  return goals.find((g) => g.frontmatter.id === id) ?? null;
6204
6476
  }
6205
6477
  var CONFIDENCE_LABEL = {
6206
- low: chalk31.red.bold("\uB0AE\uC74C (\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC \uB610\uB294 \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C)"),
6207
- medium: chalk31.yellow.bold("\uC911\uAC04 (\uCEE4\uBC84\uB9AC\uC9C0/\uC2E0\uC120\uB3C4 \uBD80\uC871 \u2014 \uC99D\uAC70 \uC5C6\uC74C \u2260 \uD1B5\uACFC)"),
6208
- high: chalk31.green.bold("\uB192\uC74C (\uC758\uC2EC 0 + \uCEE4\uBC84\uB9AC\uC9C0\xB7\uC2E0\uC120\uB3C4 \uCDA9\uBD84 \u2014 \uB2E8 \uBCF4\uC7A5 \uC544\uB2D8)")
6478
+ low: chalk32.red.bold("\uB0AE\uC74C (\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC \uB610\uB294 \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C)"),
6479
+ medium: chalk32.yellow.bold("\uC911\uAC04 (\uCEE4\uBC84\uB9AC\uC9C0/\uC2E0\uC120\uB3C4 \uBD80\uC871 \u2014 \uC99D\uAC70 \uC5C6\uC74C \u2260 \uD1B5\uACFC)"),
6480
+ high: chalk32.green.bold("\uB192\uC74C (\uC758\uC2EC 0 + \uCEE4\uBC84\uB9AC\uC9C0\xB7\uC2E0\uC120\uB3C4 \uCDA9\uBD84 \u2014 \uB2E8 \uBCF4\uC7A5 \uC544\uB2D8)")
6209
6481
  };
6210
6482
  async function review(opts = {}) {
6211
6483
  if (!ensureNotHardStopped("review")) return;
6212
6484
  const cwd = process.cwd();
6213
6485
  const goals = listGoals(GOALS_DIR2);
6214
6486
  if (goals.length === 0) {
6215
- console.error(chalk31.yellow(" \u26A0\uFE0F goals/ \uC5D0 goal \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
6487
+ console.error(chalk32.yellow(" \u26A0\uFE0F goals/ \uC5D0 goal \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
6216
6488
  process.exitCode = 1;
6217
6489
  return;
6218
6490
  }
6219
6491
  const goal = resolveGoal(opts.id, goals);
6220
6492
  if (!goal || typeof goal.frontmatter.id !== "number") {
6221
- console.error(chalk31.red(` \u274C \uB300\uC0C1 goal \uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4${opts.id ? ` (--id ${opts.id})` : " (active goal \uC5C6\uC74C)"}.`));
6493
+ console.error(chalk32.red(` \u274C \uB300\uC0C1 goal \uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4${opts.id ? ` (--id ${opts.id})` : " (active goal \uC5C6\uC74C)"}.`));
6222
6494
  process.exitCode = 1;
6223
6495
  return;
6224
6496
  }
@@ -6226,11 +6498,11 @@ async function review(opts = {}) {
6226
6498
  const goalStatus = goal.frontmatter.status ?? "NOT_STARTED";
6227
6499
  const checks = parseCompletionChecks(goal.body);
6228
6500
  if (opts.id === void 0 && goalStatus === "NOT_STARTED") {
6229
- console.error(chalk31.yellow(` \u26A0\uFE0F active goal ${goalId} \uAC00 NOT_STARTED \u2014 \uC644\uB8CC \uC8FC\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC80\uC99D \uB300\uC0C1\uC740 --id \uB85C \uC9C0\uC815\uD558\uC138\uC694.`));
6501
+ console.error(chalk32.yellow(` \u26A0\uFE0F active goal ${goalId} \uAC00 NOT_STARTED \u2014 \uC644\uB8CC \uC8FC\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC80\uC99D \uB300\uC0C1\uC740 --id \uB85C \uC9C0\uC815\uD558\uC138\uC694.`));
6230
6502
  }
6231
- const jsonPath = join12(cwd, REPORT_PATH_REL);
6232
- if (!existsSync17(jsonPath)) {
6233
- console.error(chalk31.yellow(` \u26A0\uFE0F \uC99D\uAC70 \uBD80\uC7AC \u2014 ${REPORT_PATH_REL} \uC5C6\uC74C. review \uB97C \uC911\uB2E8\uD569\uB2C8\uB2E4(\uC0C8 \uC99D\uAC70 \uC548 \uB9CC\uB4E6).`));
6503
+ const jsonPath = join13(cwd, REPORT_PATH_REL);
6504
+ if (!existsSync18(jsonPath)) {
6505
+ console.error(chalk32.yellow(` \u26A0\uFE0F \uC99D\uAC70 \uBD80\uC7AC \u2014 ${REPORT_PATH_REL} \uC5C6\uC74C. review \uB97C \uC911\uB2E8\uD569\uB2C8\uB2E4(\uC0C8 \uC99D\uAC70 \uC548 \uB9CC\uB4E6).`));
6234
6506
  printNextStep({
6235
6507
  message: "\uC99D\uAC70(latest.json)\uAC00 \uC788\uC5B4\uC57C review \uAC00 \uAD50\uCC28\uAC80\uC99D\uD569\uB2C8\uB2E4:",
6236
6508
  command: "vhk verify",
@@ -6243,7 +6515,7 @@ async function review(opts = {}) {
6243
6515
  try {
6244
6516
  report = readJsonFile(jsonPath);
6245
6517
  } catch {
6246
- console.error(chalk31.red(` \u274C ${REPORT_PATH_REL} \uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uC190\uC0C1). vhk verify \uB85C \uC7AC\uC0DD\uC131\uD558\uC138\uC694.`));
6518
+ console.error(chalk32.red(` \u274C ${REPORT_PATH_REL} \uB97C \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4(\uC190\uC0C1). vhk verify \uB85C \uC7AC\uC0DD\uC131\uD558\uC138\uC694.`));
6247
6519
  process.exitCode = 1;
6248
6520
  return;
6249
6521
  }
@@ -6255,44 +6527,44 @@ async function review(opts = {}) {
6255
6527
  goalStatus,
6256
6528
  reportStatus: report.status
6257
6529
  };
6258
- console.log(chalk31.bold(`
6530
+ console.log(chalk32.bold(`
6259
6531
  \u{1F52C} \uC801\uB300\uC801 \uC790\uAE30\uAC80\uC99D (review) \u2014 Goal ${goalId}`));
6260
- console.log(chalk31.gray("\u2500".repeat(44)));
6532
+ console.log(chalk32.gray("\u2500".repeat(44)));
6261
6533
  console.log(
6262
- chalk31.dim(
6534
+ chalk32.dim(
6263
6535
  ` goal status: ${goalStatus} \xB7 verify: ${report.status} \xB7 \uCCB4\uD06C\uB41C \uC644\uB8CC\uC870\uAC74 ${result.checkedCount}\uAC1C (\uB9E4\uD551 ${result.mappedCount} / \uBBF8\uAC80\uC99D ${result.unmappedCount}, coverage ${result.coverage * 100 | 0}%)`
6264
6536
  )
6265
6537
  );
6266
- console.log(chalk31.dim(` \uC99D\uAC70 \uC2E0\uC120\uB3C4: ${result.freshness.note}`));
6538
+ console.log(chalk32.dim(` \uC99D\uAC70 \uC2E0\uC120\uB3C4: ${result.freshness.note}`));
6267
6539
  if (result.checkedCount === 0) {
6268
- console.log(chalk31.yellow("\n \u26AA \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C(\uCCB4\uD06C\uB41C \uC644\uB8CC\uC870\uAC74 0\uAC1C) \u2014 \uC2EC\uBB38\uD560 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(vacuous)."));
6540
+ console.log(chalk32.yellow("\n \u26AA \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C(\uCCB4\uD06C\uB41C \uC644\uB8CC\uC870\uAC74 0\uAC1C) \u2014 \uC2EC\uBB38\uD560 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4(vacuous)."));
6269
6541
  }
6270
6542
  if (result.suspicions.length > 0) {
6271
- console.log(chalk31.red.bold(`
6543
+ console.log(chalk32.red.bold(`
6272
6544
  \u{1F6A9} \uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC ${result.suspicions.length}\uAC74`));
6273
- for (const s of result.suspicions) console.log(chalk31.red(` \u2717 ${s.check}
6545
+ for (const s of result.suspicions) console.log(chalk32.red(` \u2717 ${s.check}
6274
6546
  \u21B3 ${s.reason}`));
6275
6547
  }
6276
6548
  if (result.gaps.length > 0) {
6277
- console.log(chalk31.yellow.bold(`
6549
+ console.log(chalk32.yellow.bold(`
6278
6550
  \u26A0\uFE0F \uBBF8\uAC80\uC99D(unmapped) ${result.gaps.length}\uAC74 \u2014 \uAC8C\uC774\uD2B8\uB85C \uC790\uB3D9 \uD655\uC778 \uBD88\uAC00`));
6279
- for (const g of result.gaps) console.log(chalk31.yellow(` ? ${g.check}`));
6551
+ for (const g of result.gaps) console.log(chalk32.yellow(` ? ${g.check}`));
6280
6552
  }
6281
6553
  if (result.checkedCount > 0 && result.suspicions.length === 0 && result.gaps.length === 0) {
6282
- console.log(chalk31.green("\n \u2713 \uCCB4\uD06C\uB41C \uC644\uB8CC\uC870\uAC74\uC774 \uBAA8\uB450 \uAC8C\uC774\uD2B8 \uC99D\uAC70\uB85C \uB4B7\uBC1B\uCE68\uB428."));
6554
+ console.log(chalk32.green("\n \u2713 \uCCB4\uD06C\uB41C \uC644\uB8CC\uC870\uAC74\uC774 \uBAA8\uB450 \uAC8C\uC774\uD2B8 \uC99D\uAC70\uB85C \uB4B7\uBC1B\uCE68\uB428."));
6283
6555
  }
6284
6556
  console.log(`
6285
6557
  \uC2E0\uB8B0\uB3C4: ${CONFIDENCE_LABEL[result.confidence]}`);
6286
- console.log(chalk31.yellow(`
6558
+ console.log(chalk32.yellow(`
6287
6559
  ${result.disclaimer}`));
6288
6560
  let mergeOk = false;
6289
6561
  try {
6290
6562
  const merged = { ...report, review: result };
6291
- writeFileSync12(jsonPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
6563
+ writeFileSync13(jsonPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
6292
6564
  mergeOk = true;
6293
- console.log(chalk31.dim(` \u{1F4C4} \uD310\uC815 \uBCD1\uD569: ${REPORT_PATH_REL} (review \uC139\uC158)`));
6565
+ console.log(chalk32.dim(` \u{1F4C4} \uD310\uC815 \uBCD1\uD569: ${REPORT_PATH_REL} (review \uC139\uC158)`));
6294
6566
  } catch (e) {
6295
- console.error(chalk31.red(` \u274C review \uD310\uC815 \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6567
+ console.error(chalk32.red(` \u274C review \uD310\uC815 \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6296
6568
  }
6297
6569
  if (!mergeOk) {
6298
6570
  process.exitCode = 1;
@@ -6313,8 +6585,8 @@ ${result.disclaimer}`));
6313
6585
  cursorHint: "\uC644\uB8CC\uC870\uAC74 \uCC44\uC6CC\uC918"
6314
6586
  });
6315
6587
  } else if (result.suspicions.length > 0) {
6316
- console.log(chalk31.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6317
- console.log(chalk31.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6588
+ console.log(chalk32.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6589
+ console.log(chalk32.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6318
6590
  printNextStep({
6319
6591
  message: "\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC\uC73C\uB85C \uC2E4\uD328(exit 1) \u2014 \uC99D\uAC70 \uBCF4\uAC15 \uD6C4 \uB2E4\uC2DC \uAC80\uC99D\uD558\uC138\uC694:",
6320
6592
  command: "vhk verify",
@@ -6328,8 +6600,8 @@ ${result.disclaimer}`));
6328
6600
  cursorHint: "goal \uC644\uB8CC \uCC98\uB9AC\uD574\uC918"
6329
6601
  });
6330
6602
  } else {
6331
- console.log(chalk31.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6332
- console.log(chalk31.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6603
+ console.log(chalk32.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6604
+ console.log(chalk32.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6333
6605
  printNextStep({
6334
6606
  message: `\uC99D\uAC70 \uBD88\uCDA9\uBD84(\uC2E0\uB8B0\uB3C4 ${result.confidence}) \u2014 goal done \uAE08\uC9C0. \uCEE4\uBC84\uB9AC\uC9C0/\uC2E0\uC120\uB3C4 \uBCF4\uAC15 \uD6C4 \uC7AC\uAC80\uC99D:`,
6335
6607
  command: "vhk verify",
@@ -6339,12 +6611,12 @@ ${result.disclaimer}`));
6339
6611
  }
6340
6612
 
6341
6613
  // src/commands/mission.ts
6342
- import { existsSync as existsSync18, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13, rmSync as rmSync4 } from "fs";
6343
- import { join as join13 } from "path";
6344
- import chalk32 from "chalk";
6614
+ import { existsSync as existsSync19, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, rmSync as rmSync4 } from "fs";
6615
+ import { join as join14 } from "path";
6616
+ import chalk33 from "chalk";
6345
6617
  import inquirer12 from "inquirer";
6346
6618
  import { simpleGit as simpleGit3 } from "simple-git";
6347
- var MISSION_PATH_REL = join13(".vhk", "mission.json");
6619
+ var MISSION_PATH_REL = join14(".vhk", "mission.json");
6348
6620
  var MISSION_SCHEMA_VERSION = 1;
6349
6621
  var MISSION_DISCLAIMER = "\u26A0\uFE0F mission check \uB294 \uACBD\uB85C glob \uAE30\uC900\uC785\uB2C8\uB2E4 \u2014 objective \uC758\uBBF8 \uBD80\uD569\uC740 \uAC80\uC99D\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC2E0\uB8B0\uB3C4 \uC2E0\uD638, \uBCF4\uC7A5 \uC544\uB2D8).";
6350
6622
  function globToRegExp(glob) {
@@ -6392,8 +6664,8 @@ function checkMission(changedFiles, mission) {
6392
6664
  return { violations, warnings, disclaimer: MISSION_DISCLAIMER };
6393
6665
  }
6394
6666
  function readMission(cwd = process.cwd()) {
6395
- const p = join13(cwd, MISSION_PATH_REL);
6396
- if (!existsSync18(p)) return null;
6667
+ const p = join14(cwd, MISSION_PATH_REL);
6668
+ if (!existsSync19(p)) return null;
6397
6669
  try {
6398
6670
  const m = readJsonFile(p);
6399
6671
  if (m && typeof m.objective === "string") return m;
@@ -6403,8 +6675,8 @@ function readMission(cwd = process.cwd()) {
6403
6675
  }
6404
6676
  }
6405
6677
  function writeMission(cwd, mission) {
6406
- mkdirSync12(join13(cwd, ".vhk"), { recursive: true });
6407
- writeFileSync13(join13(cwd, MISSION_PATH_REL), JSON.stringify(mission, null, 2) + "\n", "utf-8");
6678
+ mkdirSync13(join14(cwd, ".vhk"), { recursive: true });
6679
+ writeFileSync14(join14(cwd, MISSION_PATH_REL), JSON.stringify(mission, null, 2) + "\n", "utf-8");
6408
6680
  }
6409
6681
  async function collectChangedFiles(cwd) {
6410
6682
  const status2 = await simpleGit3(cwd).status();
@@ -6425,7 +6697,7 @@ async function missionSet(opts = {}) {
6425
6697
  objective = ans.obj.trim();
6426
6698
  }
6427
6699
  if (!objective) {
6428
- console.error(chalk32.red(' \u274C objective \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. --objective "..." \uB85C \uC9C0\uC815\uD558\uC138\uC694(\uBE44\uB300\uD654\uD615).'));
6700
+ console.error(chalk33.red(' \u274C objective \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. --objective "..." \uB85C \uC9C0\uC815\uD558\uC138\uC694(\uBE44\uB300\uD654\uD615).'));
6429
6701
  process.exitCode = 1;
6430
6702
  return;
6431
6703
  }
@@ -6444,12 +6716,12 @@ async function missionSet(opts = {}) {
6444
6716
  try {
6445
6717
  writeMission(cwd, mission);
6446
6718
  } catch (e) {
6447
- console.error(chalk32.red(` \u274C mission.json \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6719
+ console.error(chalk33.red(` \u274C mission.json \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6448
6720
  process.exitCode = 1;
6449
6721
  return;
6450
6722
  }
6451
- console.log(chalk32.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uC800\uC7A5"));
6452
- console.log(chalk32.dim(` \u{1F4C4} ${MISSION_PATH_REL}`));
6723
+ console.log(chalk33.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uC800\uC7A5"));
6724
+ console.log(chalk33.dim(` \u{1F4C4} ${MISSION_PATH_REL}`));
6453
6725
  console.log(` objective: ${mission.objective}`);
6454
6726
  console.log(` scope: ${mission.scope.length ? mission.scope.join(", ") : "(\uC81C\uD55C \uC5C6\uC74C)"}`);
6455
6727
  console.log(` forbidden: ${mission.forbidden.length ? mission.forbidden.join(", ") : "(\uC5C6\uC74C)"}`);
@@ -6459,64 +6731,64 @@ async function missionShow() {
6459
6731
  const cwd = process.cwd();
6460
6732
  const mission = readMission(cwd);
6461
6733
  if (!mission) {
6462
- console.error(chalk32.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhk/mission.json)."));
6734
+ console.error(chalk33.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhk/mission.json)."));
6463
6735
  printNextStep({ message: "\uBA3C\uC800 \uBBF8\uC158\uC744 \uC120\uC5B8\uD558\uC138\uC694:", command: 'vhk mission set --objective "..."', cursorHint: "\uBBF8\uC158 \uC815\uD574\uC918" });
6464
6736
  process.exitCode = 1;
6465
6737
  return;
6466
6738
  }
6467
- console.log(chalk32.bold("\n\u{1F3AF} \uD604\uC7AC \uBBF8\uC158 \uACC4\uC57D"));
6739
+ console.log(chalk33.bold("\n\u{1F3AF} \uD604\uC7AC \uBBF8\uC158 \uACC4\uC57D"));
6468
6740
  console.log(` objective: ${mission.objective}`);
6469
6741
  console.log(` scope: ${mission.scope.length ? mission.scope.join(", ") : "(\uC81C\uD55C \uC5C6\uC74C)"}`);
6470
6742
  console.log(` forbidden: ${mission.forbidden.length ? mission.forbidden.join(", ") : "(\uC5C6\uC74C)"}`);
6471
- console.log(chalk32.dim(` \uC0DD\uC131 ${mission.createdAt} \xB7 \uAC31\uC2E0 ${mission.updatedAt}`));
6743
+ console.log(chalk33.dim(` \uC0DD\uC131 ${mission.createdAt} \xB7 \uAC31\uC2E0 ${mission.updatedAt}`));
6472
6744
  }
6473
6745
  async function missionCheck() {
6474
6746
  const cwd = process.cwd();
6475
6747
  const mission = readMission(cwd);
6476
6748
  if (!mission) {
6477
- console.error(chalk32.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uBA3C\uC800 vhk mission set \uC73C\uB85C \uC120\uC5B8\uD558\uC138\uC694."));
6749
+ console.error(chalk33.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uBA3C\uC800 vhk mission set \uC73C\uB85C \uC120\uC5B8\uD558\uC138\uC694."));
6478
6750
  process.exitCode = 1;
6479
6751
  return;
6480
6752
  }
6481
6753
  const changed = await collectChangedFiles(cwd);
6482
6754
  const result = checkMission(changed, mission);
6483
- console.log(chalk32.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uAC80\uC99D (mission check)"));
6484
- console.log(chalk32.dim(` objective: ${mission.objective} \xB7 \uBCC0\uACBD \uD30C\uC77C ${changed.length}\uAC1C`));
6755
+ console.log(chalk33.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uAC80\uC99D (mission check)"));
6756
+ console.log(chalk33.dim(` objective: ${mission.objective} \xB7 \uBCC0\uACBD \uD30C\uC77C ${changed.length}\uAC1C`));
6485
6757
  if (result.violations.length > 0) {
6486
- console.log(chalk32.red.bold(`
6758
+ console.log(chalk33.red.bold(`
6487
6759
  \u{1F6AB} forbidden \uC704\uBC18 ${result.violations.length}\uAC74`));
6488
- for (const v of result.violations) console.log(chalk32.red(` \u2717 ${v.file} (\uAE08\uC9C0: ${v.pattern})`));
6760
+ for (const v of result.violations) console.log(chalk33.red(` \u2717 ${v.file} (\uAE08\uC9C0: ${v.pattern})`));
6489
6761
  }
6490
6762
  if (result.warnings.length > 0) {
6491
- console.log(chalk32.yellow.bold(`
6763
+ console.log(chalk33.yellow.bold(`
6492
6764
  \u26A0\uFE0F scope \uBC16 \uBCC0\uACBD ${result.warnings.length}\uAC74 (\uACBD\uACE0)`));
6493
- for (const w of result.warnings) console.log(chalk32.yellow(` ? ${w.file}`));
6765
+ for (const w of result.warnings) console.log(chalk33.yellow(` ? ${w.file}`));
6494
6766
  }
6495
6767
  if (result.violations.length === 0 && result.warnings.length === 0) {
6496
- console.log(chalk32.green("\n \u2713 \uBCC0\uACBD\uC774 \uACC4\uC57D(scope/forbidden) \uC548\uC785\uB2C8\uB2E4."));
6768
+ console.log(chalk33.green("\n \u2713 \uBCC0\uACBD\uC774 \uACC4\uC57D(scope/forbidden) \uC548\uC785\uB2C8\uB2E4."));
6497
6769
  }
6498
- console.log(chalk32.yellow(`
6770
+ console.log(chalk33.yellow(`
6499
6771
  ${result.disclaimer}`));
6500
6772
  process.exitCode = result.violations.length > 0 ? 1 : 0;
6501
6773
  }
6502
6774
  async function missionClear() {
6503
6775
  const cwd = process.cwd();
6504
- const p = join13(cwd, MISSION_PATH_REL);
6505
- if (!existsSync18(p)) {
6506
- console.log(chalk32.dim(" \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC9C0\uC6B8 \uAC83 \uC5C6\uC74C."));
6776
+ const p = join14(cwd, MISSION_PATH_REL);
6777
+ if (!existsSync19(p)) {
6778
+ console.log(chalk33.dim(" \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC9C0\uC6B8 \uAC83 \uC5C6\uC74C."));
6507
6779
  return;
6508
6780
  }
6509
6781
  try {
6510
6782
  rmSync4(p);
6511
- console.log(chalk32.green(" \u2705 \uBBF8\uC158 \uACC4\uC57D \uC0AD\uC81C\uB428 (.vhk/mission.json)."));
6783
+ console.log(chalk33.green(" \u2705 \uBBF8\uC158 \uACC4\uC57D \uC0AD\uC81C\uB428 (.vhk/mission.json)."));
6512
6784
  } catch (e) {
6513
- console.error(chalk32.red(` \u274C \uC0AD\uC81C \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6785
+ console.error(chalk33.red(` \u274C \uC0AD\uC81C \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6514
6786
  process.exitCode = 1;
6515
6787
  }
6516
6788
  }
6517
6789
 
6518
6790
  // src/commands/pattern.ts
6519
- import chalk33 from "chalk";
6791
+ import chalk34 from "chalk";
6520
6792
  var MIN_TAG_FREQ = 3;
6521
6793
  var STOPWORDS = /* @__PURE__ */ new Set(["the", "a", "an", "is", "are", "and", "or", "in", "on", "at", "to", "for", "of", "with", "it", "was", "be"]);
6522
6794
  function tokenize(text) {
@@ -6592,41 +6864,19 @@ function detectCandidates(mem, minFreq) {
6592
6864
  processBucket(mem.successes, "reinforce", (e) => e.content ?? "");
6593
6865
  return candidates.sort((a, b) => b.count - a.count || a.signal.localeCompare(b.signal));
6594
6866
  }
6595
- function nextPatternId(mem) {
6596
- const re = /^p(\d+)$/;
6597
- let max = 0;
6598
- for (const p of mem.patterns) {
6599
- const m = p.id.match(re);
6600
- if (m) max = Math.max(max, Number(m[1]));
6601
- }
6602
- return `p${max + 1}`;
6603
- }
6604
- async function patternDetect(opts = {}) {
6605
- const minFreq = opts.min !== void 0 ? parseInt(opts.min, 10) : MIN_TAG_FREQ;
6606
- if (!Number.isFinite(minFreq) || minFreq < 1) {
6607
- console.log(chalk33.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
6608
- process.exitCode = 1;
6609
- return;
6610
- }
6611
- const cwd = process.cwd();
6612
- const loaded = loadForMutation(cwd);
6613
- if (!loaded.ok) {
6614
- console.log(chalk33.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAC10\uC9C0 \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874). \uBC31\uC5C5 \uD655\uC778 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694."));
6615
- process.exitCode = 1;
6616
- return;
6867
+ function reconcilePatterns(patterns, candidates, now) {
6868
+ let added = 0;
6869
+ let updated = 0;
6870
+ let maxId = 0;
6871
+ for (const p of patterns) {
6872
+ const m = p.id.match(/^p(\d+)$/);
6873
+ if (m) maxId = Math.max(maxId, Number(m[1]));
6617
6874
  }
6618
- const mem = loaded.mem;
6619
- const candidates = detectCandidates(mem, minFreq);
6620
- const now = (/* @__PURE__ */ new Date()).toISOString();
6621
- let added = 0, updated = 0;
6622
6875
  for (const c of candidates) {
6623
6876
  const sig = sigOf(c.kind, c.axis, c.signal);
6624
- const existing = mem.patterns.find((p) => {
6625
- const pp = p;
6626
- const sigMatch = pp._sig === sig;
6627
- const fieldMatch = pp.kind === c.kind && pp.axis === c.axis && pp.signal === c.signal;
6628
- return (sigMatch || fieldMatch) && pp.status !== "archived";
6629
- });
6877
+ const matches = (pp) => pp._sig === sig || pp.kind === c.kind && pp.axis === c.axis && pp.signal === c.signal;
6878
+ if (patterns.some((p) => matches(p) && p.status === "archived")) continue;
6879
+ const existing = patterns.find((p) => matches(p) && p.status !== "archived");
6630
6880
  if (existing) {
6631
6881
  existing._sig = sig;
6632
6882
  existing.count = c.count;
@@ -6635,8 +6885,8 @@ async function patternDetect(opts = {}) {
6635
6885
  existing.tags = c.sourceTags;
6636
6886
  updated++;
6637
6887
  } else {
6638
- const entry = {
6639
- id: nextPatternId(mem),
6888
+ patterns.push({
6889
+ id: `p${++maxId}`,
6640
6890
  kind: c.kind,
6641
6891
  axis: c.axis,
6642
6892
  signal: c.signal,
@@ -6647,11 +6897,30 @@ async function patternDetect(opts = {}) {
6647
6897
  status: "active",
6648
6898
  tags: c.sourceTags,
6649
6899
  _sig: sig
6650
- };
6651
- mem.patterns.push(entry);
6900
+ });
6652
6901
  added++;
6653
6902
  }
6654
6903
  }
6904
+ return { added, updated };
6905
+ }
6906
+ async function patternDetect(opts = {}) {
6907
+ const minFreq = opts.min !== void 0 ? parseInt(opts.min, 10) : MIN_TAG_FREQ;
6908
+ if (!Number.isFinite(minFreq) || minFreq < 1) {
6909
+ console.log(chalk34.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
6910
+ process.exitCode = 1;
6911
+ return;
6912
+ }
6913
+ const cwd = process.cwd();
6914
+ const loaded = loadForMutation(cwd);
6915
+ if (!loaded.ok) {
6916
+ console.log(chalk34.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAC10\uC9C0 \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874). \uBC31\uC5C5 \uD655\uC778 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694."));
6917
+ process.exitCode = 1;
6918
+ return;
6919
+ }
6920
+ const mem = loaded.mem;
6921
+ const candidates = detectCandidates(mem, minFreq);
6922
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6923
+ const { added, updated } = reconcilePatterns(mem.patterns, candidates, now);
6655
6924
  if (added > 0 || updated > 0) {
6656
6925
  writeMemory(cwd, mem);
6657
6926
  }
@@ -6660,26 +6929,26 @@ async function patternDetect(opts = {}) {
6660
6929
  console.log(JSON.stringify(active2, null, 2));
6661
6930
  return;
6662
6931
  }
6663
- console.log(chalk33.bold("\n\u{1F50D} " + t("pattern.detectTitle")));
6664
- console.log(chalk33.gray("\u2500".repeat(40)));
6665
- console.log(chalk33.dim(` \uC784\uACC4: ${minFreq}\uD68C \uC774\uC0C1 \xB7 active failures+successes \uC785\uB825`));
6666
- console.log(chalk33.dim(` \uD6C4\uBCF4: ${candidates.length}\uAC1C \uAC10\uC9C0 (\uCD94\uAC00 ${added} / \uAC31\uC2E0 ${updated})`));
6932
+ console.log(chalk34.bold("\n\u{1F50D} " + t("pattern.detectTitle")));
6933
+ console.log(chalk34.gray("\u2500".repeat(40)));
6934
+ console.log(chalk34.dim(` \uC784\uACC4: ${minFreq}\uD68C \uC774\uC0C1 \xB7 active failures+successes \uC785\uB825`));
6935
+ console.log(chalk34.dim(` \uD6C4\uBCF4: ${candidates.length}\uAC1C \uAC10\uC9C0 (\uCD94\uAC00 ${added} / \uAC31\uC2E0 ${updated})`));
6667
6936
  const active = mem.patterns.filter((p) => p.status !== "archived");
6668
6937
  if (active.length === 0) {
6669
- console.log(chalk33.yellow("\n\u{1F4ED} \uC784\uACC4 \uC774\uC0C1 \uBC18\uBCF5 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6670
- console.log(chalk33.gray(` failures/successes \uAC00 ${minFreq}\uAC1C \uC774\uC0C1 \uC313\uC774\uBA74 \uAC10\uC9C0\uB429\uB2C8\uB2E4.`));
6671
- console.log(chalk33.gray(" --min N \uC73C\uB85C \uC784\uACC4\uB97C \uB0AE\uCD9C \uC218 \uC788\uC2B5\uB2C8\uB2E4."));
6938
+ console.log(chalk34.yellow("\n\u{1F4ED} \uC784\uACC4 \uC774\uC0C1 \uBC18\uBCF5 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6939
+ console.log(chalk34.gray(` failures/successes \uAC00 ${minFreq}\uAC1C \uC774\uC0C1 \uC313\uC774\uBA74 \uAC10\uC9C0\uB429\uB2C8\uB2E4.`));
6940
+ console.log(chalk34.gray(" --min N \uC73C\uB85C \uC784\uACC4\uB97C \uB0AE\uCD9C \uC218 \uC788\uC2B5\uB2C8\uB2E4."));
6672
6941
  return;
6673
6942
  }
6674
- console.log(chalk33.cyan(`
6943
+ console.log(chalk34.cyan(`
6675
6944
  \uD328\uD134 \uD6C4\uBCF4 ${active.length}\uAC1C:
6676
6945
  `));
6677
6946
  for (const p of active.slice(0, 20)) {
6678
6947
  const icon = p.kind === "avoid" ? "\u26A0\uFE0F " : "\u2705";
6679
6948
  console.log(` [${p.id}] ${icon} (${p.kind}/${p.axis}) "${p.signal}" \u2014 ${p.count}\uAC74`);
6680
6949
  const preview = p.sources.slice(0, 5).join(", ") + (p.sources.length > 5 ? ` \uC678 ${p.sources.length - 5}\uAC74` : "");
6681
- console.log(chalk33.dim(` \uADFC\uAC70: ${preview}`));
6682
- console.log(chalk33.dim(` ${p.summary}`));
6950
+ console.log(chalk34.dim(` \uADFC\uAC70: ${preview}`));
6951
+ console.log(chalk34.dim(` ${p.summary}`));
6683
6952
  }
6684
6953
  printNextStep({
6685
6954
  message: `\uD328\uD134 \uAC10\uC9C0 \uC644\uB8CC! ${active.length}\uAC1C \uD6C4\uBCF4.`,
@@ -6689,8 +6958,8 @@ async function patternDetect(opts = {}) {
6689
6958
  });
6690
6959
  }
6691
6960
  async function patternList(opts = {}) {
6692
- console.log(chalk33.bold("\n\u{1F50D} " + t("pattern.listTitle")));
6693
- console.log(chalk33.gray("\u2500".repeat(40)));
6961
+ console.log(chalk34.bold("\n\u{1F50D} " + t("pattern.listTitle")));
6962
+ console.log(chalk34.gray("\u2500".repeat(40)));
6694
6963
  const mem = readMemory(process.cwd());
6695
6964
  let patterns = mem.patterns;
6696
6965
  if (!opts.all) patterns = patterns.filter((p) => p.status !== "archived");
@@ -6702,51 +6971,51 @@ async function patternList(opts = {}) {
6702
6971
  return;
6703
6972
  }
6704
6973
  if (patterns.length === 0) {
6705
- console.log(chalk33.yellow("\n\u{1F4ED} \uD45C\uC2DC\uD560 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6706
- console.log(chalk33.gray(" vhk pattern detect \uB85C \uAC10\uC9C0 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
6974
+ console.log(chalk34.yellow("\n\u{1F4ED} \uD45C\uC2DC\uD560 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6975
+ console.log(chalk34.gray(" vhk pattern detect \uB85C \uAC10\uC9C0 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
6707
6976
  return;
6708
6977
  }
6709
- console.log(chalk33.cyan(`
6978
+ console.log(chalk34.cyan(`
6710
6979
  ${patterns.length}\uAC1C${opts.all ? " (\uBCF4\uAD00 \uD3EC\uD568)" : " (\uD65C\uC131)"}:
6711
6980
  `));
6712
6981
  for (const p of patterns) {
6713
6982
  const icon = p.kind === "avoid" ? "\u26A0\uFE0F " : "\u2705";
6714
6983
  const archived = p.status === "archived" ? "\u{1F4E6} " : "";
6715
6984
  console.log(` [${p.id}] ${archived}${icon} (${p.kind}/${p.axis}) "${p.signal}" \u2014 ${p.count}\uAC74`);
6716
- if (p.summary) console.log(chalk33.dim(` ${p.summary}`));
6717
- if (p.tags?.length) console.log(chalk33.blue(` \u{1F3F7}\uFE0F ${p.tags.join(", ")}`));
6985
+ if (p.summary) console.log(chalk34.dim(` ${p.summary}`));
6986
+ if (p.tags?.length) console.log(chalk34.blue(` \u{1F3F7}\uFE0F ${p.tags.join(", ")}`));
6718
6987
  }
6719
6988
  }
6720
6989
  async function patternDismiss(idStr) {
6721
6990
  if (!idStr?.trim()) {
6722
- console.log(chalk33.red("\u274C \uD328\uD134 id \uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608: vhk pattern dismiss p1"));
6991
+ console.log(chalk34.red("\u274C \uD328\uD134 id \uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608: vhk pattern dismiss p1"));
6723
6992
  process.exitCode = 1;
6724
6993
  return;
6725
6994
  }
6726
6995
  const cwd = process.cwd();
6727
6996
  const loaded = loadForMutation(cwd);
6728
6997
  if (!loaded.ok) {
6729
- console.log(chalk33.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 dismiss \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6998
+ console.log(chalk34.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 dismiss \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6730
6999
  process.exitCode = 1;
6731
7000
  return;
6732
7001
  }
6733
7002
  const mem = loaded.mem;
6734
7003
  const pattern = mem.patterns.find((p) => p.id === idStr.trim());
6735
7004
  if (!pattern) {
6736
- console.log(chalk33.red(`\u274C \uD328\uD134 '${idStr}' \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`));
6737
- console.log(chalk33.gray(" vhk pattern list --all \uB85C \uBAA9\uB85D \uD655\uC778."));
7005
+ console.log(chalk34.red(`\u274C \uD328\uD134 '${idStr}' \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`));
7006
+ console.log(chalk34.gray(" vhk pattern list --all \uB85C \uBAA9\uB85D \uD655\uC778."));
6738
7007
  process.exitCode = 1;
6739
7008
  return;
6740
7009
  }
6741
7010
  if (pattern.status === "archived") {
6742
- console.log(chalk33.dim(` \uC774\uBBF8 \uBCF4\uAD00\uB41C \uD328\uD134\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${pattern.id}`));
7011
+ console.log(chalk34.dim(` \uC774\uBBF8 \uBCF4\uAD00\uB41C \uD328\uD134\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${pattern.id}`));
6743
7012
  return;
6744
7013
  }
6745
7014
  pattern.status = "archived";
6746
7015
  writeMemory(cwd, mem);
6747
- console.log(chalk33.green(`
7016
+ console.log(chalk34.green(`
6748
7017
  \u{1F4E6} \uD328\uD134 dismiss(\uBCF4\uAD00)\uB428: [${pattern.id}] ${pattern.summary ?? pattern.signal}`));
6749
- console.log(chalk33.dim(" \uC624\uD0D0\uC73C\uB85C \uD310\uB2E8. detect \uC7AC\uC2E4\uD589 \uC2DC \uC7AC\uC81C\uC548 \uC548 \uB428."));
7018
+ console.log(chalk34.dim(" \uC624\uD0D0\uC73C\uB85C \uD310\uB2E8. detect \uC7AC\uC2E4\uD589 \uC2DC \uC7AC\uC81C\uC548 \uC548 \uB428."));
6750
7019
  printNextStep({
6751
7020
  message: "\uD328\uD134 dismiss \uC644\uB8CC!",
6752
7021
  command: "vhk pattern list",
@@ -6755,11 +7024,11 @@ async function patternDismiss(idStr) {
6755
7024
  }
6756
7025
 
6757
7026
  // src/commands/evolve.ts
6758
- import { existsSync as existsSync19, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync7, copyFileSync as copyFileSync2, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
6759
- import { join as join14 } from "path";
6760
- import chalk34 from "chalk";
7027
+ import { existsSync as existsSync20, mkdirSync as mkdirSync14, writeFileSync as writeFileSync15, readFileSync as readFileSync8, copyFileSync as copyFileSync2, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
7028
+ import { join as join15 } from "path";
7029
+ import chalk35 from "chalk";
6761
7030
  import inquirer13 from "inquirer";
6762
- var QUEUE_PATH_REL = join14(".vhk", "evolve", "queue.json");
7031
+ var QUEUE_PATH_REL = join15(".vhk", "evolve", "queue.json");
6763
7032
  function buildDraft(p) {
6764
7033
  const axisLabel = p.axis === "tag" ? `\uD0DC\uADF8 '${p.signal}'` : `\uD0A4\uC6CC\uB4DC '${p.signal}'`;
6765
7034
  const countDesc = `${p.count}\uAC74 \uBC18\uBCF5`;
@@ -6803,10 +7072,10 @@ function stripBomStr(s) {
6803
7072
  return s.charCodeAt(0) === 65279 ? s.slice(1) : s;
6804
7073
  }
6805
7074
  function readQueue(cwd) {
6806
- const p = join14(cwd, QUEUE_PATH_REL);
6807
- if (!existsSync19(p)) return { version: 1, items: [] };
7075
+ const p = join15(cwd, QUEUE_PATH_REL);
7076
+ if (!existsSync20(p)) return { version: 1, items: [] };
6808
7077
  try {
6809
- const raw = stripBomStr(readFileSync7(p, "utf-8"));
7078
+ const raw = stripBomStr(readFileSync8(p, "utf-8"));
6810
7079
  const parsed = JSON.parse(raw);
6811
7080
  if (!parsed || !Array.isArray(parsed.items)) return { version: 1, items: [] };
6812
7081
  return parsed;
@@ -6815,10 +7084,10 @@ function readQueue(cwd) {
6815
7084
  }
6816
7085
  }
6817
7086
  function writeQueue(cwd, queue) {
6818
- const p = join14(cwd, QUEUE_PATH_REL);
6819
- mkdirSync13(join14(cwd, ".vhk", "evolve"), { recursive: true });
7087
+ const p = join15(cwd, QUEUE_PATH_REL);
7088
+ mkdirSync14(join15(cwd, ".vhk", "evolve"), { recursive: true });
6820
7089
  const tmpPath = p + ".tmp";
6821
- writeFileSync14(tmpPath, JSON.stringify(queue, null, 2) + "\n", "utf-8");
7090
+ writeFileSync15(tmpPath, JSON.stringify(queue, null, 2) + "\n", "utf-8");
6822
7091
  try {
6823
7092
  renameSync2(tmpPath, p);
6824
7093
  } catch (err) {
@@ -6847,8 +7116,8 @@ function checkApplyRef(pattern, queueItems) {
6847
7116
  }
6848
7117
  async function evolveSuggest(opts = {}) {
6849
7118
  const cwd = process.cwd();
6850
- if (!existsSync19(join14(cwd, "RULES.md"))) {
6851
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.noRules")));
7119
+ if (!existsSync20(join15(cwd, "RULES.md"))) {
7120
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.noRules")));
6852
7121
  process.exitCode = 1;
6853
7122
  return;
6854
7123
  }
@@ -6859,10 +7128,10 @@ async function evolveSuggest(opts = {}) {
6859
7128
  if (newItems.length === 0 && !opts.json) {
6860
7129
  const activeAvoid = patterns.filter((p) => p.kind === "avoid" && p.status === "active");
6861
7130
  if (activeAvoid.length === 0) {
6862
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noPatterns")));
7131
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noPatterns")));
6863
7132
  return;
6864
7133
  }
6865
- console.log(chalk34.dim("\n " + t("evolve.allSuggested")));
7134
+ console.log(chalk35.dim("\n " + t("evolve.allSuggested")));
6866
7135
  return;
6867
7136
  }
6868
7137
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -6875,16 +7144,16 @@ async function evolveSuggest(opts = {}) {
6875
7144
  console.log(JSON.stringify(pending2, null, 2));
6876
7145
  return;
6877
7146
  }
6878
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.suggestTitle")));
6879
- console.log(chalk34.gray("\u2500".repeat(40)));
6880
- console.log(chalk34.dim(" " + t("evolve.newCandidates", newItems.length)));
7147
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.suggestTitle")));
7148
+ console.log(chalk35.gray("\u2500".repeat(40)));
7149
+ console.log(chalk35.dim(" " + t("evolve.newCandidates", newItems.length)));
6881
7150
  const pending = queue.items.filter((i) => i.status === "pending");
6882
- console.log(chalk34.cyan(`
7151
+ console.log(chalk35.cyan(`
6883
7152
  \uD6C4\uBCF4 ${pending.length}\uAC1C:
6884
7153
  `));
6885
7154
  for (const item of pending) {
6886
7155
  console.log(` [${item.id}] (${item.status}) \uD328\uD134 ${item.patternId} \u2192 rule`);
6887
- console.log(chalk34.dim(` \uCD08\uC548: ${item.draft}`));
7156
+ console.log(chalk35.dim(` \uCD08\uC548: ${item.draft}`));
6888
7157
  }
6889
7158
  printNextStep({
6890
7159
  message: `\uC9C4\uD654 \uD6C4\uBCF4 ${pending.length}\uAC1C \uC0DD\uC131\uB428!`,
@@ -6905,11 +7174,11 @@ async function evolveList(opts = {}) {
6905
7174
  console.log(JSON.stringify(items, null, 2));
6906
7175
  return;
6907
7176
  }
6908
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.listTitle")));
6909
- console.log(chalk34.gray("\u2500".repeat(40)));
7177
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.listTitle")));
7178
+ console.log(chalk35.gray("\u2500".repeat(40)));
6910
7179
  if (items.length === 0) {
6911
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noQueue")));
6912
- console.log(chalk34.gray(" " + t("evolve.suggestHint")));
7180
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noQueue")));
7181
+ console.log(chalk35.gray(" " + t("evolve.suggestHint")));
6913
7182
  return;
6914
7183
  }
6915
7184
  const STATUS_ICON3 = {
@@ -6917,68 +7186,68 @@ async function evolveList(opts = {}) {
6917
7186
  rejected: "\u274C",
6918
7187
  applied: "\u2705"
6919
7188
  };
6920
- console.log(chalk34.cyan(`
7189
+ console.log(chalk35.cyan(`
6921
7190
  ${items.length}\uAC1C:
6922
7191
  `));
6923
7192
  for (const item of items) {
6924
7193
  console.log(` [${item.id}] ${STATUS_ICON3[item.status]} (${item.status}) \u2192 ${item.draft}`);
6925
- if (item.appliedAt) console.log(chalk34.dim(` \uBC18\uC601: ${item.appliedAt}`));
7194
+ if (item.appliedAt) console.log(chalk35.dim(` \uBC18\uC601: ${item.appliedAt}`));
6926
7195
  }
6927
7196
  }
6928
7197
  async function evolveApply(idStr) {
6929
7198
  if (!ensureInteractive("apply\uB294 TTY \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694.")) return;
6930
7199
  const cwd = process.cwd();
6931
- const rulesPath = join14(cwd, "RULES.md");
6932
- if (!existsSync19(rulesPath)) {
6933
- console.log(chalk34.red("\n\u274C " + t("evolve.noRules")));
7200
+ const rulesPath = join15(cwd, "RULES.md");
7201
+ if (!existsSync20(rulesPath)) {
7202
+ console.log(chalk35.red("\n\u274C " + t("evolve.noRules")));
6934
7203
  process.exitCode = 1;
6935
7204
  return;
6936
7205
  }
6937
7206
  const queue = readQueue(cwd);
6938
7207
  const item = queue.items.find((i) => i.id === idStr?.trim());
6939
7208
  if (!item) {
6940
- console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7209
+ console.log(chalk35.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
6941
7210
  process.exitCode = 1;
6942
7211
  return;
6943
7212
  }
6944
7213
  if (item.status === "applied") {
6945
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.alreadyApplied")));
7214
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.alreadyApplied")));
6946
7215
  process.exitCode = 1;
6947
7216
  return;
6948
7217
  }
6949
7218
  const hasUnresolved = queue.items.some((i) => i.status === "applied");
6950
7219
  if (hasUnresolved) {
6951
- console.log(chalk34.red("\n\u274C " + t("evolve.pendingApplyExists")));
7220
+ console.log(chalk35.red("\n\u274C " + t("evolve.pendingApplyExists")));
6952
7221
  process.exitCode = 1;
6953
7222
  return;
6954
7223
  }
6955
7224
  const memLoaded = loadForMutation(cwd);
6956
7225
  if (!memLoaded.ok) {
6957
- console.log(chalk34.red("\n\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 apply \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
7226
+ console.log(chalk35.red("\n\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 apply \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6958
7227
  process.exitCode = 1;
6959
7228
  return;
6960
7229
  }
6961
7230
  const srcPattern = memLoaded.mem.patterns.find((p) => p.id === item.patternId);
6962
7231
  const refResult = checkApplyRef(srcPattern, queue.items);
6963
7232
  if (refResult === "dismissed") {
6964
- console.log(chalk34.red("\n\u274C " + t("evolve.dismissed")));
7233
+ console.log(chalk35.red("\n\u274C " + t("evolve.dismissed")));
6965
7234
  process.exitCode = 1;
6966
7235
  return;
6967
7236
  }
6968
7237
  if (refResult === "already-applied") {
6969
- console.log(chalk34.red("\n\u274C " + t("evolve.alreadyAppliedPattern")));
7238
+ console.log(chalk35.red("\n\u274C " + t("evolve.alreadyAppliedPattern")));
6970
7239
  process.exitCode = 1;
6971
7240
  return;
6972
7241
  }
6973
- const rulesContent = readFileSync7(rulesPath, "utf-8");
7242
+ const rulesContent = readFileSync8(rulesPath, "utf-8");
6974
7243
  if (isDuplicateRule(rulesContent, item.draft)) {
6975
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.duplicateRule", item.draft)));
7244
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.duplicateRule", item.draft)));
6976
7245
  return;
6977
7246
  }
6978
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.applyTitle")));
6979
- console.log(chalk34.gray("\u2500".repeat(40)));
6980
- console.log(chalk34.cyan("\n\uCD94\uAC00\uB420 \uB8F0 \uCD08\uC548:"));
6981
- console.log(chalk34.white(` ${item.draft}`));
7247
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.applyTitle")));
7248
+ console.log(chalk35.gray("\u2500".repeat(40)));
7249
+ console.log(chalk35.cyan("\n\uCD94\uAC00\uB420 \uB8F0 \uCD08\uC548:"));
7250
+ console.log(chalk35.white(` ${item.draft}`));
6982
7251
  const { editedDraft } = await inquirer13.prompt([{
6983
7252
  type: "input",
6984
7253
  name: "editedDraft",
@@ -6993,22 +7262,22 @@ async function evolveApply(idStr) {
6993
7262
  default: false
6994
7263
  }]);
6995
7264
  if (!confirmed) {
6996
- console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
7265
+ console.log(chalk35.dim(" \uCDE8\uC18C\uB428."));
6997
7266
  return;
6998
7267
  }
6999
7268
  const backupPath = rulesPath + ".bak";
7000
7269
  copyFileSync2(rulesPath, backupPath);
7001
7270
  const appendContent = "\n" + editedDraft + "\n";
7002
7271
  try {
7003
- writeFileSync14(rulesPath, rulesContent + appendContent, "utf-8");
7272
+ writeFileSync15(rulesPath, rulesContent + appendContent, "utf-8");
7004
7273
  await sync({ yes: true });
7005
7274
  } catch (err) {
7006
7275
  try {
7007
7276
  copyFileSync2(backupPath, rulesPath);
7008
7277
  } catch {
7009
7278
  }
7010
- console.error(chalk34.red("\n\u274C RULES.md \uBC18\uC601 \uC911 \uC624\uB958 \u2014 \uC6D0\uBCF8 \uBCF5\uC6D0\uB428. \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7011
- console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7279
+ console.error(chalk35.red("\n\u274C RULES.md \uBC18\uC601 \uC911 \uC624\uB958 \u2014 \uC6D0\uBCF8 \uBCF5\uC6D0\uB428. \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7280
+ console.error(chalk35.dim(` ${err instanceof Error ? err.message : String(err)}`));
7012
7281
  process.exitCode = 1;
7013
7282
  return;
7014
7283
  }
@@ -7024,12 +7293,12 @@ async function evolveApply(idStr) {
7024
7293
  p.status = "archived";
7025
7294
  writeMemory(cwd, memLoaded.mem);
7026
7295
  } else {
7027
- console.error(chalk34.yellow(" \u26A0\uFE0F \uC18C\uC2A4 \uD328\uD134 archived \uCC98\uB9AC \uC2E4\uD328 (memory.json \uC190\uC0C1 \uC758\uC2EC). \uB8F0\uC740 \uBC18\uC601\uB410\uC2B5\uB2C8\uB2E4."));
7296
+ console.error(chalk35.yellow(" \u26A0\uFE0F \uC18C\uC2A4 \uD328\uD134 archived \uCC98\uB9AC \uC2E4\uD328 (memory.json \uC190\uC0C1 \uC758\uC2EC). \uB8F0\uC740 \uBC18\uC601\uB410\uC2B5\uB2C8\uB2E4."));
7028
7297
  }
7029
7298
  }
7030
- console.log(chalk34.green(`
7299
+ console.log(chalk35.green(`
7031
7300
  \u2705 \uB8F0 \uBC18\uC601 \uC644\uB8CC! [${item.id}]`));
7032
- console.log(chalk34.dim(" RULES.md\uC5D0 \uCD94\uAC00 + vhk sync \uC7AC\uC0DD\uC131\uB428"));
7301
+ console.log(chalk35.dim(" RULES.md\uC5D0 \uCD94\uAC00 + vhk sync \uC7AC\uC0DD\uC131\uB428"));
7033
7302
  printNextStep({
7034
7303
  message: "\uB8F0 \uBC18\uC601 \uC644\uB8CC!",
7035
7304
  command: "vhk evolve list --status applied",
@@ -7042,25 +7311,25 @@ async function evolveReject(idStr) {
7042
7311
  const queue = readQueue(cwd);
7043
7312
  const item = queue.items.find((i) => i.id === idStr?.trim());
7044
7313
  if (!item) {
7045
- console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7314
+ console.log(chalk35.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7046
7315
  process.exitCode = 1;
7047
7316
  return;
7048
7317
  }
7049
7318
  if (item.status === "rejected") {
7050
- console.log(chalk34.dim(` \uC774\uBBF8 \uAE30\uAC01\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${item.id}`));
7319
+ console.log(chalk35.dim(` \uC774\uBBF8 \uAE30\uAC01\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${item.id}`));
7051
7320
  return;
7052
7321
  }
7053
7322
  if (item.status === "applied") {
7054
- console.log(chalk34.red(`
7323
+ console.log(chalk35.red(`
7055
7324
  \u274C \uC774\uBBF8 \uBC18\uC601\uB41C \uD56D\uBAA9\uC740 \uAE30\uAC01\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 vhk evolve undo \uB85C \uB418\uB3CC\uB9AC\uC138\uC694: ${item.id}`));
7056
7325
  process.exitCode = 1;
7057
7326
  return;
7058
7327
  }
7059
7328
  item.status = "rejected";
7060
7329
  writeQueue(cwd, queue);
7061
- console.log(chalk34.green(`
7330
+ console.log(chalk35.green(`
7062
7331
  \u274C \uD6C4\uBCF4 \uAE30\uAC01\uB428: [${item.id}] ${item.draft}`));
7063
- console.log(chalk34.dim(" (A1: \uB2E4\uC74C suggest\uC5D0\uC11C \uC7AC\uC81C\uC548 \uC548 \uB428)"));
7332
+ console.log(chalk35.dim(" (A1: \uB2E4\uC74C suggest\uC5D0\uC11C \uC7AC\uC81C\uC548 \uC548 \uB428)"));
7064
7333
  printNextStep({
7065
7334
  message: "\uAE30\uAC01 \uC644\uB8CC!",
7066
7335
  command: "vhk evolve list",
@@ -7073,19 +7342,19 @@ async function evolveUndo() {
7073
7342
  const queue = readQueue(cwd);
7074
7343
  const applied = queue.items.filter((i) => i.status === "applied");
7075
7344
  if (applied.length === 0) {
7076
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noAppliedToUndo")));
7345
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noAppliedToUndo")));
7077
7346
  return;
7078
7347
  }
7079
7348
  const last = applied.sort(
7080
7349
  (a, b) => (b.appliedAt ?? "").localeCompare(a.appliedAt ?? "")
7081
7350
  )[0];
7082
- if (!last.rulesBackupPath || !existsSync19(last.rulesBackupPath)) {
7083
- console.log(chalk34.red("\n\u274C " + t("evolve.noBackup")));
7351
+ if (!last.rulesBackupPath || !existsSync20(last.rulesBackupPath)) {
7352
+ console.log(chalk35.red("\n\u274C " + t("evolve.noBackup")));
7084
7353
  process.exitCode = 1;
7085
7354
  return;
7086
7355
  }
7087
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.undoTitle")));
7088
- console.log(chalk34.dim(` \uB418\uB3CC\uB9B4 \uD56D\uBAA9: [${last.id}] ${last.draft}`));
7356
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.undoTitle")));
7357
+ console.log(chalk35.dim(` \uB418\uB3CC\uB9B4 \uD56D\uBAA9: [${last.id}] ${last.draft}`));
7089
7358
  const { confirmed } = await inquirer13.prompt([{
7090
7359
  type: "confirm",
7091
7360
  name: "confirmed",
@@ -7093,16 +7362,16 @@ async function evolveUndo() {
7093
7362
  default: false
7094
7363
  }]);
7095
7364
  if (!confirmed) {
7096
- console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
7365
+ console.log(chalk35.dim(" \uCDE8\uC18C\uB428."));
7097
7366
  return;
7098
7367
  }
7099
- copyFileSync2(last.rulesBackupPath, join14(cwd, "RULES.md"));
7368
+ copyFileSync2(last.rulesBackupPath, join15(cwd, "RULES.md"));
7100
7369
  try {
7101
7370
  await sync({ yes: true });
7102
7371
  } catch (err) {
7103
- console.error(chalk34.red("\n\u274C sync \uC7AC\uC2E4\uD589 \uC911 \uC624\uB958. RULES.md\uB294 \uBCF5\uC6D0\uB410\uC73C\uB098 .cursorrules \uB4F1 \uC7AC\uC0DD\uC131 \uC2E4\uD328."));
7104
- console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7105
- console.error(chalk34.dim(" \uC218\uB3D9\uC73C\uB85C `vhk sync` \uC2E4\uD589\uD558\uC138\uC694."));
7372
+ console.error(chalk35.red("\n\u274C sync \uC7AC\uC2E4\uD589 \uC911 \uC624\uB958. RULES.md\uB294 \uBCF5\uC6D0\uB410\uC73C\uB098 .cursorrules \uB4F1 \uC7AC\uC0DD\uC131 \uC2E4\uD328."));
7373
+ console.error(chalk35.dim(` ${err instanceof Error ? err.message : String(err)}`));
7374
+ console.error(chalk35.dim(" \uC218\uB3D9\uC73C\uB85C `vhk sync` \uC2E4\uD589\uD558\uC138\uC694."));
7106
7375
  }
7107
7376
  last.status = "pending";
7108
7377
  delete last.appliedAt;
@@ -7116,7 +7385,7 @@ async function evolveUndo() {
7116
7385
  writeMemory(cwd, memLoaded.mem);
7117
7386
  }
7118
7387
  }
7119
- console.log(chalk34.green("\n\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC! RULES.md \uBCF5\uC6D0 + sync \uC7AC\uC2E4\uD589\uB428"));
7388
+ console.log(chalk35.green("\n\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC! RULES.md \uBCF5\uC6D0 + sync \uC7AC\uC2E4\uD589\uB428"));
7120
7389
  printNextStep({
7121
7390
  message: "\uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC!",
7122
7391
  command: "vhk evolve list",
@@ -7298,6 +7567,10 @@ async function dispatchNlpRoute(route, input) {
7298
7567
  return patternList();
7299
7568
  case "evolve":
7300
7569
  return evolveList();
7570
+ case "work": {
7571
+ if (route.args?.[0] === "handoff") return workHandoff();
7572
+ return work();
7573
+ }
7301
7574
  }
7302
7575
  }
7303
7576
  var STATE_CHANGING_COMMANDS = /* @__PURE__ */ new Set([
@@ -7311,14 +7584,14 @@ function requiresConfirmation(route) {
7311
7584
  async function runNaturalLanguageRoute(input) {
7312
7585
  const route = routeNaturalLanguage(input);
7313
7586
  if (!route) {
7314
- console.log(chalk35.yellow(`
7587
+ console.log(chalk36.yellow(`
7315
7588
  \u2753 "${input}" \u2014 ${ko.nlp.notMatched}
7316
7589
  `));
7317
7590
  return;
7318
7591
  }
7319
7592
  console.log("");
7320
- console.log(chalk35.cyan(` \u{1F4AC} "${input}"`));
7321
- console.log(chalk35.cyan(` \u2192 ${route.explanation}`));
7593
+ console.log(chalk36.cyan(` \u{1F4AC} "${input}"`));
7594
+ console.log(chalk36.cyan(` \u2192 ${route.explanation}`));
7322
7595
  if (requiresConfirmation(route)) {
7323
7596
  const { confirm } = await inquirer14.prompt([{
7324
7597
  type: "confirm",
@@ -7327,7 +7600,7 @@ async function runNaturalLanguageRoute(input) {
7327
7600
  default: true
7328
7601
  }]);
7329
7602
  if (!confirm) {
7330
- console.log(chalk35.dim(` ${ko.nlp.menuHint}`));
7603
+ console.log(chalk36.dim(` ${ko.nlp.menuHint}`));
7331
7604
  return;
7332
7605
  }
7333
7606
  }
@@ -7336,7 +7609,7 @@ async function runNaturalLanguageRoute(input) {
7336
7609
  if (riskAction) {
7337
7610
  await runGuarded(
7338
7611
  riskAction,
7339
- { channel: "nl", approved: false, log: (m) => console.log(chalk35.yellow(` ${m}`)) },
7612
+ { channel: "nl", approved: false, log: (m) => console.log(chalk36.yellow(` ${m}`)) },
7340
7613
  () => dispatchNlpRoute(route, input)
7341
7614
  );
7342
7615
  return;
@@ -7345,80 +7618,80 @@ async function runNaturalLanguageRoute(input) {
7345
7618
  }
7346
7619
 
7347
7620
  // src/commands/agent.ts
7348
- import chalk36 from "chalk";
7621
+ import chalk37 from "chalk";
7349
7622
  function activeGoalId() {
7350
7623
  const goals = listGoals("goals");
7351
7624
  const id = selectActiveId(goals);
7352
7625
  return id ?? void 0;
7353
7626
  }
7354
7627
  async function blocker(description) {
7355
- console.log(chalk36.bold(`
7628
+ console.log(chalk37.bold(`
7356
7629
  ${ko.agent.blockerTitle}
7357
7630
  `));
7358
7631
  if (!description || !description.trim()) {
7359
- console.log(chalk36.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7360
- console.log(chalk36.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
7632
+ console.log(chalk37.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7633
+ console.log(chalk37.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
7361
7634
  process.exitCode = 1;
7362
7635
  return;
7363
7636
  }
7364
7637
  const goalId = activeGoalId();
7365
7638
  const r = appendBlocker(description, goalId);
7366
- console.log(chalk36.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
7639
+ console.log(chalk37.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
7367
7640
  if (r.hardStopTripped) {
7368
- console.log(chalk36.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
7369
- console.log(chalk36.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
7641
+ console.log(chalk37.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
7642
+ console.log(chalk37.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
7370
7643
  process.exitCode = 2;
7371
7644
  }
7372
7645
  }
7373
7646
  async function learn(lesson) {
7374
- console.log(chalk36.bold(`
7647
+ console.log(chalk37.bold(`
7375
7648
  ${ko.agent.learnTitle}
7376
7649
  `));
7377
7650
  if (!lesson || !lesson.trim()) {
7378
- console.log(chalk36.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7379
- console.log(chalk36.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
7651
+ console.log(chalk37.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7652
+ console.log(chalk37.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
7380
7653
  process.exitCode = 1;
7381
7654
  return;
7382
7655
  }
7383
7656
  const goalId = activeGoalId();
7384
7657
  const entry = recordLesson(process.cwd(), lesson, goalId);
7385
7658
  if (!entry) {
7386
- console.log(chalk36.red(" \u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAD50\uD6C8 \uAE30\uB85D \uC911\uB2E8. \uC6D0\uBCF8/\uBC31\uC5C5 \uD655\uC778 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7659
+ console.log(chalk37.red(" \u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAD50\uD6C8 \uAE30\uB85D \uC911\uB2E8. \uC6D0\uBCF8/\uBC31\uC5C5 \uD655\uC778 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7387
7660
  process.exitCode = 1;
7388
7661
  return;
7389
7662
  }
7390
- console.log(chalk36.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7391
- console.log(chalk36.dim(" \uAD50\uD6C8\xB7\uACB0\uC815\xB7\uC2E4\uD328\xB7\uC131\uACF5 \uBAA8\uB450 vhk memory (\uB2E8\uC77C SoT). vhk memory list \uB85C \uD655\uC778."));
7663
+ console.log(chalk37.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7664
+ console.log(chalk37.dim(" \uAD50\uD6C8\xB7\uACB0\uC815\xB7\uC2E4\uD328\xB7\uC131\uACF5 \uBAA8\uB450 vhk memory (\uB2E8\uC77C SoT). vhk memory list \uB85C \uD655\uC778."));
7392
7665
  }
7393
7666
  async function resume(opts = {}) {
7394
- console.log(chalk36.bold(`
7667
+ console.log(chalk37.bold(`
7395
7668
  ${ko.agent.resumeTitle}
7396
7669
  `));
7397
7670
  if (!isHardStopActive()) {
7398
- console.log(chalk36.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7671
+ console.log(chalk37.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7399
7672
  return;
7400
7673
  }
7401
7674
  const reason = readHardStopReason();
7402
7675
  if (reason) {
7403
- console.log(chalk36.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7404
- console.log(chalk36.dim(` ${reason.split("\n").join("\n ")}`));
7676
+ console.log(chalk37.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7677
+ console.log(chalk37.dim(` ${reason.split("\n").join("\n ")}`));
7405
7678
  console.log("");
7406
7679
  }
7407
7680
  if (!opts.confirm) {
7408
7681
  console.log(
7409
- chalk36.red(
7682
+ chalk37.red(
7410
7683
  " \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
7411
7684
  )
7412
7685
  );
7413
- console.log(chalk36.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7686
+ console.log(chalk37.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7414
7687
  process.exitCode = 1;
7415
7688
  return;
7416
7689
  }
7417
7690
  const removed = clearHardStop();
7418
7691
  if (removed) {
7419
- console.log(chalk36.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7692
+ console.log(chalk37.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7420
7693
  } else {
7421
- console.log(chalk36.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7694
+ console.log(chalk37.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7422
7695
  }
7423
7696
  }
7424
7697
 
@@ -7439,7 +7712,7 @@ async function guardCli(action, approved, run) {
7439
7712
  }]);
7440
7713
  return ok;
7441
7714
  },
7442
- log: (m) => console.log(chalk37.yellow(` ${m}`))
7715
+ log: (m) => console.log(chalk38.yellow(` ${m}`))
7443
7716
  },
7444
7717
  run
7445
7718
  );
@@ -7452,7 +7725,7 @@ async function guardCliDefer(action, approved, run) {
7452
7725
  approved,
7453
7726
  // TTY 면 통과(명령이 자체 확인), 비대화형은 confirm 불가 → 가드가 차단.
7454
7727
  confirm: async () => !!process.stdout.isTTY,
7455
- log: (m) => console.log(chalk37.yellow(` ${m}`))
7728
+ log: (m) => console.log(chalk38.yellow(` ${m}`))
7456
7729
  },
7457
7730
  run
7458
7731
  );
@@ -7497,7 +7770,8 @@ var KO_ALIASES = {
7497
7770
  learn: "\uAD50\uD6C8",
7498
7771
  resume: "\uC7AC\uAC1C",
7499
7772
  pattern: "\uD328\uD134",
7500
- evolve: "\uC9C4\uD654"
7773
+ evolve: "\uC9C4\uD654",
7774
+ work: "\uC791\uC5C5"
7501
7775
  };
7502
7776
  program.name("vhk").description("VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58 (\uD55C\uAD6D\uC5B4\uB85C \uC548\uB0B4\uD569\uB2C8\uB2E4)").version(getVhkVersion());
7503
7777
  program.configureHelp({
@@ -7545,7 +7819,9 @@ cloudCmd.command("pull").alias("\uB0B4\uB9AC\uAE30").argument("[gistId]", "\uBCF
7545
7819
  await guardCli("cloud-pull", opts?.yes === true, () => cloudPull(gistId));
7546
7820
  });
7547
7821
  program.command("ship").alias("\uCD9C\uD558").description("\uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 + \uD68C\uACE0 + \uBE4C\uB4DC \uB85C\uADF8 \uC0DD\uC131").action(ship);
7548
- program.command("doctor").alias("\uD658\uACBD").alias("\uC9C4\uB2E8").description("\uAC1C\uBC1C \uD658\uACBD \uC810\uAC80 \u2014 Node/Git/npm \uC0C1\uD0DC \uD655\uC778").action(doctor);
7822
+ program.command("doctor").alias("\uD658\uACBD").alias("\uC9C4\uB2E8").option("--strict", "\uADDC\uCE59 \uB4DC\uB9AC\uD504\uD2B8 \uBC1C\uACAC \uC2DC \uC2E4\uD328 \uCC98\uB9AC (exit 1, CI \uAC8C\uC774\uD2B8\uC6A9)").description("\uAC1C\uBC1C \uD658\uACBD \uC810\uAC80 \u2014 Node/Git/npm \uC0C1\uD0DC \uD655\uC778").action(async (opts) => {
7823
+ await doctor(opts);
7824
+ });
7549
7825
  program.command("save").alias("\uC800\uC7A5").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC2E4\uD589 (strict \uBAA8\uB4DC \uAC00\uB4DC \uBA85\uC2DC \uC2B9\uC778)").description("\uBCC0\uACBD\uC0AC\uD56D \uC800\uC7A5 (git add \u2192 commit \u2192 push)").action(async (opts) => {
7550
7826
  await guardCli("save", opts?.yes === true, () => save());
7551
7827
  });
@@ -7667,6 +7943,12 @@ memoryCmd.command("migrate").alias("\uB9C8\uC774\uADF8\uB808\uC774\uC158").descr
7667
7943
  program.command("brief").alias("\uBE0C\uB9AC\uD551").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uC694\uC57D \uBCF4\uACE0\uC11C \uC0DD\uC131 (.vhk/brief.md)").action(async () => {
7668
7944
  await brief();
7669
7945
  });
7946
+ var workCmd = program.command("work").alias("\uC791\uC5C5").description("AI \uC791\uC5C5 \uC2DC\uC791/\uC774\uC5B4\uD558\uAE30 \u2014 \uC2DC\uC791 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131 \uD6C4 \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC").action(async () => {
7947
+ await work();
7948
+ });
7949
+ workCmd.command("handoff").alias("\uC778\uC218\uC778\uACC4").description("\uC791\uC5C5 \uC911\uB2E8 \uC815\uB9AC \u2014 \uC778\uC218\uC778\uACC4 \uD504\uB86C\uD504\uD2B8 \uC0DD\uC131 \uD6C4 \uD074\uB9BD\uBCF4\uB4DC \uBCF5\uC0AC").action(async () => {
7950
+ await workHandoff();
7951
+ });
7670
7952
  var goalCmd = program.command("goal").alias("\uBAA9\uD45C").description("Goal \uB2E8\uACC4\uBCC4 \uBBF8\uC158 \uAD00\uB9AC (init / list / next / check / done / sync)").action(async () => {
7671
7953
  await goalList();
7672
7954
  });
@@ -7799,9 +8081,9 @@ if (isMainModule) {
7799
8081
  }
7800
8082
  } catch (err) {
7801
8083
  if (isPromptAbortError(err)) {
7802
- console.error(chalk37.yellow("\n \u26A0\uFE0F \uB300\uD654\uD615 \uC785\uB825\uC774 \uCDE8\uC18C/\uC885\uB8CC\uB410\uC2B5\uB2C8\uB2E4. (\uBE44\uB300\uD654\uD615 \uD658\uACBD\uC5D0\uC11C\uB294 \uD574\uB2F9 \uBA85\uB839\uC744 \uC4F8 \uC218 \uC5C6\uC5B4\uC694)"));
8084
+ console.error(chalk38.yellow("\n \u26A0\uFE0F \uB300\uD654\uD615 \uC785\uB825\uC774 \uCDE8\uC18C/\uC885\uB8CC\uB410\uC2B5\uB2C8\uB2E4. (\uBE44\uB300\uD654\uD615 \uD658\uACBD\uC5D0\uC11C\uB294 \uD574\uB2F9 \uBA85\uB839\uC744 \uC4F8 \uC218 \uC5C6\uC5B4\uC694)"));
7803
8085
  } else {
7804
- console.error(chalk37.red(`
8086
+ console.error(chalk38.red(`
7805
8087
  \u274C ${err instanceof Error ? err.message : String(err)}`));
7806
8088
  }
7807
8089
  process.exitCode = 1;