@byh3071/vhk 2.3.2 → 2.4.1

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-OHGVVAKT.js";
46
+ } from "./chunk-Y7SJVHGS.js";
47
47
 
48
48
  // src/index.ts
49
49
  import { Command, Help } from "commander";
50
50
  import { fileURLToPath as fileURLToPath4 } from "url";
51
- import fs13 from "fs";
52
- import chalk37 from "chalk";
51
+ import fs14 from "fs";
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([
@@ -520,6 +583,8 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
520
583
  "\uD328\uD134",
521
584
  "evolve",
522
585
  "\uC9C4\uD654",
586
+ "work",
587
+ "\uC791\uC5C5",
523
588
  "help"
524
589
  ]);
525
590
  function isOptionToken(token) {
@@ -557,7 +622,7 @@ function detectNaturalLanguageInput(argv) {
557
622
  }
558
623
 
559
624
  // src/lib/nlp-run.ts
560
- import chalk35 from "chalk";
625
+ import chalk36 from "chalk";
561
626
  import inquirer14 from "inquirer";
562
627
 
563
628
  // src/commands/gate.ts
@@ -2913,9 +2978,92 @@ ${ko.secure.title}
2913
2978
 
2914
2979
  // src/commands/doctor.ts
2915
2980
  import chalk9 from "chalk";
2981
+ import fs9 from "fs";
2982
+ import path10 from "path";
2983
+ import { fileURLToPath } from "url";
2984
+
2985
+ // src/lib/version-check.ts
2916
2986
  import fs8 from "fs";
2987
+ import os from "os";
2917
2988
  import path9 from "path";
2918
- import { fileURLToPath } from "url";
2989
+ var PACKAGE_NAME = "@byh3071/vhk";
2990
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
2991
+ var COOLDOWN_MS = 60 * 60 * 1e3;
2992
+ var MENU_FETCH_TIMEOUT_MS = 1500;
2993
+ function fetchLatestNpmVersion(packageName, timeoutMs = NETWORK_EXEC_TIMEOUT_MS) {
2994
+ const result = safeExecFile("npm", ["view", packageName, "version"], { timeoutMs });
2995
+ if (!result.ok) return void 0;
2996
+ const out = result.out;
2997
+ if (/^\d+\.\d+\.\d+/.test(out)) return out;
2998
+ return void 0;
2999
+ }
3000
+ function compareSemver(a, b) {
3001
+ const parse = (v) => v.replace(/^v/i, "").split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
3002
+ const [a1 = 0, a2 = 0, a3 = 0] = parse(a);
3003
+ const [b1 = 0, b2 = 0, b3 = 0] = parse(b);
3004
+ if (a1 !== b1) return a1 - b1;
3005
+ if (a2 !== b2) return a2 - b2;
3006
+ return a3 - b3;
3007
+ }
3008
+ function getCacheDir() {
3009
+ return path9.join(os.homedir(), ".vhk");
3010
+ }
3011
+ function getCachePath() {
3012
+ return path9.join(getCacheDir(), "version-check.json");
3013
+ }
3014
+ function readCache() {
3015
+ try {
3016
+ const p = getCachePath();
3017
+ if (!fs8.existsSync(p)) return null;
3018
+ const data = readJsonFile(p);
3019
+ if (!data || typeof data.checkedAt !== "number" || data.latest !== void 0 && typeof data.latest !== "string") {
3020
+ return null;
3021
+ }
3022
+ return { latest: data.latest, checkedAt: data.checkedAt, lastTriedAt: data.lastTriedAt };
3023
+ } catch {
3024
+ return null;
3025
+ }
3026
+ }
3027
+ function writeCache(cache) {
3028
+ try {
3029
+ fs8.mkdirSync(getCacheDir(), { recursive: true });
3030
+ fs8.writeFileSync(getCachePath(), JSON.stringify(cache, null, 2), "utf-8");
3031
+ } catch {
3032
+ }
3033
+ }
3034
+ function isStale(cache, now = Date.now()) {
3035
+ return now - cache.checkedAt > CACHE_TTL_MS;
3036
+ }
3037
+ function recordLatest(latest, now = Date.now()) {
3038
+ writeCache({ latest, checkedAt: now, lastTriedAt: now });
3039
+ }
3040
+ function getUpdateInfo(now = Date.now()) {
3041
+ const current = getVhkVersion();
3042
+ const cache = readCache();
3043
+ let latest;
3044
+ if (cache && !isStale(cache, now)) {
3045
+ latest = cache.latest;
3046
+ } else {
3047
+ const lastTried = cache?.lastTriedAt ?? 0;
3048
+ const cooledDown = now - lastTried > COOLDOWN_MS;
3049
+ if (cooledDown) {
3050
+ const fetched = fetchLatestNpmVersion(PACKAGE_NAME, MENU_FETCH_TIMEOUT_MS);
3051
+ if (fetched) {
3052
+ writeCache({ latest: fetched, checkedAt: now, lastTriedAt: now });
3053
+ latest = fetched;
3054
+ } else {
3055
+ writeCache({ latest: cache?.latest, checkedAt: cache?.checkedAt ?? 0, lastTriedAt: now });
3056
+ latest = cache?.latest;
3057
+ }
3058
+ } else {
3059
+ latest = cache?.latest;
3060
+ }
3061
+ }
3062
+ const updateAvailable = latest ? compareSemver(latest, current) > 0 : false;
3063
+ return { current, latest, updateAvailable };
3064
+ }
3065
+
3066
+ // src/commands/doctor.ts
2919
3067
  function checkCommand(name, command, hint) {
2920
3068
  const result = safeExecFile(command, ["--version"]);
2921
3069
  if (!result.ok) return { name, command, ok: false, hint };
@@ -2923,14 +3071,14 @@ function checkCommand(name, command, hint) {
2923
3071
  return { name, command, version, ok: true, hint };
2924
3072
  }
2925
3073
  function getVhkVersion2() {
2926
- const dir = path9.dirname(fileURLToPath(import.meta.url));
3074
+ const dir = path10.dirname(fileURLToPath(import.meta.url));
2927
3075
  const candidates = [
2928
- path9.join(dir, "../package.json"),
2929
- path9.join(dir, "../../package.json")
3076
+ path10.join(dir, "../package.json"),
3077
+ path10.join(dir, "../../package.json")
2930
3078
  ];
2931
3079
  for (const pkgPath of candidates) {
2932
3080
  try {
2933
- if (fs8.existsSync(pkgPath)) {
3081
+ if (fs9.existsSync(pkgPath)) {
2934
3082
  const pkg = readJsonFile(pkgPath);
2935
3083
  return pkg.version;
2936
3084
  }
@@ -2940,24 +3088,7 @@ function getVhkVersion2() {
2940
3088
  }
2941
3089
  return void 0;
2942
3090
  }
2943
- function fetchLatestNpmVersion(packageName) {
2944
- const result = safeExecFile("npm", ["view", packageName, "version"], {
2945
- timeoutMs: NETWORK_EXEC_TIMEOUT_MS
2946
- });
2947
- if (!result.ok) return void 0;
2948
- const out = result.out;
2949
- if (/^\d+\.\d+\.\d+/.test(out)) return out;
2950
- return void 0;
2951
- }
2952
- function compareSemver(a, b) {
2953
- const parse = (v) => v.replace(/^v/i, "").split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
2954
- const [a1 = 0, a2 = 0, a3 = 0] = parse(a);
2955
- const [b1 = 0, b2 = 0, b3 = 0] = parse(b);
2956
- if (a1 !== b1) return a1 - b1;
2957
- if (a2 !== b2) return a2 - b2;
2958
- return a3 - b3;
2959
- }
2960
- async function doctor() {
3091
+ async function doctor(opts = {}) {
2961
3092
  console.log(chalk9.bold(`
2962
3093
  ${ko.doctor.title}
2963
3094
  `));
@@ -2986,6 +3117,7 @@ ${ko.doctor.title}
2986
3117
  }
2987
3118
  if (vhkVersion) {
2988
3119
  const latest = fetchLatestNpmVersion("@byh3071/vhk");
3120
+ if (latest) recordLatest(latest);
2989
3121
  if (latest && compareSemver(latest, vhkVersion) > 0) {
2990
3122
  console.log(chalk9.yellow(` ${ko.doctor.updateAvailable(latest)}`));
2991
3123
  } else if (latest) {
@@ -3003,27 +3135,28 @@ ${ko.doctor.title}
3003
3135
  { name: ".env", hint: ".gitignore\uC5D0 \uD3EC\uD568\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778" }
3004
3136
  ];
3005
3137
  for (const file of projectFiles) {
3006
- const exists = fs8.existsSync(path9.join(cwd, file.name));
3138
+ const exists = fs9.existsSync(path10.join(cwd, file.name));
3007
3139
  if (exists) {
3008
3140
  console.log(chalk9.green(` \u2705 ${file.name}`));
3009
3141
  if (file.name === ".env") {
3010
- const gitignorePath = path9.join(cwd, ".gitignore");
3011
- if (fs8.existsSync(gitignorePath)) {
3012
- const gitignore = fs8.readFileSync(gitignorePath, "utf-8");
3142
+ const gitignorePath = path10.join(cwd, ".gitignore");
3143
+ if (fs9.existsSync(gitignorePath)) {
3144
+ const gitignore = fs9.readFileSync(gitignorePath, "utf-8");
3013
3145
  if (!gitignore.includes(".env")) {
3014
3146
  console.log(chalk9.yellow(` ${ko.doctor.envNotIgnored}`));
3015
3147
  }
3016
3148
  }
3017
3149
  }
3018
- } else if (file.name === ".env" && fs8.existsSync(path9.join(cwd, ".env.local"))) {
3019
- console.log(chalk9.green(" \u2705 .env.local") + chalk9.dim(" \u2014 \uB85C\uCEEC env \uC0AC\uC6A9 \uC911 (.env \uC5C6\uC5B4\uB3C4 \uC815\uC0C1)"));
3150
+ } else if (file.name === ".env" && fs9.existsSync(path10.join(cwd, ".env.local"))) {
3151
+ console.log(chalk9.green(" \u2705 .env.local") + chalk9.dim(" \u2014 \uB85C\uCEF4 env \uC0AC\uC6A9 \uC911 (.env \uC5C6\uC5B4\uB3C4 \uC815\uC0C1)"));
3020
3152
  } else {
3021
- console.log(chalk9.dim(` \u2B1A ${file.name}`) + chalk9.dim(` \u2014 ${file.hint}`));
3153
+ console.log(chalk9.dim(` \u26AB ${file.name}`) + chalk9.dim(` \u2014 ${file.hint}`));
3022
3154
  }
3023
3155
  }
3024
3156
  console.log("");
3025
3157
  console.log(chalk9.bold(` ${ko.doctor.driftTitle}`));
3026
3158
  const ruleDrift = checkRuleDrift(cwd);
3159
+ let ruleDrifted = false;
3027
3160
  if (!ruleDrift.checked) {
3028
3161
  console.log(chalk9.dim(` ${ko.doctor.driftNoRules}`));
3029
3162
  } else {
@@ -3032,6 +3165,7 @@ ${ko.doctor.title}
3032
3165
  console.log(chalk9.green(` ${ko.doctor.driftRuleClean}`));
3033
3166
  } else {
3034
3167
  console.log(chalk9.yellow(` ${ko.doctor.driftRuleWarn(drifted.map((d) => d.path).join(", "))}`));
3168
+ ruleDrifted = true;
3035
3169
  }
3036
3170
  }
3037
3171
  const ctxDrift = checkContextDrift(cwd);
@@ -3055,13 +3189,18 @@ ${ko.doctor.title}
3055
3189
  });
3056
3190
  process.exitCode = 1;
3057
3191
  }
3192
+ if (opts.strict && ruleDrifted) {
3193
+ console.log("");
3194
+ 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)"));
3195
+ process.exitCode = 1;
3196
+ }
3058
3197
  }
3059
3198
 
3060
3199
  // src/commands/ship.ts
3061
3200
  import chalk10 from "chalk";
3062
3201
  import inquirer4 from "inquirer";
3063
- import fs9 from "fs";
3064
- import path10 from "path";
3202
+ import fs10 from "fs";
3203
+ import path11 from "path";
3065
3204
  var CHECKLIST = [
3066
3205
  { id: "build", questionKey: "checkBuild", hintKey: "hintBuild" },
3067
3206
  { id: "test", questionKey: "checkTest", hintKey: "hintTest" },
@@ -3074,9 +3213,9 @@ function sanitizeVersion(version) {
3074
3213
  return version.trim().replace(/^v/i, "").replace(/[^a-zA-Z0-9._-]/g, "-") || "0.0.0";
3075
3214
  }
3076
3215
  function updateChangelogUnreleased(cwd, version, date) {
3077
- const changelogPath = path10.join(cwd, "CHANGELOG.md");
3078
- if (!fs9.existsSync(changelogPath)) return { status: "missing" };
3079
- const content = fs9.readFileSync(changelogPath, "utf-8");
3216
+ const changelogPath = path11.join(cwd, "CHANGELOG.md");
3217
+ if (!fs10.existsSync(changelogPath)) return { status: "missing" };
3218
+ const content = fs10.readFileSync(changelogPath, "utf-8");
3080
3219
  const unreleasedHeading = /^## \[Unreleased\][^\n]*$/m;
3081
3220
  if (!unreleasedHeading.test(content)) return { status: "no-unreleased" };
3082
3221
  const blankUnreleased = [
@@ -3093,7 +3232,7 @@ function updateChangelogUnreleased(cwd, version, date) {
3093
3232
  `## [${version}] \u2014 ${date}`
3094
3233
  ].join("\n");
3095
3234
  const updated = content.replace(unreleasedHeading, blankUnreleased);
3096
- fs9.writeFileSync(changelogPath, updated, "utf-8");
3235
+ fs10.writeFileSync(changelogPath, updated, "utf-8");
3097
3236
  return { status: "updated", version };
3098
3237
  }
3099
3238
  async function ship() {
@@ -3152,12 +3291,12 @@ ${ko.ship.title}
3152
3291
  { type: "input", name: "learned", message: ko.ship.questionLearned },
3153
3292
  { type: "input", name: "nextVersion", message: ko.ship.questionNext }
3154
3293
  ]);
3155
- const buildLogDir = path10.join(cwd, "docs", "build-log");
3156
- if (!fs9.existsSync(buildLogDir)) fs9.mkdirSync(buildLogDir, { recursive: true });
3294
+ const buildLogDir = path11.join(cwd, "docs", "build-log");
3295
+ if (!fs10.existsSync(buildLogDir)) fs10.mkdirSync(buildLogDir, { recursive: true });
3157
3296
  const today = localDate();
3158
3297
  const versionSlug = sanitizeVersion(retro.version);
3159
3298
  const fileName = `${today}-v${versionSlug}.md`;
3160
- const filePath = path10.join(buildLogDir, fileName);
3299
+ const filePath = path11.join(buildLogDir, fileName);
3161
3300
  const content = [
3162
3301
  `# \uBE4C\uB4DC \uB85C\uADF8: v${versionSlug}`,
3163
3302
  "",
@@ -3186,9 +3325,9 @@ ${ko.ship.title}
3186
3325
  "---",
3187
3326
  `*Generated by \`vhk ship\` at ${(/* @__PURE__ */ new Date()).toISOString()}*`
3188
3327
  ].join("\n");
3189
- fs9.writeFileSync(filePath, content, "utf-8");
3328
+ fs10.writeFileSync(filePath, content, "utf-8");
3190
3329
  console.log(chalk10.green(`
3191
- ${ko.ship.buildLogDone(path10.relative(cwd, filePath))}`));
3330
+ ${ko.ship.buildLogDone(path11.relative(cwd, filePath))}`));
3192
3331
  const changelogResult = updateChangelogUnreleased(cwd, versionSlug, today);
3193
3332
  if (changelogResult.status === "updated") {
3194
3333
  log.success(ko.ship.changelogUpdated(changelogResult.version));
@@ -3522,8 +3661,8 @@ ${ko.restore.notFound(targetId)}`));
3522
3661
 
3523
3662
  // src/commands/status.ts
3524
3663
  import { execFileSync as execFileSync3 } from "child_process";
3525
- import fs10 from "fs";
3526
- import path11 from "path";
3664
+ import fs11 from "fs";
3665
+ import path12 from "path";
3527
3666
  import chalk14 from "chalk";
3528
3667
  function countFileChanges(porcelain) {
3529
3668
  const lines = porcelain.split("\n").filter(Boolean);
@@ -3562,8 +3701,8 @@ function parseRecentCommitLines(logOutput) {
3562
3701
  return logOutput.split("\n").map((l) => l.trim()).filter(Boolean);
3563
3702
  }
3564
3703
  function readProjectPackage(cwd = process.cwd()) {
3565
- const pkgPath = path11.join(cwd, "package.json");
3566
- if (!fs10.existsSync(pkgPath)) return null;
3704
+ const pkgPath = path12.join(cwd, "package.json");
3705
+ if (!fs11.existsSync(pkgPath)) return null;
3567
3706
  try {
3568
3707
  const pkg = readJsonFile(pkgPath);
3569
3708
  if (!pkg.name && !pkg.version) return null;
@@ -4416,6 +4555,7 @@ async function update() {
4416
4555
  \u{1F4CC} \uD604\uC7AC \uBC84\uC804: v${current}`));
4417
4556
  const spinner = ora4("\uCD5C\uC2E0 \uBC84\uC804 \uD655\uC778 \uC911...").start();
4418
4557
  const latest = getLatestVersion();
4558
+ if (latest) recordLatest(latest);
4419
4559
  if (!latest) {
4420
4560
  spinner.fail("\uCD5C\uC2E0 \uBC84\uC804\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
4421
4561
  console.log(chalk22.yellow(" \uB124\uD2B8\uC6CC\uD06C\uB97C \uD655\uC778\uD558\uAC70\uB098 \uC218\uB3D9\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694:"));
@@ -4947,37 +5087,7 @@ function extractTechStack() {
4947
5087
  return stack;
4948
5088
  }
4949
5089
  function getVhkCommands() {
4950
- return [
4951
- "gate \u2014 \uC544\uC774\uB514\uC5B4 \uAC80\uC99D",
4952
- "init \u2014 \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654",
4953
- "recap \u2014 \uC138\uC158 \uC694\uC57D \uC800\uC7A5",
4954
- "sync \u2014 \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654",
4955
- "check \u2014 \uADDC\uCE59 \uC810\uAC80",
4956
- "secure \u2014 \uBCF4\uC548 \uC2A4\uCE94",
4957
- "ship \u2014 \uBC30\uD3EC \uCCB4\uD06C + \uD68C\uACE0",
4958
- "doctor \u2014 \uD658\uACBD \uC9C4\uB2E8",
4959
- "save \u2014 git \uC800\uC7A5 (add+commit+push)",
4960
- "undo \u2014 \uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30",
4961
- "status \u2014 git \uC0C1\uD0DC \uD655\uC778",
4962
- "diff \u2014 git \uBCC0\uACBD \uC0AC\uD56D \uC694\uC57D",
4963
- "deploy \u2014 \uD504\uB85C\uB355\uC158 \uBC30\uD3EC",
4964
- "env \u2014 \uD658\uACBD\uBCC0\uC218 \uAD00\uB9AC",
4965
- "publish \u2014 npm \uBC30\uD3EC \uC790\uB3D9\uD654",
4966
- "design \u2014 \uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131",
4967
- "design-palette \u2014 \uCEEC\uB7EC \uD314\uB808\uD2B8 \uC120\uD0DD",
4968
- "theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC",
4969
- "ref add|list|open \u2014 \uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC",
4970
- "harness \u2014 \uD1B5\uD569 \uD488\uC9C8 \uC810\uAC80",
4971
- "audit \u2014 \uBCF4\uC548 \uCDE8\uC57D\uC810 \uAC10\uC0AC",
4972
- "migrate \u2014 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uC804\uD658",
4973
- "update \u2014 VHK CLI \uC140\uD504 \uC5C5\uB370\uC774\uD2B8",
4974
- "context \u2014 \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uC0DD\uC131",
4975
- "context-show \u2014 \uB9E5\uB77D \uD30C\uC77C \uBCF4\uAE30",
4976
- "memory add|list|remove \u2014 \uACB0\uC815\uC0AC\uD56D \uAE30\uC5B5",
4977
- "brief \u2014 \uD504\uB85C\uC81D\uD2B8 \uC694\uC57D \uBCF4\uACE0\uC11C",
4978
- "mcp \u2014 MCP \uC11C\uBC84 \uC2DC\uC791",
4979
- "mcp-init \u2014 Cursor MCP \uC124\uC815"
4980
- ];
5090
+ return TOP_LEVEL_COMMANDS.map((c) => `${c.name} \u2014 ${c.desc}`);
4981
5091
  }
4982
5092
  async function context(opts = {}) {
4983
5093
  const compact = opts.compact === true;
@@ -4992,6 +5102,16 @@ async function context(opts = {}) {
4992
5102
  lines.push("> \uC774 \uD30C\uC77C\uC740 `vhk context`\uB85C \uC790\uB3D9 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
4993
5103
  lines.push("> AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D\uC744 \uC81C\uACF5\uD569\uB2C8\uB2E4.");
4994
5104
  lines.push("");
5105
+ lines.push("## \uC6D0\uBCF8 \uC9C0\uB3C4 (Source of Truth)");
5106
+ lines.push("");
5107
+ 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.');
5108
+ lines.push("");
5109
+ lines.push("- **\uADDC\uCE59(\uC6D0\uBCF8)**: `RULES.md` \u2014 \uADDC\uCE59\uC740 \uC5EC\uAE30 \uD55C \uACF3\uC5D0\uC11C\uB9CC \uC218\uC815");
5110
+ lines.push("- **\uC791\uC5C5 \uC0C1\uD0DC**: `docs/state/next-task.md`, `docs/state/blockers.md`");
5111
+ lines.push("- **\uBC84\uC804\xB7\uB9B4\uB9AC\uC2A4**: `package.json`, `CHANGELOG.md`");
5112
+ lines.push("- **\uBA85\uB839 \uBAA9\uB85D**: `COMMANDS.md` (+ `vhk help`)");
5113
+ 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");
5114
+ lines.push("");
4995
5115
  lines.push("## \uAE30\uC220 \uC2A4\uD0DD");
4996
5116
  lines.push("");
4997
5117
  for (const [key, value] of Object.entries(stack)) {
@@ -5051,9 +5171,10 @@ async function context(opts = {}) {
5051
5171
  if (compact) {
5052
5172
  lines.push("## \uCC38\uC870 \uBB38\uC11C (\uD544\uC694\uC2DC \uC5F4\uB78C)");
5053
5173
  lines.push("");
5174
+ lines.push("- \uADDC\uCE59 \uC6D0\uBCF8(SoT): `RULES.md` \u2014 \uADDC\uCE59\uC740 \uC5EC\uAE30\uC11C\uB9CC \uC218\uC815");
5054
5175
  lines.push("- \uC791\uB3D9 \uADDC\uC57D(\uC694\uC57D): `docs/context/agent-compact.md`");
5055
5176
  lines.push("- \uADDC\uC57D \uC0C1\uC138: `AGENTS.md`");
5056
- lines.push("- \uAE30\uB85D \uADDC\uCE59: `CLAUDE.md`");
5177
+ lines.push("- \uC6B4\uC601 \uC548\uB0B4\xB7\uAE30\uB85D: `CLAUDE.md`");
5057
5178
  lines.push("- \uBA85\uB839 \uC0C1\uC138: `COMMANDS.md`");
5058
5179
  lines.push("- \uAD6C\uC870 \uC0C1\uC138: `docs/ARCHITECTURE.md`");
5059
5180
  lines.push("- \uD604\uC7AC \uC0C1\uD0DC: `docs/state/next-task.md`");
@@ -5213,12 +5334,227 @@ async function brief() {
5213
5334
  });
5214
5335
  }
5215
5336
 
5216
- // src/commands/start.ts
5337
+ // src/commands/work.ts
5338
+ import { existsSync as existsSync14, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10, readFileSync as readFileSync7 } from "fs";
5339
+ import { join as join9 } from "path";
5217
5340
  import chalk26 from "chalk";
5341
+
5342
+ // src/lib/clipboard.ts
5343
+ import { spawnSync } from "child_process";
5344
+ function copyToClipboard(text) {
5345
+ try {
5346
+ if (process.platform === "win32") return copyWin32(text);
5347
+ if (process.platform === "darwin") return runWithInput("pbcopy", [], text);
5348
+ return runWithInput("wl-copy", [], text) || runWithInput("xclip", ["-selection", "clipboard"], text) || runWithInput("xsel", ["--clipboard", "--input"], text);
5349
+ } catch {
5350
+ return false;
5351
+ }
5352
+ }
5353
+ function copyWin32(text) {
5354
+ const b64 = Buffer.from(text, "utf8").toString("base64");
5355
+ const psScript = "$b=[Console]::In.ReadToEnd();$t=[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($b));Set-Clipboard -Value $t";
5356
+ const r = spawnSync(
5357
+ "powershell",
5358
+ ["-NoProfile", "-NonInteractive", "-Command", psScript],
5359
+ { input: b64, encoding: "utf8", windowsHide: true }
5360
+ );
5361
+ return r.status === 0 && !r.error;
5362
+ }
5363
+ function runWithInput(cmd, args, input) {
5364
+ const r = spawnSync(cmd, args, { input, encoding: "utf8" });
5365
+ return r.status === 0 && !r.error;
5366
+ }
5367
+
5368
+ // src/commands/work.ts
5369
+ var VHK_DIR2 = ".vhk";
5370
+ function gitShort() {
5371
+ const r = safeExecFile("git", ["status", "--short"]);
5372
+ return r.ok ? r.out.trim() : "";
5373
+ }
5374
+ function ensureVhkProject() {
5375
+ if (existsSync14("CLAUDE.md") || existsSync14(VHK_DIR2) || existsSync14("goals")) return true;
5376
+ console.log(chalk26.yellow(" \u26A0\uFE0F \uC5EC\uAE30\uB294 VHK \uD504\uB85C\uC81D\uD2B8 \uD3F4\uB354\uAC00 \uC544\uB2CC \uAC83 \uAC19\uC544\uC694."));
5377
+ 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."));
5378
+ return false;
5379
+ }
5380
+ function passHardStop() {
5381
+ if (!isHardStopActive()) {
5382
+ console.log(chalk26.green(" \u2705 HARD_STOP \uC5C6\uC74C"));
5383
+ return true;
5384
+ }
5385
+ 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."));
5386
+ const reason = readHardStopReason();
5387
+ if (reason) console.log(chalk26.red(` \uC0AC\uC720: ${reason.replace(/\s*\n\s*/g, " ")}`));
5388
+ console.log(chalk26.yellow(" \uD574\uC81C\uB294 \uC0AC\uB78C\uC774 \uC9C1\uC811: vhk resume --confirm"));
5389
+ return false;
5390
+ }
5391
+ function activeGoalLine() {
5392
+ const goals = listGoals("goals");
5393
+ if (goals.length === 0) return "\uC815\uC758\uB41C goal \uC5C6\uC74C";
5394
+ const id = selectActiveId(goals);
5395
+ if (id === null) return "\uBAA8\uB4E0 goal \uC644\uB8CC\uB428";
5396
+ const g = goals.find((x) => x.frontmatter.id === id);
5397
+ if (!g) return "\uC815\uC758\uB41C goal \uC5C6\uC74C";
5398
+ return `Goal ${id} \u2014 ${g.frontmatter.title ?? "(untitled)"}`;
5399
+ }
5400
+ function printGit(git3) {
5401
+ if (!git3) {
5402
+ console.log(chalk26.dim(" (\uBCC0\uACBD\uB41C \uD30C\uC77C \uC5C6\uC74C \u2014 \uAE68\uB057\uD55C \uC0C1\uD0DC)"));
5403
+ return;
5404
+ }
5405
+ for (const line of git3.split(/\r?\n/)) console.log(` ${line}`);
5406
+ }
5407
+ function buildStartPrompt(git3, goalLine) {
5408
+ const gitBlock = git3 || "(\uBCC0\uACBD \uC5C6\uC74C)";
5409
+ return [
5410
+ "\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.",
5411
+ "",
5412
+ "[\uADDC\uCE59 \uC6B0\uC120\uC21C\uC704]",
5413
+ "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)",
5414
+ "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.",
5415
+ "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.",
5416
+ "",
5417
+ "[\uC791\uC5C5 \uC804 Source of Truth \uCCB4\uD06C]",
5418
+ "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.",
5419
+ "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.",
5420
+ "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.",
5421
+ "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)",
5422
+ "",
5423
+ "[\uC9C0\uAE08 \uC0C1\uD0DC \u2014 \uC790\uB3D9 \uC218\uC9D1\uB428]",
5424
+ "- \uBCC0\uACBD\uB41C \uD30C\uC77C (git status --short):",
5425
+ gitBlock,
5426
+ "- \uD604\uC7AC \uBAA9\uD45C (active goal):",
5427
+ goalLine,
5428
+ "",
5429
+ "[\uD574\uC8FC\uC138\uC694]",
5430
+ "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.",
5431
+ "2. \uADF8\uB2E4\uC74C \uD560 \uC77C\uC744 3\uB2E8\uACC4 \uC774\uD558\uB85C \uB9D0\uD558\uACE0 \uC9C4\uD589\uD558\uC138\uC694.",
5432
+ "3. \uD14C\uC2A4\uD2B8\uAC00 \uD1B5\uACFC\uD558\uAE30 \uC804\uC5D0\uB294 \uC644\uB8CC(done) \uCC98\uB9AC\uD558\uC9C0 \uB9C8\uC138\uC694.",
5433
+ "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.",
5434
+ "\uBAA8\uB4E0 \uC751\uB2F5\uC740 \uD55C\uAD6D\uC5B4\uB85C."
5435
+ ].join("\n");
5436
+ }
5437
+ function buildHandoffPrompt(git3) {
5438
+ const gitBlock = git3 || "(\uBCC0\uACBD \uC5C6\uC74C)";
5439
+ return [
5440
+ "\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.",
5441
+ "\uB2E4\uC74C \uC138\uC158\uC774 \uC774\uC5B4\uBC1B\uC744 \uC218 \uC788\uAC8C \uC815\uB9AC\uD574 \uC8FC\uC138\uC694.",
5442
+ "",
5443
+ "[\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.",
5444
+ "",
5445
+ "[\uC9C0\uAE08 \uC0C1\uD0DC \u2014 \uC790\uB3D9 \uC218\uC9D1\uB428]",
5446
+ "- \uBCC0\uACBD\uB41C \uD30C\uC77C (git status --short):",
5447
+ gitBlock,
5448
+ "",
5449
+ "[\uD574\uC8FC\uC138\uC694 \u2014 \uC815\uB9AC\uB9CC, \uC0C8 \uAC1C\uBC1C \uC2DC\uC791 \uAE08\uC9C0]",
5450
+ "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.",
5451
+ "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')",
5452
+ "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)",
5453
+ "4. \uC9C0\uAE08 \uCEE4\uBC0B \uAC00\uB2A5\uD55C \uC0C1\uD0DC\uC778\uC9C0 \uD310\uB2E8\uD574 \uC8FC\uC138\uC694. (\uC774\uC720 \uC124\uBA85)",
5454
+ "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.",
5455
+ "",
5456
+ "[\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.",
5457
+ "\uBAA8\uB4E0 \uC751\uB2F5\uC740 \uD55C\uAD6D\uC5B4\uB85C."
5458
+ ].join("\n");
5459
+ }
5460
+ function emitPrompt(prompt, fileName, label) {
5461
+ let savedPath = "";
5462
+ try {
5463
+ mkdirSync10(VHK_DIR2, { recursive: true });
5464
+ savedPath = join9(VHK_DIR2, fileName);
5465
+ writeFileSync10(savedPath, prompt, "utf-8");
5466
+ } catch {
5467
+ savedPath = "";
5468
+ }
5469
+ const copied = copyToClipboard(prompt);
5470
+ if (copied) {
5471
+ console.log(chalk26.green(`
5472
+ \u{1F4CB} Claude\uC5D0\uAC8C \uC904 '${label}'\uC744 \uD074\uB9BD\uBCF4\uB4DC\uC5D0 \uBCF5\uC0AC\uD588\uC2B5\uB2C8\uB2E4! \u2705`));
5473
+ if (savedPath) console.log(chalk26.dim(` (\uC0AC\uBCF8 \uC800\uC7A5: ${savedPath})`));
5474
+ } else {
5475
+ console.log(chalk26.yellow(`
5476
+ \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:`));
5477
+ if (savedPath) console.log(chalk26.dim(` (\uD30C\uC77C\uB85C\uB3C4 \uC800\uC7A5\uB428: ${savedPath} \u2014 \uC5F4\uC5B4\uC11C \uBCF5\uC0AC \uAC00\uB2A5)`));
5478
+ 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"));
5479
+ console.log(prompt);
5480
+ 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"));
5481
+ }
5482
+ }
5483
+ async function refreshContextQuietly() {
5484
+ const origLog = console.log;
5485
+ console.log = () => {
5486
+ };
5487
+ try {
5488
+ await context({ compact: true });
5489
+ return true;
5490
+ } catch {
5491
+ return false;
5492
+ } finally {
5493
+ console.log = origLog;
5494
+ }
5495
+ }
5496
+ async function work() {
5497
+ console.log(chalk26.bold(`
5498
+ ${ko.work.workTitle}`));
5499
+ console.log(chalk26.gray("\u2500".repeat(40)));
5500
+ if (!ensureVhkProject()) return;
5501
+ if (!passHardStop()) return;
5502
+ const git3 = gitShort();
5503
+ console.log("");
5504
+ console.log(chalk26.cyan("\u{1F4CB} \uBCC0\uACBD\uB41C \uD30C\uC77C"));
5505
+ printGit(git3);
5506
+ console.log("");
5507
+ console.log(chalk26.cyan("\u{1F4D6} \uADDC\uCE59"));
5508
+ console.log(" \xB7 CLAUDE.md \uAC00 1\uC21C\uC704 \uADDC\uCE59\uC785\uB2C8\uB2E4.");
5509
+ console.log(chalk26.dim(" \xB7 AGENTS.md \uB294 Codex/\uBCF4\uC870 \uC5D0\uC774\uC804\uD2B8\uC6A9 \uCC38\uACE0 \uADDC\uCE59\uC785\uB2C8\uB2E4."));
5510
+ const goalLine = activeGoalLine();
5511
+ console.log("");
5512
+ console.log(chalk26.cyan(`\u{1F3AF} \uD604\uC7AC \uBAA9\uD45C: ${goalLine}`));
5513
+ const refreshed = await refreshContextQuietly();
5514
+ 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)"));
5515
+ const nextTaskPath = join9("docs", "state", "next-task.md");
5516
+ if (existsSync14(nextTaskPath)) {
5517
+ try {
5518
+ const lines = readFileSync7(nextTaskPath, "utf-8").split(/\r?\n/).slice(0, 12);
5519
+ console.log("");
5520
+ console.log(chalk26.cyan("\u{1F4DD} \uB2E4\uC74C \uD560 \uC77C (next-task.md)"));
5521
+ for (const l of lines) console.log(chalk26.dim(` ${l}`));
5522
+ } catch {
5523
+ }
5524
+ }
5525
+ const prompt = buildStartPrompt(git3, goalLine);
5526
+ emitPrompt(prompt, "work-prompt.md", "\uC2DC\uC791 \uD504\uB86C\uD504\uD2B8");
5527
+ printNextStep({
5528
+ message: "\uD130\uBBF8\uB110\uC5D0\uC11C claude \uB97C \uC2E4\uD589\uD55C \uB4A4, Ctrl+V \uB85C \uBD99\uC5EC\uB123\uACE0 Enter \uD558\uC138\uC694.",
5529
+ command: "claude"
5530
+ });
5531
+ }
5532
+ async function workHandoff() {
5533
+ console.log(chalk26.bold(`
5534
+ ${ko.work.handoffTitle}`));
5535
+ console.log(chalk26.gray("\u2500".repeat(40)));
5536
+ if (!ensureVhkProject()) return;
5537
+ if (!passHardStop()) return;
5538
+ const git3 = gitShort();
5539
+ console.log("");
5540
+ console.log(chalk26.cyan("\u{1F4CB} \uBC14\uB010 \uD30C\uC77C"));
5541
+ printGit(git3);
5542
+ const prompt = buildHandoffPrompt(git3);
5543
+ emitPrompt(prompt, "handoff-prompt.md", "\uC911\uB2E8 \uC815\uB9AC \uD504\uB86C\uD504\uD2B8");
5544
+ console.log("");
5545
+ 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."));
5546
+ printNextStep({
5547
+ message: "\uD130\uBBF8\uB110\uC5D0\uC11C claude \uB97C \uC2E4\uD589\uD55C \uB4A4, Ctrl+V \uB85C \uBD99\uC5EC\uB123\uACE0 Enter \uD558\uC138\uC694.",
5548
+ command: "claude"
5549
+ });
5550
+ }
5551
+
5552
+ // src/commands/start.ts
5553
+ import chalk27 from "chalk";
5218
5554
  import inquirer11 from "inquirer";
5219
5555
  import { simpleGit as simpleGit2 } from "simple-git";
5220
- import { existsSync as existsSync14 } from "fs";
5221
- import { join as join9 } from "path";
5556
+ import { existsSync as existsSync15 } from "fs";
5557
+ import { join as join10 } from "path";
5222
5558
  var VHK_FOOTPRINT_FILES = [
5223
5559
  "CLAUDE.md",
5224
5560
  ".cursorrules",
@@ -5227,7 +5563,7 @@ var VHK_FOOTPRINT_FILES = [
5227
5563
  "docs/PRD.md"
5228
5564
  ];
5229
5565
  function detectExistingFootprint(cwd) {
5230
- return VHK_FOOTPRINT_FILES.filter((rel) => existsSync14(join9(cwd, rel)));
5566
+ return VHK_FOOTPRINT_FILES.filter((rel) => existsSync15(join10(cwd, rel)));
5231
5567
  }
5232
5568
  async function runGitInit(cwd) {
5233
5569
  try {
@@ -5256,21 +5592,21 @@ async function runStep(label, fn) {
5256
5592
  }
5257
5593
  }
5258
5594
  async function start(options = {}) {
5259
- console.log(chalk26.bold(`
5595
+ console.log(chalk27.bold(`
5260
5596
  ${ko.start.title}
5261
5597
  `));
5262
- console.log(chalk26.dim(ko.start.intro));
5263
- console.log(chalk26.dim(` ${ko.start.step1}`));
5264
- console.log(chalk26.dim(` ${ko.start.step2}`));
5265
- console.log(chalk26.dim(` ${ko.start.step3}`));
5266
- console.log(chalk26.dim(` ${ko.start.step4}`));
5598
+ console.log(chalk27.dim(ko.start.intro));
5599
+ console.log(chalk27.dim(` ${ko.start.step1}`));
5600
+ console.log(chalk27.dim(` ${ko.start.step2}`));
5601
+ console.log(chalk27.dim(` ${ko.start.step3}`));
5602
+ console.log(chalk27.dim(` ${ko.start.step4}`));
5267
5603
  console.log();
5268
5604
  const cwd = process.cwd();
5269
5605
  const footprint = detectExistingFootprint(cwd);
5270
5606
  if (footprint.length > 0 && !options.yes) {
5271
- console.log(chalk26.yellow("\u26A0\uFE0F \uC774\uBBF8 VHK \uC124\uCE58 \uD754\uC801\uC774 \uAC10\uC9C0\uB410\uC5B4\uC694:"));
5272
- for (const f of footprint) console.log(chalk26.dim(` - ${f}`));
5273
- 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."));
5607
+ console.log(chalk27.yellow("\u26A0\uFE0F \uC774\uBBF8 VHK \uC124\uCE58 \uD754\uC801\uC774 \uAC10\uC9C0\uB410\uC5B4\uC694:"));
5608
+ for (const f of footprint) console.log(chalk27.dim(` - ${f}`));
5609
+ 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."));
5274
5610
  const { proceedExisting } = await inquirer11.prompt([{
5275
5611
  type: "confirm",
5276
5612
  name: "proceedExisting",
@@ -5308,7 +5644,7 @@ ${ko.start.title}
5308
5644
  await runStep("[3/4] vhk mcp-init", () => mcpInit());
5309
5645
  log.step(ko.start.step4Header);
5310
5646
  await runStep("[4/4] vhk context", () => context());
5311
- console.log(chalk26.bold.green(`
5647
+ console.log(chalk27.bold.green(`
5312
5648
  ${ko.start.allDone}
5313
5649
  `));
5314
5650
  printNextStep({
@@ -5318,15 +5654,15 @@ ${ko.start.allDone}
5318
5654
  }
5319
5655
 
5320
5656
  // src/commands/cloud.ts
5321
- import fs12 from "fs";
5322
- import os from "os";
5323
- import path13 from "path";
5324
- import chalk27 from "chalk";
5657
+ import fs13 from "fs";
5658
+ import os2 from "os";
5659
+ import path14 from "path";
5660
+ import chalk28 from "chalk";
5325
5661
 
5326
5662
  // src/lib/vhk-cloud.ts
5327
5663
  var import_ignore = __toESM(require_ignore(), 1);
5328
- import fs11 from "fs";
5329
- import path12 from "path";
5664
+ import fs12 from "fs";
5665
+ import path13 from "path";
5330
5666
  var DEFAULT_CLOUD_EXCLUDES = [
5331
5667
  "memory.json",
5332
5668
  // 개인 의사결정 메모
@@ -5339,22 +5675,22 @@ var DEFAULT_CLOUD_EXCLUDES = [
5339
5675
  ".gitignore"
5340
5676
  // .vhk/ 내부 gitignore
5341
5677
  ];
5342
- var VHK_DIR2 = ".vhk";
5678
+ var VHK_DIR3 = ".vhk";
5343
5679
  var CLOUD_CONFIG_FILE = "cloud.json";
5344
5680
  function loadVhkignore(rootDir) {
5345
5681
  const ig = (0, import_ignore.default)();
5346
5682
  ig.add(DEFAULT_CLOUD_EXCLUDES);
5347
- const ignorePath = path12.join(rootDir, ".vhkignore");
5348
- if (fs11.existsSync(ignorePath)) {
5349
- ig.add(fs11.readFileSync(ignorePath, "utf-8"));
5683
+ const ignorePath = path13.join(rootDir, ".vhkignore");
5684
+ if (fs12.existsSync(ignorePath)) {
5685
+ ig.add(fs12.readFileSync(ignorePath, "utf-8"));
5350
5686
  }
5351
5687
  return ig;
5352
5688
  }
5353
5689
  function collectVhkFiles(rootDir, ig = loadVhkignore(rootDir)) {
5354
- const vhkDir = path12.join(rootDir, VHK_DIR2);
5690
+ const vhkDir = path13.join(rootDir, VHK_DIR3);
5355
5691
  let entries;
5356
5692
  try {
5357
- entries = fs11.readdirSync(vhkDir, { withFileTypes: true });
5693
+ entries = fs12.readdirSync(vhkDir, { withFileTypes: true });
5358
5694
  } catch {
5359
5695
  return [];
5360
5696
  }
@@ -5370,8 +5706,8 @@ function partitionGistFiles(gistFiles, ig) {
5370
5706
  return { keep, excluded };
5371
5707
  }
5372
5708
  function readCloudConfig(rootDir) {
5373
- const p = path12.join(rootDir, VHK_DIR2, CLOUD_CONFIG_FILE);
5374
- if (!fs11.existsSync(p)) return null;
5709
+ const p = path13.join(rootDir, VHK_DIR3, CLOUD_CONFIG_FILE);
5710
+ if (!fs12.existsSync(p)) return null;
5375
5711
  try {
5376
5712
  const parsed = readJsonFile(p);
5377
5713
  if (parsed && typeof parsed.gistId === "string" && parsed.gistId) {
@@ -5383,17 +5719,17 @@ function readCloudConfig(rootDir) {
5383
5719
  }
5384
5720
  }
5385
5721
  function writeCloudConfig(rootDir, config) {
5386
- const vhkDir = path12.join(rootDir, VHK_DIR2);
5387
- fs11.mkdirSync(vhkDir, { recursive: true });
5388
- const p = path12.join(vhkDir, CLOUD_CONFIG_FILE);
5389
- fs11.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf-8");
5722
+ const vhkDir = path13.join(rootDir, VHK_DIR3);
5723
+ fs12.mkdirSync(vhkDir, { recursive: true });
5724
+ const p = path13.join(vhkDir, CLOUD_CONFIG_FILE);
5725
+ fs12.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf-8");
5390
5726
  ensureCloudConfigIgnored(vhkDir);
5391
5727
  }
5392
5728
  function ensureCloudConfigIgnored(vhkDir) {
5393
- const giPath = path12.join(vhkDir, ".gitignore");
5729
+ const giPath = path13.join(vhkDir, ".gitignore");
5394
5730
  let content = "";
5395
5731
  try {
5396
- if (fs11.existsSync(giPath)) content = fs11.readFileSync(giPath, "utf-8");
5732
+ if (fs12.existsSync(giPath)) content = fs12.readFileSync(giPath, "utf-8");
5397
5733
  } catch {
5398
5734
  return;
5399
5735
  }
@@ -5404,7 +5740,7 @@ ${CLOUD_CONFIG_FILE}
5404
5740
  `;
5405
5741
  const base = content.length === 0 ? "" : content.endsWith("\n") ? content : content + "\n";
5406
5742
  try {
5407
- fs11.writeFileSync(giPath, base + block, "utf-8");
5743
+ fs12.writeFileSync(giPath, base + block, "utf-8");
5408
5744
  } catch {
5409
5745
  }
5410
5746
  }
@@ -5413,14 +5749,14 @@ ${CLOUD_CONFIG_FILE}
5413
5749
  function ensureGhReady() {
5414
5750
  const ver = safeExecFile("gh", ["--version"]);
5415
5751
  if (!ver.ok) {
5416
- console.log(chalk27.red(` ${ko.cloud.noGh}`));
5417
- console.log(chalk27.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
5752
+ console.log(chalk28.red(` ${ko.cloud.noGh}`));
5753
+ console.log(chalk28.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
5418
5754
  return false;
5419
5755
  }
5420
5756
  const auth = safeExecFile("gh", ["auth", "status"]);
5421
5757
  if (!auth.ok) {
5422
- console.log(chalk27.red(` ${ko.cloud.noAuth}`));
5423
- console.log(chalk27.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
5758
+ console.log(chalk28.red(` ${ko.cloud.noAuth}`));
5759
+ console.log(chalk28.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
5424
5760
  return false;
5425
5761
  }
5426
5762
  return true;
@@ -5433,29 +5769,29 @@ function parseGistId(output) {
5433
5769
  return null;
5434
5770
  }
5435
5771
  async function cloudPush() {
5436
- console.log(chalk27.bold(`
5772
+ console.log(chalk28.bold(`
5437
5773
  ${ko.cloud.pushTitle}
5438
5774
  `));
5439
5775
  const cwd = process.cwd();
5440
- if (!fs12.existsSync(path13.join(cwd, VHK_DIR2))) {
5441
- console.log(chalk27.yellow(` ${ko.cloud.noVhkDir}`));
5776
+ if (!fs13.existsSync(path14.join(cwd, VHK_DIR3))) {
5777
+ console.log(chalk28.yellow(` ${ko.cloud.noVhkDir}`));
5442
5778
  return;
5443
5779
  }
5444
5780
  const ig = loadVhkignore(cwd);
5445
5781
  const files = collectVhkFiles(cwd, ig);
5446
5782
  if (files.length === 0) {
5447
- console.log(chalk27.yellow(` ${ko.cloud.nothingToSync}`));
5783
+ console.log(chalk28.yellow(` ${ko.cloud.nothingToSync}`));
5448
5784
  return;
5449
5785
  }
5450
5786
  if (!ensureGhReady()) {
5451
5787
  process.exitCode = 1;
5452
5788
  return;
5453
5789
  }
5454
- const filePaths = files.map((f) => path13.join(cwd, VHK_DIR2, f));
5455
- console.log(chalk27.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
5790
+ const filePaths = files.map((f) => path14.join(cwd, VHK_DIR3, f));
5791
+ console.log(chalk28.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
5456
5792
  `));
5457
5793
  const existing = readCloudConfig(cwd);
5458
- const desc = `vhk .vhk backup \u2014 ${path13.basename(cwd)}`;
5794
+ const desc = `vhk .vhk backup \u2014 ${path14.basename(cwd)}`;
5459
5795
  if (existing) {
5460
5796
  const gistFiles = listGistFiles(existing.gistId);
5461
5797
  for (let i = 0; i < files.length; i++) {
@@ -5464,8 +5800,8 @@ ${ko.cloud.pushTitle}
5464
5800
  const args = gistFiles.includes(name) ? ["gist", "edit", existing.gistId, "-f", name, src] : ["gist", "edit", existing.gistId, "-a", src];
5465
5801
  const res2 = safeExecFile("gh", args);
5466
5802
  if (!res2.ok) {
5467
- console.log(chalk27.red(` ${ko.cloud.pushFail}: ${name}`));
5468
- console.log(chalk27.dim(` ${res2.err}`));
5803
+ console.log(chalk28.red(` ${ko.cloud.pushFail}: ${name}`));
5804
+ console.log(chalk28.dim(` ${res2.err}`));
5469
5805
  process.exitCode = 1;
5470
5806
  return;
5471
5807
  }
@@ -5480,15 +5816,15 @@ ${ko.cloud.pushTitle}
5480
5816
  if (!purgeFailed.includes(name)) purgeFailed.push(name);
5481
5817
  }
5482
5818
  }
5483
- console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
5484
- console.log(chalk27.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
5819
+ console.log(chalk28.green.bold(` ${ko.cloud.pushDone}`));
5820
+ console.log(chalk28.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
5485
5821
  if (excluded.length > 0) {
5486
5822
  const purged = excluded.filter((n) => !purgeFailed.includes(n));
5487
5823
  if (purged.length > 0) {
5488
- console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${purged.length}\uAC1C gist \uC5D0\uC11C \uC81C\uAC70: ${purged.join(", ")}`));
5824
+ console.log(chalk28.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${purged.length}\uAC1C gist \uC5D0\uC11C \uC81C\uAC70: ${purged.join(", ")}`));
5489
5825
  }
5490
5826
  if (purgeFailed.length > 0) {
5491
- 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)`));
5827
+ 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)`));
5492
5828
  }
5493
5829
  }
5494
5830
  printPushNext();
@@ -5496,32 +5832,32 @@ ${ko.cloud.pushTitle}
5496
5832
  }
5497
5833
  const res = safeExecFile("gh", ["gist", "create", "--desc", desc, ...filePaths]);
5498
5834
  if (!res.ok) {
5499
- console.log(chalk27.red(` ${ko.cloud.pushFail}`));
5500
- console.log(chalk27.dim(` ${res.err || res.out}`));
5835
+ console.log(chalk28.red(` ${ko.cloud.pushFail}`));
5836
+ console.log(chalk28.dim(` ${res.err || res.out}`));
5501
5837
  process.exitCode = 1;
5502
5838
  return;
5503
5839
  }
5504
5840
  const gistId = parseGistId(res.out);
5505
5841
  if (!gistId) {
5506
- console.log(chalk27.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
5507
- console.log(chalk27.dim(` \uCD9C\uB825: ${res.out}`));
5842
+ console.log(chalk28.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
5843
+ console.log(chalk28.dim(` \uCD9C\uB825: ${res.out}`));
5508
5844
  process.exitCode = 1;
5509
5845
  return;
5510
5846
  }
5511
5847
  writeCloudConfig(cwd, { gistId });
5512
- console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
5513
- console.log(chalk27.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
5848
+ console.log(chalk28.green.bold(` ${ko.cloud.pushDone}`));
5849
+ console.log(chalk28.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
5514
5850
  printPushNext();
5515
5851
  }
5516
5852
  async function cloudPull(gistIdArg) {
5517
- console.log(chalk27.bold(`
5853
+ console.log(chalk28.bold(`
5518
5854
  ${ko.cloud.pullTitle}
5519
5855
  `));
5520
5856
  const cwd = process.cwd();
5521
5857
  const gistId = gistIdArg || readCloudConfig(cwd)?.gistId;
5522
5858
  if (!gistId) {
5523
- console.log(chalk27.yellow(` ${ko.cloud.noGistId}`));
5524
- console.log(chalk27.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
5859
+ console.log(chalk28.yellow(` ${ko.cloud.noGistId}`));
5860
+ console.log(chalk28.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
5525
5861
  return;
5526
5862
  }
5527
5863
  if (!ensureGhReady()) {
@@ -5530,34 +5866,34 @@ ${ko.cloud.pullTitle}
5530
5866
  }
5531
5867
  const allNames = listGistFiles(gistId);
5532
5868
  if (allNames.length === 0) {
5533
- console.log(chalk27.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
5869
+ console.log(chalk28.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
5534
5870
  process.exitCode = 1;
5535
5871
  return;
5536
5872
  }
5537
5873
  const { keep: names, excluded: skipped } = partitionGistFiles(allNames, loadVhkignore(cwd));
5538
5874
  if (skipped.length > 0) {
5539
- console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${skipped.length}\uAC1C \uBCF5\uC6D0 \uC2A4\uD0B5: ${skipped.join(", ")}`));
5875
+ console.log(chalk28.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${skipped.length}\uAC1C \uBCF5\uC6D0 \uC2A4\uD0B5: ${skipped.join(", ")}`));
5540
5876
  }
5541
5877
  if (names.length === 0) {
5542
- 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).`));
5878
+ 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).`));
5543
5879
  return;
5544
5880
  }
5545
- const vhkDir = path13.join(cwd, VHK_DIR2);
5546
- fs12.mkdirSync(vhkDir, { recursive: true });
5881
+ const vhkDir = path14.join(cwd, VHK_DIR3);
5882
+ fs13.mkdirSync(vhkDir, { recursive: true });
5547
5883
  let restored = 0;
5548
5884
  for (const name of names) {
5549
5885
  const res = safeExecFile("gh", ["gist", "view", gistId, "-f", name, "--raw"]);
5550
5886
  if (!res.ok) {
5551
- console.log(chalk27.red(` ${ko.cloud.pullFail}: ${name}`));
5552
- console.log(chalk27.dim(` ${res.err}`));
5887
+ console.log(chalk28.red(` ${ko.cloud.pullFail}: ${name}`));
5888
+ console.log(chalk28.dim(` ${res.err}`));
5553
5889
  continue;
5554
5890
  }
5555
- fs12.writeFileSync(path13.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
5891
+ fs13.writeFileSync(path14.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
5556
5892
  restored++;
5557
5893
  }
5558
5894
  writeCloudConfig(cwd, { gistId });
5559
- console.log(chalk27.green.bold(` ${ko.cloud.pullDone}`));
5560
- console.log(chalk27.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
5895
+ console.log(chalk28.green.bold(` ${ko.cloud.pullDone}`));
5896
+ console.log(chalk28.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
5561
5897
  printNextStep({
5562
5898
  message: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk/ \uBCF5\uC6D0 \uC644\uB8CC!",
5563
5899
  command: "vhk \uB9E5\uB77D",
@@ -5569,9 +5905,9 @@ function purgeExcludedFromGist(gistId, names) {
5569
5905
  const body = JSON.stringify({
5570
5906
  files: Object.fromEntries(names.map((n) => [n, null]))
5571
5907
  });
5572
- const tmp = path13.join(os.tmpdir(), `vhk-gist-purge-${process.pid}.json`);
5908
+ const tmp = path14.join(os2.tmpdir(), `vhk-gist-purge-${process.pid}.json`);
5573
5909
  try {
5574
- fs12.writeFileSync(tmp, body, "utf-8");
5910
+ fs13.writeFileSync(tmp, body, "utf-8");
5575
5911
  for (let attempt = 0; attempt < 2; attempt++) {
5576
5912
  const res = safeExecFile(
5577
5913
  "gh",
@@ -5583,7 +5919,7 @@ function purgeExcludedFromGist(gistId, names) {
5583
5919
  return false;
5584
5920
  } finally {
5585
5921
  try {
5586
- fs12.unlinkSync(tmp);
5922
+ fs13.unlinkSync(tmp);
5587
5923
  } catch {
5588
5924
  }
5589
5925
  }
@@ -5605,7 +5941,7 @@ function printPushNext() {
5605
5941
  }
5606
5942
 
5607
5943
  // src/commands/help.ts
5608
- import chalk28 from "chalk";
5944
+ import chalk29 from "chalk";
5609
5945
  var QUICK_ACTIONS = [
5610
5946
  { say: "\uC0C1\uD0DC \uC54C\uB824\uC918", does: "vhk status" },
5611
5947
  { say: "\uBB50 \uBC14\uB00C\uC5C8\uC5B4?", does: "vhk diff" },
@@ -5619,21 +5955,21 @@ var QUICK_ACTIONS = [
5619
5955
  { say: "\uC804\uCCB4 \uBA85\uB839\uC5B4 \uBCF4\uAE30", does: "vhk --help" }
5620
5956
  ];
5621
5957
  function quickActions() {
5622
- console.log(chalk28.bold("\n\u{1F9ED} VHK \u2014 \uC774\uB807\uAC8C \uB9D0\uD558\uBA74 \uB429\uB2C8\uB2E4 (quick actions)"));
5623
- console.log(chalk28.gray("\u2500".repeat(40)));
5958
+ console.log(chalk29.bold("\n\u{1F9ED} VHK \u2014 \uC774\uB807\uAC8C \uB9D0\uD558\uBA74 \uB429\uB2C8\uB2E4 (quick actions)"));
5959
+ console.log(chalk29.gray("\u2500".repeat(40)));
5624
5960
  for (const a of QUICK_ACTIONS) {
5625
- console.log(` "${chalk28.cyan(a.say)}" \u2192 ${chalk28.dim(a.does)}`);
5961
+ console.log(` "${chalk29.cyan(a.say)}" \u2192 ${chalk29.dim(a.does)}`);
5626
5962
  }
5627
- console.log(chalk28.gray("\n \uC804\uCCB4 \uBA85\uB839\uC740 `vhk --help` \uB610\uB294 COMMANDS.md \uB97C \uBCF4\uC138\uC694."));
5963
+ console.log(chalk29.gray("\n \uC804\uCCB4 \uBA85\uB839\uC740 `vhk --help` \uB610\uB294 COMMANDS.md \uB97C \uBCF4\uC138\uC694."));
5628
5964
  console.log("");
5629
5965
  }
5630
5966
 
5631
5967
  // src/commands/mode.ts
5632
- import chalk29 from "chalk";
5968
+ import chalk30 from "chalk";
5633
5969
 
5634
5970
  // src/lib/config.ts
5635
- import { existsSync as existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
5636
- import { join as join10 } from "path";
5971
+ import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
5972
+ import { join as join11 } from "path";
5637
5973
 
5638
5974
  // src/lib/safety-mode.ts
5639
5975
  var SAFETY_MODES = ["lite", "standard", "strict"];
@@ -5649,11 +5985,11 @@ function isSafetyMode(value) {
5649
5985
 
5650
5986
  // src/lib/config.ts
5651
5987
  var CONFIG_DIR = ".vhk";
5652
- var CONFIG_PATH = join10(CONFIG_DIR, "config.json");
5988
+ var CONFIG_PATH = join11(CONFIG_DIR, "config.json");
5653
5989
  var DEFAULT_CONFIG = { safetyMode: DEFAULT_SAFETY_MODE };
5654
5990
  function readConfig(rootDir = process.cwd()) {
5655
- const full = join10(rootDir, CONFIG_PATH);
5656
- if (!existsSync15(full)) return { ...DEFAULT_CONFIG };
5991
+ const full = join11(rootDir, CONFIG_PATH);
5992
+ if (!existsSync16(full)) return { ...DEFAULT_CONFIG };
5657
5993
  try {
5658
5994
  const raw = readJsonFile(full);
5659
5995
  return {
@@ -5664,23 +6000,23 @@ function readConfig(rootDir = process.cwd()) {
5664
6000
  }
5665
6001
  }
5666
6002
  function writeConfig(config, rootDir = process.cwd()) {
5667
- mkdirSync10(join10(rootDir, CONFIG_DIR), { recursive: true });
5668
- writeFileSync10(join10(rootDir, CONFIG_PATH), JSON.stringify(config, null, 2) + "\n", "utf-8");
6003
+ mkdirSync11(join11(rootDir, CONFIG_DIR), { recursive: true });
6004
+ writeFileSync11(join11(rootDir, CONFIG_PATH), JSON.stringify(config, null, 2) + "\n", "utf-8");
5669
6005
  }
5670
6006
 
5671
6007
  // src/commands/mode.ts
5672
6008
  async function mode(target) {
5673
- console.log(chalk29.bold("\n\u{1F6E1}\uFE0F Safety Mode"));
5674
- console.log(chalk29.gray("\u2500".repeat(40)));
6009
+ console.log(chalk30.bold("\n\u{1F6E1}\uFE0F Safety Mode"));
6010
+ console.log(chalk30.gray("\u2500".repeat(40)));
5675
6011
  const current = readConfig().safetyMode;
5676
6012
  if (!target) {
5677
- console.log(chalk29.cyan(`
5678
- \uD604\uC7AC \uBAA8\uB4DC: ${chalk29.bold(current)}`));
5679
- console.log(chalk29.dim(` ${SAFETY_MODE_DESC[current]}`));
6013
+ console.log(chalk30.cyan(`
6014
+ \uD604\uC7AC \uBAA8\uB4DC: ${chalk30.bold(current)}`));
6015
+ console.log(chalk30.dim(` ${SAFETY_MODE_DESC[current]}`));
5680
6016
  console.log("");
5681
6017
  for (const m of SAFETY_MODES) {
5682
6018
  const mark = m === current ? "\u25CF" : "\u25CB";
5683
- console.log(` ${mark} ${m.padEnd(9)} ${chalk29.dim(SAFETY_MODE_DESC[m])}`);
6019
+ console.log(` ${mark} ${m.padEnd(9)} ${chalk30.dim(SAFETY_MODE_DESC[m])}`);
5684
6020
  }
5685
6021
  printNextStep({
5686
6022
  message: "\uBAA8\uB4DC\uB97C \uBC14\uAFB8\uB824\uBA74:",
@@ -5690,23 +6026,23 @@ async function mode(target) {
5690
6026
  return;
5691
6027
  }
5692
6028
  if (!isSafetyMode(target)) {
5693
- console.log(chalk29.red(`
6029
+ console.log(chalk30.red(`
5694
6030
  \u274C \uC54C \uC218 \uC5C6\uB294 \uBAA8\uB4DC: ${target}`));
5695
- console.log(chalk29.dim(` \uAC00\uB2A5: ${SAFETY_MODES.join(" | ")}`));
6031
+ console.log(chalk30.dim(` \uAC00\uB2A5: ${SAFETY_MODES.join(" | ")}`));
5696
6032
  process.exitCode = 1;
5697
6033
  return;
5698
6034
  }
5699
6035
  writeConfig({ ...readConfig(), safetyMode: target });
5700
- console.log(chalk29.green(`
5701
- \u2705 Safety Mode \u2192 ${chalk29.bold(target)}`));
5702
- console.log(chalk29.dim(` ${SAFETY_MODE_DESC[target]}`));
6036
+ console.log(chalk30.green(`
6037
+ \u2705 Safety Mode \u2192 ${chalk30.bold(target)}`));
6038
+ console.log(chalk30.dim(` ${SAFETY_MODE_DESC[target]}`));
5703
6039
  }
5704
6040
 
5705
6041
  // src/commands/verify.ts
5706
6042
  import { execFileSync as execFileSync4 } from "child_process";
5707
- import { existsSync as existsSync16, mkdirSync as mkdirSync11, writeFileSync as writeFileSync11 } from "fs";
5708
- import { join as join11 } from "path";
5709
- import chalk30 from "chalk";
6043
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
6044
+ import { join as join12 } from "path";
6045
+ import chalk31 from "chalk";
5710
6046
 
5711
6047
  // src/commands/verify-report.ts
5712
6048
  function escapeHtml(text) {
@@ -5814,13 +6150,13 @@ ${actions}
5814
6150
 
5815
6151
  // src/commands/verify.ts
5816
6152
  var REPORT_SCHEMA_VERSION = 1;
5817
- var REPORT_DIR_REL = join11(".vhk", "reports");
5818
- var REPORT_PATH_REL = join11(REPORT_DIR_REL, "latest.json");
5819
- var REPORT_HTML_PATH_REL = join11(REPORT_DIR_REL, "latest.html");
6153
+ var REPORT_DIR_REL = join12(".vhk", "reports");
6154
+ var REPORT_PATH_REL = join12(REPORT_DIR_REL, "latest.json");
6155
+ var REPORT_HTML_PATH_REL = join12(REPORT_DIR_REL, "latest.html");
5820
6156
  var SHIM = /* @__PURE__ */ new Set(["pnpm", "npm", "npx", "yarn"]);
5821
6157
  function detectPm(cwd) {
5822
- if (existsSync16(join11(cwd, "pnpm-lock.yaml"))) return "pnpm";
5823
- if (existsSync16(join11(cwd, "yarn.lock"))) return "yarn";
6158
+ if (existsSync17(join12(cwd, "pnpm-lock.yaml"))) return "pnpm";
6159
+ if (existsSync17(join12(cwd, "yarn.lock"))) return "yarn";
5824
6160
  return "npm";
5825
6161
  }
5826
6162
  function execGate(cmd, args, cwd) {
@@ -5863,8 +6199,8 @@ function runScriptGate(id, label, cwd, pm, argvFor) {
5863
6199
  };
5864
6200
  }
5865
6201
  function readPackageScripts(cwd) {
5866
- const pkgPath = join11(cwd, "package.json");
5867
- if (!existsSync16(pkgPath)) return {};
6202
+ const pkgPath = join12(cwd, "package.json");
6203
+ if (!existsSync17(pkgPath)) return {};
5868
6204
  try {
5869
6205
  const pkg = readJsonFile(pkgPath);
5870
6206
  return pkg.scripts ?? {};
@@ -5879,7 +6215,7 @@ function runGates(cwd) {
5879
6215
  gates.push(
5880
6216
  runScriptGate("typecheck", "tsc --noEmit", cwd, pm, () => {
5881
6217
  if (scripts.typecheck) return ["run", "typecheck"];
5882
- if (existsSync16(join11(cwd, "tsconfig.json"))) return pm === "npm" ? ["exec", "--", "tsc", "--noEmit"] : ["exec", "tsc", "--noEmit"];
6218
+ if (existsSync17(join12(cwd, "tsconfig.json"))) return pm === "npm" ? ["exec", "--", "tsc", "--noEmit"] : ["exec", "tsc", "--noEmit"];
5883
6219
  return null;
5884
6220
  })
5885
6221
  );
@@ -5958,10 +6294,10 @@ function buildReport(gates, generatedAt, date) {
5958
6294
  function verifyEvidence(cwd = process.cwd()) {
5959
6295
  const gates = runGates(cwd);
5960
6296
  const report = buildReport(gates, (/* @__PURE__ */ new Date()).toISOString(), localDate());
5961
- const dir = join11(cwd, REPORT_DIR_REL);
5962
- mkdirSync11(dir, { recursive: true });
5963
- const path14 = join11(cwd, REPORT_PATH_REL);
5964
- writeFileSync11(path14, JSON.stringify(report, null, 2) + "\n", "utf-8");
6297
+ const dir = join12(cwd, REPORT_DIR_REL);
6298
+ mkdirSync12(dir, { recursive: true });
6299
+ const path15 = join12(cwd, REPORT_PATH_REL);
6300
+ writeFileSync12(path15, JSON.stringify(report, null, 2) + "\n", "utf-8");
5965
6301
  try {
5966
6302
  ensureVhkIgnored(cwd, "reports/");
5967
6303
  } catch {
@@ -5969,44 +6305,44 @@ function verifyEvidence(cwd = process.cwd()) {
5969
6305
  return { report, path: REPORT_PATH_REL };
5970
6306
  }
5971
6307
  var STATUS_BADGE = {
5972
- PASS: chalk30.green.bold("PASS"),
5973
- WARN: chalk30.yellow.bold("WARN"),
5974
- FAIL: chalk30.red.bold("FAIL")
6308
+ PASS: chalk31.green.bold("PASS"),
6309
+ WARN: chalk31.yellow.bold("WARN"),
6310
+ FAIL: chalk31.red.bold("FAIL")
5975
6311
  };
5976
6312
  async function renderVerifyReport(cwd, opts) {
5977
- const jsonPath = join11(cwd, REPORT_PATH_REL);
6313
+ const jsonPath = join12(cwd, REPORT_PATH_REL);
5978
6314
  let report;
5979
- if (existsSync16(jsonPath)) {
6315
+ if (existsSync17(jsonPath)) {
5980
6316
  try {
5981
6317
  report = readJsonFile(jsonPath);
5982
6318
  } catch {
5983
- 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."));
6319
+ 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."));
5984
6320
  report = verifyEvidence(cwd).report;
5985
6321
  }
5986
6322
  } else {
5987
- console.log(chalk30.dim(" latest.json \uC5C6\uC74C \u2014 verify 1\uD68C \uC120\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB9CC\uB4ED\uB2C8\uB2E4."));
6323
+ console.log(chalk31.dim(" latest.json \uC5C6\uC74C \u2014 verify 1\uD68C \uC120\uC2E4\uD589\uC73C\uB85C \uC99D\uAC70\uB97C \uB9CC\uB4ED\uB2C8\uB2E4."));
5988
6324
  report = verifyEvidence(cwd).report;
5989
6325
  }
5990
6326
  const html = renderReportHtml(report);
5991
- const htmlPath = join11(cwd, REPORT_HTML_PATH_REL);
6327
+ const htmlPath = join12(cwd, REPORT_HTML_PATH_REL);
5992
6328
  try {
5993
- mkdirSync11(join11(cwd, REPORT_DIR_REL), { recursive: true });
5994
- writeFileSync11(htmlPath, html, "utf-8");
6329
+ mkdirSync12(join12(cwd, REPORT_DIR_REL), { recursive: true });
6330
+ writeFileSync12(htmlPath, html, "utf-8");
5995
6331
  } catch (e) {
5996
6332
  console.error(
5997
- 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)}`)
6333
+ 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)}`)
5998
6334
  );
5999
- console.error(chalk30.dim(" \uD574\uB2F9 \uACBD\uB85C\uC758 \uC4F0\uAE30 \uAD8C\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694."));
6335
+ console.error(chalk31.dim(" \uD574\uB2F9 \uACBD\uB85C\uC758 \uC4F0\uAE30 \uAD8C\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694."));
6000
6336
  process.exitCode = 1;
6001
6337
  return;
6002
6338
  }
6003
- console.log(chalk30.bold("\n\u{1F50E} \uAC80\uC99D \uB9AC\uD3EC\uD2B8 (verify --report)"));
6339
+ console.log(chalk31.bold("\n\u{1F50E} \uAC80\uC99D \uB9AC\uD3EC\uD2B8 (verify --report)"));
6004
6340
  console.log(` \uACB0\uACFC: ${STATUS_BADGE[report.status]}`);
6005
- console.log(chalk30.dim(` \u{1F4C4} HTML: ${REPORT_HTML_PATH_REL}`));
6341
+ console.log(chalk31.dim(` \u{1F4C4} HTML: ${REPORT_HTML_PATH_REL}`));
6006
6342
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6007
6343
  if (opts.open) {
6008
6344
  if (isInteractive()) openReportInBrowser(htmlPath);
6009
- else console.log(chalk30.dim(" (\uBE44\uB300\uD654\uD615/CI/MCP \u2014 --open \uC790\uB3D9 \uC2A4\uD0B5)"));
6345
+ else console.log(chalk31.dim(" (\uBE44\uB300\uD654\uD615/CI/MCP \u2014 --open \uC790\uB3D9 \uC2A4\uD0B5)"));
6010
6346
  return;
6011
6347
  }
6012
6348
  printNextStep({
@@ -6024,8 +6360,8 @@ function openReportInBrowser(filePath) {
6024
6360
  } else {
6025
6361
  result = safeExecFile("xdg-open", [filePath]);
6026
6362
  }
6027
- if (result.ok) console.log(chalk30.green(" \u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
6028
- 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."));
6363
+ if (result.ok) console.log(chalk31.green(" \u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
6364
+ 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."));
6029
6365
  }
6030
6366
  async function verify(opts = {}) {
6031
6367
  if (!ensureNotHardStopped("verify")) return;
@@ -6034,27 +6370,27 @@ async function verify(opts = {}) {
6034
6370
  await renderVerifyReport(cwd, opts);
6035
6371
  return;
6036
6372
  }
6037
- const { report, path: path14 } = verifyEvidence(cwd);
6373
+ const { report, path: path15 } = verifyEvidence(cwd);
6038
6374
  if (opts.json) {
6039
6375
  console.log(JSON.stringify(report, null, 2));
6040
6376
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6041
6377
  return;
6042
6378
  }
6043
- console.log(chalk30.bold("\n\u{1F50E} \uAC80\uC99D \uBB36\uC74C (verify)"));
6044
- console.log(chalk30.gray("\u2500".repeat(40)));
6379
+ console.log(chalk31.bold("\n\u{1F50E} \uAC80\uC99D \uBB36\uC74C (verify)"));
6380
+ console.log(chalk31.gray("\u2500".repeat(40)));
6045
6381
  const mode2 = readConfig().safetyMode;
6046
- console.log(chalk30.dim(` \uD604\uC7AC Safety Mode: ${mode2} \u2014 ${SAFETY_MODE_DESC[mode2]}`));
6047
- const icon = (s2) => s2 === "pass" ? chalk30.green("\u2713") : s2 === "fail" ? chalk30.red("\u2717") : chalk30.yellow("\u2298");
6382
+ console.log(chalk31.dim(` \uD604\uC7AC Safety Mode: ${mode2} \u2014 ${SAFETY_MODE_DESC[mode2]}`));
6383
+ const icon = (s2) => s2 === "pass" ? chalk31.green("\u2713") : s2 === "fail" ? chalk31.red("\u2717") : chalk31.yellow("\u2298");
6048
6384
  for (const g of report.gates) {
6049
- const tail = g.detail ? chalk30.dim(` \u2014 ${g.detail}`) : "";
6385
+ const tail = g.detail ? chalk31.dim(` \u2014 ${g.detail}`) : "";
6050
6386
  console.log(` ${icon(g.status)} ${g.label}${tail}`);
6051
6387
  }
6052
6388
  const s = report.summary;
6053
6389
  console.log(
6054
6390
  `
6055
- \uACB0\uACFC: ${STATUS_BADGE[report.status]} ` + chalk30.dim(`(pass ${s.pass} / fail ${s.fail} / skip ${s.skip}, \uCD1D ${s.total})`)
6391
+ \uACB0\uACFC: ${STATUS_BADGE[report.status]} ` + chalk31.dim(`(pass ${s.pass} / fail ${s.fail} / skip ${s.skip}, \uCD1D ${s.total})`)
6056
6392
  );
6057
- console.log(chalk30.dim(` \u{1F4C4} \uC99D\uAC70: ${path14}`));
6393
+ console.log(chalk31.dim(` \u{1F4C4} \uC99D\uAC70: ${path15}`));
6058
6394
  process.exitCode = report.status === "FAIL" ? 1 : 0;
6059
6395
  if (report.status === "FAIL") {
6060
6396
  printNextStep({
@@ -6073,9 +6409,9 @@ async function verify(opts = {}) {
6073
6409
  }
6074
6410
 
6075
6411
  // src/commands/review.ts
6076
- import { existsSync as existsSync17, writeFileSync as writeFileSync12 } from "fs";
6077
- import { join as join12 } from "path";
6078
- import chalk31 from "chalk";
6412
+ import { existsSync as existsSync18, writeFileSync as writeFileSync13 } from "fs";
6413
+ import { join as join13 } from "path";
6414
+ import chalk32 from "chalk";
6079
6415
  var GOALS_DIR2 = "goals";
6080
6416
  var COVERAGE_MIN = 0.5;
6081
6417
  var STALE_AGE_MS = 6 * 60 * 60 * 1e3;
@@ -6207,22 +6543,22 @@ function resolveGoal(optId, goals) {
6207
6543
  return goals.find((g) => g.frontmatter.id === id) ?? null;
6208
6544
  }
6209
6545
  var CONFIDENCE_LABEL = {
6210
- low: chalk31.red.bold("\uB0AE\uC74C (\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC \uB610\uB294 \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C)"),
6211
- medium: chalk31.yellow.bold("\uC911\uAC04 (\uCEE4\uBC84\uB9AC\uC9C0/\uC2E0\uC120\uB3C4 \uBD80\uC871 \u2014 \uC99D\uAC70 \uC5C6\uC74C \u2260 \uD1B5\uACFC)"),
6212
- 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)")
6546
+ low: chalk32.red.bold("\uB0AE\uC74C (\uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC \uB610\uB294 \uC644\uB8CC \uC8FC\uC7A5 \uC5C6\uC74C)"),
6547
+ medium: chalk32.yellow.bold("\uC911\uAC04 (\uCEE4\uBC84\uB9AC\uC9C0/\uC2E0\uC120\uB3C4 \uBD80\uC871 \u2014 \uC99D\uAC70 \uC5C6\uC74C \u2260 \uD1B5\uACFC)"),
6548
+ 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)")
6213
6549
  };
6214
6550
  async function review(opts = {}) {
6215
6551
  if (!ensureNotHardStopped("review")) return;
6216
6552
  const cwd = process.cwd();
6217
6553
  const goals = listGoals(GOALS_DIR2);
6218
6554
  if (goals.length === 0) {
6219
- console.error(chalk31.yellow(" \u26A0\uFE0F goals/ \uC5D0 goal \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
6555
+ console.error(chalk32.yellow(" \u26A0\uFE0F goals/ \uC5D0 goal \uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
6220
6556
  process.exitCode = 1;
6221
6557
  return;
6222
6558
  }
6223
6559
  const goal = resolveGoal(opts.id, goals);
6224
6560
  if (!goal || typeof goal.frontmatter.id !== "number") {
6225
- 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)"}.`));
6561
+ 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)"}.`));
6226
6562
  process.exitCode = 1;
6227
6563
  return;
6228
6564
  }
@@ -6230,11 +6566,11 @@ async function review(opts = {}) {
6230
6566
  const goalStatus = goal.frontmatter.status ?? "NOT_STARTED";
6231
6567
  const checks = parseCompletionChecks(goal.body);
6232
6568
  if (opts.id === void 0 && goalStatus === "NOT_STARTED") {
6233
- 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.`));
6569
+ 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.`));
6234
6570
  }
6235
- const jsonPath = join12(cwd, REPORT_PATH_REL);
6236
- if (!existsSync17(jsonPath)) {
6237
- 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).`));
6571
+ const jsonPath = join13(cwd, REPORT_PATH_REL);
6572
+ if (!existsSync18(jsonPath)) {
6573
+ 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).`));
6238
6574
  printNextStep({
6239
6575
  message: "\uC99D\uAC70(latest.json)\uAC00 \uC788\uC5B4\uC57C review \uAC00 \uAD50\uCC28\uAC80\uC99D\uD569\uB2C8\uB2E4:",
6240
6576
  command: "vhk verify",
@@ -6247,7 +6583,7 @@ async function review(opts = {}) {
6247
6583
  try {
6248
6584
  report = readJsonFile(jsonPath);
6249
6585
  } catch {
6250
- 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.`));
6586
+ 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.`));
6251
6587
  process.exitCode = 1;
6252
6588
  return;
6253
6589
  }
@@ -6259,44 +6595,44 @@ async function review(opts = {}) {
6259
6595
  goalStatus,
6260
6596
  reportStatus: report.status
6261
6597
  };
6262
- console.log(chalk31.bold(`
6598
+ console.log(chalk32.bold(`
6263
6599
  \u{1F52C} \uC801\uB300\uC801 \uC790\uAE30\uAC80\uC99D (review) \u2014 Goal ${goalId}`));
6264
- console.log(chalk31.gray("\u2500".repeat(44)));
6600
+ console.log(chalk32.gray("\u2500".repeat(44)));
6265
6601
  console.log(
6266
- chalk31.dim(
6602
+ chalk32.dim(
6267
6603
  ` 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}%)`
6268
6604
  )
6269
6605
  );
6270
- console.log(chalk31.dim(` \uC99D\uAC70 \uC2E0\uC120\uB3C4: ${result.freshness.note}`));
6606
+ console.log(chalk32.dim(` \uC99D\uAC70 \uC2E0\uC120\uB3C4: ${result.freshness.note}`));
6271
6607
  if (result.checkedCount === 0) {
6272
- 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)."));
6608
+ 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)."));
6273
6609
  }
6274
6610
  if (result.suspicions.length > 0) {
6275
- console.log(chalk31.red.bold(`
6611
+ console.log(chalk32.red.bold(`
6276
6612
  \u{1F6A9} \uAC70\uC9D3\uC644\uB8CC \uC758\uC2EC ${result.suspicions.length}\uAC74`));
6277
- for (const s of result.suspicions) console.log(chalk31.red(` \u2717 ${s.check}
6613
+ for (const s of result.suspicions) console.log(chalk32.red(` \u2717 ${s.check}
6278
6614
  \u21B3 ${s.reason}`));
6279
6615
  }
6280
6616
  if (result.gaps.length > 0) {
6281
- console.log(chalk31.yellow.bold(`
6617
+ console.log(chalk32.yellow.bold(`
6282
6618
  \u26A0\uFE0F \uBBF8\uAC80\uC99D(unmapped) ${result.gaps.length}\uAC74 \u2014 \uAC8C\uC774\uD2B8\uB85C \uC790\uB3D9 \uD655\uC778 \uBD88\uAC00`));
6283
- for (const g of result.gaps) console.log(chalk31.yellow(` ? ${g.check}`));
6619
+ for (const g of result.gaps) console.log(chalk32.yellow(` ? ${g.check}`));
6284
6620
  }
6285
6621
  if (result.checkedCount > 0 && result.suspicions.length === 0 && result.gaps.length === 0) {
6286
- 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."));
6622
+ 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."));
6287
6623
  }
6288
6624
  console.log(`
6289
6625
  \uC2E0\uB8B0\uB3C4: ${CONFIDENCE_LABEL[result.confidence]}`);
6290
- console.log(chalk31.yellow(`
6626
+ console.log(chalk32.yellow(`
6291
6627
  ${result.disclaimer}`));
6292
6628
  let mergeOk = false;
6293
6629
  try {
6294
6630
  const merged = { ...report, review: result };
6295
- writeFileSync12(jsonPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
6631
+ writeFileSync13(jsonPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
6296
6632
  mergeOk = true;
6297
- console.log(chalk31.dim(` \u{1F4C4} \uD310\uC815 \uBCD1\uD569: ${REPORT_PATH_REL} (review \uC139\uC158)`));
6633
+ console.log(chalk32.dim(` \u{1F4C4} \uD310\uC815 \uBCD1\uD569: ${REPORT_PATH_REL} (review \uC139\uC158)`));
6298
6634
  } catch (e) {
6299
- console.error(chalk31.red(` \u274C review \uD310\uC815 \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6635
+ console.error(chalk32.red(` \u274C review \uD310\uC815 \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6300
6636
  }
6301
6637
  if (!mergeOk) {
6302
6638
  process.exitCode = 1;
@@ -6317,8 +6653,8 @@ ${result.disclaimer}`));
6317
6653
  cursorHint: "\uC644\uB8CC\uC870\uAC74 \uCC44\uC6CC\uC918"
6318
6654
  });
6319
6655
  } else if (result.suspicions.length > 0) {
6320
- console.log(chalk31.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6321
- console.log(chalk31.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6656
+ console.log(chalk32.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6657
+ console.log(chalk32.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6322
6658
  printNextStep({
6323
6659
  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:",
6324
6660
  command: "vhk verify",
@@ -6332,8 +6668,8 @@ ${result.disclaimer}`));
6332
6668
  cursorHint: "goal \uC644\uB8CC \uCC98\uB9AC\uD574\uC918"
6333
6669
  });
6334
6670
  } else {
6335
- console.log(chalk31.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6336
- console.log(chalk31.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6671
+ console.log(chalk32.dim("\n AI \uC7AC\uC9C8\uBB38 \uD504\uB86C\uD504\uD2B8:"));
6672
+ console.log(chalk32.cyan(result.reprompt.split("\n").map((l) => ` ${l}`).join("\n")));
6337
6673
  printNextStep({
6338
6674
  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:`,
6339
6675
  command: "vhk verify",
@@ -6343,12 +6679,12 @@ ${result.disclaimer}`));
6343
6679
  }
6344
6680
 
6345
6681
  // src/commands/mission.ts
6346
- import { existsSync as existsSync18, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13, rmSync as rmSync4 } from "fs";
6347
- import { join as join13 } from "path";
6348
- import chalk32 from "chalk";
6682
+ import { existsSync as existsSync19, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, rmSync as rmSync4 } from "fs";
6683
+ import { join as join14 } from "path";
6684
+ import chalk33 from "chalk";
6349
6685
  import inquirer12 from "inquirer";
6350
6686
  import { simpleGit as simpleGit3 } from "simple-git";
6351
- var MISSION_PATH_REL = join13(".vhk", "mission.json");
6687
+ var MISSION_PATH_REL = join14(".vhk", "mission.json");
6352
6688
  var MISSION_SCHEMA_VERSION = 1;
6353
6689
  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).";
6354
6690
  function globToRegExp(glob) {
@@ -6396,8 +6732,8 @@ function checkMission(changedFiles, mission) {
6396
6732
  return { violations, warnings, disclaimer: MISSION_DISCLAIMER };
6397
6733
  }
6398
6734
  function readMission(cwd = process.cwd()) {
6399
- const p = join13(cwd, MISSION_PATH_REL);
6400
- if (!existsSync18(p)) return null;
6735
+ const p = join14(cwd, MISSION_PATH_REL);
6736
+ if (!existsSync19(p)) return null;
6401
6737
  try {
6402
6738
  const m = readJsonFile(p);
6403
6739
  if (m && typeof m.objective === "string") return m;
@@ -6407,8 +6743,8 @@ function readMission(cwd = process.cwd()) {
6407
6743
  }
6408
6744
  }
6409
6745
  function writeMission(cwd, mission) {
6410
- mkdirSync12(join13(cwd, ".vhk"), { recursive: true });
6411
- writeFileSync13(join13(cwd, MISSION_PATH_REL), JSON.stringify(mission, null, 2) + "\n", "utf-8");
6746
+ mkdirSync13(join14(cwd, ".vhk"), { recursive: true });
6747
+ writeFileSync14(join14(cwd, MISSION_PATH_REL), JSON.stringify(mission, null, 2) + "\n", "utf-8");
6412
6748
  }
6413
6749
  async function collectChangedFiles(cwd) {
6414
6750
  const status2 = await simpleGit3(cwd).status();
@@ -6429,7 +6765,7 @@ async function missionSet(opts = {}) {
6429
6765
  objective = ans.obj.trim();
6430
6766
  }
6431
6767
  if (!objective) {
6432
- console.error(chalk32.red(' \u274C objective \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. --objective "..." \uB85C \uC9C0\uC815\uD558\uC138\uC694(\uBE44\uB300\uD654\uD615).'));
6768
+ console.error(chalk33.red(' \u274C objective \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. --objective "..." \uB85C \uC9C0\uC815\uD558\uC138\uC694(\uBE44\uB300\uD654\uD615).'));
6433
6769
  process.exitCode = 1;
6434
6770
  return;
6435
6771
  }
@@ -6448,12 +6784,12 @@ async function missionSet(opts = {}) {
6448
6784
  try {
6449
6785
  writeMission(cwd, mission);
6450
6786
  } catch (e) {
6451
- console.error(chalk32.red(` \u274C mission.json \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6787
+ console.error(chalk33.red(` \u274C mission.json \uAE30\uB85D \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6452
6788
  process.exitCode = 1;
6453
6789
  return;
6454
6790
  }
6455
- console.log(chalk32.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uC800\uC7A5"));
6456
- console.log(chalk32.dim(` \u{1F4C4} ${MISSION_PATH_REL}`));
6791
+ console.log(chalk33.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uC800\uC7A5"));
6792
+ console.log(chalk33.dim(` \u{1F4C4} ${MISSION_PATH_REL}`));
6457
6793
  console.log(` objective: ${mission.objective}`);
6458
6794
  console.log(` scope: ${mission.scope.length ? mission.scope.join(", ") : "(\uC81C\uD55C \uC5C6\uC74C)"}`);
6459
6795
  console.log(` forbidden: ${mission.forbidden.length ? mission.forbidden.join(", ") : "(\uC5C6\uC74C)"}`);
@@ -6463,64 +6799,64 @@ async function missionShow() {
6463
6799
  const cwd = process.cwd();
6464
6800
  const mission = readMission(cwd);
6465
6801
  if (!mission) {
6466
- console.error(chalk32.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhk/mission.json)."));
6802
+ console.error(chalk33.yellow(" \u26A0\uFE0F \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhk/mission.json)."));
6467
6803
  printNextStep({ message: "\uBA3C\uC800 \uBBF8\uC158\uC744 \uC120\uC5B8\uD558\uC138\uC694:", command: 'vhk mission set --objective "..."', cursorHint: "\uBBF8\uC158 \uC815\uD574\uC918" });
6468
6804
  process.exitCode = 1;
6469
6805
  return;
6470
6806
  }
6471
- console.log(chalk32.bold("\n\u{1F3AF} \uD604\uC7AC \uBBF8\uC158 \uACC4\uC57D"));
6807
+ console.log(chalk33.bold("\n\u{1F3AF} \uD604\uC7AC \uBBF8\uC158 \uACC4\uC57D"));
6472
6808
  console.log(` objective: ${mission.objective}`);
6473
6809
  console.log(` scope: ${mission.scope.length ? mission.scope.join(", ") : "(\uC81C\uD55C \uC5C6\uC74C)"}`);
6474
6810
  console.log(` forbidden: ${mission.forbidden.length ? mission.forbidden.join(", ") : "(\uC5C6\uC74C)"}`);
6475
- console.log(chalk32.dim(` \uC0DD\uC131 ${mission.createdAt} \xB7 \uAC31\uC2E0 ${mission.updatedAt}`));
6811
+ console.log(chalk33.dim(` \uC0DD\uC131 ${mission.createdAt} \xB7 \uAC31\uC2E0 ${mission.updatedAt}`));
6476
6812
  }
6477
6813
  async function missionCheck() {
6478
6814
  const cwd = process.cwd();
6479
6815
  const mission = readMission(cwd);
6480
6816
  if (!mission) {
6481
- 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."));
6817
+ 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."));
6482
6818
  process.exitCode = 1;
6483
6819
  return;
6484
6820
  }
6485
6821
  const changed = await collectChangedFiles(cwd);
6486
6822
  const result = checkMission(changed, mission);
6487
- console.log(chalk32.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uAC80\uC99D (mission check)"));
6488
- console.log(chalk32.dim(` objective: ${mission.objective} \xB7 \uBCC0\uACBD \uD30C\uC77C ${changed.length}\uAC1C`));
6823
+ console.log(chalk33.bold("\n\u{1F3AF} \uBBF8\uC158 \uACC4\uC57D \uAC80\uC99D (mission check)"));
6824
+ console.log(chalk33.dim(` objective: ${mission.objective} \xB7 \uBCC0\uACBD \uD30C\uC77C ${changed.length}\uAC1C`));
6489
6825
  if (result.violations.length > 0) {
6490
- console.log(chalk32.red.bold(`
6826
+ console.log(chalk33.red.bold(`
6491
6827
  \u{1F6AB} forbidden \uC704\uBC18 ${result.violations.length}\uAC74`));
6492
- for (const v of result.violations) console.log(chalk32.red(` \u2717 ${v.file} (\uAE08\uC9C0: ${v.pattern})`));
6828
+ for (const v of result.violations) console.log(chalk33.red(` \u2717 ${v.file} (\uAE08\uC9C0: ${v.pattern})`));
6493
6829
  }
6494
6830
  if (result.warnings.length > 0) {
6495
- console.log(chalk32.yellow.bold(`
6831
+ console.log(chalk33.yellow.bold(`
6496
6832
  \u26A0\uFE0F scope \uBC16 \uBCC0\uACBD ${result.warnings.length}\uAC74 (\uACBD\uACE0)`));
6497
- for (const w of result.warnings) console.log(chalk32.yellow(` ? ${w.file}`));
6833
+ for (const w of result.warnings) console.log(chalk33.yellow(` ? ${w.file}`));
6498
6834
  }
6499
6835
  if (result.violations.length === 0 && result.warnings.length === 0) {
6500
- console.log(chalk32.green("\n \u2713 \uBCC0\uACBD\uC774 \uACC4\uC57D(scope/forbidden) \uC548\uC785\uB2C8\uB2E4."));
6836
+ console.log(chalk33.green("\n \u2713 \uBCC0\uACBD\uC774 \uACC4\uC57D(scope/forbidden) \uC548\uC785\uB2C8\uB2E4."));
6501
6837
  }
6502
- console.log(chalk32.yellow(`
6838
+ console.log(chalk33.yellow(`
6503
6839
  ${result.disclaimer}`));
6504
6840
  process.exitCode = result.violations.length > 0 ? 1 : 0;
6505
6841
  }
6506
6842
  async function missionClear() {
6507
6843
  const cwd = process.cwd();
6508
- const p = join13(cwd, MISSION_PATH_REL);
6509
- if (!existsSync18(p)) {
6510
- console.log(chalk32.dim(" \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC9C0\uC6B8 \uAC83 \uC5C6\uC74C."));
6844
+ const p = join14(cwd, MISSION_PATH_REL);
6845
+ if (!existsSync19(p)) {
6846
+ console.log(chalk33.dim(" \uBBF8\uC158 \uACC4\uC57D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uC9C0\uC6B8 \uAC83 \uC5C6\uC74C."));
6511
6847
  return;
6512
6848
  }
6513
6849
  try {
6514
6850
  rmSync4(p);
6515
- console.log(chalk32.green(" \u2705 \uBBF8\uC158 \uACC4\uC57D \uC0AD\uC81C\uB428 (.vhk/mission.json)."));
6851
+ console.log(chalk33.green(" \u2705 \uBBF8\uC158 \uACC4\uC57D \uC0AD\uC81C\uB428 (.vhk/mission.json)."));
6516
6852
  } catch (e) {
6517
- console.error(chalk32.red(` \u274C \uC0AD\uC81C \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6853
+ console.error(chalk33.red(` \u274C \uC0AD\uC81C \uC2E4\uD328: ${e instanceof Error ? e.message : String(e)}`));
6518
6854
  process.exitCode = 1;
6519
6855
  }
6520
6856
  }
6521
6857
 
6522
6858
  // src/commands/pattern.ts
6523
- import chalk33 from "chalk";
6859
+ import chalk34 from "chalk";
6524
6860
  var MIN_TAG_FREQ = 3;
6525
6861
  var STOPWORDS = /* @__PURE__ */ new Set(["the", "a", "an", "is", "are", "and", "or", "in", "on", "at", "to", "for", "of", "with", "it", "was", "be"]);
6526
6862
  function tokenize(text) {
@@ -6638,14 +6974,14 @@ function reconcilePatterns(patterns, candidates, now) {
6638
6974
  async function patternDetect(opts = {}) {
6639
6975
  const minFreq = opts.min !== void 0 ? parseInt(opts.min, 10) : MIN_TAG_FREQ;
6640
6976
  if (!Number.isFinite(minFreq) || minFreq < 1) {
6641
- console.log(chalk33.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
6977
+ console.log(chalk34.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
6642
6978
  process.exitCode = 1;
6643
6979
  return;
6644
6980
  }
6645
6981
  const cwd = process.cwd();
6646
6982
  const loaded = loadForMutation(cwd);
6647
6983
  if (!loaded.ok) {
6648
- 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."));
6984
+ 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."));
6649
6985
  process.exitCode = 1;
6650
6986
  return;
6651
6987
  }
@@ -6661,26 +6997,26 @@ async function patternDetect(opts = {}) {
6661
6997
  console.log(JSON.stringify(active2, null, 2));
6662
6998
  return;
6663
6999
  }
6664
- console.log(chalk33.bold("\n\u{1F50D} " + t("pattern.detectTitle")));
6665
- console.log(chalk33.gray("\u2500".repeat(40)));
6666
- console.log(chalk33.dim(` \uC784\uACC4: ${minFreq}\uD68C \uC774\uC0C1 \xB7 active failures+successes \uC785\uB825`));
6667
- console.log(chalk33.dim(` \uD6C4\uBCF4: ${candidates.length}\uAC1C \uAC10\uC9C0 (\uCD94\uAC00 ${added} / \uAC31\uC2E0 ${updated})`));
7000
+ console.log(chalk34.bold("\n\u{1F50D} " + t("pattern.detectTitle")));
7001
+ console.log(chalk34.gray("\u2500".repeat(40)));
7002
+ console.log(chalk34.dim(` \uC784\uACC4: ${minFreq}\uD68C \uC774\uC0C1 \xB7 active failures+successes \uC785\uB825`));
7003
+ console.log(chalk34.dim(` \uD6C4\uBCF4: ${candidates.length}\uAC1C \uAC10\uC9C0 (\uCD94\uAC00 ${added} / \uAC31\uC2E0 ${updated})`));
6668
7004
  const active = mem.patterns.filter((p) => p.status !== "archived");
6669
7005
  if (active.length === 0) {
6670
- console.log(chalk33.yellow("\n\u{1F4ED} \uC784\uACC4 \uC774\uC0C1 \uBC18\uBCF5 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6671
- console.log(chalk33.gray(` failures/successes \uAC00 ${minFreq}\uAC1C \uC774\uC0C1 \uC313\uC774\uBA74 \uAC10\uC9C0\uB429\uB2C8\uB2E4.`));
6672
- console.log(chalk33.gray(" --min N \uC73C\uB85C \uC784\uACC4\uB97C \uB0AE\uCD9C \uC218 \uC788\uC2B5\uB2C8\uB2E4."));
7006
+ console.log(chalk34.yellow("\n\u{1F4ED} \uC784\uACC4 \uC774\uC0C1 \uBC18\uBCF5 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
7007
+ console.log(chalk34.gray(` failures/successes \uAC00 ${minFreq}\uAC1C \uC774\uC0C1 \uC313\uC774\uBA74 \uAC10\uC9C0\uB429\uB2C8\uB2E4.`));
7008
+ console.log(chalk34.gray(" --min N \uC73C\uB85C \uC784\uACC4\uB97C \uB0AE\uCD9C \uC218 \uC788\uC2B5\uB2C8\uB2E4."));
6673
7009
  return;
6674
7010
  }
6675
- console.log(chalk33.cyan(`
7011
+ console.log(chalk34.cyan(`
6676
7012
  \uD328\uD134 \uD6C4\uBCF4 ${active.length}\uAC1C:
6677
7013
  `));
6678
7014
  for (const p of active.slice(0, 20)) {
6679
7015
  const icon = p.kind === "avoid" ? "\u26A0\uFE0F " : "\u2705";
6680
7016
  console.log(` [${p.id}] ${icon} (${p.kind}/${p.axis}) "${p.signal}" \u2014 ${p.count}\uAC74`);
6681
7017
  const preview = p.sources.slice(0, 5).join(", ") + (p.sources.length > 5 ? ` \uC678 ${p.sources.length - 5}\uAC74` : "");
6682
- console.log(chalk33.dim(` \uADFC\uAC70: ${preview}`));
6683
- console.log(chalk33.dim(` ${p.summary}`));
7018
+ console.log(chalk34.dim(` \uADFC\uAC70: ${preview}`));
7019
+ console.log(chalk34.dim(` ${p.summary}`));
6684
7020
  }
6685
7021
  printNextStep({
6686
7022
  message: `\uD328\uD134 \uAC10\uC9C0 \uC644\uB8CC! ${active.length}\uAC1C \uD6C4\uBCF4.`,
@@ -6690,8 +7026,8 @@ async function patternDetect(opts = {}) {
6690
7026
  });
6691
7027
  }
6692
7028
  async function patternList(opts = {}) {
6693
- console.log(chalk33.bold("\n\u{1F50D} " + t("pattern.listTitle")));
6694
- console.log(chalk33.gray("\u2500".repeat(40)));
7029
+ console.log(chalk34.bold("\n\u{1F50D} " + t("pattern.listTitle")));
7030
+ console.log(chalk34.gray("\u2500".repeat(40)));
6695
7031
  const mem = readMemory(process.cwd());
6696
7032
  let patterns = mem.patterns;
6697
7033
  if (!opts.all) patterns = patterns.filter((p) => p.status !== "archived");
@@ -6703,51 +7039,51 @@ async function patternList(opts = {}) {
6703
7039
  return;
6704
7040
  }
6705
7041
  if (patterns.length === 0) {
6706
- console.log(chalk33.yellow("\n\u{1F4ED} \uD45C\uC2DC\uD560 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
6707
- console.log(chalk33.gray(" vhk pattern detect \uB85C \uAC10\uC9C0 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
7042
+ console.log(chalk34.yellow("\n\u{1F4ED} \uD45C\uC2DC\uD560 \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
7043
+ console.log(chalk34.gray(" vhk pattern detect \uB85C \uAC10\uC9C0 \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
6708
7044
  return;
6709
7045
  }
6710
- console.log(chalk33.cyan(`
7046
+ console.log(chalk34.cyan(`
6711
7047
  ${patterns.length}\uAC1C${opts.all ? " (\uBCF4\uAD00 \uD3EC\uD568)" : " (\uD65C\uC131)"}:
6712
7048
  `));
6713
7049
  for (const p of patterns) {
6714
7050
  const icon = p.kind === "avoid" ? "\u26A0\uFE0F " : "\u2705";
6715
7051
  const archived = p.status === "archived" ? "\u{1F4E6} " : "";
6716
7052
  console.log(` [${p.id}] ${archived}${icon} (${p.kind}/${p.axis}) "${p.signal}" \u2014 ${p.count}\uAC74`);
6717
- if (p.summary) console.log(chalk33.dim(` ${p.summary}`));
6718
- if (p.tags?.length) console.log(chalk33.blue(` \u{1F3F7}\uFE0F ${p.tags.join(", ")}`));
7053
+ if (p.summary) console.log(chalk34.dim(` ${p.summary}`));
7054
+ if (p.tags?.length) console.log(chalk34.blue(` \u{1F3F7}\uFE0F ${p.tags.join(", ")}`));
6719
7055
  }
6720
7056
  }
6721
7057
  async function patternDismiss(idStr) {
6722
7058
  if (!idStr?.trim()) {
6723
- console.log(chalk33.red("\u274C \uD328\uD134 id \uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608: vhk pattern dismiss p1"));
7059
+ console.log(chalk34.red("\u274C \uD328\uD134 id \uB97C \uC785\uB825\uD574\uC8FC\uC138\uC694. \uC608: vhk pattern dismiss p1"));
6724
7060
  process.exitCode = 1;
6725
7061
  return;
6726
7062
  }
6727
7063
  const cwd = process.cwd();
6728
7064
  const loaded = loadForMutation(cwd);
6729
7065
  if (!loaded.ok) {
6730
- console.log(chalk33.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 dismiss \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
7066
+ console.log(chalk34.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 dismiss \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6731
7067
  process.exitCode = 1;
6732
7068
  return;
6733
7069
  }
6734
7070
  const mem = loaded.mem;
6735
7071
  const pattern = mem.patterns.find((p) => p.id === idStr.trim());
6736
7072
  if (!pattern) {
6737
- console.log(chalk33.red(`\u274C \uD328\uD134 '${idStr}' \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`));
6738
- console.log(chalk33.gray(" vhk pattern list --all \uB85C \uBAA9\uB85D \uD655\uC778."));
7073
+ console.log(chalk34.red(`\u274C \uD328\uD134 '${idStr}' \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.`));
7074
+ console.log(chalk34.gray(" vhk pattern list --all \uB85C \uBAA9\uB85D \uD655\uC778."));
6739
7075
  process.exitCode = 1;
6740
7076
  return;
6741
7077
  }
6742
7078
  if (pattern.status === "archived") {
6743
- console.log(chalk33.dim(` \uC774\uBBF8 \uBCF4\uAD00\uB41C \uD328\uD134\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${pattern.id}`));
7079
+ console.log(chalk34.dim(` \uC774\uBBF8 \uBCF4\uAD00\uB41C \uD328\uD134\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${pattern.id}`));
6744
7080
  return;
6745
7081
  }
6746
7082
  pattern.status = "archived";
6747
7083
  writeMemory(cwd, mem);
6748
- console.log(chalk33.green(`
7084
+ console.log(chalk34.green(`
6749
7085
  \u{1F4E6} \uD328\uD134 dismiss(\uBCF4\uAD00)\uB428: [${pattern.id}] ${pattern.summary ?? pattern.signal}`));
6750
- console.log(chalk33.dim(" \uC624\uD0D0\uC73C\uB85C \uD310\uB2E8. detect \uC7AC\uC2E4\uD589 \uC2DC \uC7AC\uC81C\uC548 \uC548 \uB428."));
7086
+ console.log(chalk34.dim(" \uC624\uD0D0\uC73C\uB85C \uD310\uB2E8. detect \uC7AC\uC2E4\uD589 \uC2DC \uC7AC\uC81C\uC548 \uC548 \uB428."));
6751
7087
  printNextStep({
6752
7088
  message: "\uD328\uD134 dismiss \uC644\uB8CC!",
6753
7089
  command: "vhk pattern list",
@@ -6756,11 +7092,11 @@ async function patternDismiss(idStr) {
6756
7092
  }
6757
7093
 
6758
7094
  // src/commands/evolve.ts
6759
- import { existsSync as existsSync19, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync7, copyFileSync as copyFileSync2, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
6760
- import { join as join14 } from "path";
6761
- import chalk34 from "chalk";
7095
+ import { existsSync as existsSync20, mkdirSync as mkdirSync14, writeFileSync as writeFileSync15, readFileSync as readFileSync8, copyFileSync as copyFileSync2, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
7096
+ import { join as join15 } from "path";
7097
+ import chalk35 from "chalk";
6762
7098
  import inquirer13 from "inquirer";
6763
- var QUEUE_PATH_REL = join14(".vhk", "evolve", "queue.json");
7099
+ var QUEUE_PATH_REL = join15(".vhk", "evolve", "queue.json");
6764
7100
  function buildDraft(p) {
6765
7101
  const axisLabel = p.axis === "tag" ? `\uD0DC\uADF8 '${p.signal}'` : `\uD0A4\uC6CC\uB4DC '${p.signal}'`;
6766
7102
  const countDesc = `${p.count}\uAC74 \uBC18\uBCF5`;
@@ -6804,10 +7140,10 @@ function stripBomStr(s) {
6804
7140
  return s.charCodeAt(0) === 65279 ? s.slice(1) : s;
6805
7141
  }
6806
7142
  function readQueue(cwd) {
6807
- const p = join14(cwd, QUEUE_PATH_REL);
6808
- if (!existsSync19(p)) return { version: 1, items: [] };
7143
+ const p = join15(cwd, QUEUE_PATH_REL);
7144
+ if (!existsSync20(p)) return { version: 1, items: [] };
6809
7145
  try {
6810
- const raw = stripBomStr(readFileSync7(p, "utf-8"));
7146
+ const raw = stripBomStr(readFileSync8(p, "utf-8"));
6811
7147
  const parsed = JSON.parse(raw);
6812
7148
  if (!parsed || !Array.isArray(parsed.items)) return { version: 1, items: [] };
6813
7149
  return parsed;
@@ -6816,10 +7152,10 @@ function readQueue(cwd) {
6816
7152
  }
6817
7153
  }
6818
7154
  function writeQueue(cwd, queue) {
6819
- const p = join14(cwd, QUEUE_PATH_REL);
6820
- mkdirSync13(join14(cwd, ".vhk", "evolve"), { recursive: true });
7155
+ const p = join15(cwd, QUEUE_PATH_REL);
7156
+ mkdirSync14(join15(cwd, ".vhk", "evolve"), { recursive: true });
6821
7157
  const tmpPath = p + ".tmp";
6822
- writeFileSync14(tmpPath, JSON.stringify(queue, null, 2) + "\n", "utf-8");
7158
+ writeFileSync15(tmpPath, JSON.stringify(queue, null, 2) + "\n", "utf-8");
6823
7159
  try {
6824
7160
  renameSync2(tmpPath, p);
6825
7161
  } catch (err) {
@@ -6848,8 +7184,8 @@ function checkApplyRef(pattern, queueItems) {
6848
7184
  }
6849
7185
  async function evolveSuggest(opts = {}) {
6850
7186
  const cwd = process.cwd();
6851
- if (!existsSync19(join14(cwd, "RULES.md"))) {
6852
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.noRules")));
7187
+ if (!existsSync20(join15(cwd, "RULES.md"))) {
7188
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.noRules")));
6853
7189
  process.exitCode = 1;
6854
7190
  return;
6855
7191
  }
@@ -6860,10 +7196,10 @@ async function evolveSuggest(opts = {}) {
6860
7196
  if (newItems.length === 0 && !opts.json) {
6861
7197
  const activeAvoid = patterns.filter((p) => p.kind === "avoid" && p.status === "active");
6862
7198
  if (activeAvoid.length === 0) {
6863
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noPatterns")));
7199
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noPatterns")));
6864
7200
  return;
6865
7201
  }
6866
- console.log(chalk34.dim("\n " + t("evolve.allSuggested")));
7202
+ console.log(chalk35.dim("\n " + t("evolve.allSuggested")));
6867
7203
  return;
6868
7204
  }
6869
7205
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -6876,16 +7212,16 @@ async function evolveSuggest(opts = {}) {
6876
7212
  console.log(JSON.stringify(pending2, null, 2));
6877
7213
  return;
6878
7214
  }
6879
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.suggestTitle")));
6880
- console.log(chalk34.gray("\u2500".repeat(40)));
6881
- console.log(chalk34.dim(" " + t("evolve.newCandidates", newItems.length)));
7215
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.suggestTitle")));
7216
+ console.log(chalk35.gray("\u2500".repeat(40)));
7217
+ console.log(chalk35.dim(" " + t("evolve.newCandidates", newItems.length)));
6882
7218
  const pending = queue.items.filter((i) => i.status === "pending");
6883
- console.log(chalk34.cyan(`
7219
+ console.log(chalk35.cyan(`
6884
7220
  \uD6C4\uBCF4 ${pending.length}\uAC1C:
6885
7221
  `));
6886
7222
  for (const item of pending) {
6887
7223
  console.log(` [${item.id}] (${item.status}) \uD328\uD134 ${item.patternId} \u2192 rule`);
6888
- console.log(chalk34.dim(` \uCD08\uC548: ${item.draft}`));
7224
+ console.log(chalk35.dim(` \uCD08\uC548: ${item.draft}`));
6889
7225
  }
6890
7226
  printNextStep({
6891
7227
  message: `\uC9C4\uD654 \uD6C4\uBCF4 ${pending.length}\uAC1C \uC0DD\uC131\uB428!`,
@@ -6906,11 +7242,11 @@ async function evolveList(opts = {}) {
6906
7242
  console.log(JSON.stringify(items, null, 2));
6907
7243
  return;
6908
7244
  }
6909
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.listTitle")));
6910
- console.log(chalk34.gray("\u2500".repeat(40)));
7245
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.listTitle")));
7246
+ console.log(chalk35.gray("\u2500".repeat(40)));
6911
7247
  if (items.length === 0) {
6912
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noQueue")));
6913
- console.log(chalk34.gray(" " + t("evolve.suggestHint")));
7248
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noQueue")));
7249
+ console.log(chalk35.gray(" " + t("evolve.suggestHint")));
6914
7250
  return;
6915
7251
  }
6916
7252
  const STATUS_ICON3 = {
@@ -6918,68 +7254,68 @@ async function evolveList(opts = {}) {
6918
7254
  rejected: "\u274C",
6919
7255
  applied: "\u2705"
6920
7256
  };
6921
- console.log(chalk34.cyan(`
7257
+ console.log(chalk35.cyan(`
6922
7258
  ${items.length}\uAC1C:
6923
7259
  `));
6924
7260
  for (const item of items) {
6925
7261
  console.log(` [${item.id}] ${STATUS_ICON3[item.status]} (${item.status}) \u2192 ${item.draft}`);
6926
- if (item.appliedAt) console.log(chalk34.dim(` \uBC18\uC601: ${item.appliedAt}`));
7262
+ if (item.appliedAt) console.log(chalk35.dim(` \uBC18\uC601: ${item.appliedAt}`));
6927
7263
  }
6928
7264
  }
6929
7265
  async function evolveApply(idStr) {
6930
7266
  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;
6931
7267
  const cwd = process.cwd();
6932
- const rulesPath = join14(cwd, "RULES.md");
6933
- if (!existsSync19(rulesPath)) {
6934
- console.log(chalk34.red("\n\u274C " + t("evolve.noRules")));
7268
+ const rulesPath = join15(cwd, "RULES.md");
7269
+ if (!existsSync20(rulesPath)) {
7270
+ console.log(chalk35.red("\n\u274C " + t("evolve.noRules")));
6935
7271
  process.exitCode = 1;
6936
7272
  return;
6937
7273
  }
6938
7274
  const queue = readQueue(cwd);
6939
7275
  const item = queue.items.find((i) => i.id === idStr?.trim());
6940
7276
  if (!item) {
6941
- console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7277
+ console.log(chalk35.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
6942
7278
  process.exitCode = 1;
6943
7279
  return;
6944
7280
  }
6945
7281
  if (item.status === "applied") {
6946
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.alreadyApplied")));
7282
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.alreadyApplied")));
6947
7283
  process.exitCode = 1;
6948
7284
  return;
6949
7285
  }
6950
7286
  const hasUnresolved = queue.items.some((i) => i.status === "applied");
6951
7287
  if (hasUnresolved) {
6952
- console.log(chalk34.red("\n\u274C " + t("evolve.pendingApplyExists")));
7288
+ console.log(chalk35.red("\n\u274C " + t("evolve.pendingApplyExists")));
6953
7289
  process.exitCode = 1;
6954
7290
  return;
6955
7291
  }
6956
7292
  const memLoaded = loadForMutation(cwd);
6957
7293
  if (!memLoaded.ok) {
6958
- console.log(chalk34.red("\n\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 apply \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
7294
+ console.log(chalk35.red("\n\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 apply \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6959
7295
  process.exitCode = 1;
6960
7296
  return;
6961
7297
  }
6962
7298
  const srcPattern = memLoaded.mem.patterns.find((p) => p.id === item.patternId);
6963
7299
  const refResult = checkApplyRef(srcPattern, queue.items);
6964
7300
  if (refResult === "dismissed") {
6965
- console.log(chalk34.red("\n\u274C " + t("evolve.dismissed")));
7301
+ console.log(chalk35.red("\n\u274C " + t("evolve.dismissed")));
6966
7302
  process.exitCode = 1;
6967
7303
  return;
6968
7304
  }
6969
7305
  if (refResult === "already-applied") {
6970
- console.log(chalk34.red("\n\u274C " + t("evolve.alreadyAppliedPattern")));
7306
+ console.log(chalk35.red("\n\u274C " + t("evolve.alreadyAppliedPattern")));
6971
7307
  process.exitCode = 1;
6972
7308
  return;
6973
7309
  }
6974
- const rulesContent = readFileSync7(rulesPath, "utf-8");
7310
+ const rulesContent = readFileSync8(rulesPath, "utf-8");
6975
7311
  if (isDuplicateRule(rulesContent, item.draft)) {
6976
- console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.duplicateRule", item.draft)));
7312
+ console.log(chalk35.yellow("\n\u26A0\uFE0F " + t("evolve.duplicateRule", item.draft)));
6977
7313
  return;
6978
7314
  }
6979
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.applyTitle")));
6980
- console.log(chalk34.gray("\u2500".repeat(40)));
6981
- console.log(chalk34.cyan("\n\uCD94\uAC00\uB420 \uB8F0 \uCD08\uC548:"));
6982
- console.log(chalk34.white(` ${item.draft}`));
7315
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.applyTitle")));
7316
+ console.log(chalk35.gray("\u2500".repeat(40)));
7317
+ console.log(chalk35.cyan("\n\uCD94\uAC00\uB420 \uB8F0 \uCD08\uC548:"));
7318
+ console.log(chalk35.white(` ${item.draft}`));
6983
7319
  const { editedDraft } = await inquirer13.prompt([{
6984
7320
  type: "input",
6985
7321
  name: "editedDraft",
@@ -6994,22 +7330,22 @@ async function evolveApply(idStr) {
6994
7330
  default: false
6995
7331
  }]);
6996
7332
  if (!confirmed) {
6997
- console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
7333
+ console.log(chalk35.dim(" \uCDE8\uC18C\uB428."));
6998
7334
  return;
6999
7335
  }
7000
7336
  const backupPath = rulesPath + ".bak";
7001
7337
  copyFileSync2(rulesPath, backupPath);
7002
7338
  const appendContent = "\n" + editedDraft + "\n";
7003
7339
  try {
7004
- writeFileSync14(rulesPath, rulesContent + appendContent, "utf-8");
7340
+ writeFileSync15(rulesPath, rulesContent + appendContent, "utf-8");
7005
7341
  await sync({ yes: true });
7006
7342
  } catch (err) {
7007
7343
  try {
7008
7344
  copyFileSync2(backupPath, rulesPath);
7009
7345
  } catch {
7010
7346
  }
7011
- 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."));
7012
- console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7347
+ 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."));
7348
+ console.error(chalk35.dim(` ${err instanceof Error ? err.message : String(err)}`));
7013
7349
  process.exitCode = 1;
7014
7350
  return;
7015
7351
  }
@@ -7025,12 +7361,12 @@ async function evolveApply(idStr) {
7025
7361
  p.status = "archived";
7026
7362
  writeMemory(cwd, memLoaded.mem);
7027
7363
  } else {
7028
- 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."));
7364
+ 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."));
7029
7365
  }
7030
7366
  }
7031
- console.log(chalk34.green(`
7367
+ console.log(chalk35.green(`
7032
7368
  \u2705 \uB8F0 \uBC18\uC601 \uC644\uB8CC! [${item.id}]`));
7033
- console.log(chalk34.dim(" RULES.md\uC5D0 \uCD94\uAC00 + vhk sync \uC7AC\uC0DD\uC131\uB428"));
7369
+ console.log(chalk35.dim(" RULES.md\uC5D0 \uCD94\uAC00 + vhk sync \uC7AC\uC0DD\uC131\uB428"));
7034
7370
  printNextStep({
7035
7371
  message: "\uB8F0 \uBC18\uC601 \uC644\uB8CC!",
7036
7372
  command: "vhk evolve list --status applied",
@@ -7043,25 +7379,25 @@ async function evolveReject(idStr) {
7043
7379
  const queue = readQueue(cwd);
7044
7380
  const item = queue.items.find((i) => i.id === idStr?.trim());
7045
7381
  if (!item) {
7046
- console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7382
+ console.log(chalk35.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7047
7383
  process.exitCode = 1;
7048
7384
  return;
7049
7385
  }
7050
7386
  if (item.status === "rejected") {
7051
- console.log(chalk34.dim(` \uC774\uBBF8 \uAE30\uAC01\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${item.id}`));
7387
+ console.log(chalk35.dim(` \uC774\uBBF8 \uAE30\uAC01\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${item.id}`));
7052
7388
  return;
7053
7389
  }
7054
7390
  if (item.status === "applied") {
7055
- console.log(chalk34.red(`
7391
+ console.log(chalk35.red(`
7056
7392
  \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}`));
7057
7393
  process.exitCode = 1;
7058
7394
  return;
7059
7395
  }
7060
7396
  item.status = "rejected";
7061
7397
  writeQueue(cwd, queue);
7062
- console.log(chalk34.green(`
7398
+ console.log(chalk35.green(`
7063
7399
  \u274C \uD6C4\uBCF4 \uAE30\uAC01\uB428: [${item.id}] ${item.draft}`));
7064
- console.log(chalk34.dim(" (A1: \uB2E4\uC74C suggest\uC5D0\uC11C \uC7AC\uC81C\uC548 \uC548 \uB428)"));
7400
+ console.log(chalk35.dim(" (A1: \uB2E4\uC74C suggest\uC5D0\uC11C \uC7AC\uC81C\uC548 \uC548 \uB428)"));
7065
7401
  printNextStep({
7066
7402
  message: "\uAE30\uAC01 \uC644\uB8CC!",
7067
7403
  command: "vhk evolve list",
@@ -7074,19 +7410,19 @@ async function evolveUndo() {
7074
7410
  const queue = readQueue(cwd);
7075
7411
  const applied = queue.items.filter((i) => i.status === "applied");
7076
7412
  if (applied.length === 0) {
7077
- console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noAppliedToUndo")));
7413
+ console.log(chalk35.yellow("\n\u{1F4ED} " + t("evolve.noAppliedToUndo")));
7078
7414
  return;
7079
7415
  }
7080
7416
  const last = applied.sort(
7081
7417
  (a, b) => (b.appliedAt ?? "").localeCompare(a.appliedAt ?? "")
7082
7418
  )[0];
7083
- if (!last.rulesBackupPath || !existsSync19(last.rulesBackupPath)) {
7084
- console.log(chalk34.red("\n\u274C " + t("evolve.noBackup")));
7419
+ if (!last.rulesBackupPath || !existsSync20(last.rulesBackupPath)) {
7420
+ console.log(chalk35.red("\n\u274C " + t("evolve.noBackup")));
7085
7421
  process.exitCode = 1;
7086
7422
  return;
7087
7423
  }
7088
- console.log(chalk34.bold("\n\u{1F504} " + t("evolve.undoTitle")));
7089
- console.log(chalk34.dim(` \uB418\uB3CC\uB9B4 \uD56D\uBAA9: [${last.id}] ${last.draft}`));
7424
+ console.log(chalk35.bold("\n\u{1F504} " + t("evolve.undoTitle")));
7425
+ console.log(chalk35.dim(` \uB418\uB3CC\uB9B4 \uD56D\uBAA9: [${last.id}] ${last.draft}`));
7090
7426
  const { confirmed } = await inquirer13.prompt([{
7091
7427
  type: "confirm",
7092
7428
  name: "confirmed",
@@ -7094,16 +7430,16 @@ async function evolveUndo() {
7094
7430
  default: false
7095
7431
  }]);
7096
7432
  if (!confirmed) {
7097
- console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
7433
+ console.log(chalk35.dim(" \uCDE8\uC18C\uB428."));
7098
7434
  return;
7099
7435
  }
7100
- copyFileSync2(last.rulesBackupPath, join14(cwd, "RULES.md"));
7436
+ copyFileSync2(last.rulesBackupPath, join15(cwd, "RULES.md"));
7101
7437
  try {
7102
7438
  await sync({ yes: true });
7103
7439
  } catch (err) {
7104
- 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."));
7105
- console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7106
- console.error(chalk34.dim(" \uC218\uB3D9\uC73C\uB85C `vhk sync` \uC2E4\uD589\uD558\uC138\uC694."));
7440
+ 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."));
7441
+ console.error(chalk35.dim(` ${err instanceof Error ? err.message : String(err)}`));
7442
+ console.error(chalk35.dim(" \uC218\uB3D9\uC73C\uB85C `vhk sync` \uC2E4\uD589\uD558\uC138\uC694."));
7107
7443
  }
7108
7444
  last.status = "pending";
7109
7445
  delete last.appliedAt;
@@ -7117,7 +7453,7 @@ async function evolveUndo() {
7117
7453
  writeMemory(cwd, memLoaded.mem);
7118
7454
  }
7119
7455
  }
7120
- console.log(chalk34.green("\n\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC! RULES.md \uBCF5\uC6D0 + sync \uC7AC\uC2E4\uD589\uB428"));
7456
+ console.log(chalk35.green("\n\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC! RULES.md \uBCF5\uC6D0 + sync \uC7AC\uC2E4\uD589\uB428"));
7121
7457
  printNextStep({
7122
7458
  message: "\uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC!",
7123
7459
  command: "vhk evolve list",
@@ -7299,6 +7635,10 @@ async function dispatchNlpRoute(route, input) {
7299
7635
  return patternList();
7300
7636
  case "evolve":
7301
7637
  return evolveList();
7638
+ case "work": {
7639
+ if (route.args?.[0] === "handoff") return workHandoff();
7640
+ return work();
7641
+ }
7302
7642
  }
7303
7643
  }
7304
7644
  var STATE_CHANGING_COMMANDS = /* @__PURE__ */ new Set([
@@ -7312,14 +7652,14 @@ function requiresConfirmation(route) {
7312
7652
  async function runNaturalLanguageRoute(input) {
7313
7653
  const route = routeNaturalLanguage(input);
7314
7654
  if (!route) {
7315
- console.log(chalk35.yellow(`
7655
+ console.log(chalk36.yellow(`
7316
7656
  \u2753 "${input}" \u2014 ${ko.nlp.notMatched}
7317
7657
  `));
7318
7658
  return;
7319
7659
  }
7320
7660
  console.log("");
7321
- console.log(chalk35.cyan(` \u{1F4AC} "${input}"`));
7322
- console.log(chalk35.cyan(` \u2192 ${route.explanation}`));
7661
+ console.log(chalk36.cyan(` \u{1F4AC} "${input}"`));
7662
+ console.log(chalk36.cyan(` \u2192 ${route.explanation}`));
7323
7663
  if (requiresConfirmation(route)) {
7324
7664
  const { confirm } = await inquirer14.prompt([{
7325
7665
  type: "confirm",
@@ -7328,7 +7668,7 @@ async function runNaturalLanguageRoute(input) {
7328
7668
  default: true
7329
7669
  }]);
7330
7670
  if (!confirm) {
7331
- console.log(chalk35.dim(` ${ko.nlp.menuHint}`));
7671
+ console.log(chalk36.dim(` ${ko.nlp.menuHint}`));
7332
7672
  return;
7333
7673
  }
7334
7674
  }
@@ -7337,7 +7677,7 @@ async function runNaturalLanguageRoute(input) {
7337
7677
  if (riskAction) {
7338
7678
  await runGuarded(
7339
7679
  riskAction,
7340
- { channel: "nl", approved: false, log: (m) => console.log(chalk35.yellow(` ${m}`)) },
7680
+ { channel: "nl", approved: false, log: (m) => console.log(chalk36.yellow(` ${m}`)) },
7341
7681
  () => dispatchNlpRoute(route, input)
7342
7682
  );
7343
7683
  return;
@@ -7346,80 +7686,80 @@ async function runNaturalLanguageRoute(input) {
7346
7686
  }
7347
7687
 
7348
7688
  // src/commands/agent.ts
7349
- import chalk36 from "chalk";
7689
+ import chalk37 from "chalk";
7350
7690
  function activeGoalId() {
7351
7691
  const goals = listGoals("goals");
7352
7692
  const id = selectActiveId(goals);
7353
7693
  return id ?? void 0;
7354
7694
  }
7355
7695
  async function blocker(description) {
7356
- console.log(chalk36.bold(`
7696
+ console.log(chalk37.bold(`
7357
7697
  ${ko.agent.blockerTitle}
7358
7698
  `));
7359
7699
  if (!description || !description.trim()) {
7360
- console.log(chalk36.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7361
- console.log(chalk36.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
7700
+ console.log(chalk37.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7701
+ console.log(chalk37.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
7362
7702
  process.exitCode = 1;
7363
7703
  return;
7364
7704
  }
7365
7705
  const goalId = activeGoalId();
7366
7706
  const r = appendBlocker(description, goalId);
7367
- console.log(chalk36.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
7707
+ console.log(chalk37.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
7368
7708
  if (r.hardStopTripped) {
7369
- console.log(chalk36.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
7370
- console.log(chalk36.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
7709
+ console.log(chalk37.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
7710
+ console.log(chalk37.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
7371
7711
  process.exitCode = 2;
7372
7712
  }
7373
7713
  }
7374
7714
  async function learn(lesson) {
7375
- console.log(chalk36.bold(`
7715
+ console.log(chalk37.bold(`
7376
7716
  ${ko.agent.learnTitle}
7377
7717
  `));
7378
7718
  if (!lesson || !lesson.trim()) {
7379
- console.log(chalk36.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7380
- console.log(chalk36.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
7719
+ console.log(chalk37.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7720
+ console.log(chalk37.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
7381
7721
  process.exitCode = 1;
7382
7722
  return;
7383
7723
  }
7384
7724
  const goalId = activeGoalId();
7385
7725
  const entry = recordLesson(process.cwd(), lesson, goalId);
7386
7726
  if (!entry) {
7387
- 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."));
7727
+ 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."));
7388
7728
  process.exitCode = 1;
7389
7729
  return;
7390
7730
  }
7391
- console.log(chalk36.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7392
- 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."));
7731
+ console.log(chalk37.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7732
+ 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."));
7393
7733
  }
7394
7734
  async function resume(opts = {}) {
7395
- console.log(chalk36.bold(`
7735
+ console.log(chalk37.bold(`
7396
7736
  ${ko.agent.resumeTitle}
7397
7737
  `));
7398
7738
  if (!isHardStopActive()) {
7399
- console.log(chalk36.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7739
+ console.log(chalk37.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7400
7740
  return;
7401
7741
  }
7402
7742
  const reason = readHardStopReason();
7403
7743
  if (reason) {
7404
- console.log(chalk36.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7405
- console.log(chalk36.dim(` ${reason.split("\n").join("\n ")}`));
7744
+ console.log(chalk37.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7745
+ console.log(chalk37.dim(` ${reason.split("\n").join("\n ")}`));
7406
7746
  console.log("");
7407
7747
  }
7408
7748
  if (!opts.confirm) {
7409
7749
  console.log(
7410
- chalk36.red(
7750
+ chalk37.red(
7411
7751
  " \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
7412
7752
  )
7413
7753
  );
7414
- console.log(chalk36.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7754
+ console.log(chalk37.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7415
7755
  process.exitCode = 1;
7416
7756
  return;
7417
7757
  }
7418
7758
  const removed = clearHardStop();
7419
7759
  if (removed) {
7420
- console.log(chalk36.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7760
+ console.log(chalk37.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7421
7761
  } else {
7422
- console.log(chalk36.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7762
+ console.log(chalk37.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7423
7763
  }
7424
7764
  }
7425
7765
 
@@ -7440,7 +7780,7 @@ async function guardCli(action, approved, run) {
7440
7780
  }]);
7441
7781
  return ok;
7442
7782
  },
7443
- log: (m) => console.log(chalk37.yellow(` ${m}`))
7783
+ log: (m) => console.log(chalk38.yellow(` ${m}`))
7444
7784
  },
7445
7785
  run
7446
7786
  );
@@ -7453,7 +7793,7 @@ async function guardCliDefer(action, approved, run) {
7453
7793
  approved,
7454
7794
  // TTY 면 통과(명령이 자체 확인), 비대화형은 confirm 불가 → 가드가 차단.
7455
7795
  confirm: async () => !!process.stdout.isTTY,
7456
- log: (m) => console.log(chalk37.yellow(` ${m}`))
7796
+ log: (m) => console.log(chalk38.yellow(` ${m}`))
7457
7797
  },
7458
7798
  run
7459
7799
  );
@@ -7498,7 +7838,8 @@ var KO_ALIASES = {
7498
7838
  learn: "\uAD50\uD6C8",
7499
7839
  resume: "\uC7AC\uAC1C",
7500
7840
  pattern: "\uD328\uD134",
7501
- evolve: "\uC9C4\uD654"
7841
+ evolve: "\uC9C4\uD654",
7842
+ work: "\uC791\uC5C5"
7502
7843
  };
7503
7844
  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());
7504
7845
  program.configureHelp({
@@ -7546,7 +7887,9 @@ cloudCmd.command("pull").alias("\uB0B4\uB9AC\uAE30").argument("[gistId]", "\uBCF
7546
7887
  await guardCli("cloud-pull", opts?.yes === true, () => cloudPull(gistId));
7547
7888
  });
7548
7889
  program.command("ship").alias("\uCD9C\uD558").description("\uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 + \uD68C\uACE0 + \uBE4C\uB4DC \uB85C\uADF8 \uC0DD\uC131").action(ship);
7549
- 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);
7890
+ 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) => {
7891
+ await doctor(opts);
7892
+ });
7550
7893
  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) => {
7551
7894
  await guardCli("save", opts?.yes === true, () => save());
7552
7895
  });
@@ -7668,6 +8011,12 @@ memoryCmd.command("migrate").alias("\uB9C8\uC774\uADF8\uB808\uC774\uC158").descr
7668
8011
  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 () => {
7669
8012
  await brief();
7670
8013
  });
8014
+ 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 () => {
8015
+ await work();
8016
+ });
8017
+ 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 () => {
8018
+ await workHandoff();
8019
+ });
7671
8020
  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 () => {
7672
8021
  await goalList();
7673
8022
  });
@@ -7735,27 +8084,49 @@ program.on("command:*", async (operands) => {
7735
8084
  await runNaturalLanguageRoute(input);
7736
8085
  });
7737
8086
  program.action(async () => {
7738
- console.log("\n\u{1F3AF} VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58\n");
8087
+ const info = getUpdateInfo();
8088
+ console.log("\n\u{1F3AF} VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58 " + chalk38.dim(`v${info.current}`));
8089
+ if (info.updateAvailable && info.latest) {
8090
+ console.log(chalk38.yellow(`\u{1F195} \uC5C5\uB370\uC774\uD2B8 \uAC00\uB2A5: v${info.latest}`) + chalk38.dim(" \u2192 vhk update"));
8091
+ }
8092
+ const sample = QUICK_ACTIONS[0]?.say ?? "\uC0C1\uD0DC \uC54C\uB824\uC918";
8093
+ console.log(
8094
+ chalk38.dim("\u{1F4AC} \uBA85\uB839 \uC9C1\uC811 \uC785\uB825\uB3C4 \uB3FC\uC694 \u2014 \uC608: ") + chalk38.cyan("vhk status") + chalk38.dim(" \xB7 \uC790\uC5F0\uC5B4 OK: ") + chalk38.cyan(`"${sample}"`)
8095
+ );
8096
+ console.log("");
8097
+ const choices = [
8098
+ { name: "\u{1F680} \uC791\uC5C5 \uC2DC\uC791/\uC774\uC5B4\uD558\uAE30 (work)", value: "work" },
8099
+ { name: "\u{1F4A1} \uC0C8 \uC544\uC774\uB514\uC5B4 \uAC80\uC99D\uD558\uAE30", value: "gate" },
8100
+ { name: "\u{1F195} \uC0C8 \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 \uB9C8\uBC95\uC0AC (start)", value: "start" },
8101
+ { name: "\u{1F3AF} \uB2E4\uC74C \uBAA9\uD45C \uBCF4\uAE30 (goal)", value: "goal-next" },
8102
+ { name: "\u{1F4DD} \uC624\uB298 \uD55C \uC77C \uC815\uB9AC\uD558\uAE30", value: "recap" },
8103
+ { name: "\u{1F50D} \uADDC\uCE59 \uD30C\uC77C \uC810\uAC80\uD558\uAE30", value: "check" },
8104
+ { name: "\u{1F512} \uBCF4\uC548 \uC2A4\uCE94 \uB3CC\uB9AC\uAE30", value: "secure" },
8105
+ { name: "\u{1F504} \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654", value: "sync" },
8106
+ { name: "\u{1F680} \uBC30\uD3EC\uD558\uAE30", value: "ship" },
8107
+ { name: "\u{1FA7A} \uD658\uACBD \uC810\uAC80\uD558\uAE30", value: "doctor" },
8108
+ { name: "\u{1F4BE} Git\uC5D0 \uC800\uC7A5\uD558\uAE30", value: "save" },
8109
+ { name: "\u23EA \uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30", value: "undo" },
8110
+ { name: "\u{1F50D} \uBCC0\uACBD\uC0AC\uD56D \uBCF4\uAE30", value: "diff" },
8111
+ { name: "\u{1F4CA} \uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uBCF4\uAE30", value: "status" },
8112
+ { name: "\u23F8\uFE0F \uC791\uC5C5 \uC911\uB2E8 \uC815\uB9AC (handoff)", value: "work-handoff" }
8113
+ ];
7739
8114
  const { choice } = await inquirer15.prompt([{
7740
8115
  type: "list",
7741
8116
  name: "choice",
7742
8117
  message: "\uBB58 \uB3C4\uC640\uB4DC\uB9B4\uAE4C\uC694?",
7743
- choices: [
7744
- { name: "\u{1F4A1} \uC0C8 \uC544\uC774\uB514\uC5B4 \uAC80\uC99D\uD558\uAE30", value: "gate" },
7745
- { name: "\u{1F680} \uC0C8 \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 \uB9C8\uBC95\uC0AC (start)", value: "start" },
7746
- { name: "\u{1F4DD} \uC624\uB298 \uD55C \uC77C \uC815\uB9AC\uD558\uAE30", value: "recap" },
7747
- { name: "\u{1F50D} \uADDC\uCE59 \uD30C\uC77C \uC810\uAC80\uD558\uAE30", value: "check" },
7748
- { name: "\u{1F512} \uBCF4\uC548 \uC2A4\uCE94 \uB3CC\uB9AC\uAE30", value: "secure" },
7749
- { name: "\u{1F504} \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654", value: "sync" },
7750
- { name: "\u{1F680} \uBC30\uD3EC\uD558\uAE30", value: "ship" },
7751
- { name: "\u{1FA7A} \uD658\uACBD \uC810\uAC80\uD558\uAE30", value: "doctor" },
7752
- { name: "\u{1F4BE} Git\uC5D0 \uC800\uC7A5\uD558\uAE30", value: "save" },
7753
- { name: "\u23EA \uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30", value: "undo" },
7754
- { name: "\u{1F50D} \uBCC0\uACBD\uC0AC\uD56D \uBCF4\uAE30", value: "diff" },
7755
- { name: "\u{1F4CA} \uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uBCF4\uAE30", value: "status" }
7756
- ]
8118
+ pageSize: choices.length,
8119
+ // 스크롤 잔상/잘림 방지(Windows conhost): 화면에 전부
8120
+ loop: false,
8121
+ choices
7757
8122
  }]);
7758
8123
  switch (choice) {
8124
+ case "work":
8125
+ return work();
8126
+ case "work-handoff":
8127
+ return workHandoff();
8128
+ case "goal-next":
8129
+ return goalNext();
7759
8130
  case "gate":
7760
8131
  return gate();
7761
8132
  case "start":
@@ -7784,7 +8155,7 @@ program.action(async () => {
7784
8155
  });
7785
8156
  var getRealPath = (p) => {
7786
8157
  try {
7787
- return fs13.realpathSync(p);
8158
+ return fs14.realpathSync(p);
7788
8159
  } catch {
7789
8160
  return p;
7790
8161
  }
@@ -7800,9 +8171,9 @@ if (isMainModule) {
7800
8171
  }
7801
8172
  } catch (err) {
7802
8173
  if (isPromptAbortError(err)) {
7803
- 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)"));
8174
+ 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)"));
7804
8175
  } else {
7805
- console.error(chalk37.red(`
8176
+ console.error(chalk38.red(`
7806
8177
  \u274C ${err instanceof Error ? err.message : String(err)}`));
7807
8178
  }
7808
8179
  process.exitCode = 1;