@byh3071/vhk 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -918,6 +918,28 @@ var ko = {
918
918
  detectTitle: "\uD328\uD134 \uAC10\uC9C0",
919
919
  listTitle: "\uD328\uD134 \uBAA9\uB85D",
920
920
  dismissTitle: "\uD328\uD134 dismiss"
921
+ },
922
+ evolve: {
923
+ suggestTitle: "\uC9C4\uD654 \uC81C\uC548 \uC0DD\uC131",
924
+ listTitle: "\uC9C4\uD654 \uD6C4\uBCF4 \uBAA9\uB85D",
925
+ applyTitle: "\uB8F0 \uBC18\uC601",
926
+ rejectTitle: "\uD6C4\uBCF4 \uAE30\uAC01",
927
+ undoTitle: "\uCD5C\uADFC \uBC18\uC601 \uB418\uB3CC\uB9AC\uAE30",
928
+ noRules: "RULES.md \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. vhk init\uC73C\uB85C \uC0DD\uC131 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.",
929
+ noPatterns: "patterns[]\uAC00 \uBE44\uC5B4\uC788\uAC70\uB098 active avoid \uD328\uD134\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk pattern detect \uB85C \uBA3C\uC800 \uAC10\uC9C0\uD558\uC138\uC694.",
930
+ noQueue: "\uD6C4\uBCF4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. vhk evolve suggest \uB85C \uBA3C\uC800 \uC0DD\uC131\uD558\uC138\uC694.",
931
+ notFound: (id) => `\uD6C4\uBCF4 '${id}' \uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. vhk evolve list \uB85C \uD655\uC778\uD558\uC138\uC694.`,
932
+ alreadyApplied: "\uC774\uBBF8 \uBC18\uC601\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4.",
933
+ dismissed: "\uC18C\uC2A4 \uD328\uD134\uC774 dismiss\uB428 \u2014 apply \uAC70\uBD80 (dismiss\uB41C \uD328\uD134 \uAE30\uBC18 \uB8F0\uC740 \uBC18\uC601 \uC548 \uB428)",
934
+ alreadyAppliedPattern: "\uC18C\uC2A4 \uD328\uD134\uC774 \uC774\uBBF8 \uBC18\uC601\uB428 \u2014 apply \uAC70\uBD80",
935
+ duplicateRule: (draft) => `\uC911\uBCF5 \uB8F0 \uAC10\uC9C0 \u2014 RULES.md\uC5D0 \uC774\uBBF8 \uC720\uC0AC\uD55C \uB8F0\uC774 \uC788\uC2B5\uB2C8\uB2E4:
936
+ ${draft}`,
937
+ pendingApplyExists: "\uBBF8\uD574\uC18C apply\uAC00 \uC788\uC2B5\uB2C8\uB2E4. vhk evolve undo \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uAC70\uB098 \uADF8\uB300\uB85C \uC720\uC9C0\uD558\uC138\uC694.",
938
+ noAppliedToUndo: "undo\uD560 \uBC18\uC601 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
939
+ noBackup: ".bak \uD30C\uC77C\uC774 \uC5C6\uC5B4 undo \uBD88\uAC00\uD569\uB2C8\uB2E4. RULES.md\uB97C \uC218\uB3D9 \uBCF5\uC6D0\uD558\uC138\uC694.",
940
+ allSuggested: "\uBAA8\uB4E0 \uD328\uD134\uC774 \uC774\uBBF8 \uC81C\uC548\uB410\uAC70\uB098 reject\uB410\uC2B5\uB2C8\uB2E4.",
941
+ newCandidates: (n) => `\uC2E0\uADDC \uD6C4\uBCF4: ${n}\uAC1C \uCD94\uAC00\uB428`,
942
+ suggestHint: "vhk evolve suggest \uB85C \uC0DD\uC131\uD558\uC138\uC694."
921
943
  }
922
944
  };
923
945
  function lookup(path7) {
@@ -3031,6 +3053,28 @@ ${cliStatus}
3031
3053
  return runVhkCli(args, "pattern list");
3032
3054
  }
3033
3055
  );
3056
+ server.registerTool(
3057
+ "evolve-suggest",
3058
+ {
3059
+ description: "active avoid \uD328\uD134 \u2192 \uB8F0 \uCD08\uC548 \uD6C4\uBCF4 \uC0DD\uC131\xB7\uD050 \uC801\uC7AC (Goal 20)",
3060
+ inputSchema: {}
3061
+ },
3062
+ async () => runVhkCli(["evolve", "suggest", "--json"], "evolve suggest")
3063
+ );
3064
+ server.registerTool(
3065
+ "evolve-list",
3066
+ {
3067
+ description: "\uC9C4\uD654 \uD6C4\uBCF4 \uBAA9\uB85D \uC870\uD68C (pending|rejected|applied \u2014 Goal 20)",
3068
+ inputSchema: {
3069
+ status: z.enum(["pending", "rejected", "applied"]).optional().describe("\uC0C1\uD0DC \uD544\uD130")
3070
+ }
3071
+ },
3072
+ async ({ status }) => {
3073
+ const args = ["evolve", "list", "--json"];
3074
+ if (status) args.push("--status", status);
3075
+ return runVhkCli(args, "evolve list");
3076
+ }
3077
+ );
3034
3078
  return server;
3035
3079
  }
3036
3080
  async function startMcpServer() {
package/dist/index.js CHANGED
@@ -43,14 +43,14 @@ import {
43
43
  stripBom,
44
44
  sync,
45
45
  t
46
- } from "./chunk-ODNKCGUG.js";
46
+ } from "./chunk-WQWPM364.js";
47
47
 
48
48
  // src/index.ts
49
49
  import { Command, Help } from "commander";
50
50
  import { fileURLToPath as fileURLToPath4 } from "url";
51
51
  import fs13 from "fs";
52
- import chalk36 from "chalk";
53
- import inquirer14 from "inquirer";
52
+ import chalk37 from "chalk";
53
+ import inquirer15 from "inquirer";
54
54
 
55
55
  // src/lib/nlp-router.ts
56
56
  function normalize(input) {
@@ -59,6 +59,7 @@ function normalize(input) {
59
59
  var NLP_KEYWORDS = {
60
60
  save: ["\uC800\uC7A5", "\uC138\uC774\uBE0C", "\uCEE4\uBC0B", "\uC62C\uB824", "\uC62C\uB9AC\uAE30", "\uD478\uC2DC", "push", "commit"],
61
61
  pattern: ["\uD328\uD134", "\uB418\uD480\uC774", "\uBC84\uB987", "pattern"],
62
+ evolve: ["\uC9C4\uD654", "\uB8F0\uD6C4\uBCF4", "\uC9C4\uD654\uD6C4\uBCF4"],
62
63
  undo: ["\uB418\uB3CC\uB824", "\uB418\uB3CC\uB9AC\uAE30", "\uCDE8\uC18C", "\uC6D0\uB798\uB300\uB85C", "\uB864\uBC31", "\uB9AC\uC14B", "reset", "rollback"],
63
64
  status: ["\uC0C1\uD0DC", "\uD604\uD669", "\uC5B4\uB5BB\uAC8C", "\uC5B4\uB54C", "\uC9C0\uAE08"],
64
65
  diff: ["\uBCC0\uACBD", "\uBC14\uB010", "\uBB50\uBC14\uB01C", "\uBC14\uB00C\uC5C8", "\uCC28\uC774", "\uB2EC\uB77C\uC9C4", "\uC218\uC815\uB41C"]
@@ -328,6 +329,12 @@ var RULES = [
328
329
  confidence: "high",
329
330
  test: (t2) => matchesKeywords(t2, "pattern") || /^pattern$/.test(t2)
330
331
  },
332
+ {
333
+ command: "evolve",
334
+ explanation: "\uC9C4\uD654 \uD6C4\uBCF4 \uBAA9\uB85D (vhk evolve list) \u2014 apply/undo\uB294 \uC9C1\uC811 \uC2E4\uD589",
335
+ confidence: "high",
336
+ test: (t2) => matchesKeywords(t2, "evolve") || /^evolve$/.test(t2)
337
+ },
331
338
  // NLP 규칙은 한국어 표현만 매칭. 영문 `goal <sub>` 은 commander 가 직접 처리하도록
332
339
  // 가로채기 금지 — vhk goal list / next / check / done 그대로 동작.
333
340
  {
@@ -398,7 +405,8 @@ var CONTAINER_SUBCOMMANDS = {
398
405
  env: ["check"],
399
406
  mode: ["lite", "standard", "strict"],
400
407
  mission: ["set", "check", "clear"],
401
- pattern: ["detect", "list", "dismiss"]
408
+ pattern: ["detect", "list", "dismiss"],
409
+ evolve: ["suggest", "list", "apply", "reject", "undo"]
402
410
  };
403
411
  var CONTAINER_ALIASES = {
404
412
  \uBAA9\uD45C: "goal",
@@ -410,7 +418,8 @@ var CONTAINER_ALIASES = {
410
418
  \uD658\uACBD\uBCC0\uC218: "env",
411
419
  \uBAA8\uB4DC: "mode",
412
420
  \uBBF8\uC158: "mission",
413
- \uD328\uD134: "pattern"
421
+ \uD328\uD134: "pattern",
422
+ \uC9C4\uD654: "evolve"
414
423
  };
415
424
 
416
425
  // src/lib/cli-args.ts
@@ -544,8 +553,8 @@ function detectNaturalLanguageInput(argv) {
544
553
  }
545
554
 
546
555
  // src/lib/nlp-run.ts
547
- import chalk34 from "chalk";
548
- import inquirer13 from "inquirer";
556
+ import chalk35 from "chalk";
557
+ import inquirer14 from "inquirer";
549
558
 
550
559
  // src/commands/gate.ts
551
560
  import inquirer from "inquirer";
@@ -6745,6 +6754,376 @@ async function patternDismiss(idStr) {
6745
6754
  });
6746
6755
  }
6747
6756
 
6757
+ // src/commands/evolve.ts
6758
+ import { existsSync as existsSync19, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync7, copyFileSync as copyFileSync2, renameSync as renameSync2, rmSync as rmSync5 } from "fs";
6759
+ import { join as join14 } from "path";
6760
+ import chalk34 from "chalk";
6761
+ import inquirer13 from "inquirer";
6762
+ var QUEUE_PATH_REL = join14(".vhk", "evolve", "queue.json");
6763
+ function buildDraft(p) {
6764
+ const axisLabel = p.axis === "tag" ? `\uD0DC\uADF8 '${p.signal}'` : `\uD0A4\uC6CC\uB4DC '${p.signal}'`;
6765
+ const countDesc = `${p.count}\uAC74 \uBC18\uBCF5`;
6766
+ return `- ${axisLabel} \uAD00\uB828 \uC791\uC5C5 \uC2DC \uC0AC\uC804 \uC810\uAC80 \uD544\uC218 (\uADFC\uAC70: ${countDesc}, ${p.summary})`;
6767
+ }
6768
+ function buildDedupeKey(patternId, kind) {
6769
+ return `${patternId}:${kind}`;
6770
+ }
6771
+ function generateCandidates(patterns, existing) {
6772
+ const rejectedKeys = new Set(
6773
+ existing.filter((i) => i.status === "rejected").map((i) => i.dedupeKey)
6774
+ );
6775
+ const occupiedKeys = new Set(
6776
+ existing.filter((i) => i.status === "pending" || i.status === "applied").map((i) => i.dedupeKey)
6777
+ );
6778
+ const eligible = patterns.filter((p) => p.kind === "avoid" && p.status === "active").sort((a, b) => a.id.localeCompare(b.id));
6779
+ const result = [];
6780
+ for (const p of eligible) {
6781
+ const dedupeKey = buildDedupeKey(p.id, "rule");
6782
+ if (rejectedKeys.has(dedupeKey)) continue;
6783
+ if (occupiedKeys.has(dedupeKey)) continue;
6784
+ result.push({
6785
+ patternId: p.id,
6786
+ kind: "rule",
6787
+ status: "pending",
6788
+ draft: buildDraft(p),
6789
+ dedupeKey
6790
+ });
6791
+ }
6792
+ return result;
6793
+ }
6794
+ function isDuplicateRule(rulesContent, draft) {
6795
+ const normalize2 = (s) => s.trim().replace(/\s+/g, " ").toLowerCase();
6796
+ const normalizedDraft = normalize2(draft);
6797
+ for (const line of rulesContent.split(/\r?\n/)) {
6798
+ if (normalize2(line) === normalizedDraft) return true;
6799
+ }
6800
+ return false;
6801
+ }
6802
+ function stripBomStr(s) {
6803
+ return s.charCodeAt(0) === 65279 ? s.slice(1) : s;
6804
+ }
6805
+ function readQueue(cwd) {
6806
+ const p = join14(cwd, QUEUE_PATH_REL);
6807
+ if (!existsSync19(p)) return { version: 1, items: [] };
6808
+ try {
6809
+ const raw = stripBomStr(readFileSync7(p, "utf-8"));
6810
+ const parsed = JSON.parse(raw);
6811
+ if (!parsed || !Array.isArray(parsed.items)) return { version: 1, items: [] };
6812
+ return parsed;
6813
+ } catch {
6814
+ return { version: 1, items: [] };
6815
+ }
6816
+ }
6817
+ function writeQueue(cwd, queue) {
6818
+ const p = join14(cwd, QUEUE_PATH_REL);
6819
+ mkdirSync13(join14(cwd, ".vhk", "evolve"), { recursive: true });
6820
+ const tmpPath = p + ".tmp";
6821
+ writeFileSync14(tmpPath, JSON.stringify(queue, null, 2) + "\n", "utf-8");
6822
+ try {
6823
+ renameSync2(tmpPath, p);
6824
+ } catch (err) {
6825
+ try {
6826
+ rmSync5(tmpPath, { force: true });
6827
+ } catch {
6828
+ }
6829
+ throw err;
6830
+ }
6831
+ }
6832
+ function nextQueueId(queue) {
6833
+ const re = /^e(\d+)$/;
6834
+ let max = 0;
6835
+ for (const item of queue.items) {
6836
+ const m = item.id.match(re);
6837
+ if (m) max = Math.max(max, Number(m[1]));
6838
+ }
6839
+ return `e${max + 1}`;
6840
+ }
6841
+ function checkApplyRef(pattern, queueItems) {
6842
+ if (pattern === void 0 || pattern.status !== "archived") return "ok";
6843
+ const hasApplied = queueItems.some(
6844
+ (i) => i.patternId === pattern.id && i.status === "applied"
6845
+ );
6846
+ return hasApplied ? "already-applied" : "dismissed";
6847
+ }
6848
+ async function evolveSuggest(opts = {}) {
6849
+ const cwd = process.cwd();
6850
+ if (!existsSync19(join14(cwd, "RULES.md"))) {
6851
+ console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.noRules")));
6852
+ process.exitCode = 1;
6853
+ return;
6854
+ }
6855
+ const mem = readMemory(cwd);
6856
+ const patterns = mem.patterns;
6857
+ const queue = readQueue(cwd);
6858
+ const newItems = generateCandidates(patterns, queue.items);
6859
+ if (newItems.length === 0 && !opts.json) {
6860
+ const activeAvoid = patterns.filter((p) => p.kind === "avoid" && p.status === "active");
6861
+ if (activeAvoid.length === 0) {
6862
+ console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noPatterns")));
6863
+ return;
6864
+ }
6865
+ console.log(chalk34.dim("\n " + t("evolve.allSuggested")));
6866
+ return;
6867
+ }
6868
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6869
+ for (const c of newItems) {
6870
+ queue.items.push({ ...c, id: nextQueueId(queue), createdAt: now });
6871
+ }
6872
+ writeQueue(cwd, queue);
6873
+ if (opts.json) {
6874
+ const pending2 = queue.items.filter((i) => i.status === "pending");
6875
+ console.log(JSON.stringify(pending2, null, 2));
6876
+ return;
6877
+ }
6878
+ console.log(chalk34.bold("\n\u{1F504} " + t("evolve.suggestTitle")));
6879
+ console.log(chalk34.gray("\u2500".repeat(40)));
6880
+ console.log(chalk34.dim(" " + t("evolve.newCandidates", newItems.length)));
6881
+ const pending = queue.items.filter((i) => i.status === "pending");
6882
+ console.log(chalk34.cyan(`
6883
+ \uD6C4\uBCF4 ${pending.length}\uAC1C:
6884
+ `));
6885
+ for (const item of pending) {
6886
+ console.log(` [${item.id}] (${item.status}) \uD328\uD134 ${item.patternId} \u2192 rule`);
6887
+ console.log(chalk34.dim(` \uCD08\uC548: ${item.draft}`));
6888
+ }
6889
+ printNextStep({
6890
+ message: `\uC9C4\uD654 \uD6C4\uBCF4 ${pending.length}\uAC1C \uC0DD\uC131\uB428!`,
6891
+ command: "vhk evolve list",
6892
+ cursorHint: "\uC9C4\uD654 \uD6C4\uBCF4 \uBCF4\uC5EC\uC918",
6893
+ alternative: "vhk evolve apply <id> \uB85C \uBC18\uC601"
6894
+ });
6895
+ }
6896
+ async function evolveList(opts = {}) {
6897
+ const cwd = process.cwd();
6898
+ const queue = readQueue(cwd);
6899
+ const VALID = ["pending", "rejected", "applied"];
6900
+ let items = queue.items;
6901
+ if (opts.status && VALID.includes(opts.status)) {
6902
+ items = items.filter((i) => i.status === opts.status);
6903
+ }
6904
+ if (opts.json) {
6905
+ console.log(JSON.stringify(items, null, 2));
6906
+ return;
6907
+ }
6908
+ console.log(chalk34.bold("\n\u{1F504} " + t("evolve.listTitle")));
6909
+ console.log(chalk34.gray("\u2500".repeat(40)));
6910
+ if (items.length === 0) {
6911
+ console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noQueue")));
6912
+ console.log(chalk34.gray(" " + t("evolve.suggestHint")));
6913
+ return;
6914
+ }
6915
+ const STATUS_ICON3 = {
6916
+ pending: "\u23F3",
6917
+ rejected: "\u274C",
6918
+ applied: "\u2705"
6919
+ };
6920
+ console.log(chalk34.cyan(`
6921
+ ${items.length}\uAC1C:
6922
+ `));
6923
+ for (const item of items) {
6924
+ console.log(` [${item.id}] ${STATUS_ICON3[item.status]} (${item.status}) \u2192 ${item.draft}`);
6925
+ if (item.appliedAt) console.log(chalk34.dim(` \uBC18\uC601: ${item.appliedAt}`));
6926
+ }
6927
+ }
6928
+ async function evolveApply(idStr) {
6929
+ if (!ensureInteractive("apply\uB294 TTY \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694.")) return;
6930
+ const cwd = process.cwd();
6931
+ const rulesPath = join14(cwd, "RULES.md");
6932
+ if (!existsSync19(rulesPath)) {
6933
+ console.log(chalk34.red("\n\u274C " + t("evolve.noRules")));
6934
+ process.exitCode = 1;
6935
+ return;
6936
+ }
6937
+ const queue = readQueue(cwd);
6938
+ const item = queue.items.find((i) => i.id === idStr?.trim());
6939
+ if (!item) {
6940
+ console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
6941
+ process.exitCode = 1;
6942
+ return;
6943
+ }
6944
+ if (item.status === "applied") {
6945
+ console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.alreadyApplied")));
6946
+ process.exitCode = 1;
6947
+ return;
6948
+ }
6949
+ const hasUnresolved = queue.items.some((i) => i.status === "applied");
6950
+ if (hasUnresolved) {
6951
+ console.log(chalk34.red("\n\u274C " + t("evolve.pendingApplyExists")));
6952
+ process.exitCode = 1;
6953
+ return;
6954
+ }
6955
+ const memLoaded = loadForMutation(cwd);
6956
+ if (!memLoaded.ok) {
6957
+ console.log(chalk34.red("\n\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 apply \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874)."));
6958
+ process.exitCode = 1;
6959
+ return;
6960
+ }
6961
+ const srcPattern = memLoaded.mem.patterns.find((p) => p.id === item.patternId);
6962
+ const refResult = checkApplyRef(srcPattern, queue.items);
6963
+ if (refResult === "dismissed") {
6964
+ console.log(chalk34.red("\n\u274C " + t("evolve.dismissed")));
6965
+ process.exitCode = 1;
6966
+ return;
6967
+ }
6968
+ if (refResult === "already-applied") {
6969
+ console.log(chalk34.red("\n\u274C " + t("evolve.alreadyAppliedPattern")));
6970
+ process.exitCode = 1;
6971
+ return;
6972
+ }
6973
+ const rulesContent = readFileSync7(rulesPath, "utf-8");
6974
+ if (isDuplicateRule(rulesContent, item.draft)) {
6975
+ console.log(chalk34.yellow("\n\u26A0\uFE0F " + t("evolve.duplicateRule", item.draft)));
6976
+ return;
6977
+ }
6978
+ console.log(chalk34.bold("\n\u{1F504} " + t("evolve.applyTitle")));
6979
+ console.log(chalk34.gray("\u2500".repeat(40)));
6980
+ console.log(chalk34.cyan("\n\uCD94\uAC00\uB420 \uB8F0 \uCD08\uC548:"));
6981
+ console.log(chalk34.white(` ${item.draft}`));
6982
+ const { editedDraft } = await inquirer13.prompt([{
6983
+ type: "input",
6984
+ name: "editedDraft",
6985
+ message: "\uB8F0 \uBB38\uAD6C \uC218\uC815 (Enter = \uADF8\uB300\uB85C):",
6986
+ default: item.draft
6987
+ }]);
6988
+ const { confirmed } = await inquirer13.prompt([{
6989
+ type: "confirm",
6990
+ name: "confirmed",
6991
+ message: `RULES.md\uC5D0 \uC774 \uB8F0\uC744 \uCD94\uAC00\uD560\uAE4C\uC694?
6992
+ ${editedDraft}`,
6993
+ default: false
6994
+ }]);
6995
+ if (!confirmed) {
6996
+ console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
6997
+ return;
6998
+ }
6999
+ const backupPath = rulesPath + ".bak";
7000
+ copyFileSync2(rulesPath, backupPath);
7001
+ const appendContent = "\n" + editedDraft + "\n";
7002
+ try {
7003
+ writeFileSync14(rulesPath, rulesContent + appendContent, "utf-8");
7004
+ await sync({ yes: true });
7005
+ } catch (err) {
7006
+ try {
7007
+ copyFileSync2(backupPath, rulesPath);
7008
+ } catch {
7009
+ }
7010
+ console.error(chalk34.red("\n\u274C RULES.md \uBC18\uC601 \uC911 \uC624\uB958 \u2014 \uC6D0\uBCF8 \uBCF5\uC6D0\uB428. \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7011
+ console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7012
+ process.exitCode = 1;
7013
+ return;
7014
+ }
7015
+ const now = (/* @__PURE__ */ new Date()).toISOString();
7016
+ item.status = "applied";
7017
+ item.draft = editedDraft;
7018
+ item.appliedAt = now;
7019
+ item.rulesBackupPath = backupPath;
7020
+ writeQueue(cwd, queue);
7021
+ if (srcPattern) {
7022
+ const p = memLoaded.mem.patterns.find((x) => x.id === srcPattern.id);
7023
+ if (p) {
7024
+ p.status = "archived";
7025
+ writeMemory(cwd, memLoaded.mem);
7026
+ } else {
7027
+ console.error(chalk34.yellow(" \u26A0\uFE0F \uC18C\uC2A4 \uD328\uD134 archived \uCC98\uB9AC \uC2E4\uD328 (memory.json \uC190\uC0C1 \uC758\uC2EC). \uB8F0\uC740 \uBC18\uC601\uB410\uC2B5\uB2C8\uB2E4."));
7028
+ }
7029
+ }
7030
+ console.log(chalk34.green(`
7031
+ \u2705 \uB8F0 \uBC18\uC601 \uC644\uB8CC! [${item.id}]`));
7032
+ console.log(chalk34.dim(" RULES.md\uC5D0 \uCD94\uAC00 + vhk sync \uC7AC\uC0DD\uC131\uB428"));
7033
+ printNextStep({
7034
+ message: "\uB8F0 \uBC18\uC601 \uC644\uB8CC!",
7035
+ command: "vhk evolve list --status applied",
7036
+ cursorHint: "\uBC18\uC601\uB41C \uB8F0 \uBAA9\uB85D \uBCF4\uC5EC\uC918",
7037
+ alternative: "vhk evolve undo \u2014 \uB418\uB3CC\uB9AC\uAE30"
7038
+ });
7039
+ }
7040
+ async function evolveReject(idStr) {
7041
+ const cwd = process.cwd();
7042
+ const queue = readQueue(cwd);
7043
+ const item = queue.items.find((i) => i.id === idStr?.trim());
7044
+ if (!item) {
7045
+ console.log(chalk34.red("\n\u274C " + t("evolve.notFound", idStr ?? "")));
7046
+ process.exitCode = 1;
7047
+ return;
7048
+ }
7049
+ if (item.status === "rejected") {
7050
+ console.log(chalk34.dim(` \uC774\uBBF8 \uAE30\uAC01\uB41C \uD6C4\uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCC0\uACBD \uC5C6\uC74C: ${item.id}`));
7051
+ return;
7052
+ }
7053
+ if (item.status === "applied") {
7054
+ console.log(chalk34.red(`
7055
+ \u274C \uC774\uBBF8 \uBC18\uC601\uB41C \uD56D\uBAA9\uC740 \uAE30\uAC01\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 vhk evolve undo \uB85C \uB418\uB3CC\uB9AC\uC138\uC694: ${item.id}`));
7056
+ process.exitCode = 1;
7057
+ return;
7058
+ }
7059
+ item.status = "rejected";
7060
+ writeQueue(cwd, queue);
7061
+ console.log(chalk34.green(`
7062
+ \u274C \uD6C4\uBCF4 \uAE30\uAC01\uB428: [${item.id}] ${item.draft}`));
7063
+ console.log(chalk34.dim(" (A1: \uB2E4\uC74C suggest\uC5D0\uC11C \uC7AC\uC81C\uC548 \uC548 \uB428)"));
7064
+ printNextStep({
7065
+ message: "\uAE30\uAC01 \uC644\uB8CC!",
7066
+ command: "vhk evolve list",
7067
+ cursorHint: "\uB0A8\uC740 \uD6C4\uBCF4 \uBCF4\uC5EC\uC918"
7068
+ });
7069
+ }
7070
+ async function evolveUndo() {
7071
+ if (!ensureInteractive("undo\uB294 TTY \uD655\uC778\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694.")) return;
7072
+ const cwd = process.cwd();
7073
+ const queue = readQueue(cwd);
7074
+ const applied = queue.items.filter((i) => i.status === "applied");
7075
+ if (applied.length === 0) {
7076
+ console.log(chalk34.yellow("\n\u{1F4ED} " + t("evolve.noAppliedToUndo")));
7077
+ return;
7078
+ }
7079
+ const last = applied.sort(
7080
+ (a, b) => (b.appliedAt ?? "").localeCompare(a.appliedAt ?? "")
7081
+ )[0];
7082
+ if (!last.rulesBackupPath || !existsSync19(last.rulesBackupPath)) {
7083
+ console.log(chalk34.red("\n\u274C " + t("evolve.noBackup")));
7084
+ process.exitCode = 1;
7085
+ return;
7086
+ }
7087
+ console.log(chalk34.bold("\n\u{1F504} " + t("evolve.undoTitle")));
7088
+ console.log(chalk34.dim(` \uB418\uB3CC\uB9B4 \uD56D\uBAA9: [${last.id}] ${last.draft}`));
7089
+ const { confirmed } = await inquirer13.prompt([{
7090
+ type: "confirm",
7091
+ name: "confirmed",
7092
+ message: "RULES.md\uB97C .bak\uC73C\uB85C \uBCF5\uC6D0\uD558\uACE0 vhk sync\uB97C \uC7AC\uC2E4\uD589\uD560\uAE4C\uC694?",
7093
+ default: false
7094
+ }]);
7095
+ if (!confirmed) {
7096
+ console.log(chalk34.dim(" \uCDE8\uC18C\uB428."));
7097
+ return;
7098
+ }
7099
+ copyFileSync2(last.rulesBackupPath, join14(cwd, "RULES.md"));
7100
+ try {
7101
+ await sync({ yes: true });
7102
+ } catch (err) {
7103
+ console.error(chalk34.red("\n\u274C sync \uC7AC\uC2E4\uD589 \uC911 \uC624\uB958. RULES.md\uB294 \uBCF5\uC6D0\uB410\uC73C\uB098 .cursorrules \uB4F1 \uC7AC\uC0DD\uC131 \uC2E4\uD328."));
7104
+ console.error(chalk34.dim(` ${err instanceof Error ? err.message : String(err)}`));
7105
+ console.error(chalk34.dim(" \uC218\uB3D9\uC73C\uB85C `vhk sync` \uC2E4\uD589\uD558\uC138\uC694."));
7106
+ }
7107
+ last.status = "pending";
7108
+ delete last.appliedAt;
7109
+ delete last.rulesBackupPath;
7110
+ writeQueue(cwd, queue);
7111
+ const memLoaded = loadForMutation(cwd);
7112
+ if (memLoaded.ok) {
7113
+ const p = memLoaded.mem.patterns.find((x) => x.id === last.patternId);
7114
+ if (p && p.status === "archived") {
7115
+ p.status = "active";
7116
+ writeMemory(cwd, memLoaded.mem);
7117
+ }
7118
+ }
7119
+ console.log(chalk34.green("\n\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC! RULES.md \uBCF5\uC6D0 + sync \uC7AC\uC2E4\uD589\uB428"));
7120
+ printNextStep({
7121
+ message: "\uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC!",
7122
+ command: "vhk evolve list",
7123
+ cursorHint: "\uD6C4\uBCF4 \uBAA9\uB85D \uBCF4\uC5EC\uC918"
7124
+ });
7125
+ }
7126
+
6748
7127
  // src/lib/risk-policy.ts
6749
7128
  var HIGH_RISK_ACTIONS = [
6750
7129
  "undo",
@@ -6917,6 +7296,8 @@ async function dispatchNlpRoute(route, input) {
6917
7296
  return missionShow();
6918
7297
  case "pattern":
6919
7298
  return patternList();
7299
+ case "evolve":
7300
+ return evolveList();
6920
7301
  }
6921
7302
  }
6922
7303
  var STATE_CHANGING_COMMANDS = /* @__PURE__ */ new Set([
@@ -6930,23 +7311,23 @@ function requiresConfirmation(route) {
6930
7311
  async function runNaturalLanguageRoute(input) {
6931
7312
  const route = routeNaturalLanguage(input);
6932
7313
  if (!route) {
6933
- console.log(chalk34.yellow(`
7314
+ console.log(chalk35.yellow(`
6934
7315
  \u2753 "${input}" \u2014 ${ko.nlp.notMatched}
6935
7316
  `));
6936
7317
  return;
6937
7318
  }
6938
7319
  console.log("");
6939
- console.log(chalk34.cyan(` \u{1F4AC} "${input}"`));
6940
- console.log(chalk34.cyan(` \u2192 ${route.explanation}`));
7320
+ console.log(chalk35.cyan(` \u{1F4AC} "${input}"`));
7321
+ console.log(chalk35.cyan(` \u2192 ${route.explanation}`));
6941
7322
  if (requiresConfirmation(route)) {
6942
- const { confirm } = await inquirer13.prompt([{
7323
+ const { confirm } = await inquirer14.prompt([{
6943
7324
  type: "confirm",
6944
7325
  name: "confirm",
6945
7326
  message: `${route.explanation} \u2014 ${ko.nlp.matched}`,
6946
7327
  default: true
6947
7328
  }]);
6948
7329
  if (!confirm) {
6949
- console.log(chalk34.dim(` ${ko.nlp.menuHint}`));
7330
+ console.log(chalk35.dim(` ${ko.nlp.menuHint}`));
6950
7331
  return;
6951
7332
  }
6952
7333
  }
@@ -6955,7 +7336,7 @@ async function runNaturalLanguageRoute(input) {
6955
7336
  if (riskAction) {
6956
7337
  await runGuarded(
6957
7338
  riskAction,
6958
- { channel: "nl", approved: false, log: (m) => console.log(chalk34.yellow(` ${m}`)) },
7339
+ { channel: "nl", approved: false, log: (m) => console.log(chalk35.yellow(` ${m}`)) },
6959
7340
  () => dispatchNlpRoute(route, input)
6960
7341
  );
6961
7342
  return;
@@ -6964,80 +7345,80 @@ async function runNaturalLanguageRoute(input) {
6964
7345
  }
6965
7346
 
6966
7347
  // src/commands/agent.ts
6967
- import chalk35 from "chalk";
7348
+ import chalk36 from "chalk";
6968
7349
  function activeGoalId() {
6969
7350
  const goals = listGoals("goals");
6970
7351
  const id = selectActiveId(goals);
6971
7352
  return id ?? void 0;
6972
7353
  }
6973
7354
  async function blocker(description) {
6974
- console.log(chalk35.bold(`
7355
+ console.log(chalk36.bold(`
6975
7356
  ${ko.agent.blockerTitle}
6976
7357
  `));
6977
7358
  if (!description || !description.trim()) {
6978
- console.log(chalk35.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
6979
- console.log(chalk35.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
7359
+ console.log(chalk36.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7360
+ console.log(chalk36.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
6980
7361
  process.exitCode = 1;
6981
7362
  return;
6982
7363
  }
6983
7364
  const goalId = activeGoalId();
6984
7365
  const r = appendBlocker(description, goalId);
6985
- console.log(chalk35.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
7366
+ console.log(chalk36.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
6986
7367
  if (r.hardStopTripped) {
6987
- console.log(chalk35.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
6988
- console.log(chalk35.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
7368
+ console.log(chalk36.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
7369
+ console.log(chalk36.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
6989
7370
  process.exitCode = 2;
6990
7371
  }
6991
7372
  }
6992
7373
  async function learn(lesson) {
6993
- console.log(chalk35.bold(`
7374
+ console.log(chalk36.bold(`
6994
7375
  ${ko.agent.learnTitle}
6995
7376
  `));
6996
7377
  if (!lesson || !lesson.trim()) {
6997
- console.log(chalk35.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
6998
- console.log(chalk35.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
7378
+ console.log(chalk36.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
7379
+ console.log(chalk36.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
6999
7380
  process.exitCode = 1;
7000
7381
  return;
7001
7382
  }
7002
7383
  const goalId = activeGoalId();
7003
7384
  const entry = recordLesson(process.cwd(), lesson, goalId);
7004
7385
  if (!entry) {
7005
- console.log(chalk35.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."));
7386
+ console.log(chalk36.red(" \u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAD50\uD6C8 \uAE30\uB85D \uC911\uB2E8. \uC6D0\uBCF8/\uBC31\uC5C5 \uD655\uC778 \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694."));
7006
7387
  process.exitCode = 1;
7007
7388
  return;
7008
7389
  }
7009
- console.log(chalk35.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7010
- console.log(chalk35.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."));
7390
+ console.log(chalk36.green(` \u2705 \uAD50\uD6C8 \uAE30\uB85D \u2192 memory failures.lesson (${entry.id})`));
7391
+ console.log(chalk36.dim(" \uAD50\uD6C8\xB7\uACB0\uC815\xB7\uC2E4\uD328\xB7\uC131\uACF5 \uBAA8\uB450 vhk memory (\uB2E8\uC77C SoT). vhk memory list \uB85C \uD655\uC778."));
7011
7392
  }
7012
7393
  async function resume(opts = {}) {
7013
- console.log(chalk35.bold(`
7394
+ console.log(chalk36.bold(`
7014
7395
  ${ko.agent.resumeTitle}
7015
7396
  `));
7016
7397
  if (!isHardStopActive()) {
7017
- console.log(chalk35.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7398
+ console.log(chalk36.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
7018
7399
  return;
7019
7400
  }
7020
7401
  const reason = readHardStopReason();
7021
7402
  if (reason) {
7022
- console.log(chalk35.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7023
- console.log(chalk35.dim(` ${reason.split("\n").join("\n ")}`));
7403
+ console.log(chalk36.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
7404
+ console.log(chalk36.dim(` ${reason.split("\n").join("\n ")}`));
7024
7405
  console.log("");
7025
7406
  }
7026
7407
  if (!opts.confirm) {
7027
7408
  console.log(
7028
- chalk35.red(
7409
+ chalk36.red(
7029
7410
  " \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
7030
7411
  )
7031
7412
  );
7032
- console.log(chalk35.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7413
+ console.log(chalk36.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
7033
7414
  process.exitCode = 1;
7034
7415
  return;
7035
7416
  }
7036
7417
  const removed = clearHardStop();
7037
7418
  if (removed) {
7038
- console.log(chalk35.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7419
+ console.log(chalk36.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
7039
7420
  } else {
7040
- console.log(chalk35.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7421
+ console.log(chalk36.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
7041
7422
  }
7042
7423
  }
7043
7424
 
@@ -7050,7 +7431,7 @@ async function guardCli(action, approved, run) {
7050
7431
  channel: "cli",
7051
7432
  approved,
7052
7433
  confirm: async () => {
7053
- const { ok } = await inquirer14.prompt([{
7434
+ const { ok } = await inquirer15.prompt([{
7054
7435
  type: "confirm",
7055
7436
  name: "ok",
7056
7437
  message: `\u26A0\uFE0F \uC704\uD5D8 \uC791\uC5C5(${action})\uC744 \uC2E4\uD589\uD560\uAE4C\uC694?`,
@@ -7058,7 +7439,7 @@ async function guardCli(action, approved, run) {
7058
7439
  }]);
7059
7440
  return ok;
7060
7441
  },
7061
- log: (m) => console.log(chalk36.yellow(` ${m}`))
7442
+ log: (m) => console.log(chalk37.yellow(` ${m}`))
7062
7443
  },
7063
7444
  run
7064
7445
  );
@@ -7071,7 +7452,7 @@ async function guardCliDefer(action, approved, run) {
7071
7452
  approved,
7072
7453
  // TTY 면 통과(명령이 자체 확인), 비대화형은 confirm 불가 → 가드가 차단.
7073
7454
  confirm: async () => !!process.stdout.isTTY,
7074
- log: (m) => console.log(chalk36.yellow(` ${m}`))
7455
+ log: (m) => console.log(chalk37.yellow(` ${m}`))
7075
7456
  },
7076
7457
  run
7077
7458
  );
@@ -7115,7 +7496,8 @@ var KO_ALIASES = {
7115
7496
  blocker: "\uBE14\uB85C\uCEE4",
7116
7497
  learn: "\uAD50\uD6C8",
7117
7498
  resume: "\uC7AC\uAC1C",
7118
- pattern: "\uD328\uD134"
7499
+ pattern: "\uD328\uD134",
7500
+ evolve: "\uC9C4\uD654"
7119
7501
  };
7120
7502
  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());
7121
7503
  program.configureHelp({
@@ -7327,6 +7709,24 @@ patternCmd.command("list").alias("\uBAA9\uB85D").option("--kind <kind>", "avoid|
7327
7709
  patternCmd.command("dismiss <id>").alias("\uBCF4\uAD00").description("\uC624\uD0D0 \uD328\uD134 dismiss (\u2192archived, \uC7AC\uC81C\uC548 \uC548 \uB428)").action(async (id) => {
7328
7710
  await patternDismiss(id);
7329
7711
  });
7712
+ var evolveCmd = program.command("evolve").alias("\uC9C4\uD654").description("\uD328\uD134 \u2192 \uB8F0 \uD6C4\uBCF4 \uC81C\uC548\xB7\uBC18\uC601\xB7undo (Evolution Loop \uB3C4\uBBF8\uB178 4) \u2014 apply/undo\uB294 TTY \uD544\uC218").action(async () => {
7713
+ await evolveList();
7714
+ });
7715
+ evolveCmd.command("suggest").alias("\uC81C\uC548").option("--json", "JSON \uCD9C\uB825 (CI/MCP\uC6A9)").description("active avoid \uD328\uD134 \u2192 \uB8F0 \uCD08\uC548 \uD6C4\uBCF4 \uC0DD\uC131\xB7\uD050 \uC801\uC7AC").action(async (opts) => {
7716
+ await evolveSuggest(opts);
7717
+ });
7718
+ evolveCmd.command("list").alias("\uBAA9\uB85D").option("--status <status>", "pending|rejected|applied \uD544\uD130").option("--json", "JSON \uCD9C\uB825 (CI/MCP\uC6A9)").description("\uC9C4\uD654 \uD6C4\uBCF4 \uBAA9\uB85D").action(async (opts) => {
7719
+ await evolveList(opts);
7720
+ });
7721
+ evolveCmd.command("apply <id>").alias("\uBC18\uC601").description("\uD6C4\uBCF4 TTY \uD655\uC778 \u2192 RULES.md append \u2192 sync \uC7AC\uC0DD\uC131 (\uB300\uD654\uD615 \uD544\uC218)").action(async (id) => {
7722
+ await evolveApply(id);
7723
+ });
7724
+ evolveCmd.command("reject <id>").alias("\uAE30\uAC01").description("\uD6C4\uBCF4 \uAE30\uAC01 (\uC7AC\uC81C\uC548 \uC5B5\uC81C)").action(async (id) => {
7725
+ await evolveReject(id);
7726
+ });
7727
+ evolveCmd.command("undo").alias("\uB418\uB3CC\uB9AC\uAE30").description("\uCD5C\uADFC apply 1\uAC74 \uB418\uB3CC\uB9AC\uAE30(.bak \uBCF5\uC6D0 + sync \u2014 \uB300\uD654\uD615 \uD544\uC218)").action(async () => {
7728
+ await evolveUndo();
7729
+ });
7330
7730
  program.on("command:*", async (operands) => {
7331
7731
  const unknown = operands[0] ?? "";
7332
7732
  const rest = operands.slice(1);
@@ -7335,7 +7735,7 @@ program.on("command:*", async (operands) => {
7335
7735
  });
7336
7736
  program.action(async () => {
7337
7737
  console.log("\n\u{1F3AF} VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58\n");
7338
- const { choice } = await inquirer14.prompt([{
7738
+ const { choice } = await inquirer15.prompt([{
7339
7739
  type: "list",
7340
7740
  name: "choice",
7341
7741
  message: "\uBB58 \uB3C4\uC640\uB4DC\uB9B4\uAE4C\uC694?",
@@ -7399,9 +7799,9 @@ if (isMainModule) {
7399
7799
  }
7400
7800
  } catch (err) {
7401
7801
  if (isPromptAbortError(err)) {
7402
- console.error(chalk36.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)"));
7802
+ console.error(chalk37.yellow("\n \u26A0\uFE0F \uB300\uD654\uD615 \uC785\uB825\uC774 \uCDE8\uC18C/\uC885\uB8CC\uB410\uC2B5\uB2C8\uB2E4. (\uBE44\uB300\uD654\uD615 \uD658\uACBD\uC5D0\uC11C\uB294 \uD574\uB2F9 \uBA85\uB839\uC744 \uC4F8 \uC218 \uC5C6\uC5B4\uC694)"));
7403
7803
  } else {
7404
- console.error(chalk36.red(`
7804
+ console.error(chalk37.red(`
7405
7805
  \u274C ${err instanceof Error ? err.message : String(err)}`));
7406
7806
  }
7407
7807
  process.exitCode = 1;
package/dist/mcp/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  resolveVhkCliInvocation,
4
4
  startMcpServer
5
- } from "../chunk-ODNKCGUG.js";
5
+ } from "../chunk-WQWPM364.js";
6
6
 
7
7
  // src/mcp/index.ts
8
8
  var cli = resolveVhkCliInvocation();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byh3071/vhk",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Vibe Harness Kit — AI 코딩 도구·기기를 바꿔도 규칙·맥락이 따라가는 포터빌리티 CLI (sync: Cursor·Claude·Windsurf·Copilot·Antigravity / cloud 백업)",
5
5
  "bin": {
6
6
  "vhk": "dist/index.js",