@byh3071/vhk 1.6.4 → 1.6.6
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-EJTVXWUZ.js → chunk-HLUFOT2T.js} +146 -116
- package/dist/index.js +485 -507
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
countLocalCommits,
|
|
13
13
|
deploy,
|
|
14
14
|
detectExistingRuleFiles,
|
|
15
|
+
ensureInteractive,
|
|
15
16
|
env,
|
|
16
17
|
envCheck,
|
|
17
18
|
filterSevereFindings,
|
|
@@ -22,12 +23,15 @@ import {
|
|
|
22
23
|
gitOut,
|
|
23
24
|
gitRun,
|
|
24
25
|
hasGitRemote,
|
|
26
|
+
isInteractive,
|
|
27
|
+
isPromptAbortError,
|
|
25
28
|
ko,
|
|
26
29
|
listBackups,
|
|
27
30
|
localDate,
|
|
28
31
|
printContextResumeHint,
|
|
29
32
|
printNextStep,
|
|
30
33
|
printSecurityWarnings,
|
|
34
|
+
promptOrDefault,
|
|
31
35
|
publish,
|
|
32
36
|
readJsonFile,
|
|
33
37
|
require_ignore,
|
|
@@ -38,12 +42,12 @@ import {
|
|
|
38
42
|
stripBom,
|
|
39
43
|
sync,
|
|
40
44
|
t
|
|
41
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-HLUFOT2T.js";
|
|
42
46
|
|
|
43
47
|
// src/index.ts
|
|
44
48
|
import { Command, Help } from "commander";
|
|
45
49
|
import { pathToFileURL } from "url";
|
|
46
|
-
import
|
|
50
|
+
import chalk33 from "chalk";
|
|
47
51
|
import inquirer13 from "inquirer";
|
|
48
52
|
|
|
49
53
|
// src/lib/nlp-router.ts
|
|
@@ -500,42 +504,12 @@ function detectNaturalLanguageInput(argv) {
|
|
|
500
504
|
}
|
|
501
505
|
|
|
502
506
|
// src/lib/nlp-run.ts
|
|
503
|
-
import
|
|
507
|
+
import chalk31 from "chalk";
|
|
504
508
|
import inquirer12 from "inquirer";
|
|
505
509
|
|
|
506
510
|
// src/commands/gate.ts
|
|
507
511
|
import inquirer from "inquirer";
|
|
508
|
-
import chalk2 from "chalk";
|
|
509
|
-
|
|
510
|
-
// src/lib/interactive.ts
|
|
511
512
|
import chalk from "chalk";
|
|
512
|
-
function isInteractive(opts) {
|
|
513
|
-
if (opts?.yes) return false;
|
|
514
|
-
if (process.env.VHK_FORCE_INTERACTIVE === "1") return true;
|
|
515
|
-
return !!process.stdin.isTTY;
|
|
516
|
-
}
|
|
517
|
-
async function promptOrDefault(ask, fallback, opts) {
|
|
518
|
-
if (!isInteractive(opts)) return fallback;
|
|
519
|
-
try {
|
|
520
|
-
return await ask();
|
|
521
|
-
} catch (err) {
|
|
522
|
-
if (isPromptAbortError(err)) return fallback;
|
|
523
|
-
throw err;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
function ensureInteractive(hint = "") {
|
|
527
|
-
if (isInteractive()) return true;
|
|
528
|
-
console.error(chalk.yellow(" \u26A0\uFE0F \uC774 \uBA85\uB839\uC740 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uBE44-TTY/\uD30C\uC774\uD504 \uD658\uACBD\uC5D0\uC11C\uB294 \uC2E4\uD589\uD560 \uC218 \uC5C6\uC5B4\uC694."));
|
|
529
|
-
if (hint) console.error(chalk.dim(` ${hint}`));
|
|
530
|
-
process.exitCode = 1;
|
|
531
|
-
return false;
|
|
532
|
-
}
|
|
533
|
-
function isPromptAbortError(err) {
|
|
534
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
535
|
-
return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
// src/commands/gate.ts
|
|
539
513
|
var GATE_QUESTIONS = [
|
|
540
514
|
{ id: 1, stage: "\uBB38\uC81C \uC815\uC758", question: "\uC774 \uC544\uC774\uB514\uC5B4\uAC00 \uD574\uACB0\uD558\uB294 \uBB38\uC81C\uB97C \uD55C \uBB38\uC7A5\uC73C\uB85C \uB9D0\uD574\uBCF4\uC138\uC694.", failIf: "\uD55C \uBB38\uC7A5 \uBD88\uAC00 \u2192 \uBBF8\uC131\uC219", quick: true },
|
|
541
515
|
{ id: 2, stage: "\uD575\uC2EC \uAE30\uB2A5", question: "\uB531 1\uAC1C \uAE30\uB2A5\uB9CC \uACE0\uB974\uBA74?", failIf: "2\uAC1C \uC774\uC0C1 \u2192 \uBC94\uC704 \uCD08\uACFC", quick: true },
|
|
@@ -558,7 +532,7 @@ function judgeGate(failCount, holdCount) {
|
|
|
558
532
|
}
|
|
559
533
|
async function gate() {
|
|
560
534
|
if (!ensureInteractive("\uC544\uC774\uB514\uC5B4 \uAC80\uC99D\uC740 \uB300\uD654\uD615 \uC9C8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110(PowerShell \uB4F1)\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694. Git Bash \uBA74 VHK_FORCE_INTERACTIVE=1.")) return;
|
|
561
|
-
console.log(
|
|
535
|
+
console.log(chalk.bold(`
|
|
562
536
|
${ko.gate.title}
|
|
563
537
|
`));
|
|
564
538
|
const { mode: mode2 } = await inquirer.prompt([{
|
|
@@ -577,33 +551,33 @@ ${ko.gate.title}
|
|
|
577
551
|
name: "source",
|
|
578
552
|
message: ko.gate.skipSourcePrompt
|
|
579
553
|
}]);
|
|
580
|
-
console.log(
|
|
554
|
+
console.log(chalk.green.bold(`
|
|
581
555
|
${ko.gate.skipGo}`));
|
|
582
|
-
console.log(
|
|
556
|
+
console.log(chalk.dim(ko.gate.skipSourceLabel(source)));
|
|
583
557
|
return;
|
|
584
558
|
}
|
|
585
559
|
const questions = mode2 === "quick" ? GATE_QUESTIONS.filter((q) => q.quick) : GATE_QUESTIONS;
|
|
586
560
|
const total = questions.length;
|
|
587
561
|
const header = mode2 === "quick" ? ko.gate.quickHeader : ko.gate.fullHeader;
|
|
588
|
-
console.log(
|
|
562
|
+
console.log(chalk.dim(`
|
|
589
563
|
${header} ${ko.gate.modeCountSuffix(total)}
|
|
590
564
|
`));
|
|
591
|
-
console.log(
|
|
565
|
+
console.log(chalk.dim(`
|
|
592
566
|
${ko.gate.welcome}
|
|
593
567
|
`));
|
|
594
|
-
console.log(
|
|
568
|
+
console.log(chalk.dim(` ${ko.gate.ideaHint}`));
|
|
595
569
|
const { idea } = await inquirer.prompt([
|
|
596
570
|
{ type: "input", name: "idea", message: ko.gate.idea }
|
|
597
571
|
]);
|
|
598
|
-
console.log(
|
|
572
|
+
console.log(chalk.dim(` ${ko.gate.painPointHint}`));
|
|
599
573
|
const { painPoint } = await inquirer.prompt([
|
|
600
574
|
{ type: "input", name: "painPoint", message: ko.gate.painPoint }
|
|
601
575
|
]);
|
|
602
|
-
console.log(
|
|
576
|
+
console.log(chalk.dim(` ${ko.gate.edgeHint}`));
|
|
603
577
|
const { edge } = await inquirer.prompt([
|
|
604
578
|
{ type: "input", name: "edge", message: ko.gate.edge }
|
|
605
579
|
]);
|
|
606
|
-
console.log(
|
|
580
|
+
console.log(chalk.dim(`
|
|
607
581
|
${ko.gate.checklistStart}
|
|
608
582
|
`));
|
|
609
583
|
let failCount = 0;
|
|
@@ -611,7 +585,7 @@ ${ko.gate.checklistStart}
|
|
|
611
585
|
const results = [];
|
|
612
586
|
for (let i = 0; i < questions.length; i++) {
|
|
613
587
|
const q = questions[i];
|
|
614
|
-
if (q.hint) console.log(
|
|
588
|
+
if (q.hint) console.log(chalk.dim(`${ko.gate.hintPrefix} ${q.hint}`));
|
|
615
589
|
const { answer } = await inquirer.prompt([{
|
|
616
590
|
type: "input",
|
|
617
591
|
name: "answer",
|
|
@@ -630,22 +604,22 @@ ${ko.gate.checklistStart}
|
|
|
630
604
|
if (status2 === "fail") failCount++;
|
|
631
605
|
if (status2 === "hold") holdCount++;
|
|
632
606
|
results.push({ id: q.id, stage: q.stage, status: status2, answer });
|
|
633
|
-
const icon = status2 === "pass" ?
|
|
607
|
+
const icon = status2 === "pass" ? chalk.green(ko.gate.statusPassLine) : status2 === "hold" ? chalk.yellow(ko.gate.statusHoldLine) : chalk.red(ko.gate.statusFailLine);
|
|
634
608
|
console.log(icon);
|
|
635
609
|
}
|
|
636
|
-
console.log(
|
|
610
|
+
console.log(chalk.bold(`
|
|
637
611
|
${ko.gate.verdictTitle}
|
|
638
612
|
`));
|
|
639
|
-
console.log(`${ko.gate.ideaLabel} ${
|
|
613
|
+
console.log(`${ko.gate.ideaLabel} ${chalk.cyan(idea)}`);
|
|
640
614
|
console.log(`${ko.gate.painPointLabel} ${painPoint}`);
|
|
641
615
|
console.log(`${ko.gate.edgeLabel} ${edge}`);
|
|
642
616
|
console.log(`${ko.gate.countLine(failCount, holdCount, total)}
|
|
643
617
|
`);
|
|
644
618
|
const verdict = judgeGate(failCount, holdCount);
|
|
645
619
|
if (verdict === "GO") {
|
|
646
|
-
console.log(
|
|
620
|
+
console.log(chalk.green.bold(ko.gate.go));
|
|
647
621
|
if (holdCount > 0) {
|
|
648
|
-
console.log(
|
|
622
|
+
console.log(chalk.yellow(ko.gate.holdRemainHint));
|
|
649
623
|
}
|
|
650
624
|
printNextStep({
|
|
651
625
|
message: "\uC544\uC774\uB514\uC5B4 \uD1B5\uACFC! \uC774\uC81C \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E4\uC5B4\uBCF4\uC138\uC694.",
|
|
@@ -653,20 +627,20 @@ ${ko.gate.verdictTitle}
|
|
|
653
627
|
cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9CC\uB4E4\uC5B4\uC918"
|
|
654
628
|
});
|
|
655
629
|
} else if (verdict === "REFINE") {
|
|
656
|
-
console.log(
|
|
630
|
+
console.log(chalk.yellow.bold(ko.gate.refine));
|
|
657
631
|
printNextStep({
|
|
658
632
|
message: "\uC870\uAE08 \uB354 \uB2E4\uB4EC\uC740 \uD6C4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uBCF4\uC138\uC694.",
|
|
659
633
|
command: "vhk \uAC80\uC99D",
|
|
660
634
|
cursorHint: "\uC544\uC774\uB514\uC5B4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uC918"
|
|
661
635
|
});
|
|
662
636
|
} else {
|
|
663
|
-
console.log(
|
|
637
|
+
console.log(chalk.red.bold(ko.gate.drop));
|
|
664
638
|
}
|
|
665
639
|
}
|
|
666
640
|
|
|
667
641
|
// src/commands/init.ts
|
|
668
642
|
import inquirer2 from "inquirer";
|
|
669
|
-
import
|
|
643
|
+
import chalk3 from "chalk";
|
|
670
644
|
import fs2 from "fs";
|
|
671
645
|
import path2 from "path";
|
|
672
646
|
|
|
@@ -988,13 +962,13 @@ function VHK_CONTEXT_SEED(name, type, stack) {
|
|
|
988
962
|
}
|
|
989
963
|
|
|
990
964
|
// src/utils/logger.ts
|
|
991
|
-
import
|
|
965
|
+
import chalk2 from "chalk";
|
|
992
966
|
var log = {
|
|
993
|
-
success: (msg) => console.log(
|
|
994
|
-
error: (msg) => console.log(
|
|
995
|
-
warn: (msg) => console.log(
|
|
996
|
-
info: (msg) => console.log(
|
|
997
|
-
step: (msg) => console.log(
|
|
967
|
+
success: (msg) => console.log(chalk2.green(`\u2705 ${msg}`)),
|
|
968
|
+
error: (msg) => console.log(chalk2.red(`\u274C ${msg}`)),
|
|
969
|
+
warn: (msg) => console.log(chalk2.yellow(`\u26A0\uFE0F ${msg}`)),
|
|
970
|
+
info: (msg) => console.log(chalk2.blue(`\u2139\uFE0F ${msg}`)),
|
|
971
|
+
step: (msg) => console.log(chalk2.bold(`
|
|
998
972
|
\u25B8 ${msg}`))
|
|
999
973
|
};
|
|
1000
974
|
|
|
@@ -1237,11 +1211,11 @@ async function collectAnswers(options, defaults = {}) {
|
|
|
1237
1211
|
async function init(options = {}) {
|
|
1238
1212
|
const skipGate = Boolean(options.skipGate || options.fromNotion);
|
|
1239
1213
|
if (skipGate) {
|
|
1240
|
-
console.log(
|
|
1214
|
+
console.log(chalk3.dim(`
|
|
1241
1215
|
${ko.init.skipGate}
|
|
1242
1216
|
`));
|
|
1243
1217
|
}
|
|
1244
|
-
console.log(
|
|
1218
|
+
console.log(chalk3.bold(`
|
|
1245
1219
|
${ko.init.title}
|
|
1246
1220
|
`));
|
|
1247
1221
|
printSecurityWarnings();
|
|
@@ -1267,8 +1241,8 @@ ${ko.init.title}
|
|
|
1267
1241
|
}
|
|
1268
1242
|
const detected = detectProjectStack(process.cwd());
|
|
1269
1243
|
const stack = detected ?? STACK_PRESETS[answers.type];
|
|
1270
|
-
if (detected) console.log(
|
|
1271
|
-
console.log(
|
|
1244
|
+
if (detected) console.log(chalk3.dim(" \u{1F50E} package.json \uC758\uC874\uC131\uC5D0\uC11C \uC2E4\uC81C \uC2A4\uD0DD \uAC10\uC9C0"));
|
|
1245
|
+
console.log(chalk3.dim(`
|
|
1272
1246
|
${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
1273
1247
|
`));
|
|
1274
1248
|
if (isInteractive(options)) {
|
|
@@ -1299,7 +1273,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1299
1273
|
}]);
|
|
1300
1274
|
if (adopt) {
|
|
1301
1275
|
adoptedRules = buildAdoptedRules(existingRules, answers.name);
|
|
1302
|
-
console.log(
|
|
1276
|
+
console.log(chalk3.dim(` ${ko.init.adoptPreview(existingRules.length)}`));
|
|
1303
1277
|
}
|
|
1304
1278
|
}
|
|
1305
1279
|
}
|
|
@@ -1324,21 +1298,21 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1324
1298
|
log.success(filePath);
|
|
1325
1299
|
}
|
|
1326
1300
|
await writeInitExtras(cwd, !isInteractive(options));
|
|
1327
|
-
console.log(
|
|
1301
|
+
console.log(chalk3.bold.green(`
|
|
1328
1302
|
${ko.init.done}`));
|
|
1329
|
-
console.log(
|
|
1303
|
+
console.log(chalk3.dim(`
|
|
1330
1304
|
${ko.init.nextSteps}`));
|
|
1331
1305
|
if (options.fromNotion) {
|
|
1332
1306
|
console.log(` 1. ${ko.init.notionReviewHint}`);
|
|
1333
1307
|
console.log(` 2. ${ko.init.gitHintLabel}`);
|
|
1334
|
-
console.log(` ${
|
|
1308
|
+
console.log(` ${chalk3.cyan(ko.init.gitHintCommand)}`);
|
|
1335
1309
|
console.log(` 3. ${ko.init.startDev}
|
|
1336
1310
|
`);
|
|
1337
1311
|
} else {
|
|
1338
1312
|
console.log(` 1. ${ko.init.fillHint}`);
|
|
1339
1313
|
console.log(` 2. ${ko.init.prdHint}`);
|
|
1340
1314
|
console.log(` 3. ${ko.init.gitHintLabel}`);
|
|
1341
|
-
console.log(` ${
|
|
1315
|
+
console.log(` ${chalk3.cyan(ko.init.gitHintCommand)}`);
|
|
1342
1316
|
console.log(` 4. ${ko.init.startDev}
|
|
1343
1317
|
`);
|
|
1344
1318
|
}
|
|
@@ -1470,7 +1444,7 @@ async function writeInitExtras(projectDir, noninteractive = false) {
|
|
|
1470
1444
|
|
|
1471
1445
|
// src/commands/recap.ts
|
|
1472
1446
|
import inquirer3 from "inquirer";
|
|
1473
|
-
import
|
|
1447
|
+
import chalk5 from "chalk";
|
|
1474
1448
|
import fs4 from "fs";
|
|
1475
1449
|
import path5 from "path";
|
|
1476
1450
|
|
|
@@ -1656,7 +1630,7 @@ function createAdrFile(cwd, title, context2, decision, consequences) {
|
|
|
1656
1630
|
}
|
|
1657
1631
|
|
|
1658
1632
|
// src/lib/hard-stop-guard.ts
|
|
1659
|
-
import
|
|
1633
|
+
import chalk4 from "chalk";
|
|
1660
1634
|
|
|
1661
1635
|
// src/lib/state-files.ts
|
|
1662
1636
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, rmSync } from "fs";
|
|
@@ -1771,11 +1745,11 @@ function clearHardStop() {
|
|
|
1771
1745
|
// src/lib/hard-stop-guard.ts
|
|
1772
1746
|
function ensureNotHardStopped(action) {
|
|
1773
1747
|
if (!isHardStopActive()) return true;
|
|
1774
|
-
console.error(
|
|
1748
|
+
console.error(chalk4.red.bold(`
|
|
1775
1749
|
\u{1F6D1} HARD STOP \uD65C\uC131 \u2014 '${action}' \uC744(\uB97C) \uC2E4\uD589\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`));
|
|
1776
1750
|
const reason = readHardStopReason();
|
|
1777
|
-
if (reason) console.error(
|
|
1778
|
-
console.error(
|
|
1751
|
+
if (reason) console.error(chalk4.dim(` \uC0AC\uC720: ${reason.replace(/\s*\n\s*/g, " ")}`));
|
|
1752
|
+
console.error(chalk4.dim(" \uD574\uC81C: vhk resume --confirm (\uC0AC\uB78C\uC774 \uC9C1\uC811 \uC2E4\uD589)"));
|
|
1779
1753
|
process.exitCode = 1;
|
|
1780
1754
|
return false;
|
|
1781
1755
|
}
|
|
@@ -1783,45 +1757,45 @@ function ensureNotHardStopped(action) {
|
|
|
1783
1757
|
// src/commands/recap.ts
|
|
1784
1758
|
async function recap(options = {}) {
|
|
1785
1759
|
if (!ensureNotHardStopped("recap")) return;
|
|
1786
|
-
console.log(
|
|
1760
|
+
console.log(chalk5.bold(`
|
|
1787
1761
|
${ko.recap.title}
|
|
1788
1762
|
`));
|
|
1789
1763
|
if (!await isGitRepo()) {
|
|
1790
|
-
console.log(
|
|
1764
|
+
console.log(chalk5.red(ko.recap.noRepo));
|
|
1791
1765
|
return;
|
|
1792
1766
|
}
|
|
1793
1767
|
if (!await hasAnyCommits()) {
|
|
1794
|
-
console.log(
|
|
1795
|
-
console.log(
|
|
1768
|
+
console.log(chalk5.yellow("\u26A0\uFE0F \uC544\uC9C1 \uCEE4\uBC0B\uC774 \uC5C6\uC5B4\uC694."));
|
|
1769
|
+
console.log(chalk5.gray(" \uD30C\uC77C\uC744 \uCD94\uAC00\uD558\uACE0 `vhk save` \uB610\uB294 `git commit`\uC73C\uB85C \uCCAB \uCEE4\uBC0B\uC744 \uB9CC\uB4E4\uC5B4 \uBCF4\uC138\uC694."));
|
|
1796
1770
|
return;
|
|
1797
1771
|
}
|
|
1798
1772
|
printSecurityWarnings();
|
|
1799
|
-
console.log(
|
|
1773
|
+
console.log(chalk5.dim(`${ko.recap.analyzing}
|
|
1800
1774
|
`));
|
|
1801
1775
|
const since = options.since || localDate();
|
|
1802
1776
|
const diff2 = await getSessionDiff(since);
|
|
1803
1777
|
const commits = await getRecentCommits(10, since);
|
|
1804
1778
|
if (diff2.filesChanged === 0 && commits.length === 0) {
|
|
1805
|
-
console.log(
|
|
1779
|
+
console.log(chalk5.yellow(ko.recap.noChanges));
|
|
1806
1780
|
return;
|
|
1807
1781
|
}
|
|
1808
|
-
console.log(
|
|
1809
|
-
console.log(` \uD30C\uC77C: ${
|
|
1810
|
-
console.log(` \uCD94\uAC00: ${
|
|
1782
|
+
console.log(chalk5.bold("\u{1F4CA} \uBCC0\uACBD \uC694\uC57D:"));
|
|
1783
|
+
console.log(` \uD30C\uC77C: ${chalk5.cyan(String(diff2.filesChanged))}\uAC1C \uBCC0\uACBD`);
|
|
1784
|
+
console.log(` \uCD94\uAC00: ${chalk5.green("+" + diff2.insertions)} / \uC0AD\uC81C: ${chalk5.red("-" + diff2.deletions)}`);
|
|
1811
1785
|
if (diff2.files.length > 0) {
|
|
1812
|
-
console.log(
|
|
1786
|
+
console.log(chalk5.dim("\n \uBCC0\uACBD \uD30C\uC77C:"));
|
|
1813
1787
|
diff2.files.slice(0, 15).forEach((f) => {
|
|
1814
|
-
const icon = f.status === "new" ?
|
|
1788
|
+
const icon = f.status === "new" ? chalk5.green("\u{1F195}") : f.status === "deleted" ? chalk5.red("\u{1F5D1}\uFE0F") : chalk5.yellow("\u270F\uFE0F");
|
|
1815
1789
|
console.log(` ${icon} ${f.file}`);
|
|
1816
1790
|
});
|
|
1817
1791
|
if (diff2.files.length > 15) {
|
|
1818
|
-
console.log(
|
|
1792
|
+
console.log(chalk5.dim(` ... \uC678 ${diff2.files.length - 15}\uAC1C`));
|
|
1819
1793
|
}
|
|
1820
1794
|
}
|
|
1821
1795
|
if (commits.length > 0) {
|
|
1822
|
-
console.log(
|
|
1796
|
+
console.log(chalk5.dim("\n \uCD5C\uADFC \uCEE4\uBC0B:"));
|
|
1823
1797
|
commits.slice(0, 5).forEach((c) => {
|
|
1824
|
-
console.log(
|
|
1798
|
+
console.log(chalk5.dim(` \u2022 ${c.message}`));
|
|
1825
1799
|
});
|
|
1826
1800
|
}
|
|
1827
1801
|
console.log("");
|
|
@@ -1890,11 +1864,11 @@ ${ko.recap.title}
|
|
|
1890
1864
|
fs4.writeFileSync(filePath, content, "utf-8");
|
|
1891
1865
|
const adrCandidates = detectAdrCandidates(diff2);
|
|
1892
1866
|
if (adrCandidates.length > 0) {
|
|
1893
|
-
console.log(
|
|
1867
|
+
console.log(chalk5.cyan.bold(`
|
|
1894
1868
|
${ko.recap.adrDetected} (${adrCandidates.length}\uAC74)`));
|
|
1895
1869
|
for (const candidate of adrCandidates) {
|
|
1896
|
-
console.log(
|
|
1897
|
-
candidate.files.forEach((f) => console.log(
|
|
1870
|
+
console.log(chalk5.cyan(` \u2022 ${candidate.title}: ${candidate.context}`));
|
|
1871
|
+
candidate.files.forEach((f) => console.log(chalk5.dim(` ${f}`)));
|
|
1898
1872
|
}
|
|
1899
1873
|
const { createAdr } = await inquirer3.prompt([{
|
|
1900
1874
|
type: "confirm",
|
|
@@ -1924,17 +1898,17 @@ ${ko.recap.adrDetected} (${adrCandidates.length}\uAC74)`));
|
|
|
1924
1898
|
adrAnswers.decision,
|
|
1925
1899
|
adrAnswers.consequences
|
|
1926
1900
|
);
|
|
1927
|
-
console.log(
|
|
1901
|
+
console.log(chalk5.green(` \u2705 ADR \uC0DD\uC131: ${path5.relative(process.cwd(), adrPath)}`));
|
|
1928
1902
|
}
|
|
1929
1903
|
}
|
|
1930
1904
|
}
|
|
1931
1905
|
const troubleshootingKeywords = /fix|bug|error|crash|hotfix|patch|revert|트러블|에러|버그|수정|핫픽스/i;
|
|
1932
1906
|
const troubleCommits = commits.filter((c) => troubleshootingKeywords.test(c.message));
|
|
1933
1907
|
if (troubleCommits.length > 0) {
|
|
1934
|
-
console.log(
|
|
1908
|
+
console.log(chalk5.yellow.bold(`
|
|
1935
1909
|
${ko.recap.troubleDetected} (${troubleCommits.length}\uAC74)`));
|
|
1936
1910
|
troubleCommits.forEach((c) => {
|
|
1937
|
-
console.log(
|
|
1911
|
+
console.log(chalk5.dim(` \u2022 ${c.message}`));
|
|
1938
1912
|
});
|
|
1939
1913
|
const { createTroubleshoot } = await inquirer3.prompt([{
|
|
1940
1914
|
type: "confirm",
|
|
@@ -1985,12 +1959,12 @@ ${ko.recap.troubleDetected} (${troubleCommits.length}\uAC74)`));
|
|
|
1985
1959
|
`*Generated by \`vhk recap\` at ${(/* @__PURE__ */ new Date()).toISOString()}*`
|
|
1986
1960
|
].join("\n");
|
|
1987
1961
|
fs4.writeFileSync(tsFilePath, tsContent, "utf-8");
|
|
1988
|
-
console.log(
|
|
1962
|
+
console.log(chalk5.green(` \u2705 \uD2B8\uB7EC\uBE14\uC288\uD305 \uBB38\uC11C \uC0DD\uC131: ${path5.relative(process.cwd(), tsFilePath)}`));
|
|
1989
1963
|
}
|
|
1990
1964
|
}
|
|
1991
|
-
console.log(
|
|
1965
|
+
console.log(chalk5.green.bold(`
|
|
1992
1966
|
${ko.recap.done}`));
|
|
1993
|
-
console.log(
|
|
1967
|
+
console.log(chalk5.dim(` \u{1F4C4} ${path5.relative(process.cwd(), filePath)}`));
|
|
1994
1968
|
const claudeMdPath = path5.join(process.cwd(), "CLAUDE.md");
|
|
1995
1969
|
if (fs4.existsSync(claudeMdPath)) {
|
|
1996
1970
|
const { updateClaude } = await inquirer3.prompt([{
|
|
@@ -2010,7 +1984,7 @@ ${ko.recap.done}`));
|
|
|
2010
1984
|
`- **\uB2E4\uC74C \uC561\uC158:** ${answers.nextTodo}`
|
|
2011
1985
|
);
|
|
2012
1986
|
fs4.writeFileSync(claudeMdPath, claudeContent, "utf-8");
|
|
2013
|
-
console.log(
|
|
1987
|
+
console.log(chalk5.green(" \u2705 CLAUDE.md \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC"));
|
|
2014
1988
|
}
|
|
2015
1989
|
}
|
|
2016
1990
|
const gitSaveCmd = process.platform === "win32" ? 'git add .; git commit -m "recap: \uC138\uC158 \uAE30\uB85D"' : 'git add . && git commit -m "recap: \uC138\uC158 \uAE30\uB85D"';
|
|
@@ -2022,7 +1996,7 @@ ${ko.recap.done}`));
|
|
|
2022
1996
|
}
|
|
2023
1997
|
|
|
2024
1998
|
// src/commands/check.ts
|
|
2025
|
-
import
|
|
1999
|
+
import chalk7 from "chalk";
|
|
2026
2000
|
import path7 from "path";
|
|
2027
2001
|
import fs6 from "fs";
|
|
2028
2002
|
|
|
@@ -2186,7 +2160,7 @@ function escapeRegex(str) {
|
|
|
2186
2160
|
// src/commands/goal.ts
|
|
2187
2161
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3 } from "fs";
|
|
2188
2162
|
import { join as join4 } from "path";
|
|
2189
|
-
import
|
|
2163
|
+
import chalk6 from "chalk";
|
|
2190
2164
|
|
|
2191
2165
|
// src/lib/goal-frontmatter.ts
|
|
2192
2166
|
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
@@ -2366,14 +2340,14 @@ function resolveGoalId(optId, goals) {
|
|
|
2366
2340
|
return selectActiveId(goals);
|
|
2367
2341
|
}
|
|
2368
2342
|
async function goalList() {
|
|
2369
|
-
console.log(
|
|
2343
|
+
console.log(chalk6.bold(`
|
|
2370
2344
|
${ko.goal.listTitle}
|
|
2371
2345
|
`));
|
|
2372
2346
|
const goals = listGoals(GOALS_DIR);
|
|
2373
2347
|
const skipped = findSkippedGoalFiles(GOALS_DIR);
|
|
2374
2348
|
if (goals.length === 0) {
|
|
2375
|
-
console.log(
|
|
2376
|
-
console.log(
|
|
2349
|
+
console.log(chalk6.yellow(" \u{1F4ED} goals/ \uB514\uB809\uD1A0\uB9AC\uC5D0 goal \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
2350
|
+
console.log(chalk6.dim(" vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
|
|
2377
2351
|
printSkippedGoalWarnings(skipped);
|
|
2378
2352
|
return;
|
|
2379
2353
|
}
|
|
@@ -2391,33 +2365,33 @@ ${ko.goal.listTitle}
|
|
|
2391
2365
|
const dups = findDuplicateIds(goals);
|
|
2392
2366
|
if (dups.length > 0) {
|
|
2393
2367
|
console.log("");
|
|
2394
|
-
console.log(
|
|
2368
|
+
console.log(chalk6.yellow(` ${ko.goal.duplicateId(dups.join(", "))}`));
|
|
2395
2369
|
}
|
|
2396
2370
|
printSkippedGoalWarnings(skipped);
|
|
2397
2371
|
}
|
|
2398
2372
|
function printSkippedGoalWarnings(skipped) {
|
|
2399
2373
|
if (skipped.length > 0) {
|
|
2400
2374
|
console.log("");
|
|
2401
|
-
console.log(
|
|
2375
|
+
console.log(chalk6.yellow(` ${ko.goal.skippedFiles(skipped.length)}`));
|
|
2402
2376
|
for (const s of skipped) {
|
|
2403
|
-
console.log(
|
|
2377
|
+
console.log(chalk6.yellow(` - goals/${s.file}: ${s.reason}`));
|
|
2404
2378
|
}
|
|
2405
|
-
console.log(
|
|
2379
|
+
console.log(chalk6.dim(" \uD544\uC218: type: goal + \uC22B\uC790 id. \uC2A4\uD0A4\uB9C8 \uC804\uCCB4: goals/_meta.md"));
|
|
2406
2380
|
}
|
|
2407
2381
|
}
|
|
2408
2382
|
async function goalNext() {
|
|
2409
|
-
console.log(
|
|
2383
|
+
console.log(chalk6.bold(`
|
|
2410
2384
|
${ko.goal.nextTitle}
|
|
2411
2385
|
`));
|
|
2412
2386
|
const goals = listGoals(GOALS_DIR);
|
|
2413
2387
|
if (goals.length === 0) {
|
|
2414
|
-
console.log(
|
|
2415
|
-
console.log(
|
|
2388
|
+
console.log(chalk6.yellow(" \u{1F4ED} \uC815\uC758\uB41C goal \uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
2389
|
+
console.log(chalk6.dim(" vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694."));
|
|
2416
2390
|
return;
|
|
2417
2391
|
}
|
|
2418
2392
|
const activeId = selectActiveId(goals);
|
|
2419
2393
|
if (activeId === null) {
|
|
2420
|
-
console.log(
|
|
2394
|
+
console.log(chalk6.green(" \u{1F389} \uBAA8\uB4E0 goal \uC774 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4!"));
|
|
2421
2395
|
return;
|
|
2422
2396
|
}
|
|
2423
2397
|
const active = goals.find((g) => g.frontmatter.id === activeId);
|
|
@@ -2439,7 +2413,7 @@ ${ko.goal.nextTitle}
|
|
|
2439
2413
|
mkdirSync2(STATE_DIR2, { recursive: true });
|
|
2440
2414
|
writeFileSync2(join4(STATE_DIR2, "next-task.md"), text, "utf-8");
|
|
2441
2415
|
console.log(
|
|
2442
|
-
|
|
2416
|
+
chalk6.green(
|
|
2443
2417
|
` \u2705 next-task.md \uAC31\uC2E0 \u2014 Goal ${activeId}: ${active.frontmatter.title ?? ""}`
|
|
2444
2418
|
)
|
|
2445
2419
|
);
|
|
@@ -2498,7 +2472,7 @@ var STATE_NEXT_TASK_TEMPLATE = "# Next Task\n\n```\nTASK: (vhk goal next \uB85C
|
|
|
2498
2472
|
var STATE_BLOCKERS_TEMPLATE = "# Blockers\n\n_Append-only. \uD574\uACB0 \uD56D\uBAA9\uC740 ~~\uCDE8\uC18C\uC120~~\uC73C\uB85C \uD45C\uAE30._\n";
|
|
2499
2473
|
var STATE_LEARNINGS_TEMPLATE = "# Learnings\n\n_Append-only. \uD55C \uC904 = \uD55C \uAD50\uD6C8._\n";
|
|
2500
2474
|
async function goalInit() {
|
|
2501
|
-
console.log(
|
|
2475
|
+
console.log(chalk6.bold(`
|
|
2502
2476
|
${ko.goal.initTitle}
|
|
2503
2477
|
`));
|
|
2504
2478
|
const targets = [
|
|
@@ -2513,15 +2487,15 @@ ${ko.goal.initTitle}
|
|
|
2513
2487
|
let skipped = 0;
|
|
2514
2488
|
for (const t2 of targets) {
|
|
2515
2489
|
if (existsSync3(t2.path)) {
|
|
2516
|
-
console.log(
|
|
2490
|
+
console.log(chalk6.gray(` \u2298 skip (\uC774\uBBF8 \uC874\uC7AC): ${t2.path}`));
|
|
2517
2491
|
skipped++;
|
|
2518
2492
|
} else {
|
|
2519
2493
|
writeFileSync2(t2.path, t2.content, "utf-8");
|
|
2520
|
-
console.log(
|
|
2494
|
+
console.log(chalk6.green(` \u2713 created: ${t2.path}`));
|
|
2521
2495
|
created++;
|
|
2522
2496
|
}
|
|
2523
2497
|
}
|
|
2524
|
-
console.log(
|
|
2498
|
+
console.log(chalk6.bold(`
|
|
2525
2499
|
\u{1F4CA} created=${created} skipped=${skipped}`));
|
|
2526
2500
|
if (created > 0) {
|
|
2527
2501
|
printNextStep({
|
|
@@ -2547,76 +2521,76 @@ function runGate(scriptPath) {
|
|
|
2547
2521
|
function warnIfBashOnWindows(scriptPath) {
|
|
2548
2522
|
if (process.platform === "win32" && scriptPath.endsWith(".sh")) {
|
|
2549
2523
|
console.log(
|
|
2550
|
-
|
|
2524
|
+
chalk6.yellow(
|
|
2551
2525
|
" \u26A0 Windows: .sh \uAC8C\uC774\uD2B8\uB294 bash \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. cross-platform .mjs \uB85C \uBC31\uD544\uD558\uC138\uC694 \u2192 vhk goal sync"
|
|
2552
2526
|
)
|
|
2553
2527
|
);
|
|
2554
2528
|
}
|
|
2555
2529
|
}
|
|
2556
2530
|
async function goalCheck(opts) {
|
|
2557
|
-
console.log(
|
|
2531
|
+
console.log(chalk6.bold(`
|
|
2558
2532
|
${ko.goal.checkTitle}
|
|
2559
2533
|
`));
|
|
2560
2534
|
const goals = listGoals(GOALS_DIR);
|
|
2561
2535
|
const id = resolveGoalId(opts.id, goals);
|
|
2562
2536
|
if (id === null) {
|
|
2563
2537
|
console.log(
|
|
2564
|
-
|
|
2538
|
+
chalk6.yellow(" \u26A0 \uB300\uC0C1 goal \uC744 \uACB0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (--id \uBA85\uC2DC \uB610\uB294 active goal \uD544\uC694).")
|
|
2565
2539
|
);
|
|
2566
2540
|
process.exitCode = 1;
|
|
2567
2541
|
return;
|
|
2568
2542
|
}
|
|
2569
2543
|
if (!goals.some((g) => g.frontmatter.id === id)) {
|
|
2570
|
-
console.log(
|
|
2544
|
+
console.log(chalk6.red(` \u274C ${ko.goal.notFound(id)}`));
|
|
2571
2545
|
process.exitCode = 1;
|
|
2572
2546
|
return;
|
|
2573
2547
|
}
|
|
2574
2548
|
const scriptPath = findGateScript(id);
|
|
2575
2549
|
if (!scriptPath) {
|
|
2576
2550
|
console.log(
|
|
2577
|
-
|
|
2551
|
+
chalk6.red(` \u274C \uAC8C\uC774\uD2B8 \uC2A4\uD06C\uB9BD\uD2B8 \uC5C6\uC74C: scripts/check-goal-${id}.{mjs,sh}`)
|
|
2578
2552
|
);
|
|
2579
2553
|
process.exitCode = 1;
|
|
2580
2554
|
return;
|
|
2581
2555
|
}
|
|
2582
2556
|
warnIfBashOnWindows(scriptPath);
|
|
2583
2557
|
const gate2 = runGate(scriptPath);
|
|
2584
|
-
console.log(
|
|
2558
|
+
console.log(chalk6.dim(` \u25B6 ${gate2.runner} ${scriptPath}
|
|
2585
2559
|
`));
|
|
2586
2560
|
if (gate2.out) console.log(gate2.out);
|
|
2587
2561
|
if (gate2.ok) {
|
|
2588
|
-
console.log(
|
|
2562
|
+
console.log(chalk6.green(`
|
|
2589
2563
|
\u2705 Goal ${id} \uAC8C\uC774\uD2B8 \uD1B5\uACFC`));
|
|
2590
2564
|
} else {
|
|
2591
|
-
console.log(
|
|
2565
|
+
console.log(chalk6.red(`
|
|
2592
2566
|
\u274C Goal ${id} \uAC8C\uC774\uD2B8 \uC2E4\uD328`));
|
|
2593
|
-
if (gate2.err && !gate2.out) console.log(
|
|
2567
|
+
if (gate2.err && !gate2.out) console.log(chalk6.dim(gate2.err.slice(0, 500)));
|
|
2594
2568
|
process.exitCode = 1;
|
|
2595
2569
|
}
|
|
2596
2570
|
}
|
|
2597
2571
|
async function goalDone(opts) {
|
|
2598
|
-
console.log(
|
|
2572
|
+
console.log(chalk6.bold(`
|
|
2599
2573
|
${ko.goal.doneTitle}
|
|
2600
2574
|
`));
|
|
2601
2575
|
const goals = listGoals(GOALS_DIR);
|
|
2602
2576
|
const id = resolveGoalId(opts.id, goals);
|
|
2603
2577
|
if (id === null) {
|
|
2604
2578
|
console.log(
|
|
2605
|
-
|
|
2579
|
+
chalk6.yellow(" \u26A0 \uB300\uC0C1 goal \uC744 \uACB0\uC815\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (--id \uBA85\uC2DC \uB610\uB294 active goal \uD544\uC694).")
|
|
2606
2580
|
);
|
|
2607
2581
|
process.exitCode = 1;
|
|
2608
2582
|
return;
|
|
2609
2583
|
}
|
|
2610
2584
|
const target = goals.find((g) => g.frontmatter.id === id);
|
|
2611
2585
|
if (!target) {
|
|
2612
|
-
console.log(
|
|
2586
|
+
console.log(chalk6.red(` \u274C ${ko.goal.notFound(id)}`));
|
|
2613
2587
|
process.exitCode = 1;
|
|
2614
2588
|
return;
|
|
2615
2589
|
}
|
|
2616
2590
|
const scriptPath = findGateScript(id);
|
|
2617
2591
|
if (!scriptPath) {
|
|
2618
2592
|
console.log(
|
|
2619
|
-
|
|
2593
|
+
chalk6.red(
|
|
2620
2594
|
` \u274C \uAC8C\uC774\uD2B8 \uC2A4\uD06C\uB9BD\uD2B8 \uC5C6\uC74C \u2014 done \uCC98\uB9AC \uAC70\uBD80: scripts/check-goal-${id}.{mjs,sh}`
|
|
2621
2595
|
)
|
|
2622
2596
|
);
|
|
@@ -2625,12 +2599,12 @@ ${ko.goal.doneTitle}
|
|
|
2625
2599
|
}
|
|
2626
2600
|
warnIfBashOnWindows(scriptPath);
|
|
2627
2601
|
const gate2 = runGate(scriptPath);
|
|
2628
|
-
console.log(
|
|
2602
|
+
console.log(chalk6.dim(` \u25B6 \uAC8C\uC774\uD2B8 \uAC80\uC99D: ${gate2.runner} ${scriptPath}
|
|
2629
2603
|
`));
|
|
2630
2604
|
if (gate2.out) console.log(gate2.out);
|
|
2631
2605
|
if (!gate2.ok) {
|
|
2632
2606
|
console.log(
|
|
2633
|
-
|
|
2607
|
+
chalk6.red(
|
|
2634
2608
|
`
|
|
2635
2609
|
\u274C \uAC8C\uC774\uD2B8 \uC2E4\uD328 \u2014 frontmatter \uBCC0\uACBD \uC5C6\uC774 \uC885\uB8CC. (Forbidden: \uC2E4\uD328 = \uBCF4\uC874)`
|
|
2636
2610
|
)
|
|
@@ -2642,7 +2616,7 @@ ${ko.goal.doneTitle}
|
|
|
2642
2616
|
const today = localDate();
|
|
2643
2617
|
const updated = updateFrontmatterStatus(content, "DONE", { completed: today });
|
|
2644
2618
|
writeFileSync2(target.filePath, updated, "utf-8");
|
|
2645
|
-
console.log(
|
|
2619
|
+
console.log(chalk6.green(`
|
|
2646
2620
|
\u2705 Goal ${id} \u2192 DONE (completed: ${today})`));
|
|
2647
2621
|
printNextStep({
|
|
2648
2622
|
message: `Goal ${id} \uC644\uB8CC! \uB2E4\uC74C goal \uB85C:`,
|
|
@@ -2715,14 +2689,14 @@ function generateGateScript(id) {
|
|
|
2715
2689
|
].join("\n");
|
|
2716
2690
|
}
|
|
2717
2691
|
async function goalSync() {
|
|
2718
|
-
console.log(
|
|
2692
|
+
console.log(chalk6.bold(`
|
|
2719
2693
|
${ko.goal.syncTitle}
|
|
2720
2694
|
`));
|
|
2721
2695
|
const goals = listGoals(GOALS_DIR);
|
|
2722
2696
|
const result = { created: [], skipped: [] };
|
|
2723
2697
|
if (goals.length === 0) {
|
|
2724
2698
|
console.log(
|
|
2725
|
-
|
|
2699
|
+
chalk6.yellow(" \u{1F4ED} goals/ \uC5D0 goal \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. vhk goal init \uC73C\uB85C \uC2DC\uC791\uD558\uC138\uC694.")
|
|
2726
2700
|
);
|
|
2727
2701
|
return result;
|
|
2728
2702
|
}
|
|
@@ -2732,19 +2706,19 @@ ${ko.goal.syncTitle}
|
|
|
2732
2706
|
if (typeof id !== "number") continue;
|
|
2733
2707
|
const target = join4(SCRIPTS_DIR, `check-goal-${id}.mjs`);
|
|
2734
2708
|
if (existsSync3(target)) {
|
|
2735
|
-
console.log(
|
|
2709
|
+
console.log(chalk6.gray(` \u2298 skip (\uC774\uBBF8 \uC874\uC7AC): ${target}`));
|
|
2736
2710
|
result.skipped.push(id);
|
|
2737
2711
|
continue;
|
|
2738
2712
|
}
|
|
2739
2713
|
const shOnly = existsSync3(join4(SCRIPTS_DIR, `check-goal-${id}.sh`));
|
|
2740
2714
|
writeFileSync2(target, generateGateScript(id), "utf-8");
|
|
2741
2715
|
console.log(
|
|
2742
|
-
|
|
2716
|
+
chalk6.green(` \u2713 created: ${target}${shOnly ? " (.sh \u2192 .mjs \uBC31\uD544, Windows 1\uAE09)" : ""}`)
|
|
2743
2717
|
);
|
|
2744
2718
|
result.created.push(id);
|
|
2745
2719
|
}
|
|
2746
2720
|
console.log(
|
|
2747
|
-
|
|
2721
|
+
chalk6.bold(`
|
|
2748
2722
|
\u{1F4CA} created=${result.created.length} skipped=${result.skipped.length}`)
|
|
2749
2723
|
);
|
|
2750
2724
|
if (result.created.length > 0) {
|
|
@@ -2765,22 +2739,22 @@ async function check(opts = {}) {
|
|
|
2765
2739
|
return checkRules();
|
|
2766
2740
|
}
|
|
2767
2741
|
async function checkRules() {
|
|
2768
|
-
console.log(
|
|
2742
|
+
console.log(chalk7.bold(`
|
|
2769
2743
|
${ko.check.title}
|
|
2770
2744
|
`));
|
|
2771
2745
|
const cwd = process.cwd();
|
|
2772
2746
|
const rulesPath = path7.join(cwd, "RULES.md");
|
|
2773
2747
|
if (!fs6.existsSync(rulesPath)) {
|
|
2774
|
-
console.log(
|
|
2775
|
-
console.log(
|
|
2748
|
+
console.log(chalk7.yellow(ko.check.noRules));
|
|
2749
|
+
console.log(chalk7.dim(" vhk init\uC73C\uB85C \uC2DC\uC791\uD558\uAC70\uB098 RULES.md\uB97C \uB9CC\uB4E4\uC5B4 \uBCF4\uC138\uC694."));
|
|
2776
2750
|
return;
|
|
2777
2751
|
}
|
|
2778
2752
|
const rules = parseRules(rulesPath);
|
|
2779
|
-
console.log(
|
|
2753
|
+
console.log(chalk7.dim(` \u{1F4CF} \uC790\uB3D9 \uAC80\uC99D \uAC00\uB2A5\uD55C \uADDC\uCE59 ${rules.length}\uAC1C \uAC10\uC9C0 (\uB098\uBA38\uC9C0 \uADDC\uCE59\uC740 \uC218\uB3D9/\uB3C4\uAD6C \uD655\uC778)
|
|
2780
2754
|
`));
|
|
2781
2755
|
if (rules.length === 0) {
|
|
2782
|
-
console.log(
|
|
2783
|
-
console.log(
|
|
2756
|
+
console.log(chalk7.yellow(ko.check.noAutoRules));
|
|
2757
|
+
console.log(chalk7.dim(" RULES.md\uC5D0 \uD30C\uC77C \uC774\uB984\xB7\uD3F4\uB354 \uADDC\uCE59\uC744 \uC801\uC73C\uBA74 \uC790\uB3D9\uC73C\uB85C \uC810\uAC80\uD574\uC694."));
|
|
2784
2758
|
return;
|
|
2785
2759
|
}
|
|
2786
2760
|
const allViolations = [];
|
|
@@ -2788,14 +2762,14 @@ ${ko.check.title}
|
|
|
2788
2762
|
for (const rule of rules) {
|
|
2789
2763
|
const violations = rule.check(cwd);
|
|
2790
2764
|
if (violations.length === 0) {
|
|
2791
|
-
const patternHint = rule.type === "content" && rule.pattern ?
|
|
2792
|
-
console.log(
|
|
2765
|
+
const patternHint = rule.type === "content" && rule.pattern ? chalk7.dim(` [\uAC80\uC0AC: ${rule.pattern.source}]`) : "";
|
|
2766
|
+
console.log(chalk7.green(` \u2705 ${rule.id}`) + chalk7.dim(` \u2014 ${rule.description.slice(0, 60)}`) + patternHint);
|
|
2793
2767
|
passCount++;
|
|
2794
2768
|
} else {
|
|
2795
|
-
console.log(
|
|
2769
|
+
console.log(chalk7.red(` \u274C ${rule.id}`) + chalk7.dim(` \u2014 ${violations.length}\uAC74 \uC704\uBC18`));
|
|
2796
2770
|
violations.forEach((v) => {
|
|
2797
|
-
const loc = v.file ?
|
|
2798
|
-
const icon = v.severity === "error" ?
|
|
2771
|
+
const loc = v.file ? chalk7.dim(` (${v.file}${v.line ? ":" + v.line : ""})`) : "";
|
|
2772
|
+
const icon = v.severity === "error" ? chalk7.red("\u2716") : v.severity === "warning" ? chalk7.yellow("\u26A0") : chalk7.blue("\u2139");
|
|
2799
2773
|
console.log(` ${icon} ${v.message}${loc}`);
|
|
2800
2774
|
});
|
|
2801
2775
|
allViolations.push(...violations);
|
|
@@ -2805,18 +2779,18 @@ ${ko.check.title}
|
|
|
2805
2779
|
const errors = allViolations.filter((v) => v.severity === "error").length;
|
|
2806
2780
|
const warnings = allViolations.filter((v) => v.severity === "warning").length;
|
|
2807
2781
|
if (allViolations.length === 0) {
|
|
2808
|
-
console.log(
|
|
2809
|
-
console.log(
|
|
2782
|
+
console.log(chalk7.green.bold(`\u2705 \uC790\uB3D9 \uAC80\uC99D \uAC00\uB2A5\uD55C \uADDC\uCE59 ${passCount}\uAC1C \uD1B5\uACFC`));
|
|
2783
|
+
console.log(chalk7.dim(" (RULES.md \uC758 \uB098\uBA38\uC9C0 \uADDC\uCE59\uC740 \uCF54\uB4DC \uC790\uB3D9 \uAC80\uC0AC \uBD88\uAC00 \u2014 \uC9C1\uC811/\uB3C4\uAD6C\uB85C \uD655\uC778\uD558\uC138\uC694.)"));
|
|
2810
2784
|
printNextStep({
|
|
2811
2785
|
message: "\uBAA8\uB4E0 \uADDC\uCE59 \uD1B5\uACFC! \uBCF4\uC548 \uC2A4\uCE94\uB3C4 \uD574\uBCFC\uAE4C\uC694?",
|
|
2812
2786
|
command: "vhk \uBCF4\uC548 scan",
|
|
2813
2787
|
cursorHint: "\uBCF4\uC548 \uC2A4\uCE94 \uB3CC\uB824\uC918"
|
|
2814
2788
|
});
|
|
2815
2789
|
} else {
|
|
2816
|
-
console.log(
|
|
2817
|
-
console.log(` \uADDC\uCE59: ${
|
|
2818
|
-
if (errors > 0) console.log(` ${
|
|
2819
|
-
if (warnings > 0) console.log(` ${
|
|
2790
|
+
console.log(chalk7.bold(ko.check.summary));
|
|
2791
|
+
console.log(` \uADDC\uCE59: ${chalk7.cyan(String(rules.length))}\uAC1C | \uD1B5\uACFC: ${chalk7.green(String(passCount))}\uAC1C | \uC704\uBC18: ${chalk7.red(String(allViolations.length))}\uAC74`);
|
|
2792
|
+
if (errors > 0) console.log(` ${chalk7.red(`\u2716 ${errors}\uAC1C \uC5D0\uB7EC`)}`);
|
|
2793
|
+
if (warnings > 0) console.log(` ${chalk7.yellow(`\u26A0 ${warnings}\uAC1C \uACBD\uACE0`)}`);
|
|
2820
2794
|
printNextStep({
|
|
2821
2795
|
message: "\uC704\uBC18 \uD56D\uBAA9\uC744 \uC218\uC815\uD55C \uD6C4 \uB2E4\uC2DC \uC810\uAC80\uD558\uC138\uC694.",
|
|
2822
2796
|
command: "vhk \uC810\uAC80",
|
|
@@ -2829,36 +2803,36 @@ ${ko.check.title}
|
|
|
2829
2803
|
}
|
|
2830
2804
|
|
|
2831
2805
|
// src/commands/secure.ts
|
|
2832
|
-
import
|
|
2806
|
+
import chalk8 from "chalk";
|
|
2833
2807
|
import fs7 from "fs";
|
|
2834
2808
|
import path8 from "path";
|
|
2835
2809
|
async function secure() {
|
|
2836
|
-
console.log(
|
|
2810
|
+
console.log(chalk8.bold(`
|
|
2837
2811
|
${ko.secure.title}
|
|
2838
2812
|
`));
|
|
2839
2813
|
const cwd = process.cwd();
|
|
2840
2814
|
const gitignorePath = path8.join(cwd, ".gitignore");
|
|
2841
2815
|
const hasGitignore = fs7.existsSync(gitignorePath);
|
|
2842
2816
|
if (!hasGitignore) {
|
|
2843
|
-
console.log(
|
|
2844
|
-
console.log(
|
|
2817
|
+
console.log(chalk8.yellow(` ${ko.secure.noGitignore}`));
|
|
2818
|
+
console.log(chalk8.dim(" .env \uD30C\uC77C\uC774 \uCEE4\uBC0B\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n"));
|
|
2845
2819
|
} else {
|
|
2846
2820
|
const gitignoreContent = fs7.readFileSync(gitignorePath, "utf-8");
|
|
2847
2821
|
if (!gitignoreContent.includes(".env")) {
|
|
2848
|
-
console.log(
|
|
2849
|
-
console.log(
|
|
2822
|
+
console.log(chalk8.yellow(` ${ko.secure.noEnvInGitignore}`));
|
|
2823
|
+
console.log(chalk8.dim(" \uCD94\uAC00\uB97C \uAD8C\uC7A5\uD569\uB2C8\uB2E4.\n"));
|
|
2850
2824
|
}
|
|
2851
2825
|
}
|
|
2852
|
-
console.log(
|
|
2826
|
+
console.log(chalk8.dim(` ${ko.secure.scanning}
|
|
2853
2827
|
`));
|
|
2854
2828
|
const { findings, scannedFiles, truncated } = scanProjectForSecrets(cwd);
|
|
2855
|
-
console.log(
|
|
2829
|
+
console.log(chalk8.dim(` \u{1F4C2} ${scannedFiles}\uAC1C \uD30C\uC77C \uC2A4\uCE94 \uC644\uB8CC (lock\xB7node_modules\xB7>${MAX_SCAN_FILE_BYTES / 1024}KB \uC81C\uC678)`));
|
|
2856
2830
|
if (truncated) {
|
|
2857
|
-
console.log(
|
|
2831
|
+
console.log(chalk8.yellow(` \u26A0\uFE0F \uACB0\uACFC ${MAX_SECRET_FINDINGS}\uAC74\uC5D0\uC11C \uCD9C\uB825\uC744 \uC81C\uD55C\uD588\uC2B5\uB2C8\uB2E4. lock \uD30C\uC77C \uB4F1\uC740 \uC790\uB3D9 \uC81C\uC678\uB429\uB2C8\uB2E4.`));
|
|
2858
2832
|
}
|
|
2859
2833
|
console.log("");
|
|
2860
2834
|
if (findings.length === 0) {
|
|
2861
|
-
console.log(
|
|
2835
|
+
console.log(chalk8.green.bold(` ${ko.secure.clean}`));
|
|
2862
2836
|
printNextStep({
|
|
2863
2837
|
message: "\uBCF4\uC548 \uC774\uC0C1 \uC5C6\uC74C! \uAE68\uB057\uD569\uB2C8\uB2E4.",
|
|
2864
2838
|
command: "vhk \uC815\uB9AC",
|
|
@@ -2870,43 +2844,43 @@ ${ko.secure.title}
|
|
|
2870
2844
|
const high = findings.filter((f) => f.severity === "high");
|
|
2871
2845
|
const medium = findings.filter((f) => f.severity === "medium");
|
|
2872
2846
|
if (critical.length > 0) {
|
|
2873
|
-
console.log(
|
|
2847
|
+
console.log(chalk8.red.bold(` \u{1F6A8} CRITICAL \u2014 ${critical.length}\uAC74`));
|
|
2874
2848
|
critical.forEach((f) => {
|
|
2875
|
-
console.log(
|
|
2876
|
-
console.log(
|
|
2849
|
+
console.log(chalk8.red(` \u2716 ${f.patternName}`));
|
|
2850
|
+
console.log(chalk8.dim(` ${f.file}:${f.line} \u2192 ${f.match}`));
|
|
2877
2851
|
});
|
|
2878
2852
|
console.log("");
|
|
2879
2853
|
}
|
|
2880
2854
|
if (high.length > 0) {
|
|
2881
|
-
console.log(
|
|
2855
|
+
console.log(chalk8.yellow.bold(` \u26A0\uFE0F HIGH \u2014 ${high.length}\uAC74`));
|
|
2882
2856
|
high.forEach((f) => {
|
|
2883
|
-
console.log(
|
|
2884
|
-
console.log(
|
|
2857
|
+
console.log(chalk8.yellow(` \u26A0 ${f.patternName}`));
|
|
2858
|
+
console.log(chalk8.dim(` ${f.file}:${f.line} \u2192 ${f.match}`));
|
|
2885
2859
|
});
|
|
2886
2860
|
console.log("");
|
|
2887
2861
|
}
|
|
2888
2862
|
if (medium.length > 0) {
|
|
2889
|
-
console.log(
|
|
2863
|
+
console.log(chalk8.blue.bold(` \u2139 MEDIUM \u2014 ${medium.length}\uAC74`));
|
|
2890
2864
|
medium.forEach((f) => {
|
|
2891
|
-
console.log(
|
|
2892
|
-
console.log(
|
|
2865
|
+
console.log(chalk8.blue(` \u2139 ${f.patternName}`));
|
|
2866
|
+
console.log(chalk8.dim(` ${f.file}:${f.line} \u2192 ${f.match}`));
|
|
2893
2867
|
});
|
|
2894
2868
|
console.log("");
|
|
2895
2869
|
}
|
|
2896
|
-
console.log(
|
|
2897
|
-
console.log(` \uCD1D ${
|
|
2870
|
+
console.log(chalk8.bold(` ${ko.secure.summary}`));
|
|
2871
|
+
console.log(` \uCD1D ${chalk8.red(String(findings.length))}\uAC74 \uAC10\uC9C0 | CRITICAL: ${critical.length} | HIGH: ${high.length} | MEDIUM: ${medium.length}`);
|
|
2898
2872
|
console.log("");
|
|
2899
|
-
console.log(
|
|
2900
|
-
console.log(
|
|
2901
|
-
console.log(
|
|
2902
|
-
console.log(
|
|
2873
|
+
console.log(chalk8.dim(" \u{1F4A1} \uC870\uCE58 \uBC29\uBC95:"));
|
|
2874
|
+
console.log(chalk8.dim(" 1. \uD574\uB2F9 \uD30C\uC77C\uC5D0\uC11C \uC2DC\uD06C\uB9BF\uC744 \uC81C\uAC70\uD558\uACE0 \uD658\uACBD\uBCC0\uC218\uB85C \uC774\uB3D9"));
|
|
2875
|
+
console.log(chalk8.dim(" 2. git history\uC5D0\uC11C\uB3C4 \uC81C\uAC70: git filter-branch \uB610\uB294 BFG Repo-Cleaner"));
|
|
2876
|
+
console.log(chalk8.dim(" 3. \uC720\uCD9C\uB41C \uD0A4\uB294 \uC989\uC2DC \uD3D0\uAE30\uD558\uACE0 \uC7AC\uBC1C\uAE09\n"));
|
|
2903
2877
|
if (critical.length > 0 || high.length > 0) {
|
|
2904
2878
|
process.exitCode = 1;
|
|
2905
2879
|
}
|
|
2906
2880
|
}
|
|
2907
2881
|
|
|
2908
2882
|
// src/commands/doctor.ts
|
|
2909
|
-
import
|
|
2883
|
+
import chalk9 from "chalk";
|
|
2910
2884
|
import fs8 from "fs";
|
|
2911
2885
|
import path9 from "path";
|
|
2912
2886
|
import { fileURLToPath } from "url";
|
|
@@ -2952,7 +2926,7 @@ function compareSemver(a, b) {
|
|
|
2952
2926
|
return a3 - b3;
|
|
2953
2927
|
}
|
|
2954
2928
|
async function doctor() {
|
|
2955
|
-
console.log(
|
|
2929
|
+
console.log(chalk9.bold(`
|
|
2956
2930
|
${ko.doctor.title}
|
|
2957
2931
|
`));
|
|
2958
2932
|
const checks = [
|
|
@@ -2964,30 +2938,30 @@ ${ko.doctor.title}
|
|
|
2964
2938
|
let allOk = true;
|
|
2965
2939
|
for (const check2 of checks) {
|
|
2966
2940
|
if (check2.ok) {
|
|
2967
|
-
console.log(
|
|
2941
|
+
console.log(chalk9.green(` \u2705 ${check2.name}`) + chalk9.dim(` \u2014 ${check2.version}`));
|
|
2968
2942
|
} else {
|
|
2969
|
-
console.log(
|
|
2970
|
-
console.log(
|
|
2943
|
+
console.log(chalk9.red(` \u274C ${check2.name} \uC5C6\uC74C`));
|
|
2944
|
+
console.log(chalk9.dim(` \u2192 ${check2.hint}`));
|
|
2971
2945
|
allOk = false;
|
|
2972
2946
|
}
|
|
2973
2947
|
}
|
|
2974
2948
|
console.log("");
|
|
2975
2949
|
const vhkVersion = getVhkVersion2();
|
|
2976
2950
|
if (vhkVersion) {
|
|
2977
|
-
console.log(
|
|
2951
|
+
console.log(chalk9.green(" \u2705 VHK") + chalk9.dim(` \u2014 v${vhkVersion}`));
|
|
2978
2952
|
} else {
|
|
2979
|
-
console.log(
|
|
2953
|
+
console.log(chalk9.green(" \u2705 VHK") + chalk9.dim(" \u2014 \uC124\uCE58\uB428"));
|
|
2980
2954
|
}
|
|
2981
2955
|
if (vhkVersion) {
|
|
2982
2956
|
const latest = fetchLatestNpmVersion("@byh3071/vhk");
|
|
2983
2957
|
if (latest && compareSemver(latest, vhkVersion) > 0) {
|
|
2984
|
-
console.log(
|
|
2958
|
+
console.log(chalk9.yellow(` ${ko.doctor.updateAvailable(latest)}`));
|
|
2985
2959
|
} else if (latest) {
|
|
2986
|
-
console.log(
|
|
2960
|
+
console.log(chalk9.dim(` ${ko.doctor.updateCurrent}`));
|
|
2987
2961
|
}
|
|
2988
2962
|
}
|
|
2989
2963
|
console.log("");
|
|
2990
|
-
console.log(
|
|
2964
|
+
console.log(chalk9.bold(` ${ko.doctor.projectFiles}`));
|
|
2991
2965
|
const cwd = process.cwd();
|
|
2992
2966
|
const projectFiles = [
|
|
2993
2967
|
{ name: "RULES.md", hint: "vhk init\uC73C\uB85C \uC0DD\uC131 \uAC00\uB2A5" },
|
|
@@ -2999,49 +2973,49 @@ ${ko.doctor.title}
|
|
|
2999
2973
|
for (const file of projectFiles) {
|
|
3000
2974
|
const exists = fs8.existsSync(path9.join(cwd, file.name));
|
|
3001
2975
|
if (exists) {
|
|
3002
|
-
console.log(
|
|
2976
|
+
console.log(chalk9.green(` \u2705 ${file.name}`));
|
|
3003
2977
|
if (file.name === ".env") {
|
|
3004
2978
|
const gitignorePath = path9.join(cwd, ".gitignore");
|
|
3005
2979
|
if (fs8.existsSync(gitignorePath)) {
|
|
3006
2980
|
const gitignore = fs8.readFileSync(gitignorePath, "utf-8");
|
|
3007
2981
|
if (!gitignore.includes(".env")) {
|
|
3008
|
-
console.log(
|
|
2982
|
+
console.log(chalk9.yellow(` ${ko.doctor.envNotIgnored}`));
|
|
3009
2983
|
}
|
|
3010
2984
|
}
|
|
3011
2985
|
}
|
|
3012
2986
|
} else if (file.name === ".env" && fs8.existsSync(path9.join(cwd, ".env.local"))) {
|
|
3013
|
-
console.log(
|
|
2987
|
+
console.log(chalk9.green(" \u2705 .env.local") + chalk9.dim(" \u2014 \uB85C\uCEEC env \uC0AC\uC6A9 \uC911 (.env \uC5C6\uC5B4\uB3C4 \uC815\uC0C1)"));
|
|
3014
2988
|
} else {
|
|
3015
|
-
console.log(
|
|
2989
|
+
console.log(chalk9.dim(` \u2B1A ${file.name}`) + chalk9.dim(` \u2014 ${file.hint}`));
|
|
3016
2990
|
}
|
|
3017
2991
|
}
|
|
3018
2992
|
console.log("");
|
|
3019
|
-
console.log(
|
|
2993
|
+
console.log(chalk9.bold(` ${ko.doctor.driftTitle}`));
|
|
3020
2994
|
const ruleDrift = checkRuleDrift(cwd);
|
|
3021
2995
|
if (!ruleDrift.checked) {
|
|
3022
|
-
console.log(
|
|
2996
|
+
console.log(chalk9.dim(` ${ko.doctor.driftNoRules}`));
|
|
3023
2997
|
} else {
|
|
3024
2998
|
const drifted = ruleDrift.results.filter((r) => r.status === "drifted");
|
|
3025
2999
|
if (drifted.length === 0) {
|
|
3026
|
-
console.log(
|
|
3000
|
+
console.log(chalk9.green(` ${ko.doctor.driftRuleClean}`));
|
|
3027
3001
|
} else {
|
|
3028
|
-
console.log(
|
|
3002
|
+
console.log(chalk9.yellow(` ${ko.doctor.driftRuleWarn(drifted.map((d) => d.path).join(", "))}`));
|
|
3029
3003
|
}
|
|
3030
3004
|
}
|
|
3031
3005
|
const ctxDrift = checkContextDrift(cwd);
|
|
3032
3006
|
if (ctxDrift.checked && ctxDrift.stale) {
|
|
3033
|
-
console.log(
|
|
3007
|
+
console.log(chalk9.yellow(` ${ko.doctor.driftContextWarn}`));
|
|
3034
3008
|
}
|
|
3035
3009
|
console.log("");
|
|
3036
3010
|
if (allOk) {
|
|
3037
|
-
console.log(
|
|
3011
|
+
console.log(chalk9.green.bold(` ${ko.doctor.allOk}`));
|
|
3038
3012
|
printNextStep({
|
|
3039
3013
|
message: ko.doctor.nextOkMessage,
|
|
3040
3014
|
command: "vhk \uC2DC\uC791",
|
|
3041
3015
|
cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9CC\uB4E4\uC5B4\uC918"
|
|
3042
3016
|
});
|
|
3043
3017
|
} else {
|
|
3044
|
-
console.log(
|
|
3018
|
+
console.log(chalk9.yellow.bold(` ${ko.doctor.missing} ${ko.doctor.missingHint}`));
|
|
3045
3019
|
printNextStep({
|
|
3046
3020
|
message: ko.doctor.nextRetryMessage,
|
|
3047
3021
|
command: "vhk doctor",
|
|
@@ -3052,7 +3026,7 @@ ${ko.doctor.title}
|
|
|
3052
3026
|
}
|
|
3053
3027
|
|
|
3054
3028
|
// src/commands/ship.ts
|
|
3055
|
-
import
|
|
3029
|
+
import chalk10 from "chalk";
|
|
3056
3030
|
import inquirer4 from "inquirer";
|
|
3057
3031
|
import fs9 from "fs";
|
|
3058
3032
|
import path10 from "path";
|
|
@@ -3092,29 +3066,30 @@ function updateChangelogUnreleased(cwd, version, date) {
|
|
|
3092
3066
|
}
|
|
3093
3067
|
async function ship() {
|
|
3094
3068
|
if (!ensureNotHardStopped("ship")) return;
|
|
3095
|
-
|
|
3069
|
+
if (!ensureInteractive("\uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8\xB7\uD68C\uACE0\uB294 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. PowerShell \uB4F1 TTY \uC5D0\uC11C \uC2E4\uD589\uD558\uC138\uC694.")) return;
|
|
3070
|
+
console.log(chalk10.bold(`
|
|
3096
3071
|
${ko.ship.title}
|
|
3097
3072
|
`));
|
|
3098
3073
|
const cwd = process.cwd();
|
|
3099
|
-
console.log(
|
|
3074
|
+
console.log(chalk10.cyan.bold(` ${ko.ship.checklist}
|
|
3100
3075
|
`));
|
|
3101
3076
|
const { passed } = await inquirer4.prompt([{
|
|
3102
3077
|
type: "checkbox",
|
|
3103
3078
|
name: "passed",
|
|
3104
3079
|
message: ko.ship.checkboxPrompt,
|
|
3105
3080
|
choices: CHECKLIST.map((c) => ({
|
|
3106
|
-
name: `${ko.ship[c.questionKey]} ${
|
|
3081
|
+
name: `${ko.ship[c.questionKey]} ${chalk10.dim(`(${ko.ship[c.hintKey]})`)}`,
|
|
3107
3082
|
value: c.id
|
|
3108
3083
|
}))
|
|
3109
3084
|
}]);
|
|
3110
3085
|
const allPassed = passed.length === CHECKLIST.length;
|
|
3111
3086
|
const skipped = CHECKLIST.filter((c) => !passed.includes(c.id));
|
|
3112
3087
|
if (!allPassed) {
|
|
3113
|
-
console.log(
|
|
3088
|
+
console.log(chalk10.yellow(`
|
|
3114
3089
|
${ko.ship.incompleteHeader}`));
|
|
3115
3090
|
skipped.forEach((s) => {
|
|
3116
|
-
console.log(
|
|
3117
|
-
console.log(
|
|
3091
|
+
console.log(chalk10.yellow(` \u2022 ${ko.ship[s.questionKey]}`));
|
|
3092
|
+
console.log(chalk10.dim(` \u2192 ${ko.ship[s.hintKey]}`));
|
|
3118
3093
|
});
|
|
3119
3094
|
const { proceed } = await inquirer4.prompt([{
|
|
3120
3095
|
type: "confirm",
|
|
@@ -3131,13 +3106,13 @@ ${ko.ship.title}
|
|
|
3131
3106
|
return;
|
|
3132
3107
|
}
|
|
3133
3108
|
} else {
|
|
3134
|
-
console.log(
|
|
3109
|
+
console.log(chalk10.green(`
|
|
3135
3110
|
${ko.ship.allPassed}
|
|
3136
3111
|
`));
|
|
3137
3112
|
}
|
|
3138
|
-
console.log(
|
|
3113
|
+
console.log(chalk10.cyan.bold(` ${ko.ship.retro}
|
|
3139
3114
|
`));
|
|
3140
|
-
console.log(
|
|
3115
|
+
console.log(chalk10.dim(` ${ko.ship.versionHint}`));
|
|
3141
3116
|
const retro = await inquirer4.prompt([
|
|
3142
3117
|
{ type: "input", name: "version", message: ko.ship.versionPrompt },
|
|
3143
3118
|
{ type: "input", name: "whatWentWell", message: ko.ship.questionWell },
|
|
@@ -3180,7 +3155,7 @@ ${ko.ship.title}
|
|
|
3180
3155
|
`*Generated by \`vhk ship\` at ${(/* @__PURE__ */ new Date()).toISOString()}*`
|
|
3181
3156
|
].join("\n");
|
|
3182
3157
|
fs9.writeFileSync(filePath, content, "utf-8");
|
|
3183
|
-
console.log(
|
|
3158
|
+
console.log(chalk10.green(`
|
|
3184
3159
|
${ko.ship.buildLogDone(path10.relative(cwd, filePath))}`));
|
|
3185
3160
|
const changelogResult = updateChangelogUnreleased(cwd, versionSlug, today);
|
|
3186
3161
|
if (changelogResult.status === "updated") {
|
|
@@ -3200,7 +3175,7 @@ ${ko.ship.title}
|
|
|
3200
3175
|
|
|
3201
3176
|
// src/commands/save.ts
|
|
3202
3177
|
import { execFileSync } from "child_process";
|
|
3203
|
-
import
|
|
3178
|
+
import chalk11 from "chalk";
|
|
3204
3179
|
import ora from "ora";
|
|
3205
3180
|
import inquirer5 from "inquirer";
|
|
3206
3181
|
|
|
@@ -3228,29 +3203,29 @@ function statusIcon(code) {
|
|
|
3228
3203
|
return "\u{1F4C4}";
|
|
3229
3204
|
}
|
|
3230
3205
|
async function save() {
|
|
3231
|
-
console.log(
|
|
3206
|
+
console.log(chalk11.bold(`
|
|
3232
3207
|
\u{1F4BE} ${t("save.title")}`));
|
|
3233
|
-
console.log(
|
|
3208
|
+
console.log(chalk11.gray("\u2500".repeat(40)));
|
|
3234
3209
|
let gitRoot;
|
|
3235
3210
|
try {
|
|
3236
3211
|
execFileSync("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
3237
3212
|
gitRoot = getGitRoot();
|
|
3238
3213
|
} catch {
|
|
3239
|
-
console.log(
|
|
3214
|
+
console.log(chalk11.red(`\u274C ${t("save.notGitRepo")}`));
|
|
3240
3215
|
return;
|
|
3241
3216
|
}
|
|
3242
|
-
console.log(
|
|
3217
|
+
console.log(chalk11.cyan(`
|
|
3243
3218
|
\u{1F512} ${t("save.securityWarnHeader")}`));
|
|
3244
3219
|
printSecurityWarnings(gitRoot);
|
|
3245
3220
|
const severe = filterSevereFindings(scanProjectForSecrets(gitRoot).findings);
|
|
3246
3221
|
if (severe.length > 0) {
|
|
3247
|
-
console.log(
|
|
3222
|
+
console.log(chalk11.red(`
|
|
3248
3223
|
\u26A0\uFE0F ${t("save.secretsFound", severe.length)}`));
|
|
3249
3224
|
severe.slice(0, 5).forEach((f) => {
|
|
3250
|
-
console.log(
|
|
3225
|
+
console.log(chalk11.dim(` ${f.file}:${f.line} \u2014 ${f.patternName}`));
|
|
3251
3226
|
});
|
|
3252
3227
|
if (severe.length > 5) {
|
|
3253
|
-
console.log(
|
|
3228
|
+
console.log(chalk11.dim(` ... \uC678 ${severe.length - 5}\uAC74 (vhk \uBCF4\uC548 scan)`));
|
|
3254
3229
|
}
|
|
3255
3230
|
const proceed = await promptOrDefault(
|
|
3256
3231
|
async () => (await inquirer5.prompt([{
|
|
@@ -3263,16 +3238,16 @@ async function save() {
|
|
|
3263
3238
|
// 비대화형 = 시크릿 커밋 안 함 (안전)
|
|
3264
3239
|
);
|
|
3265
3240
|
if (!proceed) {
|
|
3266
|
-
console.log(
|
|
3241
|
+
console.log(chalk11.gray(t("save.cancelled")));
|
|
3267
3242
|
return;
|
|
3268
3243
|
}
|
|
3269
3244
|
}
|
|
3270
3245
|
const lines = parsePorcelainLines(gitOut(["status", "--porcelain"], gitRoot));
|
|
3271
3246
|
if (lines.length === 0) {
|
|
3272
|
-
console.log(
|
|
3247
|
+
console.log(chalk11.yellow(`\u{1F4ED} ${t("save.noChanges")}`));
|
|
3273
3248
|
return;
|
|
3274
3249
|
}
|
|
3275
|
-
console.log(
|
|
3250
|
+
console.log(chalk11.cyan(`
|
|
3276
3251
|
\u{1F4CB} ${t("save.filesHeader", lines.length)}`));
|
|
3277
3252
|
lines.forEach((line) => {
|
|
3278
3253
|
const code = line.substring(0, 2);
|
|
@@ -3297,21 +3272,21 @@ async function save() {
|
|
|
3297
3272
|
spinner.text = t("save.pushing");
|
|
3298
3273
|
if (!hasGitRemote(gitRoot)) {
|
|
3299
3274
|
spinner.succeed(t("save.successLocal"));
|
|
3300
|
-
console.log(
|
|
3275
|
+
console.log(chalk11.yellow(` \u{1F4A1} ${t("save.noRemote")}`));
|
|
3301
3276
|
} else {
|
|
3302
3277
|
try {
|
|
3303
3278
|
gitRun(["push"], gitRoot);
|
|
3304
3279
|
spinner.succeed(t("save.successWithPush"));
|
|
3305
3280
|
} catch (pushErr) {
|
|
3306
3281
|
spinner.fail(t("save.pushFailed"));
|
|
3307
|
-
console.log(
|
|
3308
|
-
console.log(
|
|
3282
|
+
console.log(chalk11.red(getExecErrorMessage(pushErr)));
|
|
3283
|
+
console.log(chalk11.yellow(`
|
|
3309
3284
|
\u{1F4A1} ${t("save.commitOkPushFailed")}`));
|
|
3310
3285
|
process.exitCode = 1;
|
|
3311
3286
|
}
|
|
3312
3287
|
}
|
|
3313
3288
|
if (process.exitCode !== 1) {
|
|
3314
|
-
console.log(
|
|
3289
|
+
console.log(chalk11.green(`
|
|
3315
3290
|
\u2705 ${t("save.done", lines.length)}`));
|
|
3316
3291
|
printNextStep({
|
|
3317
3292
|
message: t("save.nextOkMessage"),
|
|
@@ -3319,7 +3294,7 @@ async function save() {
|
|
|
3319
3294
|
cursorHint: t("save.nextOkCursor")
|
|
3320
3295
|
});
|
|
3321
3296
|
} else {
|
|
3322
|
-
console.log(
|
|
3297
|
+
console.log(chalk11.green(`
|
|
3323
3298
|
\u2705 ${t("save.doneLocalOnly", lines.length)}`));
|
|
3324
3299
|
printNextStep({
|
|
3325
3300
|
message: t("save.nextPushFailMessage"),
|
|
@@ -3329,12 +3304,12 @@ async function save() {
|
|
|
3329
3304
|
}
|
|
3330
3305
|
} catch (err) {
|
|
3331
3306
|
spinner.fail(t("save.failed"));
|
|
3332
|
-
console.log(
|
|
3307
|
+
console.log(chalk11.red(getExecErrorMessage(err)));
|
|
3333
3308
|
if (didAdd) {
|
|
3334
3309
|
try {
|
|
3335
3310
|
const staged = gitOut(["diff", "--cached", "--stat"], gitRoot).trim();
|
|
3336
3311
|
if (staged) {
|
|
3337
|
-
console.log(
|
|
3312
|
+
console.log(chalk11.yellow(`
|
|
3338
3313
|
\u{1F4A1} ${t("save.stagedAfterFail")}`));
|
|
3339
3314
|
}
|
|
3340
3315
|
} catch {
|
|
@@ -3346,7 +3321,7 @@ async function save() {
|
|
|
3346
3321
|
|
|
3347
3322
|
// src/commands/undo.ts
|
|
3348
3323
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
3349
|
-
import
|
|
3324
|
+
import chalk12 from "chalk";
|
|
3350
3325
|
import inquirer6 from "inquirer";
|
|
3351
3326
|
function parseRecentCommits(logOutput) {
|
|
3352
3327
|
return logOutput.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
@@ -3370,30 +3345,30 @@ function isUndoRisky(undoCount, unpushedCount, hasRemote) {
|
|
|
3370
3345
|
return false;
|
|
3371
3346
|
}
|
|
3372
3347
|
async function undo() {
|
|
3373
|
-
console.log(
|
|
3348
|
+
console.log(chalk12.bold(`
|
|
3374
3349
|
\u23EA ${t("undo.title")}`));
|
|
3375
|
-
console.log(
|
|
3350
|
+
console.log(chalk12.gray("\u2500".repeat(40)));
|
|
3376
3351
|
let gitRoot;
|
|
3377
3352
|
try {
|
|
3378
3353
|
execFileSync2("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
3379
3354
|
gitRoot = getGitRoot();
|
|
3380
3355
|
} catch {
|
|
3381
|
-
console.log(
|
|
3356
|
+
console.log(chalk12.red(`\u274C ${t("undo.notGitRepo")}`));
|
|
3382
3357
|
return;
|
|
3383
3358
|
}
|
|
3384
3359
|
let logOutput;
|
|
3385
3360
|
try {
|
|
3386
3361
|
logOutput = gitOut(["log", "--oneline", "-5"], gitRoot).trim();
|
|
3387
3362
|
} catch {
|
|
3388
|
-
console.log(
|
|
3363
|
+
console.log(chalk12.yellow(`\u{1F4ED} ${t("undo.noCommits")}`));
|
|
3389
3364
|
return;
|
|
3390
3365
|
}
|
|
3391
3366
|
const commits = parseRecentCommits(logOutput);
|
|
3392
3367
|
if (commits.length === 0) {
|
|
3393
|
-
console.log(
|
|
3368
|
+
console.log(chalk12.yellow(`\u{1F4ED} ${t("undo.noCommits")}`));
|
|
3394
3369
|
return;
|
|
3395
3370
|
}
|
|
3396
|
-
console.log(
|
|
3371
|
+
console.log(chalk12.cyan(`
|
|
3397
3372
|
${t("undo.recentHeader")}`));
|
|
3398
3373
|
commits.forEach((c, i) => {
|
|
3399
3374
|
console.log(` ${i === 0 ? "\u{1F449}" : " "} ${c}`);
|
|
@@ -3410,7 +3385,7 @@ ${t("undo.recentHeader")}`));
|
|
|
3410
3385
|
const undoCount = Math.min(Math.max(1, count || 1), maxUndo);
|
|
3411
3386
|
const headCount = countLocalCommits(gitRoot);
|
|
3412
3387
|
if (undoCount >= headCount) {
|
|
3413
|
-
console.log(
|
|
3388
|
+
console.log(chalk12.yellow(`
|
|
3414
3389
|
\u{1F4ED} ${t("undo.rootCommit")}`));
|
|
3415
3390
|
return;
|
|
3416
3391
|
}
|
|
@@ -3419,10 +3394,10 @@ ${t("undo.recentHeader")}`));
|
|
|
3419
3394
|
const risky = isUndoRisky(undoCount, unpushed, remote);
|
|
3420
3395
|
if (risky) {
|
|
3421
3396
|
if (unpushed < 0) {
|
|
3422
|
-
console.log(
|
|
3397
|
+
console.log(chalk12.red(`
|
|
3423
3398
|
\u26A0\uFE0F ${t("undo.noUpstreamWarning")}`));
|
|
3424
3399
|
} else {
|
|
3425
|
-
console.log(
|
|
3400
|
+
console.log(chalk12.red(`
|
|
3426
3401
|
\u26A0\uFE0F ${t("undo.alreadyPushed")}`));
|
|
3427
3402
|
}
|
|
3428
3403
|
}
|
|
@@ -3433,16 +3408,16 @@ ${t("undo.recentHeader")}`));
|
|
|
3433
3408
|
default: false
|
|
3434
3409
|
}]);
|
|
3435
3410
|
if (!confirm) {
|
|
3436
|
-
console.log(
|
|
3411
|
+
console.log(chalk12.gray(t("undo.cancelled")));
|
|
3437
3412
|
return;
|
|
3438
3413
|
}
|
|
3439
3414
|
try {
|
|
3440
3415
|
gitRun(["reset", "--soft", `HEAD~${undoCount}`], gitRoot);
|
|
3441
|
-
console.log(
|
|
3416
|
+
console.log(chalk12.green(`
|
|
3442
3417
|
\u2705 ${t("undo.success")}`));
|
|
3443
|
-
console.log(
|
|
3418
|
+
console.log(chalk12.gray(` \u{1F4A1} ${t("undo.stagedHint")}`));
|
|
3444
3419
|
if (risky) {
|
|
3445
|
-
console.log(
|
|
3420
|
+
console.log(chalk12.yellow(`
|
|
3446
3421
|
\u{1F4A1} ${t("undo.forcePushHint")}`));
|
|
3447
3422
|
}
|
|
3448
3423
|
printNextStep({
|
|
@@ -3451,35 +3426,35 @@ ${t("undo.recentHeader")}`));
|
|
|
3451
3426
|
cursorHint: t("undo.nextCursor")
|
|
3452
3427
|
});
|
|
3453
3428
|
} catch (err) {
|
|
3454
|
-
console.log(
|
|
3429
|
+
console.log(chalk12.red(`\u274C ${t("undo.failed")}`));
|
|
3455
3430
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3456
|
-
console.log(
|
|
3431
|
+
console.log(chalk12.red(msg));
|
|
3457
3432
|
process.exitCode = 1;
|
|
3458
3433
|
}
|
|
3459
3434
|
}
|
|
3460
3435
|
|
|
3461
3436
|
// src/commands/restore.ts
|
|
3462
|
-
import
|
|
3437
|
+
import chalk13 from "chalk";
|
|
3463
3438
|
import inquirer7 from "inquirer";
|
|
3464
3439
|
async function restore(id) {
|
|
3465
|
-
console.log(
|
|
3440
|
+
console.log(chalk13.bold(`
|
|
3466
3441
|
${ko.restore.title}`));
|
|
3467
|
-
console.log(
|
|
3468
|
-
console.log(
|
|
3442
|
+
console.log(chalk13.gray("\u2500".repeat(40)));
|
|
3443
|
+
console.log(chalk13.dim(` ${ko.restore.notGitNote}`));
|
|
3469
3444
|
const cwd = process.cwd();
|
|
3470
3445
|
const backups = listBackups(cwd);
|
|
3471
3446
|
if (backups.length === 0) {
|
|
3472
|
-
console.log(
|
|
3447
|
+
console.log(chalk13.yellow(`
|
|
3473
3448
|
${ko.restore.noBackups}`));
|
|
3474
3449
|
return;
|
|
3475
3450
|
}
|
|
3476
3451
|
let targetId = id;
|
|
3477
3452
|
if (!targetId) {
|
|
3478
3453
|
if (!process.stdout.isTTY) {
|
|
3479
|
-
console.log(
|
|
3454
|
+
console.log(chalk13.cyan(`
|
|
3480
3455
|
${ko.restore.listHeader}`));
|
|
3481
3456
|
for (const b of backups) console.log(` ${b.id} (${b.files.length}\uAC1C \uD30C\uC77C)`);
|
|
3482
|
-
console.log(
|
|
3457
|
+
console.log(chalk13.yellow(`
|
|
3483
3458
|
${ko.restore.nonTtyHint}`));
|
|
3484
3459
|
return;
|
|
3485
3460
|
}
|
|
@@ -3498,16 +3473,16 @@ ${ko.restore.nonTtyHint}`));
|
|
|
3498
3473
|
}
|
|
3499
3474
|
try {
|
|
3500
3475
|
const restored = restoreBackup(targetId, cwd);
|
|
3501
|
-
console.log(
|
|
3476
|
+
console.log(chalk13.green(`
|
|
3502
3477
|
${ko.restore.restored(restored.length, targetId)}`));
|
|
3503
|
-
for (const r of restored) console.log(
|
|
3478
|
+
for (const r of restored) console.log(chalk13.gray(` ${r}`));
|
|
3504
3479
|
printNextStep({
|
|
3505
3480
|
message: "\uBC31\uC5C5 \uBCF5\uC6D0 \uC644\uB8CC! \uBCC0\uACBD \uB0B4\uC6A9\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
3506
3481
|
command: "vhk diff",
|
|
3507
3482
|
cursorHint: "\uBCC0\uACBD\uC0AC\uD56D \uBCF4\uC5EC\uC918"
|
|
3508
3483
|
});
|
|
3509
3484
|
} catch {
|
|
3510
|
-
console.log(
|
|
3485
|
+
console.log(chalk13.red(`
|
|
3511
3486
|
${ko.restore.notFound(targetId)}`));
|
|
3512
3487
|
process.exitCode = 1;
|
|
3513
3488
|
}
|
|
@@ -3517,7 +3492,7 @@ ${ko.restore.notFound(targetId)}`));
|
|
|
3517
3492
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3518
3493
|
import fs10 from "fs";
|
|
3519
3494
|
import path11 from "path";
|
|
3520
|
-
import
|
|
3495
|
+
import chalk14 from "chalk";
|
|
3521
3496
|
function countFileChanges(porcelain) {
|
|
3522
3497
|
const lines = porcelain.split("\n").filter(Boolean);
|
|
3523
3498
|
let staged = 0;
|
|
@@ -3592,15 +3567,15 @@ function getSyncCounts(gitRoot) {
|
|
|
3592
3567
|
}
|
|
3593
3568
|
}
|
|
3594
3569
|
async function status() {
|
|
3595
|
-
console.log(
|
|
3570
|
+
console.log(chalk14.bold(`
|
|
3596
3571
|
\u{1F4CA} ${t("status.title")}`));
|
|
3597
|
-
console.log(
|
|
3572
|
+
console.log(chalk14.gray("\u2500".repeat(40)));
|
|
3598
3573
|
let gitRoot;
|
|
3599
3574
|
try {
|
|
3600
3575
|
execFileSync3("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
3601
3576
|
gitRoot = getGitRoot();
|
|
3602
3577
|
} catch {
|
|
3603
|
-
console.log(
|
|
3578
|
+
console.log(chalk14.red(`\u274C ${t("status.notGitRepo")}`));
|
|
3604
3579
|
return;
|
|
3605
3580
|
}
|
|
3606
3581
|
let branch;
|
|
@@ -3619,29 +3594,29 @@ async function status() {
|
|
|
3619
3594
|
commits = [];
|
|
3620
3595
|
}
|
|
3621
3596
|
const pkg = readProjectPackage();
|
|
3622
|
-
console.log(
|
|
3623
|
-
\u{1F33F} ${t("status.branch")}`) +
|
|
3597
|
+
console.log(chalk14.cyan(`
|
|
3598
|
+
\u{1F33F} ${t("status.branch")}`) + chalk14.white(` ${branch}`));
|
|
3624
3599
|
console.log(
|
|
3625
|
-
|
|
3600
|
+
chalk14.cyan(`\u{1F4C1} ${t("status.changes")}`) + chalk14.white(
|
|
3626
3601
|
` staged ${counts.staged} \xB7 unstaged ${counts.unstaged} \xB7 untracked ${counts.untracked}`
|
|
3627
3602
|
)
|
|
3628
3603
|
);
|
|
3629
|
-
console.log(
|
|
3604
|
+
console.log(chalk14.cyan(`
|
|
3630
3605
|
\u{1F4CB} ${t("status.recentCommits", commits.length)}`));
|
|
3631
3606
|
if (commits.length === 0) {
|
|
3632
|
-
console.log(
|
|
3607
|
+
console.log(chalk14.dim(` ${t("status.noCommits")}`));
|
|
3633
3608
|
} else {
|
|
3634
|
-
commits.forEach((c) => console.log(` ${
|
|
3609
|
+
commits.forEach((c) => console.log(` ${chalk14.dim("\u2022")} ${c}`));
|
|
3635
3610
|
}
|
|
3636
3611
|
console.log(
|
|
3637
|
-
|
|
3638
|
-
\u{1F504} ${t("status.remote")}`) +
|
|
3612
|
+
chalk14.cyan(`
|
|
3613
|
+
\u{1F504} ${t("status.remote")}`) + chalk14.white(` ${formatSyncLabel(sync2)}`)
|
|
3639
3614
|
);
|
|
3640
|
-
console.log(
|
|
3615
|
+
console.log(chalk14.gray("\n" + "\u2500".repeat(40)));
|
|
3641
3616
|
if (pkg) {
|
|
3642
|
-
console.log(
|
|
3617
|
+
console.log(chalk14.cyan(`\u{1F4E6} ${t("status.package")}`) + chalk14.white(` ${pkg.name} v${pkg.version}`));
|
|
3643
3618
|
} else {
|
|
3644
|
-
console.log(
|
|
3619
|
+
console.log(chalk14.dim(`\u{1F4E6} ${t("status.noPackage")}`));
|
|
3645
3620
|
}
|
|
3646
3621
|
const hasChanges = counts.staged + counts.unstaged + counts.untracked > 0;
|
|
3647
3622
|
printNextStep(selectStatusNextStep(hasChanges));
|
|
@@ -3649,7 +3624,7 @@ async function status() {
|
|
|
3649
3624
|
}
|
|
3650
3625
|
|
|
3651
3626
|
// src/commands/diff.ts
|
|
3652
|
-
import
|
|
3627
|
+
import chalk15 from "chalk";
|
|
3653
3628
|
function gitOut2(args) {
|
|
3654
3629
|
const r = safeExecFile("git", args);
|
|
3655
3630
|
return r.ok ? r.out : "";
|
|
@@ -3686,51 +3661,51 @@ function summarizeNumstat(numstat) {
|
|
|
3686
3661
|
return { fileCount, totalAdd, totalDel };
|
|
3687
3662
|
}
|
|
3688
3663
|
function printFile(f) {
|
|
3689
|
-
const adds = f.additions > 0 ?
|
|
3690
|
-
const dels = f.deletions > 0 ?
|
|
3664
|
+
const adds = f.additions > 0 ? chalk15.green(`+${f.additions}`) : "";
|
|
3665
|
+
const dels = f.deletions > 0 ? chalk15.red(`-${f.deletions}`) : "";
|
|
3691
3666
|
const change = [adds, dels].filter(Boolean).join(" ");
|
|
3692
3667
|
console.log(` ${f.name} ${change}`);
|
|
3693
3668
|
}
|
|
3694
3669
|
async function diff() {
|
|
3695
|
-
console.log(
|
|
3670
|
+
console.log(chalk15.bold(`
|
|
3696
3671
|
\u{1F50D} ${t("diff.title")}`));
|
|
3697
|
-
console.log(
|
|
3672
|
+
console.log(chalk15.gray("\u2500".repeat(40)));
|
|
3698
3673
|
if (!safeExecFile("git", ["rev-parse", "--is-inside-work-tree"]).ok) {
|
|
3699
|
-
console.log(
|
|
3674
|
+
console.log(chalk15.red(`\u274C ${t("diff.notGitRepo")}`));
|
|
3700
3675
|
return;
|
|
3701
3676
|
}
|
|
3702
3677
|
const unstaged = gitOut2(["diff", "--stat"]);
|
|
3703
3678
|
const staged = gitOut2(["diff", "--cached", "--stat"]);
|
|
3704
3679
|
const untracked = gitOut2(["ls-files", "--others", "--exclude-standard"]);
|
|
3705
3680
|
if (!unstaged && !staged && !untracked) {
|
|
3706
|
-
console.log(
|
|
3681
|
+
console.log(chalk15.green(`
|
|
3707
3682
|
\u2705 ${t("diff.noChanges")}`));
|
|
3708
3683
|
return;
|
|
3709
3684
|
}
|
|
3710
3685
|
if (staged) {
|
|
3711
|
-
console.log(
|
|
3686
|
+
console.log(chalk15.cyan(`
|
|
3712
3687
|
${t("diff.stagedHeader")}`));
|
|
3713
3688
|
parseDiffStat(staged).forEach((f) => printFile(f));
|
|
3714
3689
|
}
|
|
3715
3690
|
if (unstaged) {
|
|
3716
|
-
console.log(
|
|
3691
|
+
console.log(chalk15.cyan(`
|
|
3717
3692
|
${t("diff.unstagedHeader")}`));
|
|
3718
3693
|
parseDiffStat(unstaged).forEach((f) => printFile(f));
|
|
3719
3694
|
}
|
|
3720
3695
|
if (untracked) {
|
|
3721
3696
|
const files = untracked.split("\n").filter(Boolean);
|
|
3722
|
-
console.log(
|
|
3697
|
+
console.log(chalk15.cyan(`
|
|
3723
3698
|
${t("diff.untrackedHeader", files.length)}`));
|
|
3724
|
-
files.forEach((f) => console.log(` ${
|
|
3699
|
+
files.forEach((f) => console.log(` ${chalk15.green("+")} ${f}`));
|
|
3725
3700
|
}
|
|
3726
3701
|
const numstat = gitOut2(["diff", "--numstat", "HEAD"]);
|
|
3727
3702
|
if (numstat) {
|
|
3728
3703
|
const { fileCount, totalAdd, totalDel } = summarizeNumstat(numstat);
|
|
3729
|
-
console.log(
|
|
3704
|
+
console.log(chalk15.cyan(`
|
|
3730
3705
|
${t("diff.summaryHeader")}`));
|
|
3731
3706
|
console.log(` ${t("diff.filesLine", fileCount)}`);
|
|
3732
|
-
console.log(` \uCD94\uAC00: ${
|
|
3733
|
-
console.log(` \uC0AD\uC81C: ${
|
|
3707
|
+
console.log(` \uCD94\uAC00: ${chalk15.green(`+${totalAdd}`)}\uC904`);
|
|
3708
|
+
console.log(` \uC0AD\uC81C: ${chalk15.red(`-${totalDel}`)}\uC904`);
|
|
3734
3709
|
}
|
|
3735
3710
|
console.log("");
|
|
3736
3711
|
}
|
|
@@ -3739,7 +3714,7 @@ ${t("diff.summaryHeader")}`));
|
|
|
3739
3714
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
3740
3715
|
import { join as join5, dirname } from "path";
|
|
3741
3716
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3742
|
-
import
|
|
3717
|
+
import chalk16 from "chalk";
|
|
3743
3718
|
function resolveMcpEntryPoint() {
|
|
3744
3719
|
try {
|
|
3745
3720
|
const here = fileURLToPath2(import.meta.url);
|
|
@@ -3779,8 +3754,8 @@ function resolveVhkMcpEntry() {
|
|
|
3779
3754
|
return { command: "vhk-mcp", args: [] };
|
|
3780
3755
|
}
|
|
3781
3756
|
async function mcpInit() {
|
|
3782
|
-
console.log(
|
|
3783
|
-
console.log(
|
|
3757
|
+
console.log(chalk16.bold("\n\u{1F50C} " + t("mcp.initTitle")));
|
|
3758
|
+
console.log(chalk16.gray("\u2500".repeat(40)));
|
|
3784
3759
|
const cursorDir = join5(process.cwd(), ".cursor");
|
|
3785
3760
|
if (!existsSync4(cursorDir)) {
|
|
3786
3761
|
mkdirSync3(cursorDir, { recursive: true });
|
|
@@ -3795,15 +3770,15 @@ async function mcpInit() {
|
|
|
3795
3770
|
mcpServers: { ...parsed.mcpServers ?? {}, vhk: vhkEntry }
|
|
3796
3771
|
};
|
|
3797
3772
|
} catch {
|
|
3798
|
-
console.log(
|
|
3773
|
+
console.log(chalk16.yellow("\u26A0\uFE0F \uAE30\uC874 .cursor/mcp.json \uD30C\uC2F1 \uC2E4\uD328 \u2014 \uC0C8 \uD30C\uC77C\uB85C \uB36E\uC5B4\uC501\uB2C8\uB2E4."));
|
|
3799
3774
|
config = { mcpServers: { vhk: vhkEntry } };
|
|
3800
3775
|
}
|
|
3801
3776
|
} else {
|
|
3802
3777
|
config = { mcpServers: { vhk: vhkEntry } };
|
|
3803
3778
|
}
|
|
3804
3779
|
writeFileSync3(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3805
|
-
console.log(
|
|
3806
|
-
console.log(
|
|
3780
|
+
console.log(chalk16.green("\n\u2705 Cursor MCP \uC124\uC815 \uC644\uB8CC!"));
|
|
3781
|
+
console.log(chalk16.cyan("\u{1F4C1} \uC0DD\uC131\uB41C \uD30C\uC77C:"));
|
|
3807
3782
|
console.log(` ${configPath}`);
|
|
3808
3783
|
printNextStep({
|
|
3809
3784
|
message: t("mcp.nextMessage"),
|
|
@@ -3814,7 +3789,7 @@ async function mcpInit() {
|
|
|
3814
3789
|
|
|
3815
3790
|
// src/commands/design.ts
|
|
3816
3791
|
import { existsSync as existsSync5, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
3817
|
-
import
|
|
3792
|
+
import chalk17 from "chalk";
|
|
3818
3793
|
import inquirer8 from "inquirer";
|
|
3819
3794
|
var PALETTES = [
|
|
3820
3795
|
{
|
|
@@ -3917,8 +3892,8 @@ export default vhkColors
|
|
|
3917
3892
|
`;
|
|
3918
3893
|
}
|
|
3919
3894
|
async function design() {
|
|
3920
|
-
console.log(
|
|
3921
|
-
console.log(
|
|
3895
|
+
console.log(chalk17.bold("\n\u{1F3A8} " + t("design.title")));
|
|
3896
|
+
console.log(chalk17.gray("\u2500".repeat(40)));
|
|
3922
3897
|
if (!ensureInteractive("\uCEEC\uB7EC \uD314\uB808\uD2B8 \uC120\uD0DD\uC740 \uB300\uD654\uD615\uC73C\uB85C\uB9CC \uAC00\uB2A5\uD569\uB2C8\uB2E4.")) return;
|
|
3923
3898
|
const { paletteIndex } = await inquirer8.prompt([
|
|
3924
3899
|
{
|
|
@@ -3932,7 +3907,7 @@ async function design() {
|
|
|
3932
3907
|
}
|
|
3933
3908
|
]);
|
|
3934
3909
|
const palette = PALETTES[paletteIndex];
|
|
3935
|
-
console.log(
|
|
3910
|
+
console.log(chalk17.cyan(`
|
|
3936
3911
|
\u{1F3A8} \uC120\uD0DD\uB41C \uD314\uB808\uD2B8: ${palette.name}`));
|
|
3937
3912
|
const v4 = hasTailwindV4();
|
|
3938
3913
|
const targetPath = v4 ? "src/styles/theme.css" : hasTailwind() ? "src/styles/vhk-colors.ts" : "src/styles/tokens.css";
|
|
@@ -3945,24 +3920,24 @@ async function design() {
|
|
|
3945
3920
|
default: false
|
|
3946
3921
|
}]);
|
|
3947
3922
|
if (!overwrite) {
|
|
3948
|
-
console.log(
|
|
3923
|
+
console.log(chalk17.yellow("\n\u23ED\uFE0F \uC0DD\uC131 \uCDE8\uC18C \u2014 \uAE30\uC874 \uD30C\uC77C \uC720\uC9C0."));
|
|
3949
3924
|
return;
|
|
3950
3925
|
}
|
|
3951
3926
|
}
|
|
3952
3927
|
mkdirSync4("src/styles", { recursive: true });
|
|
3953
3928
|
writeFileSync4(targetPath, content, "utf-8");
|
|
3954
3929
|
if (v4) {
|
|
3955
|
-
console.log(
|
|
3956
|
-
console.log(
|
|
3957
|
-
console.log(
|
|
3930
|
+
console.log(chalk17.green("\n\u2705 src/styles/theme.css \uC0DD\uC131 (Tailwind v4 @theme)"));
|
|
3931
|
+
console.log(chalk17.gray(' \uC9C4\uC785 CSS(\uC608: src/index.css)\uC5D0 `@import "./styles/theme.css";` \uCD94\uAC00 \u2192 bg-primary \uB4F1 \uC720\uD2F8 \uC0AC\uC6A9.'));
|
|
3932
|
+
console.log(chalk17.gray(" \uB2E4\uD06C \uD1A0\uAE00: \uB8E8\uD2B8 <html>/<body> \uC5D0 `.dark` \uD074\uB798\uC2A4 on/off."));
|
|
3958
3933
|
} else if (hasTailwind()) {
|
|
3959
|
-
console.log(
|
|
3960
|
-
console.log(
|
|
3934
|
+
console.log(chalk17.green("\n\u2705 src/styles/vhk-colors.ts \uC0DD\uC131"));
|
|
3935
|
+
console.log(chalk17.gray(" tailwind.config\uC758 extend.colors\uC5D0 import \uD574\uC11C \uC0AC\uC6A9\uD558\uC138\uC694."));
|
|
3961
3936
|
} else {
|
|
3962
|
-
console.log(
|
|
3963
|
-
console.log(
|
|
3937
|
+
console.log(chalk17.green("\n\u2705 src/styles/tokens.css \uC0DD\uC131"));
|
|
3938
|
+
console.log(chalk17.gray(" HTML\uC5D0 <link>\uB85C \uCD94\uAC00\uD558\uAC70\uB098 CSS\uC5D0\uC11C @import \uD558\uC138\uC694."));
|
|
3964
3939
|
}
|
|
3965
|
-
console.log(
|
|
3940
|
+
console.log(chalk17.bold("\n\u{1F308} \uCEEC\uB7EC \uBBF8\uB9AC\uBCF4\uAE30:"));
|
|
3966
3941
|
for (const [key, value] of Object.entries(palette.colors)) {
|
|
3967
3942
|
console.log(` ${key.padEnd(12)} ${value}`);
|
|
3968
3943
|
}
|
|
@@ -3978,7 +3953,7 @@ async function designPalette() {
|
|
|
3978
3953
|
|
|
3979
3954
|
// src/commands/theme.ts
|
|
3980
3955
|
import { existsSync as existsSync6, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
3981
|
-
import
|
|
3956
|
+
import chalk18 from "chalk";
|
|
3982
3957
|
import inquirer9 from "inquirer";
|
|
3983
3958
|
function generateDarkCSS() {
|
|
3984
3959
|
return `/* vhk theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS \uBCC0\uC218 */
|
|
@@ -4034,36 +4009,39 @@ export function initTheme(): void {
|
|
|
4034
4009
|
}
|
|
4035
4010
|
`;
|
|
4036
4011
|
}
|
|
4037
|
-
async function theme() {
|
|
4038
|
-
console.log(
|
|
4039
|
-
console.log(
|
|
4012
|
+
async function theme(options) {
|
|
4013
|
+
console.log(chalk18.bold("\n\u{1F319} " + t("theme.title")));
|
|
4014
|
+
console.log(chalk18.gray("\u2500".repeat(40)));
|
|
4040
4015
|
const cssPath = "src/styles/theme.css";
|
|
4041
4016
|
const togglePath = "src/lib/theme-toggle.ts";
|
|
4042
4017
|
const conflicts = [cssPath, togglePath].filter((p) => existsSync6(p));
|
|
4043
4018
|
if (conflicts.length > 0) {
|
|
4044
|
-
const
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4019
|
+
const overwrite = options?.yes === true ? true : await promptOrDefault(
|
|
4020
|
+
async () => (await inquirer9.prompt([{
|
|
4021
|
+
type: "confirm",
|
|
4022
|
+
name: "overwrite",
|
|
4023
|
+
message: `\uB2E4\uC74C \uD30C\uC77C\uC774 \uC774\uBBF8 \uC788\uC5B4\uC694. \uB36E\uC5B4\uC4F8\uAE4C\uC694?
|
|
4048
4024
|
${conflicts.join("\n ")}`,
|
|
4049
|
-
|
|
4050
|
-
|
|
4025
|
+
default: false
|
|
4026
|
+
}])).overwrite,
|
|
4027
|
+
false
|
|
4028
|
+
);
|
|
4051
4029
|
if (!overwrite) {
|
|
4052
|
-
console.log(
|
|
4030
|
+
console.log(chalk18.yellow("\n\u23ED\uFE0F \uC0DD\uC131 \uCDE8\uC18C \u2014 \uAE30\uC874 \uD30C\uC77C \uC720\uC9C0. (\uBE44\uB300\uD654\uD615\uC774\uBA74 --yes \uB85C \uB36E\uC5B4\uC4F0\uAE30)"));
|
|
4053
4031
|
return;
|
|
4054
4032
|
}
|
|
4055
4033
|
}
|
|
4056
4034
|
mkdirSync5("src/styles", { recursive: true });
|
|
4057
4035
|
mkdirSync5("src/lib", { recursive: true });
|
|
4058
4036
|
writeFileSync5(cssPath, generateDarkCSS(), "utf-8");
|
|
4059
|
-
console.log(
|
|
4037
|
+
console.log(chalk18.green("\n\u2705 src/styles/theme.css \uC0DD\uC131 (\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC)"));
|
|
4060
4038
|
writeFileSync5(togglePath, generateToggleUtil(), "utf-8");
|
|
4061
|
-
console.log(
|
|
4062
|
-
console.log(
|
|
4063
|
-
console.log(
|
|
4064
|
-
console.log(
|
|
4065
|
-
console.log(
|
|
4066
|
-
console.log(
|
|
4039
|
+
console.log(chalk18.green("\u2705 src/lib/theme-toggle.ts \uC0DD\uC131 (\uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0)"));
|
|
4040
|
+
console.log(chalk18.bold("\n\u{1F4D6} \uC0AC\uC6A9\uBC95:"));
|
|
4041
|
+
console.log(chalk18.gray(" 1. theme.css\uB97C \uAE00\uB85C\uBC8C \uC2A4\uD0C0\uC77C\uC5D0 \uCD94\uAC00"));
|
|
4042
|
+
console.log(chalk18.gray(' 2. import { initTheme, toggleTheme } from "./lib/theme-toggle"'));
|
|
4043
|
+
console.log(chalk18.gray(" 3. \uC571 \uC9C4\uC785\uC810\uC5D0\uC11C initTheme() \uD638\uCD9C"));
|
|
4044
|
+
console.log(chalk18.gray(" 4. \uD1A0\uAE00 \uBC84\uD2BC\uC5D0\uC11C toggleTheme() \uD638\uCD9C"));
|
|
4067
4045
|
printNextStep({
|
|
4068
4046
|
message: "\uD14C\uB9C8 \uC124\uC815 \uC644\uB8CC!",
|
|
4069
4047
|
command: "vhk ref list",
|
|
@@ -4073,7 +4051,7 @@ async function theme() {
|
|
|
4073
4051
|
|
|
4074
4052
|
// src/commands/ref.ts
|
|
4075
4053
|
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
4076
|
-
import
|
|
4054
|
+
import chalk19 from "chalk";
|
|
4077
4055
|
var REFS_PATH = ".vhk/refs.json";
|
|
4078
4056
|
function loadRefs() {
|
|
4079
4057
|
if (!existsSync7(REFS_PATH)) return [];
|
|
@@ -4089,24 +4067,24 @@ function saveRefs(refs) {
|
|
|
4089
4067
|
writeFileSync6(REFS_PATH, JSON.stringify(refs, null, 2) + "\n", "utf-8");
|
|
4090
4068
|
}
|
|
4091
4069
|
async function refAdd(url, memo = "") {
|
|
4092
|
-
console.log(
|
|
4093
|
-
console.log(
|
|
4070
|
+
console.log(chalk19.bold("\n\u{1F517} " + t("ref.addTitle")));
|
|
4071
|
+
console.log(chalk19.gray("\u2500".repeat(40)));
|
|
4094
4072
|
if (!url) {
|
|
4095
|
-
console.log(
|
|
4096
|
-
console.log(
|
|
4073
|
+
console.log(chalk19.red("\u274C URL\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694."));
|
|
4074
|
+
console.log(chalk19.gray(' \uC608: vhk ref add https://example.com --memo "\uCC38\uACE0 \uC0AC\uC774\uD2B8"'));
|
|
4097
4075
|
return;
|
|
4098
4076
|
}
|
|
4099
4077
|
const refs = loadRefs();
|
|
4100
4078
|
if (refs.some((r) => r.url === url)) {
|
|
4101
|
-
console.log(
|
|
4079
|
+
console.log(chalk19.yellow("\u26A0\uFE0F \uC774\uBBF8 \uC800\uC7A5\uB41C URL\uC785\uB2C8\uB2E4."));
|
|
4102
4080
|
return;
|
|
4103
4081
|
}
|
|
4104
4082
|
refs.push({ url, memo, addedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
4105
4083
|
saveRefs(refs);
|
|
4106
|
-
console.log(
|
|
4084
|
+
console.log(chalk19.green(`
|
|
4107
4085
|
\u2705 \uB808\uD37C\uB7F0\uC2A4 \uCD94\uAC00\uB428 (#${refs.length})`));
|
|
4108
|
-
console.log(
|
|
4109
|
-
if (memo) console.log(
|
|
4086
|
+
console.log(chalk19.cyan(` ${url}`));
|
|
4087
|
+
if (memo) console.log(chalk19.gray(` \u{1F4DD} ${memo}`));
|
|
4110
4088
|
printNextStep({
|
|
4111
4089
|
message: "\uB808\uD37C\uB7F0\uC2A4 \uC800\uC7A5 \uC644\uB8CC!",
|
|
4112
4090
|
command: "vhk ref list",
|
|
@@ -4114,22 +4092,22 @@ async function refAdd(url, memo = "") {
|
|
|
4114
4092
|
});
|
|
4115
4093
|
}
|
|
4116
4094
|
async function refList() {
|
|
4117
|
-
console.log(
|
|
4118
|
-
console.log(
|
|
4095
|
+
console.log(chalk19.bold("\n\u{1F4DA} " + t("ref.listTitle")));
|
|
4096
|
+
console.log(chalk19.gray("\u2500".repeat(40)));
|
|
4119
4097
|
const refs = loadRefs();
|
|
4120
4098
|
if (refs.length === 0) {
|
|
4121
|
-
console.log(
|
|
4122
|
-
console.log(
|
|
4099
|
+
console.log(chalk19.yellow("\n\u{1F4ED} \uC800\uC7A5\uB41C \uB808\uD37C\uB7F0\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
4100
|
+
console.log(chalk19.gray(' vhk ref add <url> --memo "\uBA54\uBAA8"\uB85C \uCD94\uAC00\uD558\uC138\uC694.'));
|
|
4123
4101
|
return;
|
|
4124
4102
|
}
|
|
4125
|
-
console.log(
|
|
4103
|
+
console.log(chalk19.cyan(`
|
|
4126
4104
|
\uCD1D ${refs.length}\uAC1C\uC758 \uB808\uD37C\uB7F0\uC2A4:
|
|
4127
4105
|
`));
|
|
4128
4106
|
refs.forEach((ref, index) => {
|
|
4129
4107
|
const date = new Date(ref.addedAt).toLocaleDateString("ko-KR");
|
|
4130
|
-
console.log(
|
|
4131
|
-
if (ref.memo) console.log(
|
|
4132
|
-
console.log(
|
|
4108
|
+
console.log(chalk19.white(` [${index + 1}] ${ref.url}`));
|
|
4109
|
+
if (ref.memo) console.log(chalk19.gray(` \u{1F4DD} ${ref.memo}`));
|
|
4110
|
+
console.log(chalk19.gray(` \u{1F4C5} ${date}`));
|
|
4133
4111
|
console.log("");
|
|
4134
4112
|
});
|
|
4135
4113
|
}
|
|
@@ -4137,7 +4115,7 @@ async function refOpen(indexStr) {
|
|
|
4137
4115
|
const refs = loadRefs();
|
|
4138
4116
|
const idx = parseInt(indexStr, 10) - 1;
|
|
4139
4117
|
if (Number.isNaN(idx) || idx < 0 || idx >= refs.length) {
|
|
4140
|
-
console.log(
|
|
4118
|
+
console.log(chalk19.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBC88\uD638\uC785\uB2C8\uB2E4. (1~${refs.length || 0})`));
|
|
4141
4119
|
return;
|
|
4142
4120
|
}
|
|
4143
4121
|
const ref = refs[idx];
|
|
@@ -4145,14 +4123,14 @@ async function refOpen(indexStr) {
|
|
|
4145
4123
|
try {
|
|
4146
4124
|
parsed = new URL(ref.url);
|
|
4147
4125
|
} catch {
|
|
4148
|
-
console.log(
|
|
4126
|
+
console.log(chalk19.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 URL: ${ref.url}`));
|
|
4149
4127
|
return;
|
|
4150
4128
|
}
|
|
4151
4129
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
4152
|
-
console.log(
|
|
4130
|
+
console.log(chalk19.red(`\u274C http(s) URL\uB9CC \uC5F4 \uC218 \uC788\uC2B5\uB2C8\uB2E4 (${parsed.protocol})`));
|
|
4153
4131
|
return;
|
|
4154
4132
|
}
|
|
4155
|
-
console.log(
|
|
4133
|
+
console.log(chalk19.cyan(`
|
|
4156
4134
|
\u{1F310} \uC5F4\uAE30: ${ref.url}`));
|
|
4157
4135
|
let result;
|
|
4158
4136
|
if (process.platform === "darwin") {
|
|
@@ -4163,15 +4141,15 @@ async function refOpen(indexStr) {
|
|
|
4163
4141
|
result = safeExecFile("xdg-open", [ref.url]);
|
|
4164
4142
|
}
|
|
4165
4143
|
if (result.ok) {
|
|
4166
|
-
console.log(
|
|
4144
|
+
console.log(chalk19.green("\u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
|
|
4167
4145
|
} else {
|
|
4168
|
-
console.log(
|
|
4146
|
+
console.log(chalk19.yellow("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. URL\uC744 \uC9C1\uC811 \uBC29\uBB38\uD574\uC8FC\uC138\uC694."));
|
|
4169
4147
|
}
|
|
4170
4148
|
}
|
|
4171
4149
|
|
|
4172
4150
|
// src/commands/harness.ts
|
|
4173
4151
|
import { existsSync as existsSync8 } from "fs";
|
|
4174
|
-
import
|
|
4152
|
+
import chalk20 from "chalk";
|
|
4175
4153
|
import ora2 from "ora";
|
|
4176
4154
|
function detectPM() {
|
|
4177
4155
|
if (existsSync8("pnpm-lock.yaml")) return "pnpm";
|
|
@@ -4213,15 +4191,15 @@ function detectChecks() {
|
|
|
4213
4191
|
}
|
|
4214
4192
|
async function harness() {
|
|
4215
4193
|
if (!ensureNotHardStopped("harness")) return;
|
|
4216
|
-
console.log(
|
|
4217
|
-
console.log(
|
|
4194
|
+
console.log(chalk20.bold("\n\u{1F527} " + t("harness.title")));
|
|
4195
|
+
console.log(chalk20.gray("\u2500".repeat(40)));
|
|
4218
4196
|
const checks = detectChecks();
|
|
4219
4197
|
if (checks.length === 0) {
|
|
4220
|
-
console.log(
|
|
4221
|
-
console.log(
|
|
4198
|
+
console.log(chalk20.yellow("\n\u26A0\uFE0F \uC2E4\uD589\uD560 \uC218 \uC788\uB294 \uC2A4\uD06C\uB9BD\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
4199
|
+
console.log(chalk20.gray(" package.json\uC5D0 lint, test, build \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uCD94\uAC00\uD574\uC8FC\uC138\uC694."));
|
|
4222
4200
|
return;
|
|
4223
4201
|
}
|
|
4224
|
-
console.log(
|
|
4202
|
+
console.log(chalk20.cyan(`
|
|
4225
4203
|
\u{1F3C3} ${checks.length}\uAC1C \uC810\uAC80 \uC2DC\uC791:
|
|
4226
4204
|
`));
|
|
4227
4205
|
const results = [];
|
|
@@ -4233,10 +4211,10 @@ async function harness() {
|
|
|
4233
4211
|
const duration = Date.now() - start2;
|
|
4234
4212
|
const sec = (duration / 1e3).toFixed(1);
|
|
4235
4213
|
if (result.ok) {
|
|
4236
|
-
spinner.succeed(`${check2.name} ${
|
|
4214
|
+
spinner.succeed(`${check2.name} ${chalk20.gray(`(${sec}s)`)}`);
|
|
4237
4215
|
results.push({ name: check2.name, command: display, passed: true, duration });
|
|
4238
4216
|
} else {
|
|
4239
|
-
spinner.fail(`${check2.name} ${
|
|
4217
|
+
spinner.fail(`${check2.name} ${chalk20.gray(`(${sec}s)`)}`);
|
|
4240
4218
|
results.push({
|
|
4241
4219
|
name: check2.name,
|
|
4242
4220
|
command: display,
|
|
@@ -4246,22 +4224,22 @@ async function harness() {
|
|
|
4246
4224
|
});
|
|
4247
4225
|
}
|
|
4248
4226
|
}
|
|
4249
|
-
console.log(
|
|
4250
|
-
console.log(
|
|
4227
|
+
console.log(chalk20.bold("\n\u{1F4CA} \uD1B5\uD569 \uB9AC\uD3EC\uD2B8:"));
|
|
4228
|
+
console.log(chalk20.gray("\u2500".repeat(40)));
|
|
4251
4229
|
for (const r of results) {
|
|
4252
|
-
const icon = r.passed ?
|
|
4230
|
+
const icon = r.passed ? chalk20.green("\u2705") : chalk20.red("\u274C");
|
|
4253
4231
|
const sec = (r.duration / 1e3).toFixed(1);
|
|
4254
|
-
console.log(` ${icon} ${r.name.padEnd(15)} ${
|
|
4232
|
+
console.log(` ${icon} ${r.name.padEnd(15)} ${chalk20.gray(`${sec}s`)}`);
|
|
4255
4233
|
}
|
|
4256
4234
|
const passed = results.filter((r) => r.passed).length;
|
|
4257
4235
|
const all = passed === results.length;
|
|
4258
|
-
console.log(
|
|
4236
|
+
console.log(chalk20.gray("\u2500".repeat(40)));
|
|
4259
4237
|
if (all) {
|
|
4260
|
-
console.log(
|
|
4238
|
+
console.log(chalk20.green.bold(`
|
|
4261
4239
|
\u{1F389} \uC804\uCCB4 \uD1B5\uACFC! (${passed}/${results.length})`));
|
|
4262
4240
|
} else {
|
|
4263
4241
|
console.log(
|
|
4264
|
-
|
|
4242
|
+
chalk20.red.bold(`
|
|
4265
4243
|
\u26A0\uFE0F ${results.length - passed}\uAC1C \uC2E4\uD328 (${passed}/${results.length} \uD1B5\uACFC)`)
|
|
4266
4244
|
);
|
|
4267
4245
|
process.exitCode = 1;
|
|
@@ -4275,7 +4253,7 @@ async function harness() {
|
|
|
4275
4253
|
|
|
4276
4254
|
// src/commands/migrate.ts
|
|
4277
4255
|
import { existsSync as existsSync9, unlinkSync, rmSync as rmSync2 } from "fs";
|
|
4278
|
-
import
|
|
4256
|
+
import chalk21 from "chalk";
|
|
4279
4257
|
import inquirer10 from "inquirer";
|
|
4280
4258
|
import ora3 from "ora";
|
|
4281
4259
|
var LOCK_FILES = {
|
|
@@ -4293,10 +4271,10 @@ function isCLIAvailable(pm) {
|
|
|
4293
4271
|
return safeExecFile(pm, ["--version"]).ok;
|
|
4294
4272
|
}
|
|
4295
4273
|
async function migrate(target) {
|
|
4296
|
-
console.log(
|
|
4297
|
-
console.log(
|
|
4274
|
+
console.log(chalk21.bold("\n\u{1F504} " + t("migrate.title")));
|
|
4275
|
+
console.log(chalk21.gray("\u2500".repeat(40)));
|
|
4298
4276
|
const current = detectCurrentPM();
|
|
4299
|
-
console.log(
|
|
4277
|
+
console.log(chalk21.cyan(`
|
|
4300
4278
|
\uD604\uC7AC \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800: ${current ?? "\uAC10\uC9C0 \uBD88\uAC00"}`));
|
|
4301
4279
|
let targetPM;
|
|
4302
4280
|
if (target && ["npm", "yarn", "pnpm"].includes(target)) {
|
|
@@ -4314,14 +4292,14 @@ async function migrate(target) {
|
|
|
4314
4292
|
targetPM = selected;
|
|
4315
4293
|
}
|
|
4316
4294
|
if (targetPM === current) {
|
|
4317
|
-
console.log(
|
|
4295
|
+
console.log(chalk21.yellow(`
|
|
4318
4296
|
\u26A0\uFE0F \uC774\uBBF8 ${targetPM}\uC744 \uC0AC\uC6A9 \uC911\uC785\uB2C8\uB2E4.`));
|
|
4319
4297
|
return;
|
|
4320
4298
|
}
|
|
4321
4299
|
if (!isCLIAvailable(targetPM)) {
|
|
4322
|
-
console.log(
|
|
4300
|
+
console.log(chalk21.red(`
|
|
4323
4301
|
\u274C ${targetPM}\uC774 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.`));
|
|
4324
|
-
console.log(
|
|
4302
|
+
console.log(chalk21.yellow(` npm i -g ${targetPM}`));
|
|
4325
4303
|
return;
|
|
4326
4304
|
}
|
|
4327
4305
|
const { confirm } = await inquirer10.prompt([
|
|
@@ -4333,7 +4311,7 @@ async function migrate(target) {
|
|
|
4333
4311
|
}
|
|
4334
4312
|
]);
|
|
4335
4313
|
if (!confirm) {
|
|
4336
|
-
console.log(
|
|
4314
|
+
console.log(chalk21.gray("\uCDE8\uC18C\uB428"));
|
|
4337
4315
|
return;
|
|
4338
4316
|
}
|
|
4339
4317
|
const cleanup = ora3("\uAE30\uC874 lock \uD30C\uC77C \uC815\uB9AC \uC911...").start();
|
|
@@ -4353,10 +4331,10 @@ async function migrate(target) {
|
|
|
4353
4331
|
install.succeed(`${targetPM} install \uC644\uB8CC!`);
|
|
4354
4332
|
} else {
|
|
4355
4333
|
install.fail(`${targetPM} install \uC2E4\uD328`);
|
|
4356
|
-
console.log(
|
|
4334
|
+
console.log(chalk21.red(installResult.err.slice(0, 300)));
|
|
4357
4335
|
return;
|
|
4358
4336
|
}
|
|
4359
|
-
console.log(
|
|
4337
|
+
console.log(chalk21.green.bold(`
|
|
4360
4338
|
\u{1F389} ${current ?? "\uC774\uC804"} \u2192 ${targetPM} \uC804\uD658 \uC644\uB8CC!`));
|
|
4361
4339
|
printNextStep({
|
|
4362
4340
|
message: "\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uC804\uD658 \uC644\uB8CC!",
|
|
@@ -4369,7 +4347,7 @@ async function migrate(target) {
|
|
|
4369
4347
|
import { existsSync as existsSync10 } from "fs";
|
|
4370
4348
|
import { dirname as dirname2, join as join6 } from "path";
|
|
4371
4349
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4372
|
-
import
|
|
4350
|
+
import chalk22 from "chalk";
|
|
4373
4351
|
import ora4 from "ora";
|
|
4374
4352
|
var PACKAGE = "@byh3071/vhk";
|
|
4375
4353
|
function getCurrentVersion() {
|
|
@@ -4399,32 +4377,32 @@ function isUpToDate(current, latest) {
|
|
|
4399
4377
|
return cc >= lc;
|
|
4400
4378
|
}
|
|
4401
4379
|
async function update() {
|
|
4402
|
-
console.log(
|
|
4403
|
-
console.log(
|
|
4380
|
+
console.log(chalk22.bold("\n\u2B06\uFE0F " + t("update.title")));
|
|
4381
|
+
console.log(chalk22.gray("\u2500".repeat(40)));
|
|
4404
4382
|
const current = getCurrentVersion();
|
|
4405
|
-
console.log(
|
|
4383
|
+
console.log(chalk22.cyan(`
|
|
4406
4384
|
\u{1F4CC} \uD604\uC7AC \uBC84\uC804: v${current}`));
|
|
4407
4385
|
const spinner = ora4("\uCD5C\uC2E0 \uBC84\uC804 \uD655\uC778 \uC911...").start();
|
|
4408
4386
|
const latest = getLatestVersion();
|
|
4409
4387
|
if (!latest) {
|
|
4410
4388
|
spinner.fail("\uCD5C\uC2E0 \uBC84\uC804\uC744 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
4411
|
-
console.log(
|
|
4412
|
-
console.log(
|
|
4389
|
+
console.log(chalk22.yellow(" \uB124\uD2B8\uC6CC\uD06C\uB97C \uD655\uC778\uD558\uAC70\uB098 \uC218\uB3D9\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694:"));
|
|
4390
|
+
console.log(chalk22.gray(` npm update -g ${PACKAGE}`));
|
|
4413
4391
|
return;
|
|
4414
4392
|
}
|
|
4415
4393
|
spinner.stop();
|
|
4416
|
-
console.log(
|
|
4394
|
+
console.log(chalk22.cyan(`\u{1F195} \uCD5C\uC2E0 \uBC84\uC804: v${latest}`));
|
|
4417
4395
|
if (isUpToDate(current, latest)) {
|
|
4418
|
-
console.log(
|
|
4396
|
+
console.log(chalk22.green("\n\u2705 \uC774\uBBF8 \uCD5C\uC2E0 \uBC84\uC804\uC785\uB2C8\uB2E4!"));
|
|
4419
4397
|
return;
|
|
4420
4398
|
}
|
|
4421
4399
|
const updateSpinner = ora4(`v${latest}\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8 \uC911...`).start();
|
|
4422
4400
|
const upd = safeExecFile("npm", ["update", "-g", PACKAGE]);
|
|
4423
4401
|
if (upd.ok) {
|
|
4424
4402
|
updateSpinner.succeed(`v${latest}\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!`);
|
|
4425
|
-
console.log(
|
|
4403
|
+
console.log(chalk22.green.bold(`
|
|
4426
4404
|
\u{1F389} VHK CLI v${latest} \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!`));
|
|
4427
|
-
console.log(
|
|
4405
|
+
console.log(chalk22.gray(" \uBCC0\uACBD \uC0AC\uD56D\uC740 GitHub Releases\uB97C \uD655\uC778\uD558\uC138\uC694."));
|
|
4428
4406
|
printNextStep({
|
|
4429
4407
|
message: t("update.nextOkMessage"),
|
|
4430
4408
|
command: "vhk --version",
|
|
@@ -4432,9 +4410,9 @@ async function update() {
|
|
|
4432
4410
|
});
|
|
4433
4411
|
} else {
|
|
4434
4412
|
updateSpinner.fail("\uC5C5\uB370\uC774\uD2B8 \uC2E4\uD328");
|
|
4435
|
-
console.log(
|
|
4436
|
-
console.log(
|
|
4437
|
-
console.log(
|
|
4413
|
+
console.log(chalk22.red(upd.err.slice(0, 300)));
|
|
4414
|
+
console.log(chalk22.yellow("\n\uC218\uB3D9\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694:"));
|
|
4415
|
+
console.log(chalk22.gray(` npm update -g ${PACKAGE}`));
|
|
4438
4416
|
printNextStep({
|
|
4439
4417
|
message: t("update.nextFailMessage"),
|
|
4440
4418
|
command: "vhk doctor",
|
|
@@ -4453,7 +4431,7 @@ import {
|
|
|
4453
4431
|
writeFileSync as writeFileSync7
|
|
4454
4432
|
} from "fs";
|
|
4455
4433
|
import { join as join7 } from "path";
|
|
4456
|
-
import
|
|
4434
|
+
import chalk23 from "chalk";
|
|
4457
4435
|
var CONTEXT_PATH = ".vhk/context.md";
|
|
4458
4436
|
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
4459
4437
|
"node_modules",
|
|
@@ -4554,8 +4532,8 @@ function getVhkCommands() {
|
|
|
4554
4532
|
}
|
|
4555
4533
|
async function context(opts = {}) {
|
|
4556
4534
|
const compact = opts.compact === true;
|
|
4557
|
-
console.log(
|
|
4558
|
-
console.log(
|
|
4535
|
+
console.log(chalk23.bold("\n\u{1F9E0} " + t("context.title")));
|
|
4536
|
+
console.log(chalk23.gray("\u2500".repeat(40)));
|
|
4559
4537
|
const stack = extractTechStack();
|
|
4560
4538
|
const tree = buildTree(".", "", compact ? 2 : 3).join("\n");
|
|
4561
4539
|
const commands = getVhkCommands();
|
|
@@ -4670,10 +4648,10 @@ async function context(opts = {}) {
|
|
|
4670
4648
|
lines.push("");
|
|
4671
4649
|
mkdirSync7(".vhk", { recursive: true });
|
|
4672
4650
|
writeFileSync7(CONTEXT_PATH, lines.join("\n"), "utf-8");
|
|
4673
|
-
console.log(
|
|
4651
|
+
console.log(chalk23.green(`
|
|
4674
4652
|
\u2705 ${CONTEXT_PATH} \uC0DD\uC131 \uC644\uB8CC!`));
|
|
4675
|
-
console.log(
|
|
4676
|
-
console.log(
|
|
4653
|
+
console.log(chalk23.gray(` \uAE30\uC220 \uC2A4\uD0DD ${Object.keys(stack).length}\uAC1C \uAC10\uC9C0`));
|
|
4654
|
+
console.log(chalk23.gray(" AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC5D0\uAC8C \uC774 \uD30C\uC77C\uC744 \uCC38\uC870\uD558\uAC8C \uD558\uC138\uC694."));
|
|
4677
4655
|
printNextStep({
|
|
4678
4656
|
message: "\uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC!",
|
|
4679
4657
|
command: "vhk context-show",
|
|
@@ -4681,11 +4659,11 @@ async function context(opts = {}) {
|
|
|
4681
4659
|
});
|
|
4682
4660
|
}
|
|
4683
4661
|
async function contextShow() {
|
|
4684
|
-
console.log(
|
|
4685
|
-
console.log(
|
|
4662
|
+
console.log(chalk23.bold("\n\u{1F4C4} " + t("context.showTitle")));
|
|
4663
|
+
console.log(chalk23.gray("\u2500".repeat(40)));
|
|
4686
4664
|
if (!existsSync11(CONTEXT_PATH)) {
|
|
4687
|
-
console.log(
|
|
4688
|
-
console.log(
|
|
4665
|
+
console.log(chalk23.yellow("\n\u26A0\uFE0F \uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
4666
|
+
console.log(chalk23.gray(" vhk context\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
|
|
4689
4667
|
return;
|
|
4690
4668
|
}
|
|
4691
4669
|
const content = readFileSync4(CONTEXT_PATH, "utf-8");
|
|
@@ -4694,7 +4672,7 @@ async function contextShow() {
|
|
|
4694
4672
|
|
|
4695
4673
|
// src/commands/memory.ts
|
|
4696
4674
|
import { existsSync as existsSync12, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
4697
|
-
import
|
|
4675
|
+
import chalk24 from "chalk";
|
|
4698
4676
|
var MEMORY_PATH = ".vhk/memory.json";
|
|
4699
4677
|
function loadMemories() {
|
|
4700
4678
|
if (!existsSync12(MEMORY_PATH)) return [];
|
|
@@ -4710,11 +4688,11 @@ function saveMemories(memories) {
|
|
|
4710
4688
|
writeFileSync8(MEMORY_PATH, JSON.stringify(memories, null, 2) + "\n", "utf-8");
|
|
4711
4689
|
}
|
|
4712
4690
|
async function memoryAdd(content, tags) {
|
|
4713
|
-
console.log(
|
|
4714
|
-
console.log(
|
|
4691
|
+
console.log(chalk24.bold("\n\u{1F9E0} " + t("memory.addTitle")));
|
|
4692
|
+
console.log(chalk24.gray("\u2500".repeat(40)));
|
|
4715
4693
|
if (!content) {
|
|
4716
|
-
console.log(
|
|
4717
|
-
console.log(
|
|
4694
|
+
console.log(chalk24.red("\u274C \uAE30\uC5B5\uD560 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694."));
|
|
4695
|
+
console.log(chalk24.gray(' \uC608: vhk memory add "API\uB294 tRPC \uC0AC\uC6A9\uD558\uAE30\uB85C \uACB0\uC815"'));
|
|
4718
4696
|
process.exitCode = 1;
|
|
4719
4697
|
return;
|
|
4720
4698
|
}
|
|
@@ -4725,9 +4703,9 @@ async function memoryAdd(content, tags) {
|
|
|
4725
4703
|
tags: tags && tags.length > 0 ? tags : []
|
|
4726
4704
|
});
|
|
4727
4705
|
saveMemories(memories);
|
|
4728
|
-
console.log(
|
|
4706
|
+
console.log(chalk24.green(`
|
|
4729
4707
|
\u2705 \uAE30\uC5B5 \uC800\uC7A5\uB428 (#${memories.length})`));
|
|
4730
|
-
console.log(
|
|
4708
|
+
console.log(chalk24.cyan(` \u{1F4DD} ${content}`));
|
|
4731
4709
|
printNextStep({
|
|
4732
4710
|
message: "\uAE30\uC5B5 \uC800\uC7A5 \uC644\uB8CC!",
|
|
4733
4711
|
command: "vhk memory list",
|
|
@@ -4735,24 +4713,24 @@ async function memoryAdd(content, tags) {
|
|
|
4735
4713
|
});
|
|
4736
4714
|
}
|
|
4737
4715
|
async function memoryList() {
|
|
4738
|
-
console.log(
|
|
4739
|
-
console.log(
|
|
4716
|
+
console.log(chalk24.bold("\n\u{1F9E0} " + t("memory.listTitle")));
|
|
4717
|
+
console.log(chalk24.gray("\u2500".repeat(40)));
|
|
4740
4718
|
const memories = loadMemories();
|
|
4741
4719
|
if (memories.length === 0) {
|
|
4742
|
-
console.log(
|
|
4743
|
-
console.log(
|
|
4720
|
+
console.log(chalk24.yellow("\n\u{1F4ED} \uC800\uC7A5\uB41C \uAE30\uC5B5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
4721
|
+
console.log(chalk24.gray(' vhk memory add "\uB0B4\uC6A9"\uC73C\uB85C \uCD94\uAC00\uD558\uC138\uC694.'));
|
|
4744
4722
|
return;
|
|
4745
4723
|
}
|
|
4746
|
-
console.log(
|
|
4724
|
+
console.log(chalk24.cyan(`
|
|
4747
4725
|
\uCD1D ${memories.length}\uAC1C\uC758 \uAE30\uC5B5:
|
|
4748
4726
|
`));
|
|
4749
4727
|
memories.forEach((m, index) => {
|
|
4750
4728
|
const date = new Date(m.addedAt).toLocaleDateString("ko-KR");
|
|
4751
|
-
console.log(
|
|
4729
|
+
console.log(chalk24.white(` [${index + 1}] ${m.content}`));
|
|
4752
4730
|
if (m.tags && m.tags.length > 0) {
|
|
4753
|
-
console.log(
|
|
4731
|
+
console.log(chalk24.blue(` \u{1F3F7}\uFE0F ${m.tags.join(", ")}`));
|
|
4754
4732
|
}
|
|
4755
|
-
console.log(
|
|
4733
|
+
console.log(chalk24.gray(` \u{1F4C5} ${date}`));
|
|
4756
4734
|
console.log("");
|
|
4757
4735
|
});
|
|
4758
4736
|
}
|
|
@@ -4760,18 +4738,18 @@ async function memoryRemove(indexStr) {
|
|
|
4760
4738
|
const memories = loadMemories();
|
|
4761
4739
|
const idx = parseInt(indexStr, 10) - 1;
|
|
4762
4740
|
if (Number.isNaN(idx) || idx < 0 || idx >= memories.length) {
|
|
4763
|
-
console.log(
|
|
4741
|
+
console.log(chalk24.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBC88\uD638\uC785\uB2C8\uB2E4. (1~${memories.length || 0})`));
|
|
4764
4742
|
return;
|
|
4765
4743
|
}
|
|
4766
4744
|
const removed = memories.splice(idx, 1)[0];
|
|
4767
4745
|
saveMemories(memories);
|
|
4768
|
-
console.log(
|
|
4769
|
-
console.log(
|
|
4746
|
+
console.log(chalk24.green("\n\u2705 \uAE30\uC5B5 \uC0AD\uC81C\uB428:"));
|
|
4747
|
+
console.log(chalk24.gray(` ${removed.content}`));
|
|
4770
4748
|
}
|
|
4771
4749
|
|
|
4772
4750
|
// src/commands/brief.ts
|
|
4773
4751
|
import { existsSync as existsSync13, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync5 } from "fs";
|
|
4774
|
-
import
|
|
4752
|
+
import chalk25 from "chalk";
|
|
4775
4753
|
var BRIEF_PATH = ".vhk/brief.md";
|
|
4776
4754
|
function readProjectIdentity() {
|
|
4777
4755
|
const out = {};
|
|
@@ -4796,8 +4774,8 @@ function git2(args) {
|
|
|
4796
4774
|
return result.ok ? result.out : "";
|
|
4797
4775
|
}
|
|
4798
4776
|
async function brief() {
|
|
4799
|
-
console.log(
|
|
4800
|
-
console.log(
|
|
4777
|
+
console.log(chalk25.bold("\n\u{1F4CB} " + t("brief.title")));
|
|
4778
|
+
console.log(chalk25.gray("\u2500".repeat(40)));
|
|
4801
4779
|
const lines = [];
|
|
4802
4780
|
lines.push("# \uD504\uB85C\uC81D\uD2B8 \uBE0C\uB9AC\uD551");
|
|
4803
4781
|
lines.push("");
|
|
@@ -4882,7 +4860,7 @@ async function brief() {
|
|
|
4882
4860
|
mkdirSync9(".vhk", { recursive: true });
|
|
4883
4861
|
writeFileSync9(BRIEF_PATH, lines.join("\n"), "utf-8");
|
|
4884
4862
|
console.log("\n" + lines.join("\n"));
|
|
4885
|
-
console.log(
|
|
4863
|
+
console.log(chalk25.green(`
|
|
4886
4864
|
\u2705 ${BRIEF_PATH} \uC800\uC7A5 \uC644\uB8CC`));
|
|
4887
4865
|
printNextStep({
|
|
4888
4866
|
message: "\uBE0C\uB9AC\uD551 \uC0DD\uC131 \uC644\uB8CC!",
|
|
@@ -4892,7 +4870,7 @@ async function brief() {
|
|
|
4892
4870
|
}
|
|
4893
4871
|
|
|
4894
4872
|
// src/commands/start.ts
|
|
4895
|
-
import
|
|
4873
|
+
import chalk26 from "chalk";
|
|
4896
4874
|
import inquirer11 from "inquirer";
|
|
4897
4875
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
4898
4876
|
import { existsSync as existsSync14 } from "fs";
|
|
@@ -4934,21 +4912,21 @@ async function runStep(label, fn) {
|
|
|
4934
4912
|
}
|
|
4935
4913
|
}
|
|
4936
4914
|
async function start(options = {}) {
|
|
4937
|
-
console.log(
|
|
4915
|
+
console.log(chalk26.bold(`
|
|
4938
4916
|
${ko.start.title}
|
|
4939
4917
|
`));
|
|
4940
|
-
console.log(
|
|
4941
|
-
console.log(
|
|
4942
|
-
console.log(
|
|
4943
|
-
console.log(
|
|
4944
|
-
console.log(
|
|
4918
|
+
console.log(chalk26.dim(ko.start.intro));
|
|
4919
|
+
console.log(chalk26.dim(` ${ko.start.step1}`));
|
|
4920
|
+
console.log(chalk26.dim(` ${ko.start.step2}`));
|
|
4921
|
+
console.log(chalk26.dim(` ${ko.start.step3}`));
|
|
4922
|
+
console.log(chalk26.dim(` ${ko.start.step4}`));
|
|
4945
4923
|
console.log();
|
|
4946
4924
|
const cwd = process.cwd();
|
|
4947
4925
|
const footprint = detectExistingFootprint(cwd);
|
|
4948
4926
|
if (footprint.length > 0 && !options.yes) {
|
|
4949
|
-
console.log(
|
|
4950
|
-
for (const f of footprint) console.log(
|
|
4951
|
-
console.log(
|
|
4927
|
+
console.log(chalk26.yellow("\u26A0\uFE0F \uC774\uBBF8 VHK \uC124\uCE58 \uD754\uC801\uC774 \uAC10\uC9C0\uB410\uC5B4\uC694:"));
|
|
4928
|
+
for (const f of footprint) console.log(chalk26.dim(` - ${f}`));
|
|
4929
|
+
console.log(chalk26.dim(" \uACC4\uC18D \uC9C4\uD589\uD558\uBA74 \uC77C\uBD80 \uD30C\uC77C(`.cursor/mcp.json`, `.vhk/context.md`)\uC740 \uAC31\uC2E0\xB7\uB36E\uC5B4\uC4F0\uAE30\uB429\uB2C8\uB2E4."));
|
|
4952
4930
|
const { proceedExisting } = await inquirer11.prompt([{
|
|
4953
4931
|
type: "confirm",
|
|
4954
4932
|
name: "proceedExisting",
|
|
@@ -4986,7 +4964,7 @@ ${ko.start.title}
|
|
|
4986
4964
|
await runStep("[3/4] vhk mcp-init", () => mcpInit());
|
|
4987
4965
|
log.step(ko.start.step4Header);
|
|
4988
4966
|
await runStep("[4/4] vhk context", () => context());
|
|
4989
|
-
console.log(
|
|
4967
|
+
console.log(chalk26.bold.green(`
|
|
4990
4968
|
${ko.start.allDone}
|
|
4991
4969
|
`));
|
|
4992
4970
|
printNextStep({
|
|
@@ -4999,7 +4977,7 @@ ${ko.start.allDone}
|
|
|
4999
4977
|
import fs12 from "fs";
|
|
5000
4978
|
import os from "os";
|
|
5001
4979
|
import path13 from "path";
|
|
5002
|
-
import
|
|
4980
|
+
import chalk27 from "chalk";
|
|
5003
4981
|
|
|
5004
4982
|
// src/lib/vhk-cloud.ts
|
|
5005
4983
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
@@ -5091,14 +5069,14 @@ ${CLOUD_CONFIG_FILE}
|
|
|
5091
5069
|
function ensureGhReady() {
|
|
5092
5070
|
const ver = safeExecFile("gh", ["--version"]);
|
|
5093
5071
|
if (!ver.ok) {
|
|
5094
|
-
console.log(
|
|
5095
|
-
console.log(
|
|
5072
|
+
console.log(chalk27.red(` ${ko.cloud.noGh}`));
|
|
5073
|
+
console.log(chalk27.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
|
|
5096
5074
|
return false;
|
|
5097
5075
|
}
|
|
5098
5076
|
const auth = safeExecFile("gh", ["auth", "status"]);
|
|
5099
5077
|
if (!auth.ok) {
|
|
5100
|
-
console.log(
|
|
5101
|
-
console.log(
|
|
5078
|
+
console.log(chalk27.red(` ${ko.cloud.noAuth}`));
|
|
5079
|
+
console.log(chalk27.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
|
|
5102
5080
|
return false;
|
|
5103
5081
|
}
|
|
5104
5082
|
return true;
|
|
@@ -5111,18 +5089,18 @@ function parseGistId(output) {
|
|
|
5111
5089
|
return null;
|
|
5112
5090
|
}
|
|
5113
5091
|
async function cloudPush() {
|
|
5114
|
-
console.log(
|
|
5092
|
+
console.log(chalk27.bold(`
|
|
5115
5093
|
${ko.cloud.pushTitle}
|
|
5116
5094
|
`));
|
|
5117
5095
|
const cwd = process.cwd();
|
|
5118
5096
|
if (!fs12.existsSync(path13.join(cwd, VHK_DIR2))) {
|
|
5119
|
-
console.log(
|
|
5097
|
+
console.log(chalk27.yellow(` ${ko.cloud.noVhkDir}`));
|
|
5120
5098
|
return;
|
|
5121
5099
|
}
|
|
5122
5100
|
const ig = loadVhkignore(cwd);
|
|
5123
5101
|
const files = collectVhkFiles(cwd, ig);
|
|
5124
5102
|
if (files.length === 0) {
|
|
5125
|
-
console.log(
|
|
5103
|
+
console.log(chalk27.yellow(` ${ko.cloud.nothingToSync}`));
|
|
5126
5104
|
return;
|
|
5127
5105
|
}
|
|
5128
5106
|
if (!ensureGhReady()) {
|
|
@@ -5130,7 +5108,7 @@ ${ko.cloud.pushTitle}
|
|
|
5130
5108
|
return;
|
|
5131
5109
|
}
|
|
5132
5110
|
const filePaths = files.map((f) => path13.join(cwd, VHK_DIR2, f));
|
|
5133
|
-
console.log(
|
|
5111
|
+
console.log(chalk27.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
|
|
5134
5112
|
`));
|
|
5135
5113
|
const existing = readCloudConfig(cwd);
|
|
5136
5114
|
const desc = `vhk .vhk backup \u2014 ${path13.basename(cwd)}`;
|
|
@@ -5142,8 +5120,8 @@ ${ko.cloud.pushTitle}
|
|
|
5142
5120
|
const args = gistFiles.includes(name) ? ["gist", "edit", existing.gistId, "-f", name, src] : ["gist", "edit", existing.gistId, "-a", src];
|
|
5143
5121
|
const res2 = safeExecFile("gh", args);
|
|
5144
5122
|
if (!res2.ok) {
|
|
5145
|
-
console.log(
|
|
5146
|
-
console.log(
|
|
5123
|
+
console.log(chalk27.red(` ${ko.cloud.pushFail}: ${name}`));
|
|
5124
|
+
console.log(chalk27.dim(` ${res2.err}`));
|
|
5147
5125
|
process.exitCode = 1;
|
|
5148
5126
|
return;
|
|
5149
5127
|
}
|
|
@@ -5158,15 +5136,15 @@ ${ko.cloud.pushTitle}
|
|
|
5158
5136
|
if (!purgeFailed.includes(name)) purgeFailed.push(name);
|
|
5159
5137
|
}
|
|
5160
5138
|
}
|
|
5161
|
-
console.log(
|
|
5162
|
-
console.log(
|
|
5139
|
+
console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
|
|
5140
|
+
console.log(chalk27.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
|
|
5163
5141
|
if (excluded.length > 0) {
|
|
5164
5142
|
const purged = excluded.filter((n) => !purgeFailed.includes(n));
|
|
5165
5143
|
if (purged.length > 0) {
|
|
5166
|
-
console.log(
|
|
5144
|
+
console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${purged.length}\uAC1C gist \uC5D0\uC11C \uC81C\uAC70: ${purged.join(", ")}`));
|
|
5167
5145
|
}
|
|
5168
5146
|
if (purgeFailed.length > 0) {
|
|
5169
|
-
console.log(
|
|
5147
|
+
console.log(chalk27.yellow(` \u26A0\uFE0F \uC81C\uC678 \uB300\uC0C1 \uC81C\uAC70 \uC2E4\uD328: ${purgeFailed.join(", ")} (\uC218\uB3D9 \uC81C\uAC70 \uAD8C\uC7A5 \u2014 pull \uC2DC\uC5D4 \uBCF5\uC6D0 \uC548 \uB428)`));
|
|
5170
5148
|
}
|
|
5171
5149
|
}
|
|
5172
5150
|
printPushNext();
|
|
@@ -5174,32 +5152,32 @@ ${ko.cloud.pushTitle}
|
|
|
5174
5152
|
}
|
|
5175
5153
|
const res = safeExecFile("gh", ["gist", "create", "--desc", desc, ...filePaths]);
|
|
5176
5154
|
if (!res.ok) {
|
|
5177
|
-
console.log(
|
|
5178
|
-
console.log(
|
|
5155
|
+
console.log(chalk27.red(` ${ko.cloud.pushFail}`));
|
|
5156
|
+
console.log(chalk27.dim(` ${res.err || res.out}`));
|
|
5179
5157
|
process.exitCode = 1;
|
|
5180
5158
|
return;
|
|
5181
5159
|
}
|
|
5182
5160
|
const gistId = parseGistId(res.out);
|
|
5183
5161
|
if (!gistId) {
|
|
5184
|
-
console.log(
|
|
5185
|
-
console.log(
|
|
5162
|
+
console.log(chalk27.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
|
|
5163
|
+
console.log(chalk27.dim(` \uCD9C\uB825: ${res.out}`));
|
|
5186
5164
|
process.exitCode = 1;
|
|
5187
5165
|
return;
|
|
5188
5166
|
}
|
|
5189
5167
|
writeCloudConfig(cwd, { gistId });
|
|
5190
|
-
console.log(
|
|
5191
|
-
console.log(
|
|
5168
|
+
console.log(chalk27.green.bold(` ${ko.cloud.pushDone}`));
|
|
5169
|
+
console.log(chalk27.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
|
|
5192
5170
|
printPushNext();
|
|
5193
5171
|
}
|
|
5194
5172
|
async function cloudPull(gistIdArg) {
|
|
5195
|
-
console.log(
|
|
5173
|
+
console.log(chalk27.bold(`
|
|
5196
5174
|
${ko.cloud.pullTitle}
|
|
5197
5175
|
`));
|
|
5198
5176
|
const cwd = process.cwd();
|
|
5199
5177
|
const gistId = gistIdArg || readCloudConfig(cwd)?.gistId;
|
|
5200
5178
|
if (!gistId) {
|
|
5201
|
-
console.log(
|
|
5202
|
-
console.log(
|
|
5179
|
+
console.log(chalk27.yellow(` ${ko.cloud.noGistId}`));
|
|
5180
|
+
console.log(chalk27.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
|
|
5203
5181
|
return;
|
|
5204
5182
|
}
|
|
5205
5183
|
if (!ensureGhReady()) {
|
|
@@ -5208,16 +5186,16 @@ ${ko.cloud.pullTitle}
|
|
|
5208
5186
|
}
|
|
5209
5187
|
const allNames = listGistFiles(gistId);
|
|
5210
5188
|
if (allNames.length === 0) {
|
|
5211
|
-
console.log(
|
|
5189
|
+
console.log(chalk27.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
|
|
5212
5190
|
process.exitCode = 1;
|
|
5213
5191
|
return;
|
|
5214
5192
|
}
|
|
5215
5193
|
const { keep: names, excluded: skipped } = partitionGistFiles(allNames, loadVhkignore(cwd));
|
|
5216
5194
|
if (skipped.length > 0) {
|
|
5217
|
-
console.log(
|
|
5195
|
+
console.log(chalk27.dim(` \u{1F512} \uC81C\uC678 \uB300\uC0C1 ${skipped.length}\uAC1C \uBCF5\uC6D0 \uC2A4\uD0B5: ${skipped.join(", ")}`));
|
|
5218
5196
|
}
|
|
5219
5197
|
if (names.length === 0) {
|
|
5220
|
-
console.log(
|
|
5198
|
+
console.log(chalk27.yellow(` \uBCF5\uC6D0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (gist \uD30C\uC77C\uC774 \uBAA8\uB450 \uC81C\uC678 \uADDC\uCE59\uC5D0 \uD574\uB2F9).`));
|
|
5221
5199
|
return;
|
|
5222
5200
|
}
|
|
5223
5201
|
const vhkDir = path13.join(cwd, VHK_DIR2);
|
|
@@ -5226,16 +5204,16 @@ ${ko.cloud.pullTitle}
|
|
|
5226
5204
|
for (const name of names) {
|
|
5227
5205
|
const res = safeExecFile("gh", ["gist", "view", gistId, "-f", name, "--raw"]);
|
|
5228
5206
|
if (!res.ok) {
|
|
5229
|
-
console.log(
|
|
5230
|
-
console.log(
|
|
5207
|
+
console.log(chalk27.red(` ${ko.cloud.pullFail}: ${name}`));
|
|
5208
|
+
console.log(chalk27.dim(` ${res.err}`));
|
|
5231
5209
|
continue;
|
|
5232
5210
|
}
|
|
5233
5211
|
fs12.writeFileSync(path13.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
|
|
5234
5212
|
restored++;
|
|
5235
5213
|
}
|
|
5236
5214
|
writeCloudConfig(cwd, { gistId });
|
|
5237
|
-
console.log(
|
|
5238
|
-
console.log(
|
|
5215
|
+
console.log(chalk27.green.bold(` ${ko.cloud.pullDone}`));
|
|
5216
|
+
console.log(chalk27.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
|
|
5239
5217
|
printNextStep({
|
|
5240
5218
|
message: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk/ \uBCF5\uC6D0 \uC644\uB8CC!",
|
|
5241
5219
|
command: "vhk \uB9E5\uB77D",
|
|
@@ -5283,7 +5261,7 @@ function printPushNext() {
|
|
|
5283
5261
|
}
|
|
5284
5262
|
|
|
5285
5263
|
// src/commands/help.ts
|
|
5286
|
-
import
|
|
5264
|
+
import chalk28 from "chalk";
|
|
5287
5265
|
var QUICK_ACTIONS = [
|
|
5288
5266
|
{ say: "\uC0C1\uD0DC \uC54C\uB824\uC918", does: "vhk status" },
|
|
5289
5267
|
{ say: "\uBB50 \uBC14\uB00C\uC5C8\uC5B4?", does: "vhk diff" },
|
|
@@ -5297,17 +5275,17 @@ var QUICK_ACTIONS = [
|
|
|
5297
5275
|
{ say: "\uC804\uCCB4 \uBA85\uB839\uC5B4 \uBCF4\uAE30", does: "vhk --help" }
|
|
5298
5276
|
];
|
|
5299
5277
|
function quickActions() {
|
|
5300
|
-
console.log(
|
|
5301
|
-
console.log(
|
|
5278
|
+
console.log(chalk28.bold("\n\u{1F9ED} VHK \u2014 \uC774\uB807\uAC8C \uB9D0\uD558\uBA74 \uB429\uB2C8\uB2E4 (quick actions)"));
|
|
5279
|
+
console.log(chalk28.gray("\u2500".repeat(40)));
|
|
5302
5280
|
for (const a of QUICK_ACTIONS) {
|
|
5303
|
-
console.log(` "${
|
|
5281
|
+
console.log(` "${chalk28.cyan(a.say)}" \u2192 ${chalk28.dim(a.does)}`);
|
|
5304
5282
|
}
|
|
5305
|
-
console.log(
|
|
5283
|
+
console.log(chalk28.gray("\n \uC804\uCCB4 \uBA85\uB839\uC740 `vhk --help` \uB610\uB294 COMMANDS.md \uB97C \uBCF4\uC138\uC694."));
|
|
5306
5284
|
console.log("");
|
|
5307
5285
|
}
|
|
5308
5286
|
|
|
5309
5287
|
// src/commands/mode.ts
|
|
5310
|
-
import
|
|
5288
|
+
import chalk29 from "chalk";
|
|
5311
5289
|
|
|
5312
5290
|
// src/lib/config.ts
|
|
5313
5291
|
import { existsSync as existsSync15, mkdirSync as mkdirSync10, writeFileSync as writeFileSync10 } from "fs";
|
|
@@ -5348,17 +5326,17 @@ function writeConfig(config, rootDir = process.cwd()) {
|
|
|
5348
5326
|
|
|
5349
5327
|
// src/commands/mode.ts
|
|
5350
5328
|
async function mode(target) {
|
|
5351
|
-
console.log(
|
|
5352
|
-
console.log(
|
|
5329
|
+
console.log(chalk29.bold("\n\u{1F6E1}\uFE0F Safety Mode"));
|
|
5330
|
+
console.log(chalk29.gray("\u2500".repeat(40)));
|
|
5353
5331
|
const current = readConfig().safetyMode;
|
|
5354
5332
|
if (!target) {
|
|
5355
|
-
console.log(
|
|
5356
|
-
\uD604\uC7AC \uBAA8\uB4DC: ${
|
|
5357
|
-
console.log(
|
|
5333
|
+
console.log(chalk29.cyan(`
|
|
5334
|
+
\uD604\uC7AC \uBAA8\uB4DC: ${chalk29.bold(current)}`));
|
|
5335
|
+
console.log(chalk29.dim(` ${SAFETY_MODE_DESC[current]}`));
|
|
5358
5336
|
console.log("");
|
|
5359
5337
|
for (const m of SAFETY_MODES) {
|
|
5360
5338
|
const mark = m === current ? "\u25CF" : "\u25CB";
|
|
5361
|
-
console.log(` ${mark} ${m.padEnd(9)} ${
|
|
5339
|
+
console.log(` ${mark} ${m.padEnd(9)} ${chalk29.dim(SAFETY_MODE_DESC[m])}`);
|
|
5362
5340
|
}
|
|
5363
5341
|
printNextStep({
|
|
5364
5342
|
message: "\uBAA8\uB4DC\uB97C \uBC14\uAFB8\uB824\uBA74:",
|
|
@@ -5368,20 +5346,20 @@ async function mode(target) {
|
|
|
5368
5346
|
return;
|
|
5369
5347
|
}
|
|
5370
5348
|
if (!isSafetyMode(target)) {
|
|
5371
|
-
console.log(
|
|
5349
|
+
console.log(chalk29.red(`
|
|
5372
5350
|
\u274C \uC54C \uC218 \uC5C6\uB294 \uBAA8\uB4DC: ${target}`));
|
|
5373
|
-
console.log(
|
|
5351
|
+
console.log(chalk29.dim(` \uAC00\uB2A5: ${SAFETY_MODES.join(" | ")}`));
|
|
5374
5352
|
process.exitCode = 1;
|
|
5375
5353
|
return;
|
|
5376
5354
|
}
|
|
5377
5355
|
writeConfig({ ...readConfig(), safetyMode: target });
|
|
5378
|
-
console.log(
|
|
5379
|
-
\u2705 Safety Mode \u2192 ${
|
|
5380
|
-
console.log(
|
|
5356
|
+
console.log(chalk29.green(`
|
|
5357
|
+
\u2705 Safety Mode \u2192 ${chalk29.bold(target)}`));
|
|
5358
|
+
console.log(chalk29.dim(` ${SAFETY_MODE_DESC[target]}`));
|
|
5381
5359
|
}
|
|
5382
5360
|
|
|
5383
5361
|
// src/commands/verify.ts
|
|
5384
|
-
import
|
|
5362
|
+
import chalk30 from "chalk";
|
|
5385
5363
|
function verificationChecklist() {
|
|
5386
5364
|
return [
|
|
5387
5365
|
"\uD0C0\uC785 \uCCB4\uD06C \u2014 pnpm exec tsc --noEmit",
|
|
@@ -5391,15 +5369,15 @@ function verificationChecklist() {
|
|
|
5391
5369
|
];
|
|
5392
5370
|
}
|
|
5393
5371
|
async function verify() {
|
|
5394
|
-
console.log(
|
|
5395
|
-
console.log(
|
|
5372
|
+
console.log(chalk30.bold("\n\u{1F50E} \uAC80\uC99D \uBB36\uC74C (verify \u2014 lite)"));
|
|
5373
|
+
console.log(chalk30.gray("\u2500".repeat(40)));
|
|
5396
5374
|
const mode2 = readConfig().safetyMode;
|
|
5397
|
-
console.log(
|
|
5398
|
-
console.log(
|
|
5375
|
+
console.log(chalk30.dim(` \uD604\uC7AC Safety Mode: ${mode2} \u2014 ${SAFETY_MODE_DESC[mode2]}`));
|
|
5376
|
+
console.log(chalk30.cyan("\n \uC704\uD5D8 \uC791\uC5C5/\uC800\uC7A5 \uC804 \uAD8C\uC7A5 \uAC80\uC99D:"));
|
|
5399
5377
|
for (const item of verificationChecklist()) {
|
|
5400
5378
|
console.log(` \u2610 ${item}`);
|
|
5401
5379
|
}
|
|
5402
|
-
console.log(
|
|
5380
|
+
console.log(chalk30.dim("\n \u203B \uBA54\uD0C0\uB7EC\uB108(\uC790\uB3D9 \uC2E4\uD589) \uC790\uB9AC \u2014 \uD604\uC7AC\uB294 \uBB36\uC74C \uC548\uB0B4\uB9CC(lite)."));
|
|
5403
5381
|
printNextStep({
|
|
5404
5382
|
message: "\uAC80\uC99D \uD1B5\uACFC \uD6C4 \uC800\uC7A5\uD558\uC138\uC694:",
|
|
5405
5383
|
command: "vhk save",
|
|
@@ -5585,14 +5563,14 @@ function requiresConfirmation(route) {
|
|
|
5585
5563
|
async function runNaturalLanguageRoute(input) {
|
|
5586
5564
|
const route = routeNaturalLanguage(input);
|
|
5587
5565
|
if (!route) {
|
|
5588
|
-
console.log(
|
|
5566
|
+
console.log(chalk31.yellow(`
|
|
5589
5567
|
\u2753 "${input}" \u2014 ${ko.nlp.notMatched}
|
|
5590
5568
|
`));
|
|
5591
5569
|
return;
|
|
5592
5570
|
}
|
|
5593
5571
|
console.log("");
|
|
5594
|
-
console.log(
|
|
5595
|
-
console.log(
|
|
5572
|
+
console.log(chalk31.cyan(` \u{1F4AC} "${input}"`));
|
|
5573
|
+
console.log(chalk31.cyan(` \u2192 ${route.explanation}`));
|
|
5596
5574
|
if (requiresConfirmation(route)) {
|
|
5597
5575
|
const { confirm } = await inquirer12.prompt([{
|
|
5598
5576
|
type: "confirm",
|
|
@@ -5601,7 +5579,7 @@ async function runNaturalLanguageRoute(input) {
|
|
|
5601
5579
|
default: true
|
|
5602
5580
|
}]);
|
|
5603
5581
|
if (!confirm) {
|
|
5604
|
-
console.log(
|
|
5582
|
+
console.log(chalk31.dim(` ${ko.nlp.menuHint}`));
|
|
5605
5583
|
return;
|
|
5606
5584
|
}
|
|
5607
5585
|
}
|
|
@@ -5610,7 +5588,7 @@ async function runNaturalLanguageRoute(input) {
|
|
|
5610
5588
|
if (riskAction) {
|
|
5611
5589
|
await runGuarded(
|
|
5612
5590
|
riskAction,
|
|
5613
|
-
{ channel: "nl", approved: false, log: (m) => console.log(
|
|
5591
|
+
{ channel: "nl", approved: false, log: (m) => console.log(chalk31.yellow(` ${m}`)) },
|
|
5614
5592
|
() => dispatchNlpRoute(route, input)
|
|
5615
5593
|
);
|
|
5616
5594
|
return;
|
|
@@ -5619,77 +5597,77 @@ async function runNaturalLanguageRoute(input) {
|
|
|
5619
5597
|
}
|
|
5620
5598
|
|
|
5621
5599
|
// src/commands/agent.ts
|
|
5622
|
-
import
|
|
5600
|
+
import chalk32 from "chalk";
|
|
5623
5601
|
function activeGoalId() {
|
|
5624
5602
|
const goals = listGoals("goals");
|
|
5625
5603
|
const id = selectActiveId(goals);
|
|
5626
5604
|
return id ?? void 0;
|
|
5627
5605
|
}
|
|
5628
5606
|
async function blocker(description) {
|
|
5629
|
-
console.log(
|
|
5607
|
+
console.log(chalk32.bold(`
|
|
5630
5608
|
${ko.agent.blockerTitle}
|
|
5631
5609
|
`));
|
|
5632
5610
|
if (!description || !description.trim()) {
|
|
5633
|
-
console.log(
|
|
5634
|
-
console.log(
|
|
5611
|
+
console.log(chalk32.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
5612
|
+
console.log(chalk32.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
|
|
5635
5613
|
process.exitCode = 1;
|
|
5636
5614
|
return;
|
|
5637
5615
|
}
|
|
5638
5616
|
const goalId = activeGoalId();
|
|
5639
5617
|
const r = appendBlocker(description, goalId);
|
|
5640
|
-
console.log(
|
|
5618
|
+
console.log(chalk32.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
|
|
5641
5619
|
if (r.hardStopTripped) {
|
|
5642
|
-
console.log(
|
|
5643
|
-
console.log(
|
|
5620
|
+
console.log(chalk32.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
|
|
5621
|
+
console.log(chalk32.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
|
|
5644
5622
|
process.exitCode = 2;
|
|
5645
5623
|
}
|
|
5646
5624
|
}
|
|
5647
5625
|
async function learn(lesson) {
|
|
5648
|
-
console.log(
|
|
5626
|
+
console.log(chalk32.bold(`
|
|
5649
5627
|
${ko.agent.learnTitle}
|
|
5650
5628
|
`));
|
|
5651
5629
|
if (!lesson || !lesson.trim()) {
|
|
5652
|
-
console.log(
|
|
5653
|
-
console.log(
|
|
5630
|
+
console.log(chalk32.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
5631
|
+
console.log(chalk32.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
|
|
5654
5632
|
process.exitCode = 1;
|
|
5655
5633
|
return;
|
|
5656
5634
|
}
|
|
5657
5635
|
const goalId = activeGoalId();
|
|
5658
5636
|
appendLearning(lesson, goalId);
|
|
5659
|
-
console.log(
|
|
5637
|
+
console.log(chalk32.green(" \u2705 learnings.md append."));
|
|
5660
5638
|
console.log(
|
|
5661
|
-
|
|
5639
|
+
chalk32.dim(" \uACB0\uC815\uC0AC\uD56D(decision)\uC740 `vhk memory add` \uB85C \uBCC4\uB3C4 \uAE30\uB85D \u2014 SoT \uBD84\uB9AC.")
|
|
5662
5640
|
);
|
|
5663
5641
|
}
|
|
5664
5642
|
async function resume(opts = {}) {
|
|
5665
|
-
console.log(
|
|
5643
|
+
console.log(chalk32.bold(`
|
|
5666
5644
|
${ko.agent.resumeTitle}
|
|
5667
5645
|
`));
|
|
5668
5646
|
if (!isHardStopActive()) {
|
|
5669
|
-
console.log(
|
|
5647
|
+
console.log(chalk32.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
|
|
5670
5648
|
return;
|
|
5671
5649
|
}
|
|
5672
5650
|
const reason = readHardStopReason();
|
|
5673
5651
|
if (reason) {
|
|
5674
|
-
console.log(
|
|
5675
|
-
console.log(
|
|
5652
|
+
console.log(chalk32.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
|
|
5653
|
+
console.log(chalk32.dim(` ${reason.split("\n").join("\n ")}`));
|
|
5676
5654
|
console.log("");
|
|
5677
5655
|
}
|
|
5678
5656
|
if (!opts.confirm) {
|
|
5679
5657
|
console.log(
|
|
5680
|
-
|
|
5658
|
+
chalk32.red(
|
|
5681
5659
|
" \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
|
|
5682
5660
|
)
|
|
5683
5661
|
);
|
|
5684
|
-
console.log(
|
|
5662
|
+
console.log(chalk32.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
|
|
5685
5663
|
process.exitCode = 1;
|
|
5686
5664
|
return;
|
|
5687
5665
|
}
|
|
5688
5666
|
const removed = clearHardStop();
|
|
5689
5667
|
if (removed) {
|
|
5690
|
-
console.log(
|
|
5668
|
+
console.log(chalk32.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
|
|
5691
5669
|
} else {
|
|
5692
|
-
console.log(
|
|
5670
|
+
console.log(chalk32.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
|
|
5693
5671
|
}
|
|
5694
5672
|
}
|
|
5695
5673
|
|
|
@@ -5710,7 +5688,7 @@ async function guardCli(action, approved, run) {
|
|
|
5710
5688
|
}]);
|
|
5711
5689
|
return ok;
|
|
5712
5690
|
},
|
|
5713
|
-
log: (m) => console.log(
|
|
5691
|
+
log: (m) => console.log(chalk33.yellow(` ${m}`))
|
|
5714
5692
|
},
|
|
5715
5693
|
run
|
|
5716
5694
|
);
|
|
@@ -5723,7 +5701,7 @@ async function guardCliDefer(action, approved, run) {
|
|
|
5723
5701
|
approved,
|
|
5724
5702
|
// TTY 면 통과(명령이 자체 확인), 비대화형은 confirm 불가 → 가드가 차단.
|
|
5725
5703
|
confirm: async () => !!process.stdout.isTTY,
|
|
5726
|
-
log: (m) => console.log(
|
|
5704
|
+
log: (m) => console.log(chalk33.yellow(` ${m}`))
|
|
5727
5705
|
},
|
|
5728
5706
|
run
|
|
5729
5707
|
);
|
|
@@ -5850,8 +5828,8 @@ program.command("design").alias("\uB514\uC790\uC778").description("\uB514\uC790\
|
|
|
5850
5828
|
program.command("design-palette").alias("\uD314\uB808\uD2B8").description("\uCEEC\uB7EC \uD314\uB808\uD2B8 \uD504\uB9AC\uC14B \uC120\uD0DD + \uC801\uC6A9").action(async () => {
|
|
5851
5829
|
await designPalette();
|
|
5852
5830
|
});
|
|
5853
|
-
program.command("theme").alias("\uD14C\uB9C8").description("\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS + \uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0 \uC0DD\uC131").action(async () => {
|
|
5854
|
-
await theme();
|
|
5831
|
+
program.command("theme").alias("\uD14C\uB9C8").option("-y, --yes", "\uAE30\uC874 \uD30C\uC77C \uB36E\uC5B4\uC4F0\uAE30 \uD655\uC778 \uC2A4\uD0B5 (\uBE44\uB300\uD654\uD615 \uC790\uB3D9 \uB36E\uC5B4\uC4F0\uAE30)").description("\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS + \uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0 \uC0DD\uC131").action(async (opts) => {
|
|
5832
|
+
await theme(opts);
|
|
5855
5833
|
});
|
|
5856
5834
|
var refCmd = program.command("ref").alias("\uB808\uD37C\uB7F0\uC2A4").description("\uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC (add / list / open)").action(async () => {
|
|
5857
5835
|
await refList();
|
|
@@ -6000,9 +5978,9 @@ if (isMainModule) {
|
|
|
6000
5978
|
}
|
|
6001
5979
|
} catch (err) {
|
|
6002
5980
|
if (isPromptAbortError(err)) {
|
|
6003
|
-
console.error(
|
|
5981
|
+
console.error(chalk33.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)"));
|
|
6004
5982
|
} else {
|
|
6005
|
-
console.error(
|
|
5983
|
+
console.error(chalk33.red(`
|
|
6006
5984
|
\u274C ${err instanceof Error ? err.message : String(err)}`));
|
|
6007
5985
|
}
|
|
6008
5986
|
process.exitCode = 1;
|