@byh3071/vhk 0.5.1 โ 0.5.3
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/README.md +13 -2
- package/dist/index.js +327 -172
- package/package.json +62 -56
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: vhk-readme
|
|
3
3
|
date: 2026-05-23
|
|
4
|
-
tags: [vhk, cli, readme, v0.5.
|
|
4
|
+
tags: [vhk, cli, readme, v0.5.3]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ๐ง VHK โ Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI** (v0.5.
|
|
9
|
+
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI** (v0.5.3)
|
|
10
|
+
>
|
|
11
|
+
> ๐ฝ๏ธ **VHK๋ VHK๋ก ๋ถํธ์คํธ๋ฉ๋จ** โ ์ด ๋ ํฌ์ `docs/`, `CLAUDE.md`, `.cursorrules`๋ `vhk init`์ด ๋ง๋ค์์ต๋๋ค.
|
|
10
12
|
|
|
11
13
|
๋ช
๋ น์ด๋ฅผ ์ธ์ฐ์ง ์์๋ ๋ฉ๋๋ค. `vhk`๋ง ์น๋ฉด ๋ฉ๋ด๊ฐ ๋์ค๊ณ , ํ๊ตญ์ด๋ก ๋งํด๋ ์์๋ฃ์ต๋๋ค.
|
|
12
14
|
|
|
@@ -103,6 +105,15 @@ vhk ๊ธฐํ ๋๋ฌ๊ณ ๋ฐ๋ก ์์
|
|
|
103
105
|
|------|------|
|
|
104
106
|
| `--since YYYY-MM-DD` | ๋ถ์ ์์์ผ (๊ธฐ๋ณธ: ์ค๋) |
|
|
105
107
|
|
|
108
|
+
## v0.5.3 ํ์ด๋ผ์ดํธ
|
|
109
|
+
|
|
110
|
+
| ๊ธฐ๋ฅ | ์ค๋ช
|
|
|
111
|
+
|------|------|
|
|
112
|
+
| **์
ํํธ์คํ
** | `vhk init`์ด vhk-cli ๋ ํฌ ์์ฒด๋ฅผ ๋ถํธ์คํธ๋ฉ โ ์๊ธฐ ๋๊ตฌ๋ก ์๊ธฐ ๋ ํฌ ๋ง๋ค๊ธฐ |
|
|
113
|
+
| **CHANGELOG.md** | ๋ณ๊ฒฝ ์ด๋ ฅ ํ์ค ํ์ผ ์ ์ค. `vhk ship`์ด `[Unreleased]` โ `[๋ฒ์ ]` ์๋ ์ด๋ |
|
|
114
|
+
| **doctor ์
๋ฐ์ดํธ ์๋ฆผ** | `vhk doctor`๊ฐ npm ์ต์ ๋ฒ์ ๋น๊ต ํ `๐ v0.X.X ์ฌ์ฉ ๊ฐ๋ฅ` ํ ์ค ํ์ |
|
|
115
|
+
| **init ์์ ์ฑ** | ์ต์
๊ฐ ํฌํจ ๋ช
๋ น ๋ผ์ฐํ
๋ฒ๊ทธ ํฝ์ค, ์ฌ์ฉ์ ์ ์ `package.json` scripts ๋ณด์กด |
|
|
116
|
+
|
|
106
117
|
## v0.5.0 ํ์ด๋ผ์ดํธ
|
|
107
118
|
|
|
108
119
|
| ๊ธฐ๋ฅ | ์ค๋ช
|
|
package/dist/index.js
CHANGED
|
@@ -485,8 +485,7 @@ var require_ignore = __commonJS({
|
|
|
485
485
|
|
|
486
486
|
// src/index.ts
|
|
487
487
|
import { Command, Help } from "commander";
|
|
488
|
-
import
|
|
489
|
-
import inquirer7 from "inquirer";
|
|
488
|
+
import inquirer8 from "inquirer";
|
|
490
489
|
|
|
491
490
|
// src/lib/nlp-router.ts
|
|
492
491
|
function normalize(input) {
|
|
@@ -496,7 +495,7 @@ var NLP_KEYWORDS = {
|
|
|
496
495
|
save: ["\uC800\uC7A5", "\uC138\uC774\uBE0C", "\uCEE4\uBC0B", "\uC62C\uB824", "\uC62C\uB9AC\uAE30", "\uD478\uC2DC", "push", "commit"],
|
|
497
496
|
undo: ["\uB418\uB3CC\uB824", "\uB418\uB3CC\uB9AC\uAE30", "\uCDE8\uC18C", "\uC6D0\uB798\uB300\uB85C", "\uB864\uBC31", "\uB9AC\uC14B", "reset", "rollback"],
|
|
498
497
|
status: ["\uC0C1\uD0DC", "\uD604\uD669", "\uC5B4\uB5BB\uAC8C", "\uC5B4\uB54C", "\uC9C0\uAE08"],
|
|
499
|
-
diff: ["\uBCC0\uACBD", "\uBC14\uB010", "\uBB50\uBC14\uB01C", "\uCC28\uC774", "\uB2EC\uB77C\uC9C4", "\uC218\uC815\uB41C"]
|
|
498
|
+
diff: ["\uBCC0\uACBD", "\uBC14\uB010", "\uBB50\uBC14\uB01C", "\uBC14\uB00C\uC5C8", "\uCC28\uC774", "\uB2EC\uB77C\uC9C4", "\uC218\uC815\uB41C"]
|
|
500
499
|
};
|
|
501
500
|
function matchesKeywords(text, command) {
|
|
502
501
|
const keywords = NLP_KEYWORDS[command];
|
|
@@ -546,7 +545,7 @@ var RULES = [
|
|
|
546
545
|
command: "diff",
|
|
547
546
|
explanation: "\uBCC0\uACBD\uC0AC\uD56D \uC694\uC57D (vhk diff)",
|
|
548
547
|
confidence: "high",
|
|
549
|
-
test: (t2) => (matchesKeywords(t2, "diff") || /^diff$/.test(t2) || /๋ณ๊ฒฝ์ฌํญ|์์ \s*๋ด์ญ|์ฐจ์ด\s
|
|
548
|
+
test: (t2) => (matchesKeywords(t2, "diff") || /^diff$/.test(t2) || /๋ณ๊ฒฝ์ฌํญ|์์ \s*๋ด์ญ|์ฐจ์ด\s*๋ณด|๋ญ\s*๋ฐ๋/.test(t2)) && !/์ ์ฅ|์ปค๋ฐ|push|ํธ์|์ํ|ํํฉ|์ธ์ด๋ธ|commit/.test(t2)
|
|
550
549
|
},
|
|
551
550
|
{
|
|
552
551
|
command: "undo",
|
|
@@ -611,6 +610,69 @@ function extractNotionUrl(input) {
|
|
|
611
610
|
return m?.[0];
|
|
612
611
|
}
|
|
613
612
|
|
|
613
|
+
// src/lib/cli-args.ts
|
|
614
|
+
var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
615
|
+
"gate",
|
|
616
|
+
"\uAC80\uC99D",
|
|
617
|
+
"\uC544\uC774\uB514\uC5B4",
|
|
618
|
+
"init",
|
|
619
|
+
"\uC2DC\uC791",
|
|
620
|
+
"\uB9CC\uB4E4\uAE30",
|
|
621
|
+
"recap",
|
|
622
|
+
"\uC815\uB9AC",
|
|
623
|
+
"\uC624\uB298",
|
|
624
|
+
"sync",
|
|
625
|
+
"\uB9DE\uCD94\uAE30",
|
|
626
|
+
"\uADDC\uCE59",
|
|
627
|
+
"check",
|
|
628
|
+
"\uC810\uAC80",
|
|
629
|
+
"\uB9B0\uD2B8",
|
|
630
|
+
"secure",
|
|
631
|
+
"\uBCF4\uC548",
|
|
632
|
+
"scan",
|
|
633
|
+
"\uC2A4\uCE94",
|
|
634
|
+
"ship",
|
|
635
|
+
"\uBC30\uD3EC",
|
|
636
|
+
"\uB9B4\uB9AC\uC988",
|
|
637
|
+
"doctor",
|
|
638
|
+
"\uD658\uACBD",
|
|
639
|
+
"\uC9C4\uB2E8",
|
|
640
|
+
"save",
|
|
641
|
+
"\uC800\uC7A5",
|
|
642
|
+
"undo",
|
|
643
|
+
"\uB418\uB3CC\uB9AC\uAE30",
|
|
644
|
+
"status",
|
|
645
|
+
"\uC0C1\uD0DC",
|
|
646
|
+
"\uD604\uD669",
|
|
647
|
+
"diff",
|
|
648
|
+
"\uBCC0\uACBD",
|
|
649
|
+
"\uCC28\uC774",
|
|
650
|
+
"help"
|
|
651
|
+
]);
|
|
652
|
+
function isOptionToken(token) {
|
|
653
|
+
return token.startsWith("-");
|
|
654
|
+
}
|
|
655
|
+
function detectNaturalLanguageInput(argv) {
|
|
656
|
+
const rest = argv.slice(2);
|
|
657
|
+
if (rest.length === 0) return null;
|
|
658
|
+
const first = rest[0];
|
|
659
|
+
if (isOptionToken(first)) return null;
|
|
660
|
+
if (rest.some(isOptionToken)) return null;
|
|
661
|
+
const input = rest.join(" ").trim();
|
|
662
|
+
if (!input) return null;
|
|
663
|
+
const firstIsKnown = KNOWN_COMMAND_TOKENS.has(first);
|
|
664
|
+
if (firstIsKnown && rest.length === 1) return null;
|
|
665
|
+
if (firstIsKnown && rest.length > 1) {
|
|
666
|
+
if (routeNaturalLanguage(input)) return input;
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
return input;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/lib/nlp-run.ts
|
|
673
|
+
import chalk16 from "chalk";
|
|
674
|
+
import inquirer7 from "inquirer";
|
|
675
|
+
|
|
614
676
|
// src/i18n/ko.ts
|
|
615
677
|
var ko = {
|
|
616
678
|
status: {
|
|
@@ -792,7 +854,9 @@ var ko = {
|
|
|
792
854
|
projectFiles: "\u{1F4C1} \uD504\uB85C\uC81D\uD2B8 \uD30C\uC77C \uD655\uC778:",
|
|
793
855
|
envNotIgnored: "\u26A0\uFE0F .env\uAC00 .gitignore\uC5D0 \uC5C6\uC74C! \uCD94\uAC00\uD558\uC138\uC694",
|
|
794
856
|
nextOkMessage: "\uD658\uACBD \uC810\uAC80 \uD1B5\uACFC! \uC774\uC81C \uD504\uB85C\uC81D\uD2B8\uB97C \uC2DC\uC791\uD558\uC138\uC694.",
|
|
795
|
-
nextRetryMessage: "\uC704 \uB3C4\uAD6C\uB97C \uC124\uCE58\uD55C \uD6C4 \uB2E4\uC2DC \uC810\uAC80\uD558\uC138\uC694."
|
|
857
|
+
nextRetryMessage: "\uC704 \uB3C4\uAD6C\uB97C \uC124\uCE58\uD55C \uD6C4 \uB2E4\uC2DC \uC810\uAC80\uD558\uC138\uC694.",
|
|
858
|
+
updateAvailable: (latest) => `\u{1F195} v${latest} \uC0AC\uC6A9 \uAC00\uB2A5 \u2014 npm i -g @byh3071/vhk`,
|
|
859
|
+
updateCurrent: "\uCD5C\uC2E0 \uBC84\uC804\uC744 \uC4F0\uACE0 \uC788\uC5B4\uC694"
|
|
796
860
|
},
|
|
797
861
|
nlp: {
|
|
798
862
|
matched: "\uC774\uAC8C \uB9DE\uB098\uC694?",
|
|
@@ -847,7 +911,10 @@ var ko = {
|
|
|
847
911
|
checkSecurity: "\uBCF4\uC548 \uC2A4\uCE94\uC744 \uB3CC\uB838\uB098\uC694?",
|
|
848
912
|
hintSecurity: "vhk \uBCF4\uC548 scan",
|
|
849
913
|
checkCommit: "\uBAA8\uB4E0 \uBCC0\uACBD\uC774 \uCEE4\uBC0B\uB418\uC5C8\uB098\uC694?",
|
|
850
|
-
hintCommit: "git status \uD655\uC778"
|
|
914
|
+
hintCommit: "git status \uD655\uC778",
|
|
915
|
+
changelogUpdated: (version) => `CHANGELOG.md \uAC31\uC2E0\uB428 \u2014 [Unreleased] \u2192 [${version}] \uC139\uC158\uC73C\uB85C \uC774\uB3D9`,
|
|
916
|
+
changelogNoUnreleased: "CHANGELOG.md\uC5D0 [Unreleased] \uC139\uC158\uC774 \uC5C6\uC5B4 \uC790\uB3D9 \uAC31\uC2E0\uC744 \uC2A4\uD0B5\uD588\uC5B4\uC694",
|
|
917
|
+
changelogMissing: "CHANGELOG.md\uAC00 \uC5C6\uC5B4\uC694. \uB9CC\uB4E4\uBA74 ship\uC774 \uC790\uB3D9\uC73C\uB85C [Unreleased] \u2192 \uBC84\uC804 \uC139\uC158\uC73C\uB85C \uC62E\uACA8\uC90D\uB2C8\uB2E4."
|
|
851
918
|
}
|
|
852
919
|
};
|
|
853
920
|
function lookup(path15) {
|
|
@@ -1668,7 +1735,7 @@ function enhancePackageScripts(projectDir) {
|
|
|
1668
1735
|
const pkgPath = path3.join(projectDir, "package.json");
|
|
1669
1736
|
if (!fs3.existsSync(pkgPath)) return false;
|
|
1670
1737
|
const pkg = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
|
|
1671
|
-
pkg.scripts = { ...pkg.scripts
|
|
1738
|
+
pkg.scripts = { ...VHK_PACKAGE_SCRIPTS, ...pkg.scripts };
|
|
1672
1739
|
fs3.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
1673
1740
|
return true;
|
|
1674
1741
|
}
|
|
@@ -2734,6 +2801,27 @@ function getVhkVersion() {
|
|
|
2734
2801
|
}
|
|
2735
2802
|
return void 0;
|
|
2736
2803
|
}
|
|
2804
|
+
function fetchLatestNpmVersion(packageName) {
|
|
2805
|
+
try {
|
|
2806
|
+
const result = execSync(`npm view ${packageName} version`, {
|
|
2807
|
+
encoding: "utf-8",
|
|
2808
|
+
timeout: 5e3,
|
|
2809
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
2810
|
+
}).trim();
|
|
2811
|
+
if (/^\d+\.\d+\.\d+/.test(result)) return result;
|
|
2812
|
+
return void 0;
|
|
2813
|
+
} catch {
|
|
2814
|
+
return void 0;
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
function compareSemver(a, b) {
|
|
2818
|
+
const parse = (v) => v.replace(/^v/i, "").split("-")[0].split(".").map((n) => parseInt(n, 10) || 0);
|
|
2819
|
+
const [a1 = 0, a2 = 0, a3 = 0] = parse(a);
|
|
2820
|
+
const [b1 = 0, b2 = 0, b3 = 0] = parse(b);
|
|
2821
|
+
if (a1 !== b1) return a1 - b1;
|
|
2822
|
+
if (a2 !== b2) return a2 - b2;
|
|
2823
|
+
return a3 - b3;
|
|
2824
|
+
}
|
|
2737
2825
|
async function doctor() {
|
|
2738
2826
|
console.log(chalk10.bold(`
|
|
2739
2827
|
${ko.doctor.title}
|
|
@@ -2761,6 +2849,14 @@ ${ko.doctor.title}
|
|
|
2761
2849
|
} else {
|
|
2762
2850
|
console.log(chalk10.green(" \u2705 VHK") + chalk10.dim(" \u2014 \uC124\uCE58\uB428"));
|
|
2763
2851
|
}
|
|
2852
|
+
if (vhkVersion) {
|
|
2853
|
+
const latest = fetchLatestNpmVersion("@byh3071/vhk");
|
|
2854
|
+
if (latest && compareSemver(latest, vhkVersion) > 0) {
|
|
2855
|
+
console.log(chalk10.yellow(` ${ko.doctor.updateAvailable(latest)}`));
|
|
2856
|
+
} else if (latest) {
|
|
2857
|
+
console.log(chalk10.dim(` ${ko.doctor.updateCurrent}`));
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2764
2860
|
console.log("");
|
|
2765
2861
|
console.log(chalk10.bold(` ${ko.doctor.projectFiles}`));
|
|
2766
2862
|
const cwd = process.cwd();
|
|
@@ -2823,6 +2919,29 @@ var CHECKLIST = [
|
|
|
2823
2919
|
function sanitizeVersion(version) {
|
|
2824
2920
|
return version.trim().replace(/^v/i, "").replace(/[^a-zA-Z0-9._-]/g, "-") || "0.0.0";
|
|
2825
2921
|
}
|
|
2922
|
+
function updateChangelogUnreleased(cwd, version, date) {
|
|
2923
|
+
const changelogPath = path13.join(cwd, "CHANGELOG.md");
|
|
2924
|
+
if (!fs13.existsSync(changelogPath)) return { status: "missing" };
|
|
2925
|
+
const content = fs13.readFileSync(changelogPath, "utf-8");
|
|
2926
|
+
const unreleasedHeading = /^## \[Unreleased\][^\n]*$/m;
|
|
2927
|
+
if (!unreleasedHeading.test(content)) return { status: "no-unreleased" };
|
|
2928
|
+
const blankUnreleased = [
|
|
2929
|
+
"## [Unreleased]",
|
|
2930
|
+
"",
|
|
2931
|
+
"### Added",
|
|
2932
|
+
"- ",
|
|
2933
|
+
"",
|
|
2934
|
+
"### Fixed",
|
|
2935
|
+
"- ",
|
|
2936
|
+
"",
|
|
2937
|
+
"---",
|
|
2938
|
+
"",
|
|
2939
|
+
`## [${version}] \u2014 ${date}`
|
|
2940
|
+
].join("\n");
|
|
2941
|
+
const updated = content.replace(unreleasedHeading, blankUnreleased);
|
|
2942
|
+
fs13.writeFileSync(changelogPath, updated, "utf-8");
|
|
2943
|
+
return { status: "updated", version };
|
|
2944
|
+
}
|
|
2826
2945
|
async function ship() {
|
|
2827
2946
|
console.log(chalk11.bold(`
|
|
2828
2947
|
${ko.ship.title}
|
|
@@ -2914,6 +3033,14 @@ ${ko.ship.title}
|
|
|
2914
3033
|
fs13.writeFileSync(filePath, content, "utf-8");
|
|
2915
3034
|
console.log(chalk11.green(`
|
|
2916
3035
|
${ko.ship.buildLogDone(path13.relative(cwd, filePath))}`));
|
|
3036
|
+
const changelogResult = updateChangelogUnreleased(cwd, versionSlug, today);
|
|
3037
|
+
if (changelogResult.status === "updated") {
|
|
3038
|
+
log.success(ko.ship.changelogUpdated(changelogResult.version));
|
|
3039
|
+
} else if (changelogResult.status === "no-unreleased") {
|
|
3040
|
+
log.warn(ko.ship.changelogNoUnreleased);
|
|
3041
|
+
} else {
|
|
3042
|
+
log.info(ko.ship.changelogMissing);
|
|
3043
|
+
}
|
|
2917
3044
|
printNextStep({
|
|
2918
3045
|
message: ko.ship.deployMessage,
|
|
2919
3046
|
command: "npm publish --access=public",
|
|
@@ -3203,104 +3330,23 @@ ${t("undo.recentHeader")}`));
|
|
|
3203
3330
|
}
|
|
3204
3331
|
}
|
|
3205
3332
|
|
|
3206
|
-
// src/commands/
|
|
3207
|
-
import { execFileSync as execFileSync4
|
|
3333
|
+
// src/commands/status.ts
|
|
3334
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
3335
|
+
import fs15 from "fs";
|
|
3336
|
+
import path14 from "path";
|
|
3208
3337
|
import chalk14 from "chalk";
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
}
|
|
3215
|
-
}
|
|
3216
|
-
function parseDiffStat(stat) {
|
|
3217
|
-
const files = [];
|
|
3218
|
-
const lines = stat.split("\n");
|
|
3219
|
-
for (const line of lines) {
|
|
3220
|
-
const match = line.match(/^\s*(.+?)\s*\|\s*(\d+)/);
|
|
3221
|
-
if (!match) continue;
|
|
3222
|
-
const name = match[1].trim();
|
|
3223
|
-
if (name.includes("changed") || name.includes("file")) continue;
|
|
3224
|
-
const plusMatch = line.match(/(\++)/);
|
|
3225
|
-
const minusMatch = line.match(/(\-+)/);
|
|
3226
|
-
files.push({
|
|
3227
|
-
name,
|
|
3228
|
-
additions: plusMatch ? plusMatch[1].length : 0,
|
|
3229
|
-
deletions: minusMatch ? minusMatch[1].length : 0
|
|
3230
|
-
});
|
|
3231
|
-
}
|
|
3232
|
-
return files;
|
|
3233
|
-
}
|
|
3234
|
-
function summarizeNumstat(numstat) {
|
|
3235
|
-
let totalAdd = 0;
|
|
3236
|
-
let totalDel = 0;
|
|
3237
|
-
let fileCount = 0;
|
|
3238
|
-
for (const line of numstat.split("\n").filter(Boolean)) {
|
|
3239
|
-
const [add, del] = line.split(" ");
|
|
3240
|
-
if (add === void 0 || del === void 0) continue;
|
|
3241
|
-
totalAdd += parseInt(add, 10) || 0;
|
|
3242
|
-
totalDel += parseInt(del, 10) || 0;
|
|
3243
|
-
fileCount++;
|
|
3244
|
-
}
|
|
3245
|
-
return { fileCount, totalAdd, totalDel };
|
|
3246
|
-
}
|
|
3247
|
-
function printFile(f) {
|
|
3248
|
-
const adds = f.additions > 0 ? chalk14.green(`+${f.additions}`) : "";
|
|
3249
|
-
const dels = f.deletions > 0 ? chalk14.red(`-${f.deletions}`) : "";
|
|
3250
|
-
const change = [adds, dels].filter(Boolean).join(" ");
|
|
3251
|
-
console.log(` ${f.name} ${change}`);
|
|
3338
|
+
|
|
3339
|
+
// src/lib/read-json.ts
|
|
3340
|
+
import fs14 from "fs";
|
|
3341
|
+
function stripBom(text) {
|
|
3342
|
+
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
3252
3343
|
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
console.log(chalk14.gray("\u2500".repeat(40)));
|
|
3257
|
-
try {
|
|
3258
|
-
execSync2("git rev-parse --is-inside-work-tree", { stdio: "pipe" });
|
|
3259
|
-
} catch {
|
|
3260
|
-
console.log(chalk14.red(`\u274C ${t("diff.notGitRepo")}`));
|
|
3261
|
-
return;
|
|
3262
|
-
}
|
|
3263
|
-
const unstaged = gitOut2(["diff", "--stat"]);
|
|
3264
|
-
const staged = gitOut2(["diff", "--cached", "--stat"]);
|
|
3265
|
-
const untracked = gitOut2(["ls-files", "--others", "--exclude-standard"]);
|
|
3266
|
-
if (!unstaged && !staged && !untracked) {
|
|
3267
|
-
console.log(chalk14.green(`
|
|
3268
|
-
\u2705 ${t("diff.noChanges")}`));
|
|
3269
|
-
return;
|
|
3270
|
-
}
|
|
3271
|
-
if (staged) {
|
|
3272
|
-
console.log(chalk14.cyan(`
|
|
3273
|
-
${t("diff.stagedHeader")}`));
|
|
3274
|
-
parseDiffStat(staged).forEach((f) => printFile(f));
|
|
3275
|
-
}
|
|
3276
|
-
if (unstaged) {
|
|
3277
|
-
console.log(chalk14.cyan(`
|
|
3278
|
-
${t("diff.unstagedHeader")}`));
|
|
3279
|
-
parseDiffStat(unstaged).forEach((f) => printFile(f));
|
|
3280
|
-
}
|
|
3281
|
-
if (untracked) {
|
|
3282
|
-
const files = untracked.split("\n").filter(Boolean);
|
|
3283
|
-
console.log(chalk14.cyan(`
|
|
3284
|
-
${t("diff.untrackedHeader", files.length)}`));
|
|
3285
|
-
files.forEach((f) => console.log(` ${chalk14.green("+")} ${f}`));
|
|
3286
|
-
}
|
|
3287
|
-
const numstat = gitOut2(["diff", "--numstat", "HEAD"]);
|
|
3288
|
-
if (numstat) {
|
|
3289
|
-
const { fileCount, totalAdd, totalDel } = summarizeNumstat(numstat);
|
|
3290
|
-
console.log(chalk14.cyan(`
|
|
3291
|
-
${t("diff.summaryHeader")}`));
|
|
3292
|
-
console.log(` ${t("diff.filesLine", fileCount)}`);
|
|
3293
|
-
console.log(` \uCD94\uAC00: ${chalk14.green(`+${totalAdd}`)}\uC904`);
|
|
3294
|
-
console.log(` \uC0AD\uC81C: ${chalk14.red(`-${totalDel}`)}\uC904`);
|
|
3295
|
-
}
|
|
3296
|
-
console.log("");
|
|
3344
|
+
function readJsonFile(filePath) {
|
|
3345
|
+
const raw = stripBom(fs14.readFileSync(filePath, "utf-8"));
|
|
3346
|
+
return JSON.parse(raw);
|
|
3297
3347
|
}
|
|
3298
3348
|
|
|
3299
3349
|
// src/commands/status.ts
|
|
3300
|
-
import { execFileSync as execFileSync5 } from "child_process";
|
|
3301
|
-
import fs14 from "fs";
|
|
3302
|
-
import path14 from "path";
|
|
3303
|
-
import chalk15 from "chalk";
|
|
3304
3350
|
function countFileChanges(porcelain) {
|
|
3305
3351
|
const lines = porcelain.split("\n").filter(Boolean);
|
|
3306
3352
|
let staged = 0;
|
|
@@ -3339,9 +3385,9 @@ function parseRecentCommitLines(logOutput) {
|
|
|
3339
3385
|
}
|
|
3340
3386
|
function readProjectPackage(cwd = process.cwd()) {
|
|
3341
3387
|
const pkgPath = path14.join(cwd, "package.json");
|
|
3342
|
-
if (!
|
|
3388
|
+
if (!fs15.existsSync(pkgPath)) return null;
|
|
3343
3389
|
try {
|
|
3344
|
-
const pkg =
|
|
3390
|
+
const pkg = readJsonFile(pkgPath);
|
|
3345
3391
|
if (!pkg.name && !pkg.version) return null;
|
|
3346
3392
|
return {
|
|
3347
3393
|
name: pkg.name ?? "(no name)",
|
|
@@ -3360,15 +3406,15 @@ function getSyncCounts(gitRoot) {
|
|
|
3360
3406
|
}
|
|
3361
3407
|
}
|
|
3362
3408
|
async function status() {
|
|
3363
|
-
console.log(
|
|
3409
|
+
console.log(chalk14.bold(`
|
|
3364
3410
|
\u{1F4CA} ${t("status.title")}`));
|
|
3365
|
-
console.log(
|
|
3411
|
+
console.log(chalk14.gray("\u2500".repeat(40)));
|
|
3366
3412
|
let gitRoot;
|
|
3367
3413
|
try {
|
|
3368
|
-
|
|
3414
|
+
execFileSync4("git", ["rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
3369
3415
|
gitRoot = getGitRoot();
|
|
3370
3416
|
} catch {
|
|
3371
|
-
console.log(
|
|
3417
|
+
console.log(chalk14.red(`\u274C ${t("status.notGitRepo")}`));
|
|
3372
3418
|
return;
|
|
3373
3419
|
}
|
|
3374
3420
|
let branch;
|
|
@@ -3387,31 +3433,183 @@ async function status() {
|
|
|
3387
3433
|
commits = [];
|
|
3388
3434
|
}
|
|
3389
3435
|
const pkg = readProjectPackage();
|
|
3390
|
-
console.log(
|
|
3391
|
-
\u{1F33F} ${t("status.branch")}`) +
|
|
3436
|
+
console.log(chalk14.cyan(`
|
|
3437
|
+
\u{1F33F} ${t("status.branch")}`) + chalk14.white(` ${branch}`));
|
|
3392
3438
|
console.log(
|
|
3393
|
-
|
|
3439
|
+
chalk14.cyan(`\u{1F4C1} ${t("status.changes")}`) + chalk14.white(
|
|
3394
3440
|
` staged ${counts.staged} \xB7 unstaged ${counts.unstaged} \xB7 untracked ${counts.untracked}`
|
|
3395
3441
|
)
|
|
3396
3442
|
);
|
|
3397
|
-
console.log(
|
|
3443
|
+
console.log(chalk14.cyan(`
|
|
3398
3444
|
\u{1F4CB} ${t("status.recentCommits")}`));
|
|
3399
3445
|
if (commits.length === 0) {
|
|
3400
|
-
console.log(
|
|
3446
|
+
console.log(chalk14.dim(` ${t("status.noCommits")}`));
|
|
3401
3447
|
} else {
|
|
3402
|
-
commits.forEach((c) => console.log(` ${
|
|
3448
|
+
commits.forEach((c) => console.log(` ${chalk14.dim("\u2022")} ${c}`));
|
|
3403
3449
|
}
|
|
3404
3450
|
console.log(
|
|
3405
|
-
|
|
3406
|
-
\u{1F504} ${t("status.remote")}`) +
|
|
3451
|
+
chalk14.cyan(`
|
|
3452
|
+
\u{1F504} ${t("status.remote")}`) + chalk14.white(` ${formatSyncLabel(sync2)}`)
|
|
3407
3453
|
);
|
|
3408
|
-
console.log(
|
|
3454
|
+
console.log(chalk14.gray("\n" + "\u2500".repeat(40)));
|
|
3409
3455
|
if (pkg) {
|
|
3410
|
-
console.log(
|
|
3456
|
+
console.log(chalk14.cyan(`\u{1F4E6} ${t("status.package")}`) + chalk14.white(` ${pkg.name} v${pkg.version}`));
|
|
3411
3457
|
} else {
|
|
3412
|
-
console.log(
|
|
3458
|
+
console.log(chalk14.dim(`\u{1F4E6} ${t("status.noPackage")}`));
|
|
3459
|
+
}
|
|
3460
|
+
console.log("");
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
// src/commands/diff.ts
|
|
3464
|
+
import { execFileSync as execFileSync5, execSync as execSync2 } from "child_process";
|
|
3465
|
+
import chalk15 from "chalk";
|
|
3466
|
+
function gitOut2(args) {
|
|
3467
|
+
try {
|
|
3468
|
+
return execFileSync5("git", args, { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
3469
|
+
} catch {
|
|
3470
|
+
return "";
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
function parseDiffStat(stat) {
|
|
3474
|
+
const files = [];
|
|
3475
|
+
const lines = stat.split("\n");
|
|
3476
|
+
for (const line of lines) {
|
|
3477
|
+
const match = line.match(/^\s*(.+?)\s*\|\s*(\d+)/);
|
|
3478
|
+
if (!match) continue;
|
|
3479
|
+
const name = match[1].trim();
|
|
3480
|
+
if (name.includes("changed") || name.includes("file")) continue;
|
|
3481
|
+
const plusMatch = line.match(/(\++)/);
|
|
3482
|
+
const minusMatch = line.match(/(\-+)/);
|
|
3483
|
+
files.push({
|
|
3484
|
+
name,
|
|
3485
|
+
additions: plusMatch ? plusMatch[1].length : 0,
|
|
3486
|
+
deletions: minusMatch ? minusMatch[1].length : 0
|
|
3487
|
+
});
|
|
3488
|
+
}
|
|
3489
|
+
return files;
|
|
3490
|
+
}
|
|
3491
|
+
function summarizeNumstat(numstat) {
|
|
3492
|
+
let totalAdd = 0;
|
|
3493
|
+
let totalDel = 0;
|
|
3494
|
+
let fileCount = 0;
|
|
3495
|
+
for (const line of numstat.split("\n").filter(Boolean)) {
|
|
3496
|
+
const [add, del] = line.split(" ");
|
|
3497
|
+
if (add === void 0 || del === void 0) continue;
|
|
3498
|
+
totalAdd += parseInt(add, 10) || 0;
|
|
3499
|
+
totalDel += parseInt(del, 10) || 0;
|
|
3500
|
+
fileCount++;
|
|
3501
|
+
}
|
|
3502
|
+
return { fileCount, totalAdd, totalDel };
|
|
3503
|
+
}
|
|
3504
|
+
function printFile(f) {
|
|
3505
|
+
const adds = f.additions > 0 ? chalk15.green(`+${f.additions}`) : "";
|
|
3506
|
+
const dels = f.deletions > 0 ? chalk15.red(`-${f.deletions}`) : "";
|
|
3507
|
+
const change = [adds, dels].filter(Boolean).join(" ");
|
|
3508
|
+
console.log(` ${f.name} ${change}`);
|
|
3509
|
+
}
|
|
3510
|
+
async function diff() {
|
|
3511
|
+
console.log(chalk15.bold(`
|
|
3512
|
+
\u{1F50D} ${t("diff.title")}`));
|
|
3513
|
+
console.log(chalk15.gray("\u2500".repeat(40)));
|
|
3514
|
+
try {
|
|
3515
|
+
execSync2("git rev-parse --is-inside-work-tree", { stdio: "pipe" });
|
|
3516
|
+
} catch {
|
|
3517
|
+
console.log(chalk15.red(`\u274C ${t("diff.notGitRepo")}`));
|
|
3518
|
+
return;
|
|
3519
|
+
}
|
|
3520
|
+
const unstaged = gitOut2(["diff", "--stat"]);
|
|
3521
|
+
const staged = gitOut2(["diff", "--cached", "--stat"]);
|
|
3522
|
+
const untracked = gitOut2(["ls-files", "--others", "--exclude-standard"]);
|
|
3523
|
+
if (!unstaged && !staged && !untracked) {
|
|
3524
|
+
console.log(chalk15.green(`
|
|
3525
|
+
\u2705 ${t("diff.noChanges")}`));
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
3528
|
+
if (staged) {
|
|
3529
|
+
console.log(chalk15.cyan(`
|
|
3530
|
+
${t("diff.stagedHeader")}`));
|
|
3531
|
+
parseDiffStat(staged).forEach((f) => printFile(f));
|
|
3532
|
+
}
|
|
3533
|
+
if (unstaged) {
|
|
3534
|
+
console.log(chalk15.cyan(`
|
|
3535
|
+
${t("diff.unstagedHeader")}`));
|
|
3536
|
+
parseDiffStat(unstaged).forEach((f) => printFile(f));
|
|
3537
|
+
}
|
|
3538
|
+
if (untracked) {
|
|
3539
|
+
const files = untracked.split("\n").filter(Boolean);
|
|
3540
|
+
console.log(chalk15.cyan(`
|
|
3541
|
+
${t("diff.untrackedHeader", files.length)}`));
|
|
3542
|
+
files.forEach((f) => console.log(` ${chalk15.green("+")} ${f}`));
|
|
3543
|
+
}
|
|
3544
|
+
const numstat = gitOut2(["diff", "--numstat", "HEAD"]);
|
|
3545
|
+
if (numstat) {
|
|
3546
|
+
const { fileCount, totalAdd, totalDel } = summarizeNumstat(numstat);
|
|
3547
|
+
console.log(chalk15.cyan(`
|
|
3548
|
+
${t("diff.summaryHeader")}`));
|
|
3549
|
+
console.log(` ${t("diff.filesLine", fileCount)}`);
|
|
3550
|
+
console.log(` \uCD94\uAC00: ${chalk15.green(`+${totalAdd}`)}\uC904`);
|
|
3551
|
+
console.log(` \uC0AD\uC81C: ${chalk15.red(`-${totalDel}`)}\uC904`);
|
|
3552
|
+
}
|
|
3553
|
+
console.log("");
|
|
3554
|
+
}
|
|
3555
|
+
|
|
3556
|
+
// src/lib/nlp-run.ts
|
|
3557
|
+
async function dispatchNlpRoute(route, input) {
|
|
3558
|
+
switch (route.command) {
|
|
3559
|
+
case "gate":
|
|
3560
|
+
return gate();
|
|
3561
|
+
case "init":
|
|
3562
|
+
return init({
|
|
3563
|
+
skipGate: route.args?.includes("--skip-gate"),
|
|
3564
|
+
fromNotion: route.args?.includes("--from-notion") ? extractNotionUrl(input) : void 0
|
|
3565
|
+
});
|
|
3566
|
+
case "recap":
|
|
3567
|
+
return recap({});
|
|
3568
|
+
case "sync":
|
|
3569
|
+
return sync();
|
|
3570
|
+
case "check":
|
|
3571
|
+
return check();
|
|
3572
|
+
case "secure":
|
|
3573
|
+
return secure();
|
|
3574
|
+
case "ship":
|
|
3575
|
+
return ship();
|
|
3576
|
+
case "doctor":
|
|
3577
|
+
return doctor();
|
|
3578
|
+
case "save":
|
|
3579
|
+
return save();
|
|
3580
|
+
case "undo":
|
|
3581
|
+
return undo();
|
|
3582
|
+
case "status":
|
|
3583
|
+
return status();
|
|
3584
|
+
case "diff":
|
|
3585
|
+
return diff();
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
async function runNaturalLanguageRoute(input) {
|
|
3589
|
+
const route = routeNaturalLanguage(input);
|
|
3590
|
+
if (!route) {
|
|
3591
|
+
console.log(chalk16.yellow(`
|
|
3592
|
+
\u2753 "${input}" \u2014 ${ko.nlp.notMatched}
|
|
3593
|
+
`));
|
|
3594
|
+
return;
|
|
3413
3595
|
}
|
|
3414
3596
|
console.log("");
|
|
3597
|
+
console.log(chalk16.cyan(` \u{1F4AC} "${input}"`));
|
|
3598
|
+
console.log(chalk16.cyan(` \u2192 ${route.explanation}`));
|
|
3599
|
+
if (route.confidence === "low") {
|
|
3600
|
+
const { confirm } = await inquirer7.prompt([{
|
|
3601
|
+
type: "confirm",
|
|
3602
|
+
name: "confirm",
|
|
3603
|
+
message: `${route.explanation} \u2014 ${ko.nlp.matched}`,
|
|
3604
|
+
default: true
|
|
3605
|
+
}]);
|
|
3606
|
+
if (!confirm) {
|
|
3607
|
+
console.log(chalk16.dim(` ${ko.nlp.menuHint}`));
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
console.log("");
|
|
3612
|
+
await dispatchNlpRoute(route, input);
|
|
3415
3613
|
}
|
|
3416
3614
|
|
|
3417
3615
|
// src/index.ts
|
|
@@ -3431,7 +3629,7 @@ var KO_ALIASES = {
|
|
|
3431
3629
|
status: "\uC0C1\uD0DC",
|
|
3432
3630
|
diff: "\uBCC0\uACBD"
|
|
3433
3631
|
};
|
|
3434
|
-
program.name("vhk").description("VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58 (\uD55C\uAD6D\uC5B4\uB85C \uC548\uB0B4\uD569\uB2C8\uB2E4)").version("0.5.
|
|
3632
|
+
program.name("vhk").description("VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58 (\uD55C\uAD6D\uC5B4\uB85C \uC548\uB0B4\uD569\uB2C8\uB2E4)").version("0.5.3");
|
|
3435
3633
|
program.configureHelp({
|
|
3436
3634
|
formatHelp(cmd, helper) {
|
|
3437
3635
|
if (cmd.parent) {
|
|
@@ -3472,62 +3670,14 @@ program.command("status").alias("\uC0C1\uD0DC").description("\uD504\uB85C\uC81D\
|
|
|
3472
3670
|
});
|
|
3473
3671
|
program.command("diff").alias("\uBCC0\uACBD").alias("\uCC28\uC774").description("Git \uBCC0\uACBD\uC0AC\uD56D \uD55C\uAD6D\uC5B4 \uC694\uC57D (staged / unstaged / \uC0C8 \uD30C\uC77C)").action(diff);
|
|
3474
3672
|
program.on("command:*", async (operands) => {
|
|
3475
|
-
const
|
|
3476
|
-
const
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
console.log(chalk16.cyan(` \u{1F4AC} "${input}"`));
|
|
3480
|
-
console.log(chalk16.cyan(` \u2192 ${route.explanation}`));
|
|
3481
|
-
if (route.confidence === "low") {
|
|
3482
|
-
const { confirm } = await inquirer7.prompt([{
|
|
3483
|
-
type: "confirm",
|
|
3484
|
-
name: "confirm",
|
|
3485
|
-
message: `${route.explanation} \u2014 ${ko.nlp.matched}`,
|
|
3486
|
-
default: true
|
|
3487
|
-
}]);
|
|
3488
|
-
if (!confirm) {
|
|
3489
|
-
console.log(chalk16.dim(` ${ko.nlp.menuHint}`));
|
|
3490
|
-
return;
|
|
3491
|
-
}
|
|
3492
|
-
}
|
|
3493
|
-
console.log("");
|
|
3494
|
-
switch (route.command) {
|
|
3495
|
-
case "gate":
|
|
3496
|
-
return gate();
|
|
3497
|
-
case "init":
|
|
3498
|
-
return init({
|
|
3499
|
-
skipGate: route.args?.includes("--skip-gate"),
|
|
3500
|
-
fromNotion: route.args?.includes("--from-notion") ? extractNotionUrl(input) : void 0
|
|
3501
|
-
});
|
|
3502
|
-
case "recap":
|
|
3503
|
-
return recap({});
|
|
3504
|
-
case "sync":
|
|
3505
|
-
return sync();
|
|
3506
|
-
case "check":
|
|
3507
|
-
return check();
|
|
3508
|
-
case "secure":
|
|
3509
|
-
return secure();
|
|
3510
|
-
case "ship":
|
|
3511
|
-
return ship();
|
|
3512
|
-
case "doctor":
|
|
3513
|
-
return doctor();
|
|
3514
|
-
case "save":
|
|
3515
|
-
return save();
|
|
3516
|
-
case "undo":
|
|
3517
|
-
return undo();
|
|
3518
|
-
case "status":
|
|
3519
|
-
return status();
|
|
3520
|
-
case "diff":
|
|
3521
|
-
return diff();
|
|
3522
|
-
}
|
|
3523
|
-
}
|
|
3524
|
-
console.log(chalk16.yellow(`
|
|
3525
|
-
\u2753 "${input}" \u2014 ${ko.nlp.notMatched}
|
|
3526
|
-
`));
|
|
3673
|
+
const unknown = operands[0] ?? "";
|
|
3674
|
+
const rest = operands.slice(1);
|
|
3675
|
+
const input = [unknown, ...rest].join(" ").trim();
|
|
3676
|
+
await runNaturalLanguageRoute(input);
|
|
3527
3677
|
});
|
|
3528
3678
|
program.action(async () => {
|
|
3529
3679
|
console.log("\n\u{1F3AF} VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58\n");
|
|
3530
|
-
const { choice } = await
|
|
3680
|
+
const { choice } = await inquirer8.prompt([{
|
|
3531
3681
|
type: "list",
|
|
3532
3682
|
name: "choice",
|
|
3533
3683
|
message: "\uBB58 \uB3C4\uC640\uB4DC\uB9B4\uAE4C\uC694?",
|
|
@@ -3573,4 +3723,9 @@ program.action(async () => {
|
|
|
3573
3723
|
return diff();
|
|
3574
3724
|
}
|
|
3575
3725
|
});
|
|
3576
|
-
|
|
3726
|
+
var nlInput = detectNaturalLanguageInput(process.argv);
|
|
3727
|
+
if (nlInput !== null) {
|
|
3728
|
+
await runNaturalLanguageRoute(nlInput);
|
|
3729
|
+
} else {
|
|
3730
|
+
await program.parseAsync(process.argv);
|
|
3731
|
+
}
|
package/package.json
CHANGED
|
@@ -1,56 +1,62 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@byh3071/vhk",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Vibe Harness Kit โ ๋ฐ์ด๋ธ์ฝ๋ฉ ํ์ฌ์ดํด CLI",
|
|
5
|
-
"bin": {
|
|
6
|
-
"vhk": "
|
|
7
|
-
},
|
|
8
|
-
"type": "module",
|
|
9
|
-
"scripts": {
|
|
10
|
-
"dev": "tsx src/index.ts",
|
|
11
|
-
"build": "tsup",
|
|
12
|
-
"test": "vitest",
|
|
13
|
-
"test:run": "vitest --run",
|
|
14
|
-
"prepublishOnly": "pnpm build && pnpm test:run"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
"
|
|
55
|
-
|
|
56
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@byh3071/vhk",
|
|
3
|
+
"version": "0.5.3",
|
|
4
|
+
"description": "Vibe Harness Kit โ ๋ฐ์ด๋ธ์ฝ๋ฉ ํ์ฌ์ดํด CLI",
|
|
5
|
+
"bin": {
|
|
6
|
+
"vhk": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsx src/index.ts",
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"test": "vitest",
|
|
13
|
+
"test:run": "vitest --run",
|
|
14
|
+
"prepublishOnly": "pnpm build && pnpm test:run",
|
|
15
|
+
"save": "vhk save",
|
|
16
|
+
"check": "vhk check",
|
|
17
|
+
"scan": "vhk secure scan",
|
|
18
|
+
"recap": "vhk recap",
|
|
19
|
+
"ship": "vhk ship",
|
|
20
|
+
"doctor": "vhk doctor"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"vibe-coding",
|
|
29
|
+
"harness",
|
|
30
|
+
"cli",
|
|
31
|
+
"scaffold",
|
|
32
|
+
"session-log",
|
|
33
|
+
"rules-sync"
|
|
34
|
+
],
|
|
35
|
+
"author": "byh3071 <byh3071@gmail.com>",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/byh3071-cpu/vhk.git"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@notionhq/client": "^5.22.0",
|
|
46
|
+
"chalk": "^5.6.2",
|
|
47
|
+
"commander": "^14.0.3",
|
|
48
|
+
"handlebars": "^4.7.9",
|
|
49
|
+
"inquirer": "^9.3.8",
|
|
50
|
+
"ora": "^9.4.0",
|
|
51
|
+
"simple-git": "^3.36.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/inquirer": "^9.0.9",
|
|
55
|
+
"@types/node": "^25.9.1",
|
|
56
|
+
"ignore": "^7.0.5",
|
|
57
|
+
"tsup": "^8.5.1",
|
|
58
|
+
"tsx": "^4.22.3",
|
|
59
|
+
"typescript": "^6.0.3",
|
|
60
|
+
"vitest": "^4.1.7"
|
|
61
|
+
}
|
|
62
|
+
}
|