@byh3071/vhk 1.3.1 โ 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -7
- package/dist/{chunk-6S3JYYZ3.js โ chunk-4KWZANQG.js} +25 -2
- package/dist/index.js +442 -34
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: vhk-readme
|
|
3
3
|
date: 2026-05-28
|
|
4
|
-
tags: [vhk, cli, readme, v1.
|
|
4
|
+
tags: [vhk, cli, readme, v1.5.0, ga]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ๐ง VHK โ Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> ๐ **v1.
|
|
9
|
+
> ๐ **v1.5.0** โ **๊ท์น์ ํ ๋ฒ๋ก CursorยทClaudeยทWindsurfยทCopilotยทAntigravity์, ๋งฅ๋ฝ์ ํด๋ผ์ฐ๋๋ก.**
|
|
10
|
+
> ๋๊ตฌยท๊ธฐ๊ธฐ๋ฅผ ์ฎ๊ฒจ๋ `vhk` ๋ช
๋ น์ผ๋ก ๊ทธ๋๋ก ๋ถ๋ฌ์ต๋๋ค. (ํฌํฐ๋น๋ฆฌํฐ)
|
|
10
11
|
>
|
|
11
12
|
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI**.
|
|
12
13
|
>
|
|
@@ -14,6 +15,20 @@ tags: [vhk, cli, readme, v1.3.0, ga]
|
|
|
14
15
|
|
|
15
16
|
๋ช
๋ น์ด๋ฅผ ์ธ์ฐ์ง ์์๋ ๋ฉ๋๋ค. `vhk`๋ง ์น๋ฉด ๋ฉ๋ด๊ฐ ๋์ค๊ณ , ํ๊ตญ์ด๋ก ๋งํด๋ ์์๋ฃ์ต๋๋ค.
|
|
16
17
|
|
|
18
|
+
## ์ VHK? โ ํฌํฐ๋น๋ฆฌํฐ
|
|
19
|
+
|
|
20
|
+
AI ์ฝ๋ฉ ๋๊ตฌ๋ ์ ๋ง๋ค ๊ท์น ํ์ผ์ด ๋ค๋ฅด๊ณ (`.cursorrules`ยท`CLAUDE.md`ยท`.windsurfrules`ยท`.github/copilot-instructions.md`ยท`.agents/rules/`โฆ), ์ปดํจํฐ๋ฅผ ๋ฐ๊พธ๋ฉด ํ๋ก์ ํธ ๋งฅ๋ฝ์ ์ฒ์๋ถํฐ ๋ค์ ๋ชจ์๋๋ค. VHK๋ ์ด ๋์ ํ ๊ณณ์์ ๊ด๋ฆฌํฉ๋๋ค.
|
|
21
|
+
|
|
22
|
+
| ๋ฌธ์ | VHK ํด๊ฒฐ | ๋ช
๋ น |
|
|
23
|
+
|------|----------|------|
|
|
24
|
+
| ๋๊ตฌ๋ง๋ค ๊ท์น ํ์ผ์ด ๋ฐ๋ก ๋
ผ๋ค | `RULES.md` ํ ๋ฒ โ CursorยทClaudeยทWindsurfยทCopilotยทAntigravity ๊ท์น ๋์ ์์ฑ | `vhk sync` |
|
|
25
|
+
| ์ปดํจํฐยทํ๊ฒฝ ๋ฐ๋๋ฉด ๋งฅ๋ฝ ์ ์ค | `.vhk/` ๋งฅ๋ฝ์ GitHub gist๋ก ๋ฐฑ์
ยท๋ณต์ | `vhk cloud push` / `pull` |
|
|
26
|
+
| ์ ํ๋ก์ ํธ ์ธํ
๋ฐ๋ณต | ์ ํ๋ณ ๋ฌธ์ยท๊ท์นยท๋งฅ๋ฝ ๋ผ๋๋ฅผ ํ ๋ฒ์ | `vhk init` |
|
|
27
|
+
|
|
28
|
+
> ๊ท์นยท๋งฅ๋ฝ์ **์๋์ด ์๋๋ผ ๋ช
๋ น์ผ๋ก** ๋๊ธฐํ๋ฉ๋๋ค(ํ ์ค์ด๋ฉด ์ถฉ๋ถ). ๊ฐ์ธ ๋ฉ๋ชจ(`memory.json`)ยท์ฐธ๊ณ ๋งํฌ(`refs.json`)๋ ํ๋ผ์ด๋ฒ์ ์ํด ๊ธฐ๋ณธ ์ ์ธ, ์ PC์ ์ฝ๋ ์์ฒด๋ `git clone` ์ผ๋ก ๋ฐ์ต๋๋ค.
|
|
29
|
+
>
|
|
30
|
+
> โน๏ธ WindsurfยทCopilotยทAntigravity ์ถ๋ ฅ ๊ฒฝ๋กยทํฌ๋งท์ ๊ฐ ๋๊ตฌ์ **๊ณต์ ๋ฌธ์ ๊ธฐ์ค**์ผ๋ก ์์ฑํฉ๋๋ค(`.windsurfrules` ยท `.github/copilot-instructions.md` ยท `.agents/rules/`). Antigravity ๋ ํ์ผ๋น 12,000์ ์ ํ์ด ์์ด ์ด๊ณผ ์ ์์ ํ๊ฒ ์ ์ญํ๊ณ ์ ์ฒด๋ `RULES.md` ์ ๋จ์ต๋๋ค.
|
|
31
|
+
|
|
17
32
|
## 3๋ถ ์์ ์์ํ๊ธฐ (Getting Started)
|
|
18
33
|
|
|
19
34
|
### 1. ์ค์น
|
|
@@ -40,12 +55,12 @@ vhk start
|
|
|
40
55
|
vhk gate # ํต 5๋ฌธํญ โ GO / ๋ค๋ฌ๊ธฐ / ๋ค๋ฅธ ์์ด๋์ด
|
|
41
56
|
```
|
|
42
57
|
|
|
43
|
-
### 3.
|
|
58
|
+
### 3. ๊ทธ ์ธ ๊ธฐ๋ฅ ํ๋์ (v1.5)
|
|
44
59
|
|
|
45
60
|
| ๊ธฐ๋ฅ | ํ ์ค ์์ฝ | ์ง์
๋ช
๋ น |
|
|
46
61
|
|------|-----------|-----------|
|
|
47
62
|
| ๐ฏ **Goals ์ฒด๊ณ** | ๋จ๊ณ๋ณ ๋ฏธ์
+ ๊ฒ์ดํธ ์คํฌ๋ฆฝํธ๋ก AI๊ฐ ๋ชฉํ๋ฅผ ์ค์ค๋ก ์ถ์ | `vhk goal init` |
|
|
48
|
-
| โถ๏ธ **์์จ ๋ฃจํ** | `goal next โ ์์
โ goal check โ goal done`. FAIL 3
|
|
63
|
+
| โถ๏ธ **์์จ ๋ฃจํ** | `goal next โ ์์
โ goal check โ goal done`. FAIL ์ `vhk blocker` ์๋ ๊ธฐ๋ก โ ๋ธ๋ก์ปค 3๊ฑด ๋์ ์ HARD_STOP ์๋ | `vhk goal next` |
|
|
49
64
|
| ๐ง **HARD_STOP ์์ ์ฅ์น** | ๋ธ๋ก์ปค 3๊ฑด ๋์ โ `.vhk/HARD_STOP` ํธ๋ฆฝ์์ด์ด. `vhk resume --confirm` ๋ง ํด์ | `vhk blocker "<์ฆ์>"` |
|
|
50
65
|
| ๐ **MCP 24 tool** | CursorยทClaude Desktop ๋ฑ์์ vhk๋ฅผ ์ฑํ
์ผ๋ก ํธ์ถ | `vhk mcp-init` |
|
|
51
66
|
| ๐ **์ปจํ
์คํธ ์์ํ** | `.vhk/context.md` + `memory.json` + `brief.md` ๋ก ์ธ์
๊ฐ ๋งฅ๋ฝ ์ ์ง | `vhk context` |
|
|
@@ -115,11 +130,13 @@ vhk ๊ธฐํ ๋๋ฌ๊ณ ๋ฐ๋ก ์์
|
|
|
115
130
|
| `vhk gate` | `๊ฒ์ฆ`, `์์ด๋์ด` | ์์ด๋์ด ๊ฒ์ฆ (ํต 5๋ฌธํญ / ํ 13๋ฌธํญ / ์คํต) |
|
|
116
131
|
| `vhk init` | `์์`, `๋ง๋ค๊ธฐ` | ํ๋ก์ ํธ ์ด๊ธฐํ + ํ๋ค์ค ์์ฑ |
|
|
117
132
|
| `vhk recap` | `์ ๋ฆฌ`, `์ค๋` | Git ๋ณ๊ฒฝ โ `docs/log/` ์ธ์
๋ก๊ทธ |
|
|
118
|
-
| `vhk sync` | `๊ท์น`, `๋ง์ถ๊ธฐ` | RULES.md โ `.cursorrules` + CLAUDE.md |
|
|
133
|
+
| `vhk sync` | `๊ท์น`, `๋ง์ถ๊ธฐ` | RULES.md โ `.cursorrules` + CLAUDE.md + `.windsurfrules` + `.github/copilot-instructions.md` + `.agents/rules/vhk-rules.md` (5๊ฐ) |
|
|
119
134
|
| `vhk check` | `์ ๊ฒ`, `๋ฆฐํธ` | RULES.md ๊ท์น ์๋ฐ ๊ฒ์ฌ |
|
|
120
135
|
| `vhk secure` | `๋ณด์` | ์ํฌ๋ฆฟยทํค ์ ์ถ ์ค์บ (`scan` / `์ค์บ` ๋์ผ). **CRITICAL/HIGH ๋ฐ๊ฒฌ ์ exit code 1** (CI์ฉ) |
|
|
121
136
|
| `vhk ship` | `์ถํ` | ๋ฐฐํฌ ์ฒดํฌ๋ฆฌ์คํธ + ํ๊ณ + ๋น๋ ๋ก๊ทธ |
|
|
122
137
|
| `vhk doctor` | `ํ๊ฒฝ`, `์ง๋จ` | Node / npm / pnpm / Git ํ๊ฒฝ ์ ๊ฒ |
|
|
138
|
+
| `vhk cloud push` | `ํด๋ผ์ฐ๋`, `์ฌ๋ฆฌ๊ธฐ` | `.vhk/` ๋ฅผ GitHub secret gist ๋ก ๋ฐฑ์
(gh CLI ์ธ์ฆ ์ฌ์ฉ) |
|
|
139
|
+
| `vhk cloud pull` | `๋ด๋ฆฌ๊ธฐ` | gist ์์ `.vhk/` ๋ณต์ (`vhk cloud pull <gistId>` ๋๋ cloud.json) |
|
|
123
140
|
| `vhk save` | `์ ์ฅ`, `์ปค๋ฐ` | git add ยท commit ยท push ํ ๋ฒ์ |
|
|
124
141
|
| `vhk undo` | `๋๋๋ฆฌ๊ธฐ`, `์ทจ์` | ์ต๊ทผ ์ปค๋ฐ soft reset (๋ณ๊ฒฝ์ staged ์ ์ง) |
|
|
125
142
|
| `vhk diff` | `๋ณ๊ฒฝ`, `์ฐจ์ด` | staged / unstaged / ์ ํ์ผ ์์ฝ (์ค ์ ํฉ๊ณ๋ trackedยทHEAD ๊ธฐ์ค) |
|
|
@@ -298,10 +315,10 @@ vhk ref open 1 # 1๋ฒ ๋ ํผ๋ฐ์ค๋ฅผ ๋ธ๋ผ์ฐ์ ๋ก ์ด๊ธฐ
|
|
|
298
315
|
|
|
299
316
|
| ๊ธฐ๋ฅ | ์ค๋ช
|
|
|
300
317
|
|------|------|
|
|
301
|
-
| **MCP ์๋ฒ** | `vhk mcp` โ stdio MCP ์๋ฒ ์ฒซ ๋์
(v0.6.0 ๋น์ 8๊ฐ ๋๊ตฌ โ save/undo/status/diff/ship/doctor/check/recap). ํ์ฌ v1.
|
|
318
|
+
| **MCP ์๋ฒ** | `vhk mcp` โ stdio MCP ์๋ฒ ์ฒซ ๋์
(v0.6.0 ๋น์ 8๊ฐ ๋๊ตฌ โ save/undo/status/diff/ship/doctor/check/recap). ํ์ฌ v1.5 ๊ธฐ์ค **24๊ฐ** ๋ก ํ์ฅ โ ์ "Cursor์ MCP๋ก ์ฐ๋ํ๊ธฐ" ์น์
์ฐธ์กฐ |
|
|
302
319
|
| **mcp-init** | `vhk mcp-init` โ Cursor `.cursor/mcp.json` ์๋ ์์ฑ. ์ฌ์์ ํ ๋ฒ์ผ๋ก ์ฐ๋ ์๋ฃ |
|
|
303
320
|
| **์์ฐ์ด ๋ผ์ฐํ
ํ์ฅ** | `vhk mcp์ค์ ` โ `vhk mcp-init` ๋ณ์นญ |
|
|
304
|
-
| **๋ณด์** | MCP save ๋๊ตฌ์ shell injection ์ฐจ๋จ โ ๋ชจ๋ git ํธ์ถ์ `
|
|
321
|
+
| **๋ณด์** | MCP save ๋๊ตฌ์ shell injection ์ฐจ๋จ โ ๋ชจ๋ git ํธ์ถ์ shell ๋ฏธ๊ฒฝ์ `safeExecFile` ์ฌ์ฉ |
|
|
305
322
|
|
|
306
323
|
## v0.5.3 ํ์ด๋ผ์ดํธ
|
|
307
324
|
|
|
@@ -340,8 +357,26 @@ vhk ref open 1 # 1๋ฒ ๋ ํผ๋ฐ์ค๋ฅผ ๋ธ๋ผ์ฐ์ ๋ก ์ด๊ธฐ
|
|
|
340
357
|
- `docs/PRD.md`, `docs/ARCHITECTURE.md`
|
|
341
358
|
- `docs/adr/`, `docs/log/`, `docs/troubleshooting/`
|
|
342
359
|
- `COMMANDS.md`, `BACKLOG.md` (ํ๋ก์ ํธ ์ ํ์ ๋ฐ๋ผ)
|
|
360
|
+
- `.vhk/README.md` + `.vhk/context.md` (์ ํ๋ณ ์จ์ โ ๊ท๊ฒฉ: [`docs/spec.md`](docs/spec.md))
|
|
361
|
+
- `.vhk/.gitignore` + `.vhkignore` (๋ก์ปฌ ์ ์ฉยทํด๋ผ์ฐ๋ ์ ์ธ ๊ท์น)
|
|
362
|
+
- ๋ฃจํธ `.gitignore` (`.env`ยท`node_modules`ยท`dist` ๋ณดํธ โ ๊ธฐ์กด ํ์ผ์ ๋ณด์กดํ๊ณ ๋๋ฝ๋ถ๋ง ์ถ๊ฐ)
|
|
343
363
|
- `package.json` scripts: `save`, `check`, `scan`, `recap`, `ship`, `doctor` โ `vhk` ํธ์ถ
|
|
344
364
|
|
|
365
|
+
## ํด๋ผ์ฐ๋ ๋ฐฑ์
(vhk cloud)
|
|
366
|
+
|
|
367
|
+
`.vhk/` ํ๋ก์ ํธ ๋งฅ๋ฝ์ GitHub **secret gist** ๋ก ๋ฐฑ์
ยท๋ณต์ํฉ๋๋ค. ์ปดํจํฐ๋ฅผ ๋ฐ๊ฟ๋
|
|
368
|
+
๊ท์นยท๋งฅ๋ฝ์ด ๋ฐ๋ผ์ต๋๋ค. ๊ท๊ฒฉ์ [`docs/spec.md`](docs/spec.md) ์ฐธ์กฐ.
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
vhk cloud push # .vhk/ โ secret gist ๋ฐฑ์
(gist id ๋ .vhk/cloud.json ์ ์ ์ฅ)
|
|
372
|
+
vhk cloud pull # cloud.json ์ gist ์์ ๋ณต์
|
|
373
|
+
vhk cloud pull <gistId> # ์ ํ๊ฒฝ์์ gist id ๋ก ์ง์ ๋ณต์
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
- **์ธ์ฆ:** `gh` CLI ์ฌ์ฉ (`gh auth login`, gist ๊ถํ). ์ฝ๋ยท์ค์ ์ ํ ํฐ์ ์ ์ฅํ์ง ์์ต๋๋ค.
|
|
377
|
+
- **ํ๋ผ์ด๋ฒ์:** gist ๋ secret(๋น๊ณต๊ฐ). ๊ฐ์ธ ๋ฉ๋ชจ(`memory.json`)ยท์ฐธ๊ณ ๋งํฌ(`refs.json`)ยท
|
|
378
|
+
`HARD_STOP` ์ ๊ธฐ๋ณธ ์ ์ธ๋ฉ๋๋ค. ์ถ๊ฐ ์ ์ธ๋ ๋ฃจํธ `.vhkignore` ์ ํ ์ค์ฉ ์ ์ผ์ธ์.
|
|
379
|
+
|
|
345
380
|
## ์์ฐ์ด ์์
|
|
346
381
|
|
|
347
382
|
| ๋งํ๋ฉด | ์คํ |
|
|
@@ -696,7 +696,9 @@ var ko = {
|
|
|
696
696
|
gitHintCommand: 'git init && git add . && git commit -m "feat: \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791"',
|
|
697
697
|
startDev: "\uC774\uC81C \uAC1C\uBC1C\uD574 \uBCF4\uC138\uC694! \u{1F680}",
|
|
698
698
|
commandsMdDone: "\u{1F4CB} COMMANDS.md \uC0DD\uC131",
|
|
699
|
-
scriptsDone: "\u{1F4E6} package.json scripts \uCD94\uAC00"
|
|
699
|
+
scriptsDone: "\u{1F4E6} package.json scripts \uCD94\uAC00",
|
|
700
|
+
gitignoreCreated: "\u{1F512} .gitignore \uC0DD\uC131 (.env\xB7node_modules\xB7dist \uC81C\uC678)",
|
|
701
|
+
gitignoreUpdated: "\u{1F512} .gitignore \uBCF4\uAC15 (\uB204\uB77D \uD56D\uBAA9 \uCD94\uAC00)"
|
|
700
702
|
},
|
|
701
703
|
recap: {
|
|
702
704
|
title: "\u{1F4DD} \uC624\uB298 \uD55C \uC77C \uC815\uB9AC",
|
|
@@ -752,8 +754,25 @@ var ko = {
|
|
|
752
754
|
noRules: "\u26A0\uFE0F RULES.md \uD30C\uC77C\uC774 \uC5C6\uC5B4\uC694.",
|
|
753
755
|
cursorrulesDone: "\u2705 .cursorrules \uB9DE\uCDA4 \uC644\uB8CC",
|
|
754
756
|
claudeDone: "\u2705 CLAUDE.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
757
|
+
windsurfDone: "\u2705 .windsurfrules \uB9DE\uCDA4 \uC644\uB8CC",
|
|
758
|
+
copilotDone: "\u2705 .github/copilot-instructions.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
759
|
+
antigravityDone: "\u2705 .agents/rules/vhk-rules.md \uB9DE\uCDA4 \uC644\uB8CC",
|
|
760
|
+
antigravityTruncated: "Antigravity 12,000\uC790 \uC81C\uD55C\uC73C\uB85C \uC77C\uBD80 \uC808\uC0AD\uB428 \u2014 \uC804\uCCB4\uB294 RULES.md \uCC38\uC870",
|
|
755
761
|
done: "\u{1F504} \uB9DE\uCD94\uAE30 \uC644\uB8CC!"
|
|
756
762
|
},
|
|
763
|
+
cloud: {
|
|
764
|
+
pushTitle: "\u2601\uFE0F .vhk \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 (gist \uC62C\uB9AC\uAE30)",
|
|
765
|
+
pullTitle: "\u2601\uFE0F .vhk \uD074\uB77C\uC6B0\uB4DC \uBCF5\uC6D0 (gist \uB0B4\uB9AC\uAE30)",
|
|
766
|
+
noGh: "gh CLI \uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
767
|
+
noAuth: "gh \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 (gist \uAD8C\uD55C).",
|
|
768
|
+
noVhkDir: ".vhk/ \uD3F4\uB354\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. vhk init \uB610\uB294 vhk context \uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.",
|
|
769
|
+
nothingToSync: "\uBC31\uC5C5\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhkignore \uB85C \uBAA8\uB450 \uC81C\uC678\uB428).",
|
|
770
|
+
noGistId: "\uBCF5\uC6D0\uD560 gist id \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
771
|
+
pushDone: "\u2705 \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 \uC644\uB8CC",
|
|
772
|
+
pullDone: "\u2705 \uD074\uB77C\uC6B0\uB4DC \uBCF5\uC6D0 \uC644\uB8CC",
|
|
773
|
+
pushFail: "\u274C \uBC31\uC5C5 \uC2E4\uD328",
|
|
774
|
+
pullFail: "\u274C \uBCF5\uC6D0 \uC2E4\uD328"
|
|
775
|
+
},
|
|
757
776
|
ship: {
|
|
758
777
|
title: "\u{1F680} \uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
759
778
|
checklist: "\u{1F4CB} \uBC30\uD3EC \uC804 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
@@ -866,7 +885,9 @@ var ko = {
|
|
|
866
885
|
nextTitle: "\u27A1\uFE0F \uB2E4\uC74C Goal",
|
|
867
886
|
initTitle: "\u{1F3D7}\uFE0F goals/ \uAD6C\uC870 \uC2A4\uCE90\uD3F4\uB529",
|
|
868
887
|
checkTitle: "\u2705 Goal \uAC8C\uC774\uD2B8 \uAC80\uC99D",
|
|
869
|
-
doneTitle: "\u{1F3C1} Goal \uC644\uB8CC \uCC98\uB9AC"
|
|
888
|
+
doneTitle: "\u{1F3C1} Goal \uC644\uB8CC \uCC98\uB9AC",
|
|
889
|
+
duplicateId: (ids) => `\u26A0 \uC911\uBCF5\uB41C goal id: ${ids} \u2014 \uAC19\uC740 id \uD30C\uC77C\uC774 \uC5EC\uB7EC \uAC1C\uBA74 \uCCAB \uB9E4\uCE58\uB9CC \uC0AC\uC6A9\uB429\uB2C8\uB2E4. id \uB97C \uC720\uC77C\uD558\uAC8C \uACE0\uCE58\uC138\uC694.`,
|
|
890
|
+
notFound: (id) => `goal id ${id} \uC5C6\uC74C \u2014 vhk goal list \uB85C \uD655\uC778\uD558\uC138\uC694.`
|
|
870
891
|
},
|
|
871
892
|
agent: {
|
|
872
893
|
blockerTitle: "\u{1F6D1} Blocker \uAE30\uB85D",
|
|
@@ -2134,9 +2155,11 @@ async function startMcpServer() {
|
|
|
2134
2155
|
}
|
|
2135
2156
|
|
|
2136
2157
|
export {
|
|
2158
|
+
__toESM,
|
|
2137
2159
|
ko,
|
|
2138
2160
|
t,
|
|
2139
2161
|
printNextStep,
|
|
2162
|
+
require_ignore,
|
|
2140
2163
|
printSecurityWarnings,
|
|
2141
2164
|
filterTrackedPaths,
|
|
2142
2165
|
readJsonFile,
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
MAX_SCAN_FILE_BYTES,
|
|
4
4
|
MAX_SECRET_FINDINGS,
|
|
5
|
+
__toESM,
|
|
5
6
|
audit,
|
|
6
7
|
deploy,
|
|
7
8
|
env,
|
|
@@ -14,11 +15,12 @@ import {
|
|
|
14
15
|
printSecurityWarnings,
|
|
15
16
|
publish,
|
|
16
17
|
readJsonFile,
|
|
18
|
+
require_ignore,
|
|
17
19
|
safeExecFile,
|
|
18
20
|
scanProjectForSecrets,
|
|
19
21
|
startMcpServer,
|
|
20
22
|
t
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-4KWZANQG.js";
|
|
22
24
|
|
|
23
25
|
// src/index.ts
|
|
24
26
|
import { Command, Help } from "commander";
|
|
@@ -40,6 +42,19 @@ function matchesKeywords(text, command) {
|
|
|
40
42
|
return keywords.some((kw) => text.includes(kw.toLowerCase()));
|
|
41
43
|
}
|
|
42
44
|
var RULES = [
|
|
45
|
+
// ์๋ฌธ `vhk cloud push|pull [id]` ์ commander ๊ฐ ์ง์ ์ฒ๋ฆฌ(๊ฐ๋ก์ฑ๊ธฐ ๊ธ์ง) โ ํ๊ตญ์ด ํํ๋ง ๋งค์นญ.
|
|
46
|
+
{
|
|
47
|
+
command: "cloud-pull",
|
|
48
|
+
explanation: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk \uBCF5\uC6D0 (vhk cloud pull)",
|
|
49
|
+
confidence: "high",
|
|
50
|
+
test: (t2) => (/(ํด๋ผ์ฐ๋|gist)\s*(์์)?\s*(๋ณต์|๋ด๋ ค๋ฐ?|๋ด๋ฆฌ|๋ฐ์)/.test(t2) || /(\.?vhk\s*)?(๋ณต์ํด|๋ณต๊ตฌํด|๋ณต์\s*ํ|๋ณต๊ตฌ\s*ํ)/.test(t2)) && !/๋ฐฑ์
|์ฌ๋ ค|์ฌ๋ฆฌ/.test(t2)
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
command: "cloud-push",
|
|
54
|
+
explanation: ".vhk \uB97C \uD074\uB77C\uC6B0\uB4DC\uC5D0 \uBC31\uC5C5 (vhk cloud push)",
|
|
55
|
+
confidence: "high",
|
|
56
|
+
test: (t2) => (/(ํด๋ผ์ฐ๋|gist)\s*(์)?\s*(๋ฐฑ์
|์ฌ๋ ค|์ฌ๋ฆฌ)/.test(t2) || /(\.?vhk\s*)?๋ฐฑ์
\s*ํด|(\.?vhk\s*)?๋ฐฑ์
ํ/.test(t2)) && !/๋ณต์|๋ด๋ ค|๋ด๋ฆฌ|๋ณต๊ตฌ/.test(t2)
|
|
57
|
+
},
|
|
43
58
|
{
|
|
44
59
|
command: "start",
|
|
45
60
|
explanation: "\uB178\uC158\uC5D0\uC11C \uAC00\uC838\uC640 \uC0C8 \uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 \uB9C8\uBC95\uC0AC (vhk start --from-notion)",
|
|
@@ -177,7 +192,7 @@ var RULES = [
|
|
|
177
192
|
command: "save",
|
|
178
193
|
explanation: "Git\uC5D0 \uC800\uC7A5 (vhk \uC800\uC7A5)",
|
|
179
194
|
confidence: "high",
|
|
180
|
-
test: (t2) => (matchesKeywords(t2, "save") || /๊นํ๋ธ|github/.test(t2)) && !/์ ๋ฆฌ|recap|๋๋|์ทจ์|rollback|reset
|
|
195
|
+
test: (t2) => (matchesKeywords(t2, "save") || /๊นํ๋ธ|github/.test(t2)) && !/์ ๋ฆฌ|recap|๋๋|์ทจ์|rollback|reset|๋ฆฌ์
|๋กค๋ฐฑ|์๋๋๋ก|ํด๋ผ์ฐ๋|cloud|gist/.test(t2)
|
|
181
196
|
},
|
|
182
197
|
{
|
|
183
198
|
command: "recap",
|
|
@@ -352,6 +367,8 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
352
367
|
"\uAE30\uC5B5",
|
|
353
368
|
"brief",
|
|
354
369
|
"\uBE0C\uB9AC\uD551",
|
|
370
|
+
"cloud",
|
|
371
|
+
"\uD074\uB77C\uC6B0\uB4DC",
|
|
355
372
|
"goal",
|
|
356
373
|
"\uBAA9\uD45C",
|
|
357
374
|
"blocker",
|
|
@@ -383,7 +400,7 @@ function detectNaturalLanguageInput(argv) {
|
|
|
383
400
|
}
|
|
384
401
|
|
|
385
402
|
// src/lib/nlp-run.ts
|
|
386
|
-
import
|
|
403
|
+
import chalk27 from "chalk";
|
|
387
404
|
import inquirer11 from "inquirer";
|
|
388
405
|
|
|
389
406
|
// src/commands/gate.ts
|
|
@@ -738,6 +755,70 @@ function COMMANDS_MD_TEMPLATE() {
|
|
|
738
755
|
].join("\n");
|
|
739
756
|
}
|
|
740
757
|
|
|
758
|
+
// src/templates/vhk-dir.ts
|
|
759
|
+
function VHK_README_TEMPLATE() {
|
|
760
|
+
return [
|
|
761
|
+
"# `.vhk/` \u2014 VHK runtime state",
|
|
762
|
+
"",
|
|
763
|
+
"\uC774 \uB514\uB809\uD1A0\uB9AC\uB294 VHK\uAC00 \uD504\uB85C\uC81D\uD2B8\uBCC4 \uC0C1\uD0DC\uB97C \uC800\uC7A5\uD558\uB294 \uACF3\uC785\uB2C8\uB2E4.",
|
|
764
|
+
"\uC804\uCCB4 \uADDC\uACA9\uC740 `docs/spec.md` (spec_version 1.0) \uCC38\uC870.",
|
|
765
|
+
"",
|
|
766
|
+
"## \uD2B8\uB798\uD0B9 \uC815\uCC45",
|
|
767
|
+
"",
|
|
768
|
+
"| \uD30C\uC77C | \uD2B8\uB798\uD0B9 | \uC6A9\uB3C4 |",
|
|
769
|
+
"| --- | --- | --- |",
|
|
770
|
+
"| `README.md` | \u2705 | \uBCF8 \uC548\uB0B4 |",
|
|
771
|
+
"| `context.md` | \u2705 | \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D (`vhk context` \uB85C \uAC31\uC2E0) |",
|
|
772
|
+
"| `brief.md` | \u2705 | \uC0C1\uD0DC \uC694\uC57D \uBE0C\uB9AC\uD551 (`vhk brief`) |",
|
|
773
|
+
"| `memory.json` | \u274C \uB85C\uCEEC \uC804\uC6A9 | \uC758\uC0AC\uACB0\uC815 \uBA54\uBAA8 (`vhk memory add`) |",
|
|
774
|
+
"| `refs.json` | \u274C \uB85C\uCEEC \uC804\uC6A9 | \uCC38\uACE0 URL (`vhk ref add`) |",
|
|
775
|
+
"| `HARD_STOP` | \u274C \uB85C\uCEEC \uC804\uC6A9 | \uC874\uC7AC\uD558\uBA74 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC989\uC2DC \uC911\uB2E8 |",
|
|
776
|
+
"",
|
|
777
|
+
"> `memory.json`\xB7`refs.json` \uC740 \uAC1C\uC778 \uBA54\uBAA8 \uB178\uCD9C \uBC29\uC9C0\uB97C \uC704\uD574 `.gitignore` \uC5D0 \uB4F1\uB85D\uB429\uB2C8\uB2E4.",
|
|
778
|
+
"> `HARD_STOP` \uD574\uC81C\uB294 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uAC00\uB2A5\uD569\uB2C8\uB2E4.",
|
|
779
|
+
""
|
|
780
|
+
].join("\n");
|
|
781
|
+
}
|
|
782
|
+
function VHK_GITIGNORE_TEMPLATE() {
|
|
783
|
+
return [
|
|
784
|
+
"# VHK \uB85C\uCEEC \uC804\uC6A9 \u2014 \uAC1C\uC778 \uBA54\uBAA8/\uCC38\uACE0\uB9C1\uD06C/\uC548\uC804\uC2E0\uD638 (docs/spec.md \uD2B8\uB798\uD0B9 \uC815\uCC45)",
|
|
785
|
+
"memory.json",
|
|
786
|
+
"refs.json",
|
|
787
|
+
"HARD_STOP",
|
|
788
|
+
""
|
|
789
|
+
].join("\n");
|
|
790
|
+
}
|
|
791
|
+
function VHK_IGNORE_TEMPLATE() {
|
|
792
|
+
return [
|
|
793
|
+
"# vhk cloud push \uBC31\uC5C5\uC5D0\uC11C \uC81C\uC678\uD560 .vhk/ \uD30C\uC77C (\uD55C \uC904\uC5D0 \uD558\uB098)",
|
|
794
|
+
"# \uAE30\uBCF8 \uC81C\uC678(\uC790\uB3D9): memory.json, refs.json, HARD_STOP, cloud.json, .gitignore",
|
|
795
|
+
"# \uC608) \uC544\uB798 \uC8FC\uC11D\uC744 \uD480\uBA74 brief.md \uB3C4 \uBC31\uC5C5\uC5D0\uC11C \uC81C\uC678\uB429\uB2C8\uB2E4.",
|
|
796
|
+
"# brief.md",
|
|
797
|
+
""
|
|
798
|
+
].join("\n");
|
|
799
|
+
}
|
|
800
|
+
function VHK_CONTEXT_SEED(name, type, stack) {
|
|
801
|
+
const stackList = stack.map((s) => "- " + s).join("\n");
|
|
802
|
+
return [
|
|
803
|
+
"# " + name + " \u2014 \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D",
|
|
804
|
+
"",
|
|
805
|
+
"> \u26A1 \uC774 \uD30C\uC77C\uC740 vhk init \uC774 \uC0DD\uC131\uD55C \uC528\uC557\uC785\uB2C8\uB2E4. `vhk context` \uB85C \uAC31\uC2E0\uD558\uC138\uC694.",
|
|
806
|
+
"",
|
|
807
|
+
"## \uD504\uB85C\uC81D\uD2B8 \uC720\uD615",
|
|
808
|
+
"- " + type,
|
|
809
|
+
"",
|
|
810
|
+
"## \uAE30\uC220 \uC2A4\uD0DD",
|
|
811
|
+
stackList,
|
|
812
|
+
"",
|
|
813
|
+
"## \uC8FC\uC694 \uACB0\uC815\uC0AC\uD56D",
|
|
814
|
+
"- (\uC544\uC9C1 \uC5C6\uC74C \u2014 `vhk memory add` \uB85C \uAE30\uB85D)",
|
|
815
|
+
"",
|
|
816
|
+
"## \uB2E4\uC74C \uB2E8\uACC4",
|
|
817
|
+
"- docs/PRD.md \uC791\uC131",
|
|
818
|
+
""
|
|
819
|
+
].join("\n");
|
|
820
|
+
}
|
|
821
|
+
|
|
741
822
|
// src/utils/logger.ts
|
|
742
823
|
import chalk2 from "chalk";
|
|
743
824
|
var log = {
|
|
@@ -995,7 +1076,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
995
1076
|
}
|
|
996
1077
|
}
|
|
997
1078
|
const cwd = process.cwd();
|
|
998
|
-
const files = generateFiles(answers.name, answers.description, stack, prdContent);
|
|
1079
|
+
const files = generateFiles(answers.name, answers.description, stack, prdContent, answers.type);
|
|
999
1080
|
log.step(ko.init.filesGenerating);
|
|
1000
1081
|
for (const [filePath, content] of Object.entries(files)) {
|
|
1001
1082
|
const fullPath = path2.join(cwd, filePath);
|
|
@@ -1040,7 +1121,7 @@ ${ko.init.nextSteps}`));
|
|
|
1040
1121
|
alternative: "VS Code/Cursor\uC5D0\uC11C \uD3F4\uB354\uB97C \uC5F4\uC5B4\uB3C4 \uB429\uB2C8\uB2E4"
|
|
1041
1122
|
});
|
|
1042
1123
|
}
|
|
1043
|
-
function generateFiles(name, description, stack, prdContent = {}) {
|
|
1124
|
+
function generateFiles(name, description, stack, prdContent = {}, type = "") {
|
|
1044
1125
|
const stackStr = stack.join(" + ");
|
|
1045
1126
|
const prd = {
|
|
1046
1127
|
tagline: description,
|
|
@@ -1065,7 +1146,12 @@ function generateFiles(name, description, stack, prdContent = {}) {
|
|
|
1065
1146
|
## v1.1 \uD6C4\uBCF4
|
|
1066
1147
|
|
|
1067
1148
|
-
|
|
1068
|
-
|
|
1149
|
+
`,
|
|
1150
|
+
// .vhk/ ์จ์ โ ๊ท๊ฒฉ: docs/spec.md (spec_version 1.0)
|
|
1151
|
+
".vhk/README.md": VHK_README_TEMPLATE(),
|
|
1152
|
+
".vhk/context.md": VHK_CONTEXT_SEED(name, type || "unknown", stack),
|
|
1153
|
+
".vhk/.gitignore": VHK_GITIGNORE_TEMPLATE(),
|
|
1154
|
+
".vhkignore": VHK_IGNORE_TEMPLATE()
|
|
1069
1155
|
};
|
|
1070
1156
|
}
|
|
1071
1157
|
var VHK_PACKAGE_SCRIPTS = {
|
|
@@ -1076,6 +1162,32 @@ var VHK_PACKAGE_SCRIPTS = {
|
|
|
1076
1162
|
ship: "vhk ship",
|
|
1077
1163
|
doctor: "vhk doctor"
|
|
1078
1164
|
};
|
|
1165
|
+
var ROOT_GITIGNORE_ENTRIES = [
|
|
1166
|
+
".env",
|
|
1167
|
+
".env.local",
|
|
1168
|
+
".env.*.local",
|
|
1169
|
+
"node_modules/",
|
|
1170
|
+
"dist/",
|
|
1171
|
+
"*.tsbuildinfo",
|
|
1172
|
+
".DS_Store"
|
|
1173
|
+
];
|
|
1174
|
+
function ensureRootGitignore(projectDir) {
|
|
1175
|
+
const gitignorePath = path2.join(projectDir, ".gitignore");
|
|
1176
|
+
if (!fs2.existsSync(gitignorePath)) {
|
|
1177
|
+
fs2.writeFileSync(gitignorePath, ROOT_GITIGNORE_ENTRIES.join("\n") + "\n", "utf-8");
|
|
1178
|
+
return "created";
|
|
1179
|
+
}
|
|
1180
|
+
const content = fs2.readFileSync(gitignorePath, "utf-8");
|
|
1181
|
+
const existing = new Set(content.split("\n").map((l) => l.trim()));
|
|
1182
|
+
const missing = ROOT_GITIGNORE_ENTRIES.filter((e) => !existing.has(e));
|
|
1183
|
+
if (missing.length === 0) return "unchanged";
|
|
1184
|
+
const prefix = content.endsWith("\n") ? "" : "\n";
|
|
1185
|
+
fs2.appendFileSync(gitignorePath, `${prefix}
|
|
1186
|
+
# vhk init
|
|
1187
|
+
${missing.join("\n")}
|
|
1188
|
+
`, "utf-8");
|
|
1189
|
+
return "updated";
|
|
1190
|
+
}
|
|
1079
1191
|
function enhancePackageScripts(projectDir) {
|
|
1080
1192
|
const pkgPath = path2.join(projectDir, "package.json");
|
|
1081
1193
|
if (!fs2.existsSync(pkgPath)) return false;
|
|
@@ -1106,6 +1218,12 @@ async function writeInitExtras(projectDir) {
|
|
|
1106
1218
|
if (enhancePackageScripts(projectDir)) {
|
|
1107
1219
|
log.success(ko.init.scriptsDone);
|
|
1108
1220
|
}
|
|
1221
|
+
const gitignoreResult = ensureRootGitignore(projectDir);
|
|
1222
|
+
if (gitignoreResult === "created") {
|
|
1223
|
+
log.success(ko.init.gitignoreCreated);
|
|
1224
|
+
} else if (gitignoreResult === "updated") {
|
|
1225
|
+
log.success(ko.init.gitignoreUpdated);
|
|
1226
|
+
}
|
|
1109
1227
|
}
|
|
1110
1228
|
|
|
1111
1229
|
// src/commands/recap.ts
|
|
@@ -1558,12 +1676,12 @@ function parseRulesMd(content) {
|
|
|
1558
1676
|
}
|
|
1559
1677
|
return sections;
|
|
1560
1678
|
}
|
|
1561
|
-
function
|
|
1679
|
+
function buildCodingDoc(headerTitle, sections, projectName) {
|
|
1562
1680
|
const codingSections = sections.filter(
|
|
1563
1681
|
(s) => CURSORRULES_KEYS.some((k) => s.title.includes(k))
|
|
1564
1682
|
);
|
|
1565
1683
|
const lines = [
|
|
1566
|
-
`# ${projectName} \u2014
|
|
1684
|
+
`# ${projectName} \u2014 ${headerTitle}`,
|
|
1567
1685
|
"",
|
|
1568
1686
|
"> \uCF54\uB529/\uB514\uC790\uC778 \uC804\uC6A9. \uAE30\uB85D/\uC6B4\uC601 \u2192 CLAUDE.md \uCC38\uC870.",
|
|
1569
1687
|
"> \u26A1 \uC774 \uD30C\uC77C\uC740 RULES.md\uC5D0\uC11C \uC790\uB3D9 \uC0DD\uC131\uB428 (vhk sync). \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0.",
|
|
@@ -1579,6 +1697,39 @@ function toCursorrules(sections, projectName) {
|
|
|
1579
1697
|
}
|
|
1580
1698
|
return lines.join("\n");
|
|
1581
1699
|
}
|
|
1700
|
+
function toCursorrules(sections, projectName) {
|
|
1701
|
+
return buildCodingDoc("Cursor Rules", sections, projectName);
|
|
1702
|
+
}
|
|
1703
|
+
function toWindsurfrules(sections, projectName) {
|
|
1704
|
+
return buildCodingDoc("Windsurf Rules", sections, projectName);
|
|
1705
|
+
}
|
|
1706
|
+
function toCopilotInstructions(sections, projectName) {
|
|
1707
|
+
return buildCodingDoc("GitHub Copilot Instructions", sections, projectName);
|
|
1708
|
+
}
|
|
1709
|
+
var ANTIGRAVITY_CHAR_LIMIT = 12e3;
|
|
1710
|
+
var ANTIGRAVITY_TRUNCATE_MARKER = "\n\n<!-- \u26A0\uFE0F Antigravity 12,000\uC790 \uC81C\uD55C\uC73C\uB85C \uC808\uC0AD\uB428 \u2014 \uC804\uCCB4 \uADDC\uCE59\uC740 RULES.md \uCC38\uC870 -->\n";
|
|
1711
|
+
function truncateForAntigravity(content, limit = ANTIGRAVITY_CHAR_LIMIT) {
|
|
1712
|
+
if (Buffer.byteLength(content, "utf8") <= limit) return content;
|
|
1713
|
+
const SAFETY = 200;
|
|
1714
|
+
const budget = limit - Buffer.byteLength(ANTIGRAVITY_TRUNCATE_MARKER, "utf8") - SAFETY;
|
|
1715
|
+
let lo = 0;
|
|
1716
|
+
let hi = content.length;
|
|
1717
|
+
while (lo < hi) {
|
|
1718
|
+
const mid = lo + hi + 1 >> 1;
|
|
1719
|
+
if (Buffer.byteLength(content.slice(0, mid), "utf8") <= budget) lo = mid;
|
|
1720
|
+
else hi = mid - 1;
|
|
1721
|
+
}
|
|
1722
|
+
const charCut = lo;
|
|
1723
|
+
let cut = content.lastIndexOf("\n## ", charCut);
|
|
1724
|
+
if (cut < charCut * 0.5) {
|
|
1725
|
+
const nl = content.lastIndexOf("\n", charCut);
|
|
1726
|
+
cut = nl > 0 ? nl : charCut;
|
|
1727
|
+
}
|
|
1728
|
+
return content.slice(0, cut).trimEnd() + ANTIGRAVITY_TRUNCATE_MARKER;
|
|
1729
|
+
}
|
|
1730
|
+
function toAntigravityRules(sections, projectName) {
|
|
1731
|
+
return truncateForAntigravity(buildCodingDoc("Antigravity Rules", sections, projectName));
|
|
1732
|
+
}
|
|
1582
1733
|
function toClaudeMd(sections, existing) {
|
|
1583
1734
|
const recordSections = sections.filter(
|
|
1584
1735
|
(s) => CLAUDE_MD_KEYS.some((k) => s.title.includes(k))
|
|
@@ -1638,9 +1789,25 @@ ${ko.sync.title}
|
|
|
1638
1789
|
- **\uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8:** ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`;
|
|
1639
1790
|
fs5.writeFileSync(claudePath, toClaudeMd(sections, existingClaude), "utf-8");
|
|
1640
1791
|
console.log(chalk5.green(` ${ko.sync.claudeDone}`));
|
|
1792
|
+
const windsurfPath = path6.join(cwd, ".windsurfrules");
|
|
1793
|
+
fs5.writeFileSync(windsurfPath, toWindsurfrules(sections, projectName), "utf-8");
|
|
1794
|
+
console.log(chalk5.green(` ${ko.sync.windsurfDone}`));
|
|
1795
|
+
const copilotPath = path6.join(cwd, ".github", "copilot-instructions.md");
|
|
1796
|
+
fs5.mkdirSync(path6.dirname(copilotPath), { recursive: true });
|
|
1797
|
+
fs5.writeFileSync(copilotPath, toCopilotInstructions(sections, projectName), "utf-8");
|
|
1798
|
+
console.log(chalk5.green(` ${ko.sync.copilotDone}`));
|
|
1799
|
+
const antigravityPath = path6.join(cwd, ".agents", "rules", "vhk-rules.md");
|
|
1800
|
+
fs5.mkdirSync(path6.dirname(antigravityPath), { recursive: true });
|
|
1801
|
+
const antigravityDoc = toAntigravityRules(sections, projectName);
|
|
1802
|
+
fs5.writeFileSync(antigravityPath, antigravityDoc, "utf-8");
|
|
1803
|
+
console.log(chalk5.green(` ${ko.sync.antigravityDone}`));
|
|
1804
|
+
if (antigravityDoc.includes("\uC808\uC0AD\uB428")) {
|
|
1805
|
+
console.log(chalk5.yellow(` \u26A0\uFE0F ${ko.sync.antigravityTruncated}`));
|
|
1806
|
+
}
|
|
1641
1807
|
console.log(chalk5.bold.green(`
|
|
1642
1808
|
${ko.sync.done}`));
|
|
1643
|
-
console.log(chalk5.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md
|
|
1809
|
+
console.log(chalk5.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md + .windsurfrules"));
|
|
1810
|
+
console.log(chalk5.dim(" + .github/copilot-instructions.md + .agents/rules/vhk-rules.md (\uC790\uB3D9 \uC0DD\uC131)"));
|
|
1644
1811
|
console.log(chalk5.dim(" \uADDC\uCE59 \uBCC0\uACBD\uC740 \uD56D\uC0C1 RULES.md\uC5D0\uC11C\uB9CC \uD558\uC138\uC694."));
|
|
1645
1812
|
printNextStep({
|
|
1646
1813
|
message: "\uADDC\uCE59 \uB3D9\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C Cursor\uAC00 \uC0C8 \uADDC\uCE59\uC744 \uB530\uB985\uB2C8\uB2E4.",
|
|
@@ -1882,6 +2049,19 @@ function listGoals(goalsDir) {
|
|
|
1882
2049
|
parsed.sort((a, b) => a.frontmatter.id - b.frontmatter.id);
|
|
1883
2050
|
return parsed;
|
|
1884
2051
|
}
|
|
2052
|
+
function findDuplicateIds(goals) {
|
|
2053
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2054
|
+
for (const g of goals) {
|
|
2055
|
+
const id = g.frontmatter.id;
|
|
2056
|
+
if (typeof id !== "number") continue;
|
|
2057
|
+
counts.set(id, (counts.get(id) ?? 0) + 1);
|
|
2058
|
+
}
|
|
2059
|
+
const dups = [];
|
|
2060
|
+
for (const [id, n] of counts) {
|
|
2061
|
+
if (n > 1) dups.push(id);
|
|
2062
|
+
}
|
|
2063
|
+
return dups.sort((a, b) => a - b);
|
|
2064
|
+
}
|
|
1885
2065
|
function updateFrontmatterStatus(content, newStatus, extraFields) {
|
|
1886
2066
|
const m = content.match(FRONTMATTER_RE);
|
|
1887
2067
|
if (!m) return content;
|
|
@@ -1966,6 +2146,11 @@ ${ko.goal.listTitle}
|
|
|
1966
2146
|
` [${id}] ${icon} ${status2.padEnd(11)} ${pri} ${ver} ${fm.title ?? "(untitled)"}`
|
|
1967
2147
|
);
|
|
1968
2148
|
}
|
|
2149
|
+
const dups = findDuplicateIds(goals);
|
|
2150
|
+
if (dups.length > 0) {
|
|
2151
|
+
console.log("");
|
|
2152
|
+
console.log(chalk6.yellow(` ${ko.goal.duplicateId(dups.join(", "))}`));
|
|
2153
|
+
}
|
|
1969
2154
|
}
|
|
1970
2155
|
async function goalNext() {
|
|
1971
2156
|
console.log(chalk6.bold(`
|
|
@@ -2079,6 +2264,11 @@ ${ko.goal.checkTitle}
|
|
|
2079
2264
|
process.exitCode = 1;
|
|
2080
2265
|
return;
|
|
2081
2266
|
}
|
|
2267
|
+
if (!goals.some((g) => g.frontmatter.id === id)) {
|
|
2268
|
+
console.log(chalk6.red(` \u274C ${ko.goal.notFound(id)}`));
|
|
2269
|
+
process.exitCode = 1;
|
|
2270
|
+
return;
|
|
2271
|
+
}
|
|
2082
2272
|
const scriptPath = findGateScript(id);
|
|
2083
2273
|
if (!scriptPath) {
|
|
2084
2274
|
console.log(
|
|
@@ -2116,7 +2306,7 @@ ${ko.goal.doneTitle}
|
|
|
2116
2306
|
}
|
|
2117
2307
|
const target = goals.find((g) => g.frontmatter.id === id);
|
|
2118
2308
|
if (!target) {
|
|
2119
|
-
console.log(chalk6.red(` \u274C
|
|
2309
|
+
console.log(chalk6.red(` \u274C ${ko.goal.notFound(id)}`));
|
|
2120
2310
|
process.exitCode = 1;
|
|
2121
2311
|
return;
|
|
2122
2312
|
}
|
|
@@ -4361,6 +4551,211 @@ ${ko.start.allDone}
|
|
|
4361
4551
|
});
|
|
4362
4552
|
}
|
|
4363
4553
|
|
|
4554
|
+
// src/commands/cloud.ts
|
|
4555
|
+
import fs13 from "fs";
|
|
4556
|
+
import path14 from "path";
|
|
4557
|
+
import chalk26 from "chalk";
|
|
4558
|
+
|
|
4559
|
+
// src/lib/vhk-cloud.ts
|
|
4560
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
4561
|
+
import fs12 from "fs";
|
|
4562
|
+
import path13 from "path";
|
|
4563
|
+
var DEFAULT_CLOUD_EXCLUDES = [
|
|
4564
|
+
"memory.json",
|
|
4565
|
+
// ๊ฐ์ธ ์์ฌ๊ฒฐ์ ๋ฉ๋ชจ
|
|
4566
|
+
"refs.json",
|
|
4567
|
+
// ๊ฐ์ธ ์ฐธ๊ณ ๋งํฌ
|
|
4568
|
+
"HARD_STOP",
|
|
4569
|
+
// ๋ก์ปฌ ์์ ์ ํธ
|
|
4570
|
+
"cloud.json",
|
|
4571
|
+
// gist ํฌ์ธํฐ (๋ฐฑ์
๋์ ์๋)
|
|
4572
|
+
".gitignore"
|
|
4573
|
+
// .vhk/ ๋ด๋ถ gitignore
|
|
4574
|
+
];
|
|
4575
|
+
var VHK_DIR2 = ".vhk";
|
|
4576
|
+
var CLOUD_CONFIG_FILE = "cloud.json";
|
|
4577
|
+
function loadVhkignore(rootDir) {
|
|
4578
|
+
const ig = (0, import_ignore.default)();
|
|
4579
|
+
ig.add(DEFAULT_CLOUD_EXCLUDES);
|
|
4580
|
+
const ignorePath = path13.join(rootDir, ".vhkignore");
|
|
4581
|
+
if (fs12.existsSync(ignorePath)) {
|
|
4582
|
+
ig.add(fs12.readFileSync(ignorePath, "utf-8"));
|
|
4583
|
+
}
|
|
4584
|
+
return ig;
|
|
4585
|
+
}
|
|
4586
|
+
function collectVhkFiles(rootDir, ig = loadVhkignore(rootDir)) {
|
|
4587
|
+
const vhkDir = path13.join(rootDir, VHK_DIR2);
|
|
4588
|
+
let entries;
|
|
4589
|
+
try {
|
|
4590
|
+
entries = fs12.readdirSync(vhkDir, { withFileTypes: true });
|
|
4591
|
+
} catch {
|
|
4592
|
+
return [];
|
|
4593
|
+
}
|
|
4594
|
+
return entries.filter((e) => e.isFile()).map((e) => e.name).filter((name) => !ig.ignores(name)).sort();
|
|
4595
|
+
}
|
|
4596
|
+
function readCloudConfig(rootDir) {
|
|
4597
|
+
const p = path13.join(rootDir, VHK_DIR2, CLOUD_CONFIG_FILE);
|
|
4598
|
+
if (!fs12.existsSync(p)) return null;
|
|
4599
|
+
try {
|
|
4600
|
+
const parsed = JSON.parse(fs12.readFileSync(p, "utf-8"));
|
|
4601
|
+
if (parsed && typeof parsed.gistId === "string" && parsed.gistId) {
|
|
4602
|
+
return { gistId: parsed.gistId };
|
|
4603
|
+
}
|
|
4604
|
+
return null;
|
|
4605
|
+
} catch {
|
|
4606
|
+
return null;
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
function writeCloudConfig(rootDir, config) {
|
|
4610
|
+
const vhkDir = path13.join(rootDir, VHK_DIR2);
|
|
4611
|
+
fs12.mkdirSync(vhkDir, { recursive: true });
|
|
4612
|
+
const p = path13.join(vhkDir, CLOUD_CONFIG_FILE);
|
|
4613
|
+
fs12.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
// src/commands/cloud.ts
|
|
4617
|
+
function ensureGhReady() {
|
|
4618
|
+
const ver = safeExecFile("gh", ["--version"]);
|
|
4619
|
+
if (!ver.ok) {
|
|
4620
|
+
console.log(chalk26.red(` ${ko.cloud.noGh}`));
|
|
4621
|
+
console.log(chalk26.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
|
|
4622
|
+
return false;
|
|
4623
|
+
}
|
|
4624
|
+
const auth = safeExecFile("gh", ["auth", "status"]);
|
|
4625
|
+
if (!auth.ok) {
|
|
4626
|
+
console.log(chalk26.red(` ${ko.cloud.noAuth}`));
|
|
4627
|
+
console.log(chalk26.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
|
|
4628
|
+
return false;
|
|
4629
|
+
}
|
|
4630
|
+
return true;
|
|
4631
|
+
}
|
|
4632
|
+
function parseGistId(output) {
|
|
4633
|
+
const match = output.match(/gist\.github\.com\/(?:[^/]+\/)?([0-9a-f]+)/i);
|
|
4634
|
+
if (match) return match[1];
|
|
4635
|
+
const trimmed = output.trim();
|
|
4636
|
+
if (/^[0-9a-f]{8,}$/i.test(trimmed)) return trimmed;
|
|
4637
|
+
return null;
|
|
4638
|
+
}
|
|
4639
|
+
async function cloudPush() {
|
|
4640
|
+
console.log(chalk26.bold(`
|
|
4641
|
+
${ko.cloud.pushTitle}
|
|
4642
|
+
`));
|
|
4643
|
+
const cwd = process.cwd();
|
|
4644
|
+
if (!fs13.existsSync(path14.join(cwd, VHK_DIR2))) {
|
|
4645
|
+
console.log(chalk26.yellow(` ${ko.cloud.noVhkDir}`));
|
|
4646
|
+
return;
|
|
4647
|
+
}
|
|
4648
|
+
const files = collectVhkFiles(cwd);
|
|
4649
|
+
if (files.length === 0) {
|
|
4650
|
+
console.log(chalk26.yellow(` ${ko.cloud.nothingToSync}`));
|
|
4651
|
+
return;
|
|
4652
|
+
}
|
|
4653
|
+
if (!ensureGhReady()) {
|
|
4654
|
+
process.exitCode = 1;
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
const filePaths = files.map((f) => path14.join(cwd, VHK_DIR2, f));
|
|
4658
|
+
console.log(chalk26.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
|
|
4659
|
+
`));
|
|
4660
|
+
const existing = readCloudConfig(cwd);
|
|
4661
|
+
const desc = `vhk .vhk backup \u2014 ${path14.basename(cwd)}`;
|
|
4662
|
+
if (existing) {
|
|
4663
|
+
const gistFiles = listGistFiles(existing.gistId);
|
|
4664
|
+
for (let i = 0; i < files.length; i++) {
|
|
4665
|
+
const name = files[i];
|
|
4666
|
+
const src = filePaths[i];
|
|
4667
|
+
const args = gistFiles.includes(name) ? ["gist", "edit", existing.gistId, "-f", name, src] : ["gist", "edit", existing.gistId, "-a", src];
|
|
4668
|
+
const res2 = safeExecFile("gh", args);
|
|
4669
|
+
if (!res2.ok) {
|
|
4670
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail}: ${name}`));
|
|
4671
|
+
console.log(chalk26.dim(` ${res2.err}`));
|
|
4672
|
+
process.exitCode = 1;
|
|
4673
|
+
return;
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pushDone}`));
|
|
4677
|
+
console.log(chalk26.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
|
|
4678
|
+
printPushNext();
|
|
4679
|
+
return;
|
|
4680
|
+
}
|
|
4681
|
+
const res = safeExecFile("gh", ["gist", "create", "--desc", desc, ...filePaths]);
|
|
4682
|
+
if (!res.ok) {
|
|
4683
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail}`));
|
|
4684
|
+
console.log(chalk26.dim(` ${res.err || res.out}`));
|
|
4685
|
+
process.exitCode = 1;
|
|
4686
|
+
return;
|
|
4687
|
+
}
|
|
4688
|
+
const gistId = parseGistId(res.out);
|
|
4689
|
+
if (!gistId) {
|
|
4690
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
|
|
4691
|
+
console.log(chalk26.dim(` \uCD9C\uB825: ${res.out}`));
|
|
4692
|
+
process.exitCode = 1;
|
|
4693
|
+
return;
|
|
4694
|
+
}
|
|
4695
|
+
writeCloudConfig(cwd, { gistId });
|
|
4696
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pushDone}`));
|
|
4697
|
+
console.log(chalk26.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
|
|
4698
|
+
printPushNext();
|
|
4699
|
+
}
|
|
4700
|
+
async function cloudPull(gistIdArg) {
|
|
4701
|
+
console.log(chalk26.bold(`
|
|
4702
|
+
${ko.cloud.pullTitle}
|
|
4703
|
+
`));
|
|
4704
|
+
const cwd = process.cwd();
|
|
4705
|
+
const gistId = gistIdArg || readCloudConfig(cwd)?.gistId;
|
|
4706
|
+
if (!gistId) {
|
|
4707
|
+
console.log(chalk26.yellow(` ${ko.cloud.noGistId}`));
|
|
4708
|
+
console.log(chalk26.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
|
|
4709
|
+
return;
|
|
4710
|
+
}
|
|
4711
|
+
if (!ensureGhReady()) {
|
|
4712
|
+
process.exitCode = 1;
|
|
4713
|
+
return;
|
|
4714
|
+
}
|
|
4715
|
+
const names = listGistFiles(gistId);
|
|
4716
|
+
if (names.length === 0) {
|
|
4717
|
+
console.log(chalk26.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
|
|
4718
|
+
process.exitCode = 1;
|
|
4719
|
+
return;
|
|
4720
|
+
}
|
|
4721
|
+
const vhkDir = path14.join(cwd, VHK_DIR2);
|
|
4722
|
+
fs13.mkdirSync(vhkDir, { recursive: true });
|
|
4723
|
+
let restored = 0;
|
|
4724
|
+
for (const name of names) {
|
|
4725
|
+
const res = safeExecFile("gh", ["gist", "view", gistId, "-f", name, "--raw"]);
|
|
4726
|
+
if (!res.ok) {
|
|
4727
|
+
console.log(chalk26.red(` ${ko.cloud.pullFail}: ${name}`));
|
|
4728
|
+
console.log(chalk26.dim(` ${res.err}`));
|
|
4729
|
+
continue;
|
|
4730
|
+
}
|
|
4731
|
+
fs13.writeFileSync(path14.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
|
|
4732
|
+
restored++;
|
|
4733
|
+
}
|
|
4734
|
+
writeCloudConfig(cwd, { gistId });
|
|
4735
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pullDone}`));
|
|
4736
|
+
console.log(chalk26.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
|
|
4737
|
+
printNextStep({
|
|
4738
|
+
message: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk/ \uBCF5\uC6D0 \uC644\uB8CC!",
|
|
4739
|
+
command: "vhk \uB9E5\uB77D",
|
|
4740
|
+
cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uBCF4\uC5EC\uC918"
|
|
4741
|
+
});
|
|
4742
|
+
}
|
|
4743
|
+
function listGistFiles(gistId) {
|
|
4744
|
+
const res = safeExecFile("gh", ["gist", "view", gistId, "--files"]);
|
|
4745
|
+
if (!res.ok) return [];
|
|
4746
|
+
return res.out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
4747
|
+
}
|
|
4748
|
+
function ensureTrailingNewline(s) {
|
|
4749
|
+
return s.endsWith("\n") ? s : s + "\n";
|
|
4750
|
+
}
|
|
4751
|
+
function printPushNext() {
|
|
4752
|
+
printNextStep({
|
|
4753
|
+
message: "\uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 \uC644\uB8CC! \uB2E4\uB978 \uD658\uACBD\uC5D0\uC11C vhk cloud pull \uB85C \uBCF5\uC6D0\uD558\uC138\uC694.",
|
|
4754
|
+
command: "vhk cloud pull",
|
|
4755
|
+
cursorHint: "\uB2E4\uB978 \uCEF4\uD4E8\uD130\uC5D0\uC11C .vhk \uBCF5\uC6D0\uD574\uC918"
|
|
4756
|
+
});
|
|
4757
|
+
}
|
|
4758
|
+
|
|
4364
4759
|
// src/lib/nlp-run.ts
|
|
4365
4760
|
async function dispatchNlpRoute(route, input) {
|
|
4366
4761
|
switch (route.command) {
|
|
@@ -4429,6 +4824,10 @@ async function dispatchNlpRoute(route, input) {
|
|
|
4429
4824
|
return memoryList();
|
|
4430
4825
|
case "brief":
|
|
4431
4826
|
return brief();
|
|
4827
|
+
case "cloud-push":
|
|
4828
|
+
return cloudPush();
|
|
4829
|
+
case "cloud-pull":
|
|
4830
|
+
return cloudPull();
|
|
4432
4831
|
case "goal": {
|
|
4433
4832
|
const sub = route.args?.[0];
|
|
4434
4833
|
if (sub === "next") return goalNext();
|
|
@@ -4441,14 +4840,14 @@ async function dispatchNlpRoute(route, input) {
|
|
|
4441
4840
|
async function runNaturalLanguageRoute(input) {
|
|
4442
4841
|
const route = routeNaturalLanguage(input);
|
|
4443
4842
|
if (!route) {
|
|
4444
|
-
console.log(
|
|
4843
|
+
console.log(chalk27.yellow(`
|
|
4445
4844
|
\u2753 "${input}" \u2014 ${ko.nlp.notMatched}
|
|
4446
4845
|
`));
|
|
4447
4846
|
return;
|
|
4448
4847
|
}
|
|
4449
4848
|
console.log("");
|
|
4450
|
-
console.log(
|
|
4451
|
-
console.log(
|
|
4849
|
+
console.log(chalk27.cyan(` \u{1F4AC} "${input}"`));
|
|
4850
|
+
console.log(chalk27.cyan(` \u2192 ${route.explanation}`));
|
|
4452
4851
|
if (route.confidence === "low") {
|
|
4453
4852
|
const { confirm } = await inquirer11.prompt([{
|
|
4454
4853
|
type: "confirm",
|
|
@@ -4457,7 +4856,7 @@ async function runNaturalLanguageRoute(input) {
|
|
|
4457
4856
|
default: true
|
|
4458
4857
|
}]);
|
|
4459
4858
|
if (!confirm) {
|
|
4460
|
-
console.log(
|
|
4859
|
+
console.log(chalk27.dim(` ${ko.nlp.menuHint}`));
|
|
4461
4860
|
return;
|
|
4462
4861
|
}
|
|
4463
4862
|
}
|
|
@@ -4466,77 +4865,77 @@ async function runNaturalLanguageRoute(input) {
|
|
|
4466
4865
|
}
|
|
4467
4866
|
|
|
4468
4867
|
// src/commands/agent.ts
|
|
4469
|
-
import
|
|
4868
|
+
import chalk28 from "chalk";
|
|
4470
4869
|
function activeGoalId() {
|
|
4471
4870
|
const goals = listGoals("goals");
|
|
4472
4871
|
const id = selectActiveId(goals);
|
|
4473
4872
|
return id ?? void 0;
|
|
4474
4873
|
}
|
|
4475
4874
|
async function blocker(description) {
|
|
4476
|
-
console.log(
|
|
4875
|
+
console.log(chalk28.bold(`
|
|
4477
4876
|
${ko.agent.blockerTitle}
|
|
4478
4877
|
`));
|
|
4479
4878
|
if (!description || !description.trim()) {
|
|
4480
|
-
console.log(
|
|
4481
|
-
console.log(
|
|
4879
|
+
console.log(chalk28.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
4880
|
+
console.log(chalk28.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
|
|
4482
4881
|
process.exitCode = 1;
|
|
4483
4882
|
return;
|
|
4484
4883
|
}
|
|
4485
4884
|
const goalId = activeGoalId();
|
|
4486
4885
|
const r = appendBlocker(description, goalId);
|
|
4487
|
-
console.log(
|
|
4886
|
+
console.log(chalk28.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
|
|
4488
4887
|
if (r.hardStopTripped) {
|
|
4489
|
-
console.log(
|
|
4490
|
-
console.log(
|
|
4888
|
+
console.log(chalk28.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
|
|
4889
|
+
console.log(chalk28.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
|
|
4491
4890
|
process.exitCode = 2;
|
|
4492
4891
|
}
|
|
4493
4892
|
}
|
|
4494
4893
|
async function learn(lesson) {
|
|
4495
|
-
console.log(
|
|
4894
|
+
console.log(chalk28.bold(`
|
|
4496
4895
|
${ko.agent.learnTitle}
|
|
4497
4896
|
`));
|
|
4498
4897
|
if (!lesson || !lesson.trim()) {
|
|
4499
|
-
console.log(
|
|
4500
|
-
console.log(
|
|
4898
|
+
console.log(chalk28.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
4899
|
+
console.log(chalk28.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
|
|
4501
4900
|
process.exitCode = 1;
|
|
4502
4901
|
return;
|
|
4503
4902
|
}
|
|
4504
4903
|
const goalId = activeGoalId();
|
|
4505
4904
|
appendLearning(lesson, goalId);
|
|
4506
|
-
console.log(
|
|
4905
|
+
console.log(chalk28.green(" \u2705 learnings.md append."));
|
|
4507
4906
|
console.log(
|
|
4508
|
-
|
|
4907
|
+
chalk28.dim(" \uACB0\uC815\uC0AC\uD56D(decision)\uC740 `vhk memory add` \uB85C \uBCC4\uB3C4 \uAE30\uB85D \u2014 SoT \uBD84\uB9AC.")
|
|
4509
4908
|
);
|
|
4510
4909
|
}
|
|
4511
4910
|
async function resume(opts = {}) {
|
|
4512
|
-
console.log(
|
|
4911
|
+
console.log(chalk28.bold(`
|
|
4513
4912
|
${ko.agent.resumeTitle}
|
|
4514
4913
|
`));
|
|
4515
4914
|
if (!isHardStopActive()) {
|
|
4516
|
-
console.log(
|
|
4915
|
+
console.log(chalk28.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
|
|
4517
4916
|
return;
|
|
4518
4917
|
}
|
|
4519
4918
|
const reason = readHardStopReason();
|
|
4520
4919
|
if (reason) {
|
|
4521
|
-
console.log(
|
|
4522
|
-
console.log(
|
|
4920
|
+
console.log(chalk28.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
|
|
4921
|
+
console.log(chalk28.dim(` ${reason.split("\n").join("\n ")}`));
|
|
4523
4922
|
console.log("");
|
|
4524
4923
|
}
|
|
4525
4924
|
if (!opts.confirm) {
|
|
4526
4925
|
console.log(
|
|
4527
|
-
|
|
4926
|
+
chalk28.red(
|
|
4528
4927
|
" \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
|
|
4529
4928
|
)
|
|
4530
4929
|
);
|
|
4531
|
-
console.log(
|
|
4930
|
+
console.log(chalk28.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
|
|
4532
4931
|
process.exitCode = 1;
|
|
4533
4932
|
return;
|
|
4534
4933
|
}
|
|
4535
4934
|
const removed = clearHardStop();
|
|
4536
4935
|
if (removed) {
|
|
4537
|
-
console.log(
|
|
4936
|
+
console.log(chalk28.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
|
|
4538
4937
|
} else {
|
|
4539
|
-
console.log(
|
|
4938
|
+
console.log(chalk28.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
|
|
4540
4939
|
}
|
|
4541
4940
|
}
|
|
4542
4941
|
|
|
@@ -4612,6 +5011,15 @@ program.command("check").alias("\uC810\uAC80").alias("\uB9B0\uD2B8").option("--g
|
|
|
4612
5011
|
});
|
|
4613
5012
|
var secureCmd = program.command("secure").alias("\uBCF4\uC548").description("\uBCF4\uC548 \uB3C4\uAD6C \uBAA8\uC74C \u2014 scan: \uC2DC\uD06C\uB9BF\xB7\uD0A4 \uC720\uCD9C \uAC80\uC0AC").action(secure);
|
|
4614
5013
|
secureCmd.command("scan").alias("\uC2A4\uCE94").description("\uC2DC\uD06C\uB9BF/\uD0A4 \uC720\uCD9C \uC2A4\uCE94").action(secure);
|
|
5014
|
+
var cloudCmd = program.command("cloud").alias("\uD074\uB77C\uC6B0\uB4DC").description(".vhk/ \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5\xB7\uBCF5\uC6D0 (GitHub gist) \u2014 push: \uC62C\uB9AC\uAE30, pull: \uB0B4\uB9AC\uAE30").action(() => {
|
|
5015
|
+
cloudCmd.help();
|
|
5016
|
+
});
|
|
5017
|
+
cloudCmd.command("push").alias("\uC62C\uB9AC\uAE30").description(".vhk/ \uB97C secret gist \uB85C \uBC31\uC5C5").action(async () => {
|
|
5018
|
+
await cloudPush();
|
|
5019
|
+
});
|
|
5020
|
+
cloudCmd.command("pull").alias("\uB0B4\uB9AC\uAE30").argument("[gistId]", "\uBCF5\uC6D0\uD560 gist id (\uC0DD\uB7B5 \uC2DC .vhk/cloud.json \uC0AC\uC6A9)").description("gist \uC5D0\uC11C .vhk/ \uBCF5\uC6D0").action(async (gistId) => {
|
|
5021
|
+
await cloudPull(gistId);
|
|
5022
|
+
});
|
|
4615
5023
|
program.command("ship").alias("\uCD9C\uD558").description("\uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 + \uD68C\uACE0 + \uBE4C\uB4DC \uB85C\uADF8 \uC0DD\uC131").action(ship);
|
|
4616
5024
|
program.command("doctor").alias("\uD658\uACBD").alias("\uC9C4\uB2E8").description("\uAC1C\uBC1C \uD658\uACBD \uC810\uAC80 \u2014 Node/Git/npm \uC0C1\uD0DC \uD655\uC778").action(doctor);
|
|
4617
5025
|
program.command("save").alias("\uC800\uC7A5").description("\uBCC0\uACBD\uC0AC\uD56D \uC800\uC7A5 (git add \u2192 commit \u2192 push)").action(async () => {
|
package/dist/mcp/index.js
CHANGED