@byh3071/vhk 1.3.0 β 1.3.1
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 +54 -21
- package/dist/{chunk-3HGOQLRT.js β chunk-6S3JYYZ3.js} +56 -17
- package/dist/index.js +78 -45
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,57 +1,90 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: vhk-readme
|
|
3
|
-
date: 2026-05-
|
|
4
|
-
tags: [vhk, cli, readme, v1.
|
|
3
|
+
date: 2026-05-28
|
|
4
|
+
tags: [vhk, cli, readme, v1.3.0, ga]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# π§ VHK β Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> π **v1.
|
|
9
|
+
> π **v1.3.0** β λ°μ΄λΈμ½λμ μ¬μΈμ CLI. 컨ν
μ€νΈ + μμ¨ νλ€μ€.
|
|
10
10
|
>
|
|
11
|
-
> AI μ½λ© μμ΄μ νΈλ₯Ό λΆλ¦¬λ μ¬λμ μν **νκ΅μ΄ νμ¬μ΄ν΄ CLI
|
|
11
|
+
> AI μ½λ© μμ΄μ νΈλ₯Ό λΆλ¦¬λ μ¬λμ μν **νκ΅μ΄ νμ¬μ΄ν΄ CLI**.
|
|
12
12
|
>
|
|
13
13
|
> π½οΈ **VHKλ VHKλ‘ λΆνΈμ€νΈλ©λ¨** β μ΄ λ ν¬μ `docs/`, `CLAUDE.md`, `.cursorrules`λ `vhk init`μ΄ λ§λ€μμ΅λλ€.
|
|
14
14
|
|
|
15
15
|
λͺ
λ Ήμ΄λ₯Ό μΈμ°μ§ μμλ λ©λλ€. `vhk`λ§ μΉλ©΄ λ©λ΄κ° λμ€κ³ , νκ΅μ΄λ‘ λ§ν΄λ μμλ£μ΅λλ€.
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## 3λΆ μμ μμνκΈ° (Getting Started)
|
|
18
|
+
|
|
19
|
+
### 1. μ€μΉ
|
|
18
20
|
|
|
19
21
|
```bash
|
|
20
22
|
npm install -g @byh3071/vhk
|
|
23
|
+
vhk --version
|
|
21
24
|
```
|
|
22
25
|
|
|
26
|
+
> Node.js β₯ 20 νμ. `npx @byh3071/vhk` λ‘ 1νμ± μ€νλ κ°λ₯.
|
|
27
|
+
|
|
28
|
+
### 2. 첫 νλ‘μ νΈ β `vhk start` (λ§λ²μ¬)
|
|
29
|
+
|
|
23
30
|
```bash
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
mkdir my-app && cd my-app
|
|
32
|
+
vhk start
|
|
26
33
|
```
|
|
27
34
|
|
|
28
|
-
|
|
35
|
+
`vhk start` ν λ²μ΄λ©΄ **git init β λ¬Έμ μμ± β MCP λ±λ‘ β 컨ν
μ€νΈ νμΌ** κΉμ§ μλμΌλ‘ λλ©λλ€.
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
pnpm link --global
|
|
35
|
-
vhk --version
|
|
37
|
+
κΈ°νμ΄ λ§ λ μ¬λλ€λ©΄ κ²μ¦λΆν°:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
vhk gate # ν΅ 5λ¬Έν β GO / λ€λ¬κΈ° / λ€λ₯Έ μμ΄λμ΄
|
|
36
41
|
```
|
|
37
42
|
|
|
38
|
-
|
|
43
|
+
### 3. v1.3 ν΅μ¬ κΈ°λ₯ νλμ
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
| κΈ°λ₯ | ν μ€ μμ½ | μ§μ
λͺ
λ Ή |
|
|
46
|
+
|------|-----------|-----------|
|
|
47
|
+
| π― **Goals 체κ³** | λ¨κ³λ³ λ―Έμ
+ κ²μ΄νΈ μ€ν¬λ¦½νΈλ‘ AIκ° λͺ©νλ₯Ό μ€μ€λ‘ μΆμ | `vhk goal init` |
|
|
48
|
+
| βΆοΈ **μμ¨ λ£¨ν** | `goal next β μμ
β goal check β goal done`. FAIL 3νλ©΄ μλ λΈλ‘컀 | `vhk goal next` |
|
|
49
|
+
| π§ **HARD_STOP μμ μ₯μΉ** | λΈλ‘컀 3건 λμ β `.vhk/HARD_STOP` νΈλ¦½μμ΄μ΄. `vhk resume --confirm` λ§ ν΄μ | `vhk blocker "<μ¦μ>"` |
|
|
50
|
+
| π **MCP 24 tool** | CursorΒ·Claude Desktop λ±μμ vhkλ₯Ό μ±ν
μΌλ‘ νΈμΆ | `vhk mcp-init` |
|
|
51
|
+
| π **컨ν
μ€νΈ μμν** | `.vhk/context.md` + `memory.json` + `brief.md` λ‘ μΈμ
κ° λ§₯λ½ μ μ§ | `vhk context` |
|
|
52
|
+
|
|
53
|
+
### 4. κΆμ₯ μΌμΌ μ¬μ΄ν΄
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
μΈμ
μμ : vhk context # AIμ μ€ νλ‘μ νΈ λ§₯λ½ κ°±μ
|
|
57
|
+
vhk goal next # μ€λ μμ
ν λ―Έμ
μλ μ ν
|
|
58
|
+
|
|
59
|
+
κ°λ° ...
|
|
60
|
+
|
|
61
|
+
μΈμ
μ’
λ£ : vhk goal check # κ²μ΄νΈ μ€ν¬λ¦½νΈλ‘ ν΅κ³Ό κ²μ¦
|
|
62
|
+
vhk goal done # ν΅κ³Ό μ status: DONE μΌλ‘ μ μ΄
|
|
63
|
+
vhk save # add β commit β push ν λ²μ
|
|
64
|
+
vhk recap # docs/log/ μ μ€λ κΈ°λ‘
|
|
42
65
|
```
|
|
43
66
|
|
|
44
|
-
|
|
67
|
+
### 5. μμ°μ΄λ‘λ λ©λλ€
|
|
45
68
|
|
|
46
69
|
```bash
|
|
47
|
-
# μμ°μ΄λ‘λ κ°λ₯
|
|
48
70
|
vhk νλ‘μ νΈ λ§λ€κ³ μΆμ΄
|
|
49
71
|
vhk κΈ°ν λλ¬κ³ λ°λ‘ μμ
|
|
50
72
|
vhk μ€λ ν μΌ μ 리
|
|
51
73
|
vhk μ μ₯ν΄μ€
|
|
52
|
-
vhk
|
|
74
|
+
vhk λ€μ λͺ©ν
|
|
75
|
+
vhk λΈλ‘컀 "API νΈμΆ μ€ν¨"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## λΉ λ₯Έ μμ (μΈν°λν°λΈ λ©λ΄)
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
vhk
|
|
53
84
|
```
|
|
54
85
|
|
|
86
|
+
μΈμ μμ΄ μ€ννλ©΄ **γλ λμλ릴κΉμ?γ** λ©λ΄κ° μ΄λ¦½λλ€.
|
|
87
|
+
|
|
55
88
|
## μν¬νλ‘μ° (κΆμ₯ μμ)
|
|
56
89
|
|
|
57
90
|
```text
|
|
@@ -265,7 +298,7 @@ vhk ref open 1 # 1λ² λ νΌλ°μ€λ₯Ό λΈλΌμ°μ λ‘ μ΄κΈ°
|
|
|
265
298
|
|
|
266
299
|
| κΈ°λ₯ | μ€λͺ
|
|
|
267
300
|
|------|------|
|
|
268
|
-
| **MCP μλ²** | `vhk mcp` β 8κ° λꡬ
|
|
301
|
+
| **MCP μλ²** | `vhk mcp` β stdio MCP μλ² μ²« λμ
(v0.6.0 λΉμ 8κ° λꡬ β save/undo/status/diff/ship/doctor/check/recap). νμ¬ v1.3 κΈ°μ€ **24κ°** λ‘ νμ₯ β μ "Cursorμ MCPλ‘ μ°λνκΈ°" μΉμ
μ°Έμ‘° |
|
|
269
302
|
| **mcp-init** | `vhk mcp-init` β Cursor `.cursor/mcp.json` μλ μμ±. μ¬μμ ν λ²μΌλ‘ μ°λ μλ£ |
|
|
270
303
|
| **μμ°μ΄ λΌμ°ν
νμ₯** | `vhk mcpμ€μ ` β `vhk mcp-init` λ³μΉ |
|
|
271
304
|
| **보μ** | MCP save λꡬμ shell injection μ°¨λ¨ β λͺ¨λ git νΈμΆμ `execFileSync` μ¬μ© |
|
|
@@ -551,7 +551,11 @@ var ko = {
|
|
|
551
551
|
package: "package.json:",
|
|
552
552
|
noPackage: "package.json \uC5C6\uC74C",
|
|
553
553
|
detached: "(detached HEAD)",
|
|
554
|
-
unknownBranch: "(\uC54C \uC218 \uC5C6\uC74C)"
|
|
554
|
+
unknownBranch: "(\uC54C \uC218 \uC5C6\uC74C)",
|
|
555
|
+
nextWithChangesMessage: "\uBCC0\uACBD\uC0AC\uD56D\uC774 \uC788\uC5B4\uC694. \uCEE4\uBC0B\xB7\uD478\uC2DC\uB97C \uC9C4\uD589\uD558\uC138\uC694.",
|
|
556
|
+
nextWithChangesCursor: "\uC800\uC7A5\uD574\uC918",
|
|
557
|
+
nextCleanMessage: "\uD074\uB9B0 \uC0C1\uD0DC! \uB2E4\uC74C \uBBF8\uC158\uC73C\uB85C \uB118\uC5B4\uAC00\uC138\uC694.",
|
|
558
|
+
nextCleanCursor: "\uB2E4\uC74C \uBAA9\uD45C \uC54C\uB824\uC918"
|
|
555
559
|
},
|
|
556
560
|
save: {
|
|
557
561
|
title: "\uC800\uC7A5\uD558\uAE30",
|
|
@@ -573,7 +577,11 @@ var ko = {
|
|
|
573
577
|
pushFailed: "push \uC2E4\uD328 (\uB85C\uCEEC \uCEE4\uBC0B\uC740 \uC644\uB8CC\uB428)",
|
|
574
578
|
commitOkPushFailed: "\uB85C\uCEEC \uCEE4\uBC0B\uC740 \uB410\uC9C0\uB9CC \uC6D0\uACA9 push\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. git push\uB97C \uC9C1\uC811 \uD655\uC778\uD558\uC138\uC694.",
|
|
575
579
|
done: (n) => `${n}\uAC1C \uD30C\uC77C \uC800\uC7A5 \uC644\uB8CC!`,
|
|
576
|
-
doneLocalOnly: (n) => `${n}\uAC1C \uD30C\uC77C \uB85C\uCEEC \uC800\uC7A5\uB428 (push\uB294 \uC2E4\uD328)
|
|
580
|
+
doneLocalOnly: (n) => `${n}\uAC1C \uD30C\uC77C \uB85C\uCEEC \uC800\uC7A5\uB428 (push\uB294 \uC2E4\uD328)`,
|
|
581
|
+
nextOkMessage: "\uC800\uC7A5 \uC644\uB8CC! \uC624\uB298 \uC791\uC5C5\uC744 \uC815\uB9AC\uD574\uB450\uBA74 \uC88B\uC544\uC694.",
|
|
582
|
+
nextOkCursor: "\uC624\uB298 \uD55C \uC77C \uC815\uB9AC\uD574\uC918",
|
|
583
|
+
nextPushFailMessage: "\uCEE4\uBC0B\uC740 \uB410\uC9C0\uB9CC push \uC2E4\uD328. \uC6D0\uACA9\uC744 \uD655\uC778\uD558\uC138\uC694.",
|
|
584
|
+
nextPushFailCursor: "\uC65C push \uC2E4\uD328\uC778\uC9C0 \uC54C\uB824\uC918"
|
|
577
585
|
},
|
|
578
586
|
undo: {
|
|
579
587
|
title: "\uB418\uB3CC\uB9AC\uAE30",
|
|
@@ -590,7 +598,9 @@ var ko = {
|
|
|
590
598
|
stagedHint: "\uBCC0\uACBD\uC0AC\uD56D\uC740 \uC2A4\uD14C\uC774\uC9D5 \uC601\uC5ED\uC5D0 \uB0A8\uC544 \uC788\uC5B4\uC694.",
|
|
591
599
|
rootCommit: "\uCCAB \uCEE4\uBC0B\uB9CC \uC788\uC5B4\uC11C \uB354 \uB418\uB3CC\uB9B4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
592
600
|
forcePushHint: "\uC6D0\uACA9\uACFC \uB9DE\uCD94\uB824\uBA74: git push --force-with-lease (\uD63C\uC790 \uC791\uC5C5\uD55C \uBE0C\uB79C\uCE58\uC5D0\uC11C\uB9CC, \uD300\uACFC \uD569\uC758 \uD6C4)",
|
|
593
|
-
failed: "\uB418\uB3CC\uB9AC\uAE30 \uC2E4\uD328"
|
|
601
|
+
failed: "\uB418\uB3CC\uB9AC\uAE30 \uC2E4\uD328",
|
|
602
|
+
nextMessage: "\uBCC0\uACBD\uC0AC\uD56D\uC774 \uC2A4\uD14C\uC774\uC9D5 \uC601\uC5ED\uC5D0 \uB0A8\uC558\uC5B4\uC694. \uBA54\uC2DC\uC9C0 \uACE0\uCCD0\uC11C \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694.",
|
|
603
|
+
nextCursor: "\uCEE4\uBC0B \uBA54\uC2DC\uC9C0 \uBC14\uAFD4\uC11C \uC800\uC7A5\uD574\uC918"
|
|
594
604
|
},
|
|
595
605
|
diff: {
|
|
596
606
|
title: "\uBCC0\uACBD\uC0AC\uD56D \uD655\uC778",
|
|
@@ -799,7 +809,9 @@ var ko = {
|
|
|
799
809
|
},
|
|
800
810
|
mcp: {
|
|
801
811
|
initTitle: "Cursor MCP \uC5F0\uB3D9 \uC124\uC815",
|
|
802
|
-
serverStarted: "VHK MCP \uC11C\uBC84 \uC2DC\uC791\uB428"
|
|
812
|
+
serverStarted: "VHK MCP \uC11C\uBC84 \uC2DC\uC791\uB428",
|
|
813
|
+
nextMessage: "Cursor / Claude Desktop \uC744 \uC7AC\uC2DC\uC791\uD55C \uB4A4 \uCC44\uD305\uC5D0\uC11C vhk \uB3C4\uAD6C\uB97C \uD638\uCD9C\uD558\uC138\uC694.",
|
|
814
|
+
nextCursor: "\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uC54C\uB824\uC918"
|
|
803
815
|
},
|
|
804
816
|
deploy: {
|
|
805
817
|
title: "\uBC30\uD3EC\uD558\uAE30",
|
|
@@ -836,7 +848,11 @@ var ko = {
|
|
|
836
848
|
selectTarget: "\uC5B4\uB5A4 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB85C \uC804\uD658\uD560\uAE4C\uC694?"
|
|
837
849
|
},
|
|
838
850
|
update: {
|
|
839
|
-
title: "VHK CLI \uC5C5\uB370\uC774\uD2B8"
|
|
851
|
+
title: "VHK CLI \uC5C5\uB370\uC774\uD2B8",
|
|
852
|
+
nextOkMessage: "\uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC! \uC0C8 \uBC84\uC804 \uD655\uC778\uD558\uC138\uC694.",
|
|
853
|
+
nextOkCursor: "vhk \uBC84\uC804 \uC54C\uB824\uC918",
|
|
854
|
+
nextFailMessage: "\uC5C5\uB370\uC774\uD2B8 \uC2E4\uD328. \uD658\uACBD \uC810\uAC80\uBD80\uD130 \uD574\uBCF4\uC138\uC694.",
|
|
855
|
+
nextFailCursor: "vhk doctor \uC2E4\uD589\uD574\uC918"
|
|
840
856
|
},
|
|
841
857
|
context: {
|
|
842
858
|
title: "\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131",
|
|
@@ -1300,11 +1316,33 @@ async function audit(autoFix = false) {
|
|
|
1300
1316
|
});
|
|
1301
1317
|
}
|
|
1302
1318
|
|
|
1319
|
+
// src/lib/version.ts
|
|
1320
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1321
|
+
import { dirname, join } from "path";
|
|
1322
|
+
import { fileURLToPath } from "url";
|
|
1323
|
+
function getVhkVersion() {
|
|
1324
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
1325
|
+
for (const pkgPath of [
|
|
1326
|
+
join(dir, "../../package.json"),
|
|
1327
|
+
join(dir, "../package.json")
|
|
1328
|
+
]) {
|
|
1329
|
+
try {
|
|
1330
|
+
if (existsSync5(pkgPath)) {
|
|
1331
|
+
const pkg = readJsonFile(pkgPath);
|
|
1332
|
+
if (pkg.version) return pkg.version;
|
|
1333
|
+
}
|
|
1334
|
+
} catch {
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return "0.0.0";
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1303
1341
|
// src/mcp/server.ts
|
|
1304
1342
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1305
1343
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1306
1344
|
import { z } from "zod";
|
|
1307
|
-
import { existsSync as
|
|
1345
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3, appendFileSync as appendFileSync2 } from "fs";
|
|
1308
1346
|
|
|
1309
1347
|
// src/lib/scan-secrets.ts
|
|
1310
1348
|
import fs3 from "fs";
|
|
@@ -1590,7 +1628,7 @@ function filterSevereFindings(findings) {
|
|
|
1590
1628
|
}
|
|
1591
1629
|
|
|
1592
1630
|
// src/mcp/server.ts
|
|
1593
|
-
var SERVER_VERSION =
|
|
1631
|
+
var SERVER_VERSION = getVhkVersion();
|
|
1594
1632
|
function isGitRepo() {
|
|
1595
1633
|
return safeExecFile("git", ["rev-parse", "--is-inside-work-tree"]).ok;
|
|
1596
1634
|
}
|
|
@@ -1697,7 +1735,7 @@ ${preview}${more}
|
|
|
1697
1735
|
});
|
|
1698
1736
|
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 () => {
|
|
1699
1737
|
const lines = [];
|
|
1700
|
-
if (
|
|
1738
|
+
if (existsSync6("package.json")) {
|
|
1701
1739
|
try {
|
|
1702
1740
|
const pkg = readJsonFile("package.json");
|
|
1703
1741
|
lines.push(`\u{1F4E6} \uD504\uB85C\uC81D\uD2B8: ${pkg.name ?? "(\uC774\uB984 \uC5C6\uC74C)"} v${pkg.version ?? "?"}`);
|
|
@@ -1782,7 +1820,7 @@ ${preview}${more}
|
|
|
1782
1820
|
checks.push(build.ok ? "\u2705 \uBE4C\uB4DC \uC131\uACF5" : "\u274C \uBE4C\uB4DC \uC2E4\uD328");
|
|
1783
1821
|
const test = safeExecFile("pnpm", ["test", "--run"]);
|
|
1784
1822
|
checks.push(test.ok ? "\u2705 \uD14C\uC2A4\uD2B8 \uD1B5\uACFC" : "\u274C \uD14C\uC2A4\uD2B8 \uC2E4\uD328");
|
|
1785
|
-
if (
|
|
1823
|
+
if (existsSync6("package.json")) {
|
|
1786
1824
|
try {
|
|
1787
1825
|
const pkg = readJsonFile("package.json");
|
|
1788
1826
|
checks.push(`\u{1F4E6} \uBC84\uC804: ${pkg.version}`);
|
|
@@ -1820,11 +1858,11 @@ ${preview}${more}
|
|
|
1820
1858
|
const recommended = ["CLAUDE.md", ".cursorrules", "docs/PRD.md", "docs/ARCHITECTURE.md"];
|
|
1821
1859
|
const lines = ["\u{1F50D} \uD504\uB85C\uC81D\uD2B8 \uC810\uAC80", "", "\uD544\uC218:"];
|
|
1822
1860
|
required.forEach((f) => {
|
|
1823
|
-
lines.push(` ${
|
|
1861
|
+
lines.push(` ${existsSync6(f) ? "\u2705" : "\u274C"} ${f}`);
|
|
1824
1862
|
});
|
|
1825
1863
|
lines.push("", "\uAD8C\uC7A5 (VHK \uD558\uB124\uC2A4):");
|
|
1826
1864
|
recommended.forEach((f) => {
|
|
1827
|
-
lines.push(` ${
|
|
1865
|
+
lines.push(` ${existsSync6(f) ? "\u2705" : "\u26A0\uFE0F"} ${f}`);
|
|
1828
1866
|
});
|
|
1829
1867
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
1830
1868
|
});
|
|
@@ -1858,7 +1896,7 @@ ${log.out}` }] };
|
|
|
1858
1896
|
description: ".env \u2192 .env.example \uB3D9\uAE30\uD654 + .gitignore\uC5D0 .env \uC790\uB3D9 \uCD94\uAC00"
|
|
1859
1897
|
},
|
|
1860
1898
|
async () => {
|
|
1861
|
-
if (!
|
|
1899
|
+
if (!existsSync6(".env")) {
|
|
1862
1900
|
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." }] };
|
|
1863
1901
|
}
|
|
1864
1902
|
const keys = parseEnvKeys(readFileSync4(".env", "utf-8"));
|
|
@@ -1868,7 +1906,7 @@ ${log.out}` }] };
|
|
|
1868
1906
|
const exampleContent = keys.map((k) => `${k}=`).join("\n") + "\n";
|
|
1869
1907
|
writeFileSync3(".env.example", exampleContent, "utf-8");
|
|
1870
1908
|
const gitignoreLines = [];
|
|
1871
|
-
if (
|
|
1909
|
+
if (existsSync6(".gitignore")) {
|
|
1872
1910
|
const content = readFileSync4(".gitignore", "utf-8");
|
|
1873
1911
|
if (!content.split("\n").some((l) => l.trim() === ".env")) {
|
|
1874
1912
|
appendFileSync2(".gitignore", "\n.env\n");
|
|
@@ -1889,11 +1927,11 @@ ${log.out}` }] };
|
|
|
1889
1927
|
description: "\uD544\uC218 \uD658\uACBD\uBCC0\uC218 \uB204\uB77D \uAC80\uC0AC (.env.example \uAE30\uC900)"
|
|
1890
1928
|
},
|
|
1891
1929
|
async () => {
|
|
1892
|
-
if (!
|
|
1930
|
+
if (!existsSync6(".env.example")) {
|
|
1893
1931
|
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." }] };
|
|
1894
1932
|
}
|
|
1895
1933
|
const requiredKeys = parseEnvKeys(readFileSync4(".env.example", "utf-8"));
|
|
1896
|
-
const currentKeys =
|
|
1934
|
+
const currentKeys = existsSync6(".env") ? parseEnvKeys(readFileSync4(".env", "utf-8")) : [];
|
|
1897
1935
|
const missing = requiredKeys.filter((k) => !currentKeys.includes(k));
|
|
1898
1936
|
const extra = currentKeys.filter((k) => !requiredKeys.includes(k));
|
|
1899
1937
|
const lines = [`\u{1F4CB} \uD544\uC218 \uD658\uACBD\uBCC0\uC218: ${requiredKeys.length}\uAC1C`];
|
|
@@ -2007,7 +2045,7 @@ ${cliStatus}
|
|
|
2007
2045
|
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)"
|
|
2008
2046
|
},
|
|
2009
2047
|
async () => {
|
|
2010
|
-
if (!
|
|
2048
|
+
if (!existsSync6("package.json")) {
|
|
2011
2049
|
return { content: [{ type: "text", text: "\u274C package.json \uC5C6\uC74C." }] };
|
|
2012
2050
|
}
|
|
2013
2051
|
try {
|
|
@@ -2035,7 +2073,7 @@ ${cliStatus}
|
|
|
2035
2073
|
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)"
|
|
2036
2074
|
},
|
|
2037
2075
|
async () => {
|
|
2038
|
-
const current =
|
|
2076
|
+
const current = existsSync6("pnpm-lock.yaml") ? "pnpm" : existsSync6("yarn.lock") ? "yarn" : existsSync6("package-lock.json") ? "npm" : null;
|
|
2039
2077
|
const candidates = ["npm", "yarn", "pnpm"].filter((pm) => pm !== current);
|
|
2040
2078
|
const lines = [`\uD604\uC7AC PM: ${current ?? "\uAC10\uC9C0 \uBD88\uAC00 (lock \uD30C\uC77C \uC5C6\uC74C)"}`];
|
|
2041
2079
|
for (const pm of candidates) {
|
|
@@ -2112,5 +2150,6 @@ export {
|
|
|
2112
2150
|
envCheck,
|
|
2113
2151
|
publish,
|
|
2114
2152
|
audit,
|
|
2153
|
+
getVhkVersion,
|
|
2115
2154
|
startMcpServer
|
|
2116
2155
|
};
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
envCheck,
|
|
9
9
|
filterSevereFindings,
|
|
10
10
|
filterTrackedPaths,
|
|
11
|
+
getVhkVersion,
|
|
11
12
|
ko,
|
|
12
13
|
printNextStep,
|
|
13
14
|
printSecurityWarnings,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
scanProjectForSecrets,
|
|
18
19
|
startMcpServer,
|
|
19
20
|
t
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-6S3JYYZ3.js";
|
|
21
22
|
|
|
22
23
|
// src/index.ts
|
|
23
24
|
import { Command, Help } from "commander";
|
|
@@ -2052,9 +2053,18 @@ ${ko.goal.initTitle}
|
|
|
2052
2053
|
});
|
|
2053
2054
|
}
|
|
2054
2055
|
}
|
|
2056
|
+
function findGateScript(id) {
|
|
2057
|
+
const mjs = join2(SCRIPTS_DIR, `check-goal-${id}.mjs`);
|
|
2058
|
+
if (existsSync2(mjs)) return mjs;
|
|
2059
|
+
const sh = join2(SCRIPTS_DIR, `check-goal-${id}.sh`);
|
|
2060
|
+
if (existsSync2(sh)) return sh;
|
|
2061
|
+
return null;
|
|
2062
|
+
}
|
|
2055
2063
|
function runGate(scriptPath) {
|
|
2056
|
-
const
|
|
2057
|
-
|
|
2064
|
+
const isMjs = scriptPath.endsWith(".mjs");
|
|
2065
|
+
const runner = isMjs ? "node" : "bash";
|
|
2066
|
+
const r = safeExecFile(runner, [scriptPath]);
|
|
2067
|
+
return { ok: r.ok, out: r.out, err: r.ok ? "" : r.err, runner };
|
|
2058
2068
|
}
|
|
2059
2069
|
async function goalCheck(opts) {
|
|
2060
2070
|
console.log(chalk6.bold(`
|
|
@@ -2069,15 +2079,17 @@ ${ko.goal.checkTitle}
|
|
|
2069
2079
|
process.exitCode = 1;
|
|
2070
2080
|
return;
|
|
2071
2081
|
}
|
|
2072
|
-
const scriptPath =
|
|
2073
|
-
if (!
|
|
2074
|
-
console.log(
|
|
2082
|
+
const scriptPath = findGateScript(id);
|
|
2083
|
+
if (!scriptPath) {
|
|
2084
|
+
console.log(
|
|
2085
|
+
chalk6.red(` \u274C \uAC8C\uC774\uD2B8 \uC2A4\uD06C\uB9BD\uD2B8 \uC5C6\uC74C: scripts/check-goal-${id}.{mjs,sh}`)
|
|
2086
|
+
);
|
|
2075
2087
|
process.exitCode = 1;
|
|
2076
2088
|
return;
|
|
2077
2089
|
}
|
|
2078
|
-
console.log(chalk6.dim(` \u25B6 bash ${scriptPath}
|
|
2079
|
-
`));
|
|
2080
2090
|
const gate2 = runGate(scriptPath);
|
|
2091
|
+
console.log(chalk6.dim(` \u25B6 ${gate2.runner} ${scriptPath}
|
|
2092
|
+
`));
|
|
2081
2093
|
if (gate2.out) console.log(gate2.out);
|
|
2082
2094
|
if (gate2.ok) {
|
|
2083
2095
|
console.log(chalk6.green(`
|
|
@@ -2108,15 +2120,19 @@ ${ko.goal.doneTitle}
|
|
|
2108
2120
|
process.exitCode = 1;
|
|
2109
2121
|
return;
|
|
2110
2122
|
}
|
|
2111
|
-
const scriptPath =
|
|
2112
|
-
if (!
|
|
2113
|
-
console.log(
|
|
2123
|
+
const scriptPath = findGateScript(id);
|
|
2124
|
+
if (!scriptPath) {
|
|
2125
|
+
console.log(
|
|
2126
|
+
chalk6.red(
|
|
2127
|
+
` \u274C \uAC8C\uC774\uD2B8 \uC2A4\uD06C\uB9BD\uD2B8 \uC5C6\uC74C \u2014 done \uCC98\uB9AC \uAC70\uBD80: scripts/check-goal-${id}.{mjs,sh}`
|
|
2128
|
+
)
|
|
2129
|
+
);
|
|
2114
2130
|
process.exitCode = 1;
|
|
2115
2131
|
return;
|
|
2116
2132
|
}
|
|
2117
|
-
console.log(chalk6.dim(` \u25B6 \uAC8C\uC774\uD2B8 \uAC80\uC99D: bash ${scriptPath}
|
|
2118
|
-
`));
|
|
2119
2133
|
const gate2 = runGate(scriptPath);
|
|
2134
|
+
console.log(chalk6.dim(` \u25B6 \uAC8C\uC774\uD2B8 \uAC80\uC99D: ${gate2.runner} ${scriptPath}
|
|
2135
|
+
`));
|
|
2120
2136
|
if (gate2.out) console.log(gate2.out);
|
|
2121
2137
|
if (!gate2.ok) {
|
|
2122
2138
|
console.log(
|
|
@@ -2298,7 +2314,7 @@ function checkCommand(name, command, hint) {
|
|
|
2298
2314
|
const version = result.out.split("\n")[0];
|
|
2299
2315
|
return { name, command, version, ok: true, hint };
|
|
2300
2316
|
}
|
|
2301
|
-
function
|
|
2317
|
+
function getVhkVersion2() {
|
|
2302
2318
|
const dir = path10.dirname(fileURLToPath(import.meta.url));
|
|
2303
2319
|
const candidates = [
|
|
2304
2320
|
path10.join(dir, "../package.json"),
|
|
@@ -2352,7 +2368,7 @@ ${ko.doctor.title}
|
|
|
2352
2368
|
}
|
|
2353
2369
|
}
|
|
2354
2370
|
console.log("");
|
|
2355
|
-
const vhkVersion =
|
|
2371
|
+
const vhkVersion = getVhkVersion2();
|
|
2356
2372
|
if (vhkVersion) {
|
|
2357
2373
|
console.log(chalk9.green(" \u2705 VHK") + chalk9.dim(` \u2014 v${vhkVersion}`));
|
|
2358
2374
|
} else {
|
|
@@ -2709,9 +2725,19 @@ async function save() {
|
|
|
2709
2725
|
if (process.exitCode !== 1) {
|
|
2710
2726
|
console.log(chalk11.green(`
|
|
2711
2727
|
\u2705 ${t("save.done", lines.length)}`));
|
|
2728
|
+
printNextStep({
|
|
2729
|
+
message: t("save.nextOkMessage"),
|
|
2730
|
+
command: "vhk recap",
|
|
2731
|
+
cursorHint: t("save.nextOkCursor")
|
|
2732
|
+
});
|
|
2712
2733
|
} else {
|
|
2713
2734
|
console.log(chalk11.green(`
|
|
2714
2735
|
\u2705 ${t("save.doneLocalOnly", lines.length)}`));
|
|
2736
|
+
printNextStep({
|
|
2737
|
+
message: t("save.nextPushFailMessage"),
|
|
2738
|
+
command: "vhk doctor",
|
|
2739
|
+
cursorHint: t("save.nextPushFailCursor")
|
|
2740
|
+
});
|
|
2715
2741
|
}
|
|
2716
2742
|
} catch (err) {
|
|
2717
2743
|
spinner.fail(t("save.failed"));
|
|
@@ -2831,6 +2857,11 @@ ${t("undo.recentHeader")}`));
|
|
|
2831
2857
|
console.log(chalk12.yellow(`
|
|
2832
2858
|
\u{1F4A1} ${t("undo.forcePushHint")}`));
|
|
2833
2859
|
}
|
|
2860
|
+
printNextStep({
|
|
2861
|
+
message: t("undo.nextMessage"),
|
|
2862
|
+
command: "vhk save",
|
|
2863
|
+
cursorHint: t("undo.nextCursor")
|
|
2864
|
+
});
|
|
2834
2865
|
} catch (err) {
|
|
2835
2866
|
console.log(chalk12.red(`\u274C ${t("undo.failed")}`));
|
|
2836
2867
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -2954,7 +2985,20 @@ async function status() {
|
|
|
2954
2985
|
} else {
|
|
2955
2986
|
console.log(chalk13.dim(`\u{1F4E6} ${t("status.noPackage")}`));
|
|
2956
2987
|
}
|
|
2957
|
-
|
|
2988
|
+
const hasChanges = counts.staged + counts.unstaged + counts.untracked > 0;
|
|
2989
|
+
if (hasChanges) {
|
|
2990
|
+
printNextStep({
|
|
2991
|
+
message: t("status.nextWithChangesMessage"),
|
|
2992
|
+
command: "vhk save",
|
|
2993
|
+
cursorHint: t("status.nextWithChangesCursor")
|
|
2994
|
+
});
|
|
2995
|
+
} else {
|
|
2996
|
+
printNextStep({
|
|
2997
|
+
message: t("status.nextCleanMessage"),
|
|
2998
|
+
command: "vhk goal next",
|
|
2999
|
+
cursorHint: t("status.nextCleanCursor")
|
|
3000
|
+
});
|
|
3001
|
+
}
|
|
2958
3002
|
}
|
|
2959
3003
|
|
|
2960
3004
|
// src/commands/diff.ts
|
|
@@ -3114,10 +3158,11 @@ async function mcpInit() {
|
|
|
3114
3158
|
console.log(chalk15.green("\n\u2705 Cursor MCP \uC124\uC815 \uC644\uB8CC!"));
|
|
3115
3159
|
console.log(chalk15.cyan("\u{1F4C1} \uC0DD\uC131\uB41C \uD30C\uC77C:"));
|
|
3116
3160
|
console.log(` ${configPath}`);
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3161
|
+
printNextStep({
|
|
3162
|
+
message: t("mcp.nextMessage"),
|
|
3163
|
+
command: "vhk mcp",
|
|
3164
|
+
cursorHint: t("mcp.nextCursor")
|
|
3165
|
+
});
|
|
3121
3166
|
}
|
|
3122
3167
|
|
|
3123
3168
|
// src/commands/design.ts
|
|
@@ -3696,11 +3741,21 @@ async function update() {
|
|
|
3696
3741
|
console.log(chalk21.green.bold(`
|
|
3697
3742
|
\u{1F389} VHK CLI v${latest} \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC!`));
|
|
3698
3743
|
console.log(chalk21.gray(" \uBCC0\uACBD \uC0AC\uD56D\uC740 GitHub Releases\uB97C \uD655\uC778\uD558\uC138\uC694."));
|
|
3744
|
+
printNextStep({
|
|
3745
|
+
message: t("update.nextOkMessage"),
|
|
3746
|
+
command: "vhk --version",
|
|
3747
|
+
cursorHint: t("update.nextOkCursor")
|
|
3748
|
+
});
|
|
3699
3749
|
} else {
|
|
3700
3750
|
updateSpinner.fail("\uC5C5\uB370\uC774\uD2B8 \uC2E4\uD328");
|
|
3701
3751
|
console.log(chalk21.red(upd.err.slice(0, 300)));
|
|
3702
3752
|
console.log(chalk21.yellow("\n\uC218\uB3D9\uC73C\uB85C \uC5C5\uB370\uC774\uD2B8\uD558\uC138\uC694:"));
|
|
3703
3753
|
console.log(chalk21.gray(` npm update -g ${PACKAGE}`));
|
|
3754
|
+
printNextStep({
|
|
3755
|
+
message: t("update.nextFailMessage"),
|
|
3756
|
+
command: "vhk doctor",
|
|
3757
|
+
cursorHint: t("update.nextFailCursor")
|
|
3758
|
+
});
|
|
3704
3759
|
}
|
|
3705
3760
|
}
|
|
3706
3761
|
|
|
@@ -4410,28 +4465,6 @@ async function runNaturalLanguageRoute(input) {
|
|
|
4410
4465
|
await dispatchNlpRoute(route, input);
|
|
4411
4466
|
}
|
|
4412
4467
|
|
|
4413
|
-
// src/lib/version.ts
|
|
4414
|
-
import { existsSync as existsSync15 } from "fs";
|
|
4415
|
-
import { dirname as dirname3, join as join8 } from "path";
|
|
4416
|
-
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
4417
|
-
function getVhkVersion2() {
|
|
4418
|
-
const dir = dirname3(fileURLToPath4(import.meta.url));
|
|
4419
|
-
for (const pkgPath of [
|
|
4420
|
-
join8(dir, "../../package.json"),
|
|
4421
|
-
join8(dir, "../package.json")
|
|
4422
|
-
]) {
|
|
4423
|
-
try {
|
|
4424
|
-
if (existsSync15(pkgPath)) {
|
|
4425
|
-
const pkg = readJsonFile(pkgPath);
|
|
4426
|
-
if (pkg.version) return pkg.version;
|
|
4427
|
-
}
|
|
4428
|
-
} catch {
|
|
4429
|
-
continue;
|
|
4430
|
-
}
|
|
4431
|
-
}
|
|
4432
|
-
return "0.0.0";
|
|
4433
|
-
}
|
|
4434
|
-
|
|
4435
4468
|
// src/commands/agent.ts
|
|
4436
4469
|
import chalk27 from "chalk";
|
|
4437
4470
|
function activeGoalId() {
|
|
@@ -4545,7 +4578,7 @@ var KO_ALIASES = {
|
|
|
4545
4578
|
learn: "\uAD50\uD6C8",
|
|
4546
4579
|
resume: "\uC7AC\uAC1C"
|
|
4547
4580
|
};
|
|
4548
|
-
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(
|
|
4581
|
+
program.name("vhk").description("VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58 (\uD55C\uAD6D\uC5B4\uB85C \uC548\uB0B4\uD569\uB2C8\uB2E4)").version(getVhkVersion());
|
|
4549
4582
|
program.configureHelp({
|
|
4550
4583
|
formatHelp(cmd, helper) {
|
|
4551
4584
|
if (cmd.parent) {
|
|
@@ -4591,10 +4624,10 @@ program.command("status").alias("\uC0C1\uD0DC").description("\uD504\uB85C\uC81D\
|
|
|
4591
4624
|
await status();
|
|
4592
4625
|
});
|
|
4593
4626
|
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);
|
|
4594
|
-
program.command("mcp").description("MCP \uC11C\uBC84 \uC2DC\uC791 (
|
|
4627
|
+
program.command("mcp").description("MCP \uC11C\uBC84 \uC2DC\uC791 (24 tool stdio \u2014 Cursor\xB7Claude Desktop \uB4F1)").action(async () => {
|
|
4595
4628
|
await startMcpServer();
|
|
4596
4629
|
});
|
|
4597
|
-
program.command("mcp-init").alias("mcp\uC124\uC815").description("Cursor MCP \uC5F0\uB3D9 \uC124\uC815 \uC790\uB3D9 \uC0DD\uC131 (.cursor/mcp.json)").action(async () => {
|
|
4630
|
+
program.command("mcp-init").alias("mcp\uC124\uC815").description("Cursor\xB7Claude Desktop MCP \uC5F0\uB3D9 \uC124\uC815 \uC790\uB3D9 \uC0DD\uC131 (.cursor/mcp.json)").action(async () => {
|
|
4598
4631
|
await mcpInit();
|
|
4599
4632
|
});
|
|
4600
4633
|
program.command("deploy").alias("\uBC30\uD3EC").description("\uD504\uB85C\uB355\uC158 \uBC30\uD3EC (Vercel/Netlify/Cloudflare \uC790\uB3D9 \uAC10\uC9C0)").action(async () => {
|
package/dist/mcp/index.js
CHANGED