@byh3071/vhk 1.6.0 โ 1.6.2
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 +17 -3
- package/dist/{chunk-O3A6SO7G.js โ chunk-ACJN723Q.js} +146 -44
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1957 -951
- package/dist/mcp/index.js +6 -1
- package/package.json +72 -71
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: vhk-readme
|
|
3
3
|
date: 2026-05-28
|
|
4
|
-
tags: [vhk, cli, readme, v1.6.
|
|
4
|
+
tags: [vhk, cli, readme, v1.6.1, ga]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ๐ง VHK โ Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> ๐ **v1.6.
|
|
9
|
+
> ๐ **v1.6.1** โ **๊ท์น์ ํ ๋ฒ๋ก CursorยทClaudeยทWindsurfยทCopilotยทAntigravity์, ๋งฅ๋ฝ์ ํด๋ผ์ฐ๋๋ก.**
|
|
10
10
|
> ๋๊ตฌยท๊ธฐ๊ธฐ๋ฅผ ์ฎ๊ฒจ๋ `vhk` ๋ช
๋ น์ผ๋ก ๊ทธ๋๋ก ๋ถ๋ฌ์ต๋๋ค. (ํฌํฐ๋น๋ฆฌํฐ)
|
|
11
11
|
>
|
|
12
12
|
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI**.
|
|
@@ -29,6 +29,20 @@ AI ์ฝ๋ฉ ๋๊ตฌ๋ ์ ๋ง๋ค ๊ท์น ํ์ผ์ด ๋ค๋ฅด๊ณ (`.cursorrules`ยท`CLAUDE
|
|
|
29
29
|
>
|
|
30
30
|
> โน๏ธ WindsurfยทCopilotยทAntigravity ์ถ๋ ฅ ๊ฒฝ๋กยทํฌ๋งท์ ๊ฐ ๋๊ตฌ์ **๊ณต์ ๋ฌธ์ ๊ธฐ์ค**์ผ๋ก ์์ฑํฉ๋๋ค(`.windsurfrules` ยท `.github/copilot-instructions.md` ยท `.agents/rules/`). Antigravity ๋ ํ์ผ๋น 12,000์ ์ ํ์ด ์์ด ์ด๊ณผ ์ ์์ ํ๊ฒ ์ ์ญํ๊ณ ์ ์ฒด๋ `RULES.md` ์ ๋จ์ต๋๋ค.
|
|
31
31
|
|
|
32
|
+
### Cursor / Copilot / Antigravity ์์ ์ด๋ ๊ฒ ๋งํ์ธ์
|
|
33
|
+
|
|
34
|
+
๊ท์น ํ์ผ์ ๋๊ธฐํํ๋ฉด, ์์ด์ ํธ ์ฑํ
์ฐฝ์์ ๋ช
๋ น์ ์ธ์ฐ์ง ์๊ณ ํ๊ตญ์ด๋ก ๋งํด๋ ๋ฉ๋๋ค:
|
|
35
|
+
|
|
36
|
+
| ํ๊ณ ์ถ์ ์ผ | ์ฑํ
์ฐฝ์ ์ด๋ ๊ฒ | ์คํ๋๋ ๋ช
๋ น |
|
|
37
|
+
|------|------|------|
|
|
38
|
+
| ๊ท์น ํ ๋ฒ๋ก ๋๊ธฐํ | "๊ท์น ๋๊ธฐํํด์ค" | `vhk sync` |
|
|
39
|
+
| ์ง๊ธ ์ํ ๋ณด๊ธฐ | "์ํ ์๋ ค์ค" | `vhk status` |
|
|
40
|
+
| ๋ญ ๋ฐ๋์๋์ง | "๋ญ ๋ฐ๋์์ด?" | `vhk diff` |
|
|
41
|
+
| ์ฒ์์ด๋ผ ๋ง๋งํจ | "์ฒ์ ๋ญ ํด?" / "๋์๋ง" | `vhk start` |
|
|
42
|
+
| ์ ์ฅ(์ปค๋ฐ) | "์ ์ฅํด์ค" | `vhk save` |
|
|
43
|
+
|
|
44
|
+
> MCP๋ฅผ ๋ฑ๋กํ๋ฉด(`vhk mcp-init`) ์ ๋ฌธ์ฅ์ด ๊ณง๋ฐ๋ก vhk ๋๊ตฌ ํธ์ถ๋ก ์ด์ด์ง๋๋ค. RULES.md ํ ๋ฒ์ด ๋ค์ฏ ๋๊ตฌ์ ๊ฐ์ ๊ท์น์ ๊น์์ค๋๋ค.
|
|
45
|
+
|
|
32
46
|
## 3๋ถ ์์ ์์ํ๊ธฐ (Getting Started)
|
|
33
47
|
|
|
34
48
|
### 1. ์ค์น
|
|
@@ -156,7 +170,7 @@ vhk ๊ธฐํ ๋๋ฌ๊ณ ๋ฐ๋ก ์์
|
|
|
156
170
|
| `vhk audit` | `๊ฐ์ฌ` | npm/pnpm/yarn ๋ณด์ ์ทจ์ฝ์ ๊ฐ์ฌ (`--fix`๋ก ์๋ ์์ , npm๋ง) |
|
|
157
171
|
| `vhk migrate [target]` | `์ ํ` | ํจํค์ง ๋งค๋์ ์ ํ (`npm` / `yarn` / `pnpm`, lockfile + node_modules ์ฌ๊ตฌ์ฑ) |
|
|
158
172
|
| `vhk update` | `์
๋ฐ์ดํธ` | VHK CLI ์ต์ ๋ฒ์ ์ผ๋ก ์
ํ ์
๋ฐ์ดํธ |
|
|
159
|
-
| `vhk context` | `๋งฅ๋ฝ` | ํ๋ก์ ํธ ํธ๋ฆฌยท์คํยทCLI ๋ช
๋ น ๋ชฉ๋ก์ `.vhk/context.md`๋ก ์๋ ์์ฑ (AI ์ด์์คํดํธ์ฉ) |
|
|
173
|
+
| `vhk context` | `๋งฅ๋ฝ` | ํ๋ก์ ํธ ํธ๋ฆฌยท์คํยทCLI ๋ช
๋ น ๋ชฉ๋ก์ `.vhk/context.md`๋ก ์๋ ์์ฑ (AI ์ด์์คํดํธ์ฉ). `--compact` ๋ก ํ ํฐ ์ ๊ฐํ(Active Goal + ์ต๊ทผ blockers/learnings/memories + ์ฐธ์กฐ ๋งํฌ) ์ถ๋ ฅ |
|
|
160
174
|
| `vhk context-show` | `๋งฅ๋ฝ๋ณด๊ธฐ` | ํ์ฌ ์ปจํ
์คํธ ํ์ผ ๋ด์ฉ ์ถ๋ ฅ |
|
|
161
175
|
| `vhk memory` | `๊ธฐ์ต` | ๊ฒฐ์ ์ฌํญ ๊ธฐ์ต ๊ด๋ฆฌ (`add` / `list` / `remove`, `.vhk/memory.json` ๊ธฐ๋ฐ, ํ๊ทธ ์ง์) |
|
|
162
176
|
| `vhk brief` | `๋ธ๋ฆฌํ` | ํ๋ก์ ํธ ์ ๋ณด + git ์ํ + ๊ฒฐ์ ์ฌํญ + ๋ ํผ๋ฐ์ค ํตํฉ ๋ณด๊ณ ์ `.vhk/brief.md` |
|
|
@@ -562,7 +562,7 @@ var ko = {
|
|
|
562
562
|
notGitRepo: "Git \uC800\uC7A5\uC18C\uAC00 \uC544\uB2C8\uC5D0\uC694. \uBA3C\uC800 git init\uC744 \uC2E4\uD589\uD558\uC138\uC694.",
|
|
563
563
|
branch: "\uBE0C\uB79C\uCE58:",
|
|
564
564
|
changes: "\uBCC0\uACBD:",
|
|
565
|
-
recentCommits:
|
|
565
|
+
recentCommits: (n) => `\uCD5C\uADFC \uCEE4\uBC0B (${n}):`,
|
|
566
566
|
noCommits: "\uCEE4\uBC0B \uC5C6\uC74C",
|
|
567
567
|
remote: "\uC6D0\uACA9:",
|
|
568
568
|
noUpstream: "upstream \uC5C6\uC74C",
|
|
@@ -573,8 +573,9 @@ var ko = {
|
|
|
573
573
|
noPackage: "package.json \uC5C6\uC74C",
|
|
574
574
|
detached: "(detached HEAD)",
|
|
575
575
|
unknownBranch: "(\uC54C \uC218 \uC5C6\uC74C)",
|
|
576
|
-
nextWithChangesMessage: "\uBCC0\uACBD\uC0AC\uD56D\uC774 \uC788\uC5B4\uC694. \
|
|
577
|
-
nextWithChangesCursor: "\
|
|
576
|
+
nextWithChangesMessage: "\uBCC0\uACBD\uC0AC\uD56D\uC774 \uC788\uC5B4\uC694. \uBA3C\uC800 \uBB34\uC5C7\uC774 \uBC14\uB00C\uC5C8\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.",
|
|
577
|
+
nextWithChangesCursor: "\uBB50 \uBC14\uB00C\uC5C8\uC5B4?",
|
|
578
|
+
nextWithChangesAlt: "\uD655\uC778\uD588\uC73C\uBA74 vhk save \uB85C \uC800\uC7A5\uD558\uC138\uC694",
|
|
578
579
|
nextCleanMessage: "\uD074\uB9B0 \uC0C1\uD0DC! \uB2E4\uC74C \uBBF8\uC158\uC73C\uB85C \uB118\uC5B4\uAC00\uC138\uC694.",
|
|
579
580
|
nextCleanCursor: "\uB2E4\uC74C \uBAA9\uD45C \uC54C\uB824\uC918"
|
|
580
581
|
},
|
|
@@ -719,7 +720,10 @@ var ko = {
|
|
|
719
720
|
commandsMdDone: "\u{1F4CB} COMMANDS.md \uC0DD\uC131",
|
|
720
721
|
scriptsDone: "\u{1F4E6} package.json scripts \uCD94\uAC00",
|
|
721
722
|
gitignoreCreated: "\u{1F512} .gitignore \uC0DD\uC131 (.env\xB7node_modules\xB7dist \uC81C\uC678)",
|
|
722
|
-
gitignoreUpdated: "\u{1F512} .gitignore \uBCF4\uAC15 (\uB204\uB77D \uD56D\uBAA9 \uCD94\uAC00)"
|
|
723
|
+
gitignoreUpdated: "\u{1F512} .gitignore \uBCF4\uAC15 (\uB204\uB77D \uD56D\uBAA9 \uCD94\uAC00)",
|
|
724
|
+
adoptPrompt: (n, list) => `\u{1F4E5} \uAE30\uC874 \uADDC\uCE59 \uD30C\uC77C ${n}\uAC1C \uBC1C\uACAC (${list}). RULES.md\uB85C \uAC00\uC838\uC62C\uAE4C\uC694?`,
|
|
725
|
+
adoptPreview: (n) => `\uAE30\uC874 \uADDC\uCE59 ${n}\uAC1C\uB97C RULES.md \uD45C\uC900 \uC139\uC158\uC73C\uB85C \uBCD1\uD569\uD588\uC5B4\uC694 (\uCD9C\uCC98 \uC8FC\uC11D \uD3EC\uD568).`,
|
|
726
|
+
adoptDone: "\u{1F4E5} RULES.md \u2014 \uAE30\uC874 \uADDC\uCE59 adopt \uC644\uB8CC"
|
|
723
727
|
},
|
|
724
728
|
recap: {
|
|
725
729
|
title: "\u{1F4DD} \uC624\uB298 \uD55C \uC77C \uC815\uB9AC",
|
|
@@ -783,8 +787,29 @@ var ko = {
|
|
|
783
787
|
windsurfDone: "\u2705 .windsurfrules \uB9DE\uCDA4 \uC644\uB8CC",
|
|
784
788
|
copilotDone: "\u2705 .github/copilot-instructions.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
785
789
|
antigravityDone: "\u2705 .agents/rules/vhk-rules.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
790
|
+
agentsDone: "\u2705 AGENTS.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
786
791
|
antigravityTruncated: "Antigravity 12,000\uC790 \uC81C\uD55C\uC73C\uB85C \uC77C\uBD80 \uC808\uC0AD\uB428 \u2014 \uC804\uCCB4\uB294 RULES.md \uCC38\uC870",
|
|
787
|
-
done: "\u{1F504} \uB9DE\uCD94\uAE30 \uC644\uB8CC!"
|
|
792
|
+
done: "\u{1F504} \uB9DE\uCD94\uAE30 \uC644\uB8CC!",
|
|
793
|
+
// ์์ ๊ฐ๋ (๋ฐฐ์น 0) โ ๋ฎ์ด์ฐ๊ธฐ ์ ๋ฐฑ์
ยท๋๋ฆฌํํธ ํ์ธยท๋ฏธ๋ฆฌ๋ณด๊ธฐ
|
|
794
|
+
backupSaved: (n, id) => `\u{1F6DF} \uB36E\uC5B4\uC4F0\uAE30 \uC804 ${n}\uAC1C \uD30C\uC77C \uBC31\uC5C5\uD568 \u2192 .vhk/backups/${id} (\uBCF5\uC6D0: vhk restore)`,
|
|
795
|
+
firstSync: "\u{1F6DF} \uCCAB sync \u2014 \uAE30\uC874 \uD30C\uC77C\uC744 \uBC31\uC5C5\uD55C \uB4A4 \uC0DD\uC131\uD569\uB2C8\uB2E4.",
|
|
796
|
+
driftWarn: (p) => `\u26A0\uFE0F ${p} \uAC00 RULES.md \uC0DD\uC131\uBCF8\uACFC \uB2E4\uB985\uB2C8\uB2E4 (\uC9C1\uC811 \uC218\uC815\uD588\uC744 \uC218 \uC788\uC5B4\uC694).`,
|
|
797
|
+
driftConfirm: (n) => `\uC704 ${n}\uAC1C \uD30C\uC77C\uC758 \uAE30\uC874 \uB0B4\uC6A9\uC744 \uB36E\uC5B4\uC4F8\uAE4C\uC694? (\uBC31\uC5C5\uC740 \uC774\uBBF8 \uC800\uC7A5\uB428)`,
|
|
798
|
+
skipped: (p) => `\u23ED\uFE0F \uAC74\uB108\uB700: ${p} (\uB36E\uC5B4\uC4F0\uAE30 \uAC70\uBD80 \u2014 \uBC31\uC5C5\uB9CC \uBCF4\uAD00)`,
|
|
799
|
+
dryRunHeader: "\u{1F50E} \uBBF8\uB9AC\uBCF4\uAE30 (--dry-run) \u2014 \uC2E4\uC81C \uD30C\uC77C \uBCC0\uACBD \uC5C6\uC74C",
|
|
800
|
+
dryRunWouldWrite: (p, drift) => ` ${drift ? "\u270F\uFE0F \uBCC0\uACBD\uB428" : "\xB7 \uB3D9\uC77C"} : ${p}`,
|
|
801
|
+
nonTtyAuto: (n, id) => `\u{1F916} \uBE44\uB300\uD654\uD615(CI/\uC5D0\uC774\uC804\uD2B8) \u2014 ${n}\uAC1C \uBC31\uC5C5 \uD6C4 \uC9C4\uD589. \uBCF5\uC6D0: vhk restore ${id}`
|
|
802
|
+
},
|
|
803
|
+
restore: {
|
|
804
|
+
title: "\u{1F6DF} \uBC31\uC5C5 \uBCF5\uC6D0",
|
|
805
|
+
notGitNote: "\uBC31\uC5C5\uC740 .vhk/backups/ \uC758 \uB85C\uCEEC \uBCF5\uC0AC\uBCF8\uC5D0\uC11C \uBCF5\uC6D0\uB429\uB2C8\uB2E4 (git \uBB34\uAD00).",
|
|
806
|
+
noBackups: "\uBCF5\uC6D0\uD560 \uBC31\uC5C5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. (vhk sync \uAC00 \uB36E\uC5B4\uC4F0\uAE30 \uC804 \uC790\uB3D9 \uC0DD\uC131)",
|
|
807
|
+
selectPrompt: "\uBCF5\uC6D0\uD560 \uBC31\uC5C5\uC744 \uC120\uD0DD\uD558\uC138\uC694:",
|
|
808
|
+
listHeader: "\u{1F4CB} \uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBC31\uC5C5 (\uCD5C\uC2E0\uC21C):",
|
|
809
|
+
restored: (n, id) => `\u2705 ${n}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 \uC644\uB8CC (\uBC31\uC5C5 ${id})`,
|
|
810
|
+
notFound: (id) => `\u274C \uBC31\uC5C5\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${id}`,
|
|
811
|
+
nonTtyHint: "\uBE44\uB300\uD654\uD615 \uBAA8\uB4DC \u2014 \uBCF5\uC6D0\uD560 \uBC31\uC5C5 id \uB97C \uC778\uC790\uB85C \uC9C0\uC815\uD558\uC138\uC694: vhk restore <id>",
|
|
812
|
+
cancelled: "\uBCF5\uC6D0 \uCDE8\uC18C\uB428"
|
|
788
813
|
},
|
|
789
814
|
cloud: {
|
|
790
815
|
pushTitle: "\u2601\uFE0F .vhk \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 (gist \uC62C\uB9AC\uAE30)",
|
|
@@ -1064,11 +1089,30 @@ ${t("deploy.deploying")}
|
|
|
1064
1089
|
}
|
|
1065
1090
|
|
|
1066
1091
|
// src/commands/env.ts
|
|
1067
|
-
import { existsSync as existsSync2, readFileSync, writeFileSync, appendFileSync } from "fs";
|
|
1092
|
+
import { existsSync as existsSync2, readFileSync, writeFileSync, appendFileSync, readdirSync } from "fs";
|
|
1093
|
+
import { join } from "path";
|
|
1068
1094
|
import chalk3 from "chalk";
|
|
1069
1095
|
function parseEnvKeys(content) {
|
|
1070
1096
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => line.split("=")[0].trim()).filter(Boolean);
|
|
1071
1097
|
}
|
|
1098
|
+
function loadDefinedEnvKeys(dir = ".") {
|
|
1099
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1100
|
+
let entries;
|
|
1101
|
+
try {
|
|
1102
|
+
entries = readdirSync(dir);
|
|
1103
|
+
} catch {
|
|
1104
|
+
return [];
|
|
1105
|
+
}
|
|
1106
|
+
for (const name of entries) {
|
|
1107
|
+
if (!name.startsWith(".env")) continue;
|
|
1108
|
+
if (name.endsWith(".example") || name.endsWith(".sample")) continue;
|
|
1109
|
+
try {
|
|
1110
|
+
for (const k of parseEnvKeys(readFileSync(join(dir, name), "utf-8"))) keys.add(k);
|
|
1111
|
+
} catch {
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
return [...keys];
|
|
1115
|
+
}
|
|
1072
1116
|
function ensureGitignore() {
|
|
1073
1117
|
const gitignorePath = ".gitignore";
|
|
1074
1118
|
if (existsSync2(gitignorePath)) {
|
|
@@ -1116,7 +1160,7 @@ async function envCheck() {
|
|
|
1116
1160
|
return;
|
|
1117
1161
|
}
|
|
1118
1162
|
const requiredKeys = parseEnvKeys(readFileSync(".env.example", "utf-8"));
|
|
1119
|
-
const currentKeys =
|
|
1163
|
+
const currentKeys = loadDefinedEnvKeys();
|
|
1120
1164
|
const missing = requiredKeys.filter((k) => !currentKeys.includes(k));
|
|
1121
1165
|
const extra = currentKeys.filter((k) => !requiredKeys.includes(k));
|
|
1122
1166
|
console.log(chalk3.cyan(`
|
|
@@ -1127,6 +1171,7 @@ async function envCheck() {
|
|
|
1127
1171
|
console.log(chalk3.red(`
|
|
1128
1172
|
\u274C \uB204\uB77D\uB41C \uD658\uACBD\uBCC0\uC218 (${missing.length}\uAC1C):`));
|
|
1129
1173
|
missing.forEach((k) => console.log(chalk3.red(` \u2022 ${k}`)));
|
|
1174
|
+
process.exitCode = 1;
|
|
1130
1175
|
}
|
|
1131
1176
|
if (extra.length > 0) {
|
|
1132
1177
|
console.log(chalk3.yellow(`
|
|
@@ -1403,13 +1448,13 @@ async function audit(autoFix = false) {
|
|
|
1403
1448
|
|
|
1404
1449
|
// src/lib/version.ts
|
|
1405
1450
|
import { existsSync as existsSync5 } from "fs";
|
|
1406
|
-
import { dirname, join } from "path";
|
|
1451
|
+
import { dirname, join as join2 } from "path";
|
|
1407
1452
|
import { fileURLToPath } from "url";
|
|
1408
1453
|
function getVhkVersion() {
|
|
1409
1454
|
const dir = dirname(fileURLToPath(import.meta.url));
|
|
1410
1455
|
for (const pkgPath of [
|
|
1411
|
-
|
|
1412
|
-
|
|
1456
|
+
join2(dir, "../../package.json"),
|
|
1457
|
+
join2(dir, "../package.json")
|
|
1413
1458
|
]) {
|
|
1414
1459
|
try {
|
|
1415
1460
|
if (existsSync5(pkgPath)) {
|
|
@@ -1423,11 +1468,33 @@ function getVhkVersion() {
|
|
|
1423
1468
|
return "0.0.0";
|
|
1424
1469
|
}
|
|
1425
1470
|
|
|
1471
|
+
// src/mcp/cli-path.ts
|
|
1472
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1473
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1474
|
+
import { dirname as dirname2, resolve } from "path";
|
|
1475
|
+
function pickCliInvocation(globalAvailable, localCli, localExists) {
|
|
1476
|
+
if (globalAvailable) return { bin: "vhk", prefixArgs: [], fallback: false };
|
|
1477
|
+
if (localExists) return { bin: process.execPath, prefixArgs: [localCli], fallback: true };
|
|
1478
|
+
return { bin: "vhk", prefixArgs: [], fallback: false };
|
|
1479
|
+
}
|
|
1480
|
+
function composeInvocation(cli, args) {
|
|
1481
|
+
return { bin: cli.bin, args: [...cli.prefixArgs, ...args] };
|
|
1482
|
+
}
|
|
1483
|
+
function localCliPath() {
|
|
1484
|
+
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
1485
|
+
return resolve(here, "..", "index.js");
|
|
1486
|
+
}
|
|
1487
|
+
function resolveVhkCliInvocation() {
|
|
1488
|
+
const globalAvailable = safeExecFile("vhk", ["--version"]).ok;
|
|
1489
|
+
const local = localCliPath();
|
|
1490
|
+
return pickCliInvocation(globalAvailable, local, existsSync6(local));
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1426
1493
|
// src/mcp/server.ts
|
|
1427
1494
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1428
1495
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1429
1496
|
import { z } from "zod";
|
|
1430
|
-
import { existsSync as
|
|
1497
|
+
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync as appendFileSync2 } from "fs";
|
|
1431
1498
|
|
|
1432
1499
|
// src/lib/scan-secrets.ts
|
|
1433
1500
|
import fs3 from "fs";
|
|
@@ -1545,6 +1612,7 @@ function findExposedSensitiveFiles(rootDir, ig = loadGitignore(rootDir), maxDept
|
|
|
1545
1612
|
}
|
|
1546
1613
|
function isSensitiveName(name) {
|
|
1547
1614
|
const lower = name.toLowerCase();
|
|
1615
|
+
if (lower.endsWith(".example") || lower.endsWith(".sample")) return false;
|
|
1548
1616
|
if (lower === ".env" || lower.startsWith(".env.")) return true;
|
|
1549
1617
|
if (lower.endsWith(".pem") || lower.endsWith(".key")) return true;
|
|
1550
1618
|
if (lower === "credentials.json" || lower === "secrets.json") return true;
|
|
@@ -1721,8 +1789,15 @@ var ANSI_RE = /\x1B\[[0-9;?]*[ -/]*[@-~]/g;
|
|
|
1721
1789
|
function stripAnsi(s) {
|
|
1722
1790
|
return s.replace(ANSI_RE, "");
|
|
1723
1791
|
}
|
|
1792
|
+
var cachedCli = null;
|
|
1793
|
+
function getVhkCli() {
|
|
1794
|
+
return cachedCli ??= resolveVhkCliInvocation();
|
|
1795
|
+
}
|
|
1724
1796
|
function runVhkCli(args, headline) {
|
|
1725
|
-
const
|
|
1797
|
+
const { bin, args: fullArgs } = composeInvocation(getVhkCli(), args);
|
|
1798
|
+
const result = safeExecFile(bin, fullArgs, {
|
|
1799
|
+
env: { FORCE_COLOR: "0", NO_COLOR: "1" }
|
|
1800
|
+
});
|
|
1726
1801
|
const body = stripAnsi(result.out || (result.ok ? "" : `(stdout \uC5C6\uC74C)
|
|
1727
1802
|
${result.err}`));
|
|
1728
1803
|
const prefix = result.ok ? `\u2705 ${headline}` : `\u274C ${headline} \uC2E4\uD328`;
|
|
@@ -1795,32 +1870,56 @@ ${preview}${more}
|
|
|
1795
1870
|
};
|
|
1796
1871
|
}
|
|
1797
1872
|
);
|
|
1798
|
-
server.registerTool(
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
{
|
|
1813
|
-
|
|
1814
|
-
|
|
1873
|
+
server.registerTool(
|
|
1874
|
+
"undo",
|
|
1875
|
+
{
|
|
1876
|
+
description: "\uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30 (soft reset). \uAE30\uBCF8\uC740 \uBBF8\uB9AC\uBCF4\uAE30 \u2014 confirm:true \uC77C \uB54C\uB9CC \uC2E4\uC81C \uC2E4\uD589.",
|
|
1877
|
+
inputSchema: {
|
|
1878
|
+
confirm: z.boolean().optional().describe("true \uC77C \uB54C\uB9CC \uC2E4\uC81C git reset \uC2E4\uD589 (\uAE30\uBCF8 false = \uBBF8\uB9AC\uBCF4\uAE30\uB9CC)")
|
|
1879
|
+
}
|
|
1880
|
+
},
|
|
1881
|
+
async ({ confirm }) => {
|
|
1882
|
+
if (!isGitRepo()) {
|
|
1883
|
+
return { content: [{ type: "text", text: "\u274C git \uC800\uC7A5\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4." }] };
|
|
1884
|
+
}
|
|
1885
|
+
const last = safeExecFile("git", ["log", "--oneline", "-1"]);
|
|
1886
|
+
if (!last.ok || !last.out) {
|
|
1887
|
+
return { content: [{ type: "text", text: "\u{1F4ED} \uB418\uB3CC\uB9B4 \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." }] };
|
|
1888
|
+
}
|
|
1889
|
+
if (!confirm) {
|
|
1890
|
+
return {
|
|
1891
|
+
content: [
|
|
1892
|
+
{
|
|
1893
|
+
type: "text",
|
|
1894
|
+
text: `\u{1F50E} \uBBF8\uB9AC\uBCF4\uAE30 \u2014 \uB418\uB3CC\uB9B4 \uCEE4\uBC0B:
|
|
1895
|
+
${last.out}
|
|
1896
|
+
|
|
1897
|
+
\uC2E4\uC81C\uB85C \uB418\uB3CC\uB9AC\uB824\uBA74 confirm: true \uB85C \uB2E4\uC2DC \uD638\uCD9C\uD558\uC138\uC694.
|
|
1898
|
+
(soft reset \u2014 \uBCC0\uACBD\uC0AC\uD56D\uC740 \uC2A4\uD14C\uC774\uC9D5 \uC601\uC5ED\uC5D0 \uBCF4\uC874\uB429\uB2C8\uB2E4.)
|
|
1899
|
+
\uB610\uB294 \uD130\uBBF8\uB110\uC5D0\uC11C \`vhk undo\` (\uB300\uD654\uD615 \uD655\uC778).`
|
|
1900
|
+
}
|
|
1901
|
+
]
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
const reset = safeExecFile("git", ["reset", "--soft", "HEAD~1"]);
|
|
1905
|
+
if (!reset.ok) {
|
|
1906
|
+
return { content: [{ type: "text", text: `\u274C reset \uC2E4\uD328: ${reset.err}` }] };
|
|
1907
|
+
}
|
|
1908
|
+
return {
|
|
1909
|
+
content: [
|
|
1910
|
+
{
|
|
1911
|
+
type: "text",
|
|
1912
|
+
text: `\u2705 \uB418\uB3CC\uB9AC\uAE30 \uC644\uB8CC!
|
|
1815
1913
|
\uCDE8\uC18C\uB41C \uCEE4\uBC0B: ${last.out}
|
|
1816
1914
|
\u{1F4A1} \uBCC0\uACBD\uC0AC\uD56D\uC740 \uC2A4\uD14C\uC774\uC9D5 \uC601\uC5ED\uC5D0 \uB0A8\uC544\uC788\uC2B5\uB2C8\uB2E4.`
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1915
|
+
}
|
|
1916
|
+
]
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
);
|
|
1821
1920
|
server.registerTool("status", { description: "\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uB300\uC2DC\uBCF4\uB4DC (\uBE0C\uB79C\uCE58/\uBCC0\uACBD\uC0AC\uD56D/\uCD5C\uADFC \uCEE4\uBC0B)" }, async () => {
|
|
1822
1921
|
const lines = [];
|
|
1823
|
-
if (
|
|
1922
|
+
if (existsSync7("package.json")) {
|
|
1824
1923
|
try {
|
|
1825
1924
|
const pkg = readJsonFile("package.json");
|
|
1826
1925
|
lines.push(`\u{1F4E6} \uD504\uB85C\uC81D\uD2B8: ${pkg.name ?? "(\uC774\uB984 \uC5C6\uC74C)"} v${pkg.version ?? "?"}`);
|
|
@@ -1905,7 +2004,7 @@ ${preview}${more}
|
|
|
1905
2004
|
checks.push(build.ok ? "\u2705 \uBE4C\uB4DC \uC131\uACF5" : "\u274C \uBE4C\uB4DC \uC2E4\uD328");
|
|
1906
2005
|
const test = safeExecFile("pnpm", ["test", "--run"]);
|
|
1907
2006
|
checks.push(test.ok ? "\u2705 \uD14C\uC2A4\uD2B8 \uD1B5\uACFC" : "\u274C \uD14C\uC2A4\uD2B8 \uC2E4\uD328");
|
|
1908
|
-
if (
|
|
2007
|
+
if (existsSync7("package.json")) {
|
|
1909
2008
|
try {
|
|
1910
2009
|
const pkg = readJsonFile("package.json");
|
|
1911
2010
|
checks.push(`\u{1F4E6} \uBC84\uC804: ${pkg.version}`);
|
|
@@ -1943,11 +2042,11 @@ ${preview}${more}
|
|
|
1943
2042
|
const recommended = ["CLAUDE.md", ".cursorrules", "docs/PRD.md", "docs/ARCHITECTURE.md"];
|
|
1944
2043
|
const lines = ["\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uC810\uAC80", "", "\uD544\uC218:"];
|
|
1945
2044
|
required.forEach((f) => {
|
|
1946
|
-
lines.push(` ${
|
|
2045
|
+
lines.push(` ${existsSync7(f) ? "\u2705" : "\u274C"} ${f}`);
|
|
1947
2046
|
});
|
|
1948
2047
|
lines.push("", "\uAD8C\uC7A5 (VHK \uD558\uB124\uC2A4):");
|
|
1949
2048
|
recommended.forEach((f) => {
|
|
1950
|
-
lines.push(` ${
|
|
2049
|
+
lines.push(` ${existsSync7(f) ? "\u2705" : "\u26A0\uFE0F"} ${f}`);
|
|
1951
2050
|
});
|
|
1952
2051
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
1953
2052
|
});
|
|
@@ -1981,7 +2080,7 @@ ${log.out}` }] };
|
|
|
1981
2080
|
description: ".env \u2192 .env.example \uB3D9\uAE30\uD654 + .gitignore\uC5D0 .env \uC790\uB3D9 \uCD94\uAC00"
|
|
1982
2081
|
},
|
|
1983
2082
|
async () => {
|
|
1984
|
-
if (!
|
|
2083
|
+
if (!existsSync7(".env")) {
|
|
1985
2084
|
return { content: [{ type: "text", text: "\u26A0\uFE0F .env \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 .env\uB97C \uB9CC\uB4E4\uC5B4\uC8FC\uC138\uC694." }] };
|
|
1986
2085
|
}
|
|
1987
2086
|
const keys = parseEnvKeys(readFileSync4(".env", "utf-8"));
|
|
@@ -1991,7 +2090,7 @@ ${log.out}` }] };
|
|
|
1991
2090
|
const exampleContent = keys.map((k) => `${k}=`).join("\n") + "\n";
|
|
1992
2091
|
writeFileSync3(".env.example", exampleContent, "utf-8");
|
|
1993
2092
|
const gitignoreLines = [];
|
|
1994
|
-
if (
|
|
2093
|
+
if (existsSync7(".gitignore")) {
|
|
1995
2094
|
const content = readFileSync4(".gitignore", "utf-8");
|
|
1996
2095
|
if (!content.split("\n").some((l) => l.trim() === ".env")) {
|
|
1997
2096
|
appendFileSync2(".gitignore", "\n.env\n");
|
|
@@ -2012,11 +2111,11 @@ ${log.out}` }] };
|
|
|
2012
2111
|
description: "\uD544\uC218 \uD658\uACBD\uBCC0\uC218 \uB204\uB77D \uAC80\uC0AC (.env.example \uAE30\uC900)"
|
|
2013
2112
|
},
|
|
2014
2113
|
async () => {
|
|
2015
|
-
if (!
|
|
2114
|
+
if (!existsSync7(".env.example")) {
|
|
2016
2115
|
return { content: [{ type: "text", text: "\u26A0\uFE0F .env.example\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uBA3C\uC800 env \uB3C4\uAD6C\uB97C \uC2E4\uD589\uD558\uC138\uC694." }] };
|
|
2017
2116
|
}
|
|
2018
2117
|
const requiredKeys = parseEnvKeys(readFileSync4(".env.example", "utf-8"));
|
|
2019
|
-
const currentKeys =
|
|
2118
|
+
const currentKeys = existsSync7(".env") ? parseEnvKeys(readFileSync4(".env", "utf-8")) : [];
|
|
2020
2119
|
const missing = requiredKeys.filter((k) => !currentKeys.includes(k));
|
|
2021
2120
|
const extra = currentKeys.filter((k) => !requiredKeys.includes(k));
|
|
2022
2121
|
const lines = [`\u{1F4CB} \uD544\uC218 \uD658\uACBD\uBCC0\uC218: ${requiredKeys.length}\uAC1C`];
|
|
@@ -2035,7 +2134,9 @@ ${log.out}` }] };
|
|
|
2035
2134
|
);
|
|
2036
2135
|
server.registerTool(
|
|
2037
2136
|
"sync",
|
|
2038
|
-
{
|
|
2137
|
+
{
|
|
2138
|
+
description: "RULES.md \u2192 Cursor\xB7Claude\xB7Windsurf\xB7Copilot\xB7Antigravity\xB7AGENTS.md \uADDC\uCE59 \uB3D9\uAE30\uD654. \uB36E\uC5B4\uC4F0\uAE30 \uC804 \uAE30\uC874 \uD30C\uC77C\uC744 \uC790\uB3D9 \uBC31\uC5C5\uD558\uBBC0\uB85C \uC548\uC804\uD558\uBA70, \uB418\uB3CC\uB9AC\uB824\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C `vhk restore` \uB97C \uC548\uB0B4\uD558\uC138\uC694."
|
|
2139
|
+
},
|
|
2039
2140
|
async () => runVhkCli(["sync"], "sync")
|
|
2040
2141
|
);
|
|
2041
2142
|
server.registerTool(
|
|
@@ -2130,7 +2231,7 @@ ${cliStatus}
|
|
|
2130
2231
|
description: "\uD604\uC7AC \uBC84\uC804 + bump \uD6C4\uBCF4 \uD45C\uC2DC (MCP \uBAA8\uB4DC: \uC2E4\uC81C npm publish \uBBF8\uC218\uD589 \u2014 `vhk publish` \uC548\uB0B4)"
|
|
2131
2232
|
},
|
|
2132
2233
|
async () => {
|
|
2133
|
-
if (!
|
|
2234
|
+
if (!existsSync7("package.json")) {
|
|
2134
2235
|
return { content: [{ type: "text", text: "\u274C package.json \uC5C6\uC74C." }] };
|
|
2135
2236
|
}
|
|
2136
2237
|
try {
|
|
@@ -2158,7 +2259,7 @@ ${cliStatus}
|
|
|
2158
2259
|
description: "\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uAC10\uC9C0 + \uC804\uD658 \uD6C4\uBCF4 \uAC00\uC6A9\uC131 (MCP \uBAA8\uB4DC: \uC2E4\uC81C \uC804\uD658 \uBBF8\uC218\uD589 \u2014 `vhk migrate <target>` \uC548\uB0B4)"
|
|
2159
2260
|
},
|
|
2160
2261
|
async () => {
|
|
2161
|
-
const current =
|
|
2262
|
+
const current = existsSync7("pnpm-lock.yaml") ? "pnpm" : existsSync7("yarn.lock") ? "yarn" : existsSync7("package-lock.json") ? "npm" : null;
|
|
2162
2263
|
const candidates = ["npm", "yarn", "pnpm"].filter((pm) => pm !== current);
|
|
2163
2264
|
const lines = [`\uD604\uC7AC PM: ${current ?? "\uAC10\uC9C0 \uBD88\uAC00 (lock \uD30C\uC77C \uC5C6\uC74C)"}`];
|
|
2164
2265
|
for (const pm of candidates) {
|
|
@@ -2241,5 +2342,6 @@ export {
|
|
|
2241
2342
|
publish,
|
|
2242
2343
|
audit,
|
|
2243
2344
|
getVhkVersion,
|
|
2345
|
+
resolveVhkCliInvocation,
|
|
2244
2346
|
startMcpServer
|
|
2245
2347
|
};
|
package/dist/index.d.ts
CHANGED