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