@byh3071/vhk 1.3.1 โ 1.4.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 +23 -3
- package/dist/{chunk-6S3JYYZ3.js โ chunk-3DV7AEN4.js} +19 -1
- package/dist/index.js +391 -31
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
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.
|
|
4
|
+
tags: [vhk, cli, readme, v1.4.0, ga]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ๐ง VHK โ Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> ๐ **v1.
|
|
9
|
+
> ๐ **v1.4.0** โ ๋ฐ์ด๋ธ์ฝ๋์ ์ฌ์ธ์ CLI. ์ปจํ
์คํธ + ์์จ ํ๋ค์ค + ํฌํฐ๋น๋ฆฌํฐ.
|
|
10
10
|
>
|
|
11
11
|
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI**.
|
|
12
12
|
>
|
|
@@ -115,11 +115,13 @@ vhk ๊ธฐํ ๋๋ฌ๊ณ ๋ฐ๋ก ์์
|
|
|
115
115
|
| `vhk gate` | `๊ฒ์ฆ`, `์์ด๋์ด` | ์์ด๋์ด ๊ฒ์ฆ (ํต 5๋ฌธํญ / ํ 13๋ฌธํญ / ์คํต) |
|
|
116
116
|
| `vhk init` | `์์`, `๋ง๋ค๊ธฐ` | ํ๋ก์ ํธ ์ด๊ธฐํ + ํ๋ค์ค ์์ฑ |
|
|
117
117
|
| `vhk recap` | `์ ๋ฆฌ`, `์ค๋` | Git ๋ณ๊ฒฝ โ `docs/log/` ์ธ์
๋ก๊ทธ |
|
|
118
|
-
| `vhk sync` | `๊ท์น`, `๋ง์ถ๊ธฐ` | RULES.md โ `.cursorrules` + CLAUDE.md |
|
|
118
|
+
| `vhk sync` | `๊ท์น`, `๋ง์ถ๊ธฐ` | RULES.md โ `.cursorrules` + CLAUDE.md + `.windsurfrules` |
|
|
119
119
|
| `vhk check` | `์ ๊ฒ`, `๋ฆฐํธ` | RULES.md ๊ท์น ์๋ฐ ๊ฒ์ฌ |
|
|
120
120
|
| `vhk secure` | `๋ณด์` | ์ํฌ๋ฆฟยทํค ์ ์ถ ์ค์บ (`scan` / `์ค์บ` ๋์ผ). **CRITICAL/HIGH ๋ฐ๊ฒฌ ์ exit code 1** (CI์ฉ) |
|
|
121
121
|
| `vhk ship` | `์ถํ` | ๋ฐฐํฌ ์ฒดํฌ๋ฆฌ์คํธ + ํ๊ณ + ๋น๋ ๋ก๊ทธ |
|
|
122
122
|
| `vhk doctor` | `ํ๊ฒฝ`, `์ง๋จ` | Node / npm / pnpm / Git ํ๊ฒฝ ์ ๊ฒ |
|
|
123
|
+
| `vhk cloud push` | `ํด๋ผ์ฐ๋`, `์ฌ๋ฆฌ๊ธฐ` | `.vhk/` ๋ฅผ GitHub secret gist ๋ก ๋ฐฑ์
(gh CLI ์ธ์ฆ ์ฌ์ฉ) |
|
|
124
|
+
| `vhk cloud pull` | `๋ด๋ฆฌ๊ธฐ` | gist ์์ `.vhk/` ๋ณต์ (`vhk cloud pull <gistId>` ๋๋ cloud.json) |
|
|
123
125
|
| `vhk save` | `์ ์ฅ`, `์ปค๋ฐ` | git add ยท commit ยท push ํ ๋ฒ์ |
|
|
124
126
|
| `vhk undo` | `๋๋๋ฆฌ๊ธฐ`, `์ทจ์` | ์ต๊ทผ ์ปค๋ฐ soft reset (๋ณ๊ฒฝ์ staged ์ ์ง) |
|
|
125
127
|
| `vhk diff` | `๋ณ๊ฒฝ`, `์ฐจ์ด` | staged / unstaged / ์ ํ์ผ ์์ฝ (์ค ์ ํฉ๊ณ๋ trackedยทHEAD ๊ธฐ์ค) |
|
|
@@ -340,8 +342,26 @@ vhk ref open 1 # 1๋ฒ ๋ ํผ๋ฐ์ค๋ฅผ ๋ธ๋ผ์ฐ์ ๋ก ์ด๊ธฐ
|
|
|
340
342
|
- `docs/PRD.md`, `docs/ARCHITECTURE.md`
|
|
341
343
|
- `docs/adr/`, `docs/log/`, `docs/troubleshooting/`
|
|
342
344
|
- `COMMANDS.md`, `BACKLOG.md` (ํ๋ก์ ํธ ์ ํ์ ๋ฐ๋ผ)
|
|
345
|
+
- `.vhk/README.md` + `.vhk/context.md` (์ ํ๋ณ ์จ์ โ ๊ท๊ฒฉ: [`docs/spec.md`](docs/spec.md))
|
|
346
|
+
- `.vhk/.gitignore` + `.vhkignore` (๋ก์ปฌ ์ ์ฉยทํด๋ผ์ฐ๋ ์ ์ธ ๊ท์น)
|
|
347
|
+
- ๋ฃจํธ `.gitignore` (`.env`ยท`node_modules`ยท`dist` ๋ณดํธ โ ๊ธฐ์กด ํ์ผ์ ๋ณด์กดํ๊ณ ๋๋ฝ๋ถ๋ง ์ถ๊ฐ)
|
|
343
348
|
- `package.json` scripts: `save`, `check`, `scan`, `recap`, `ship`, `doctor` โ `vhk` ํธ์ถ
|
|
344
349
|
|
|
350
|
+
## ํด๋ผ์ฐ๋ ๋ฐฑ์
(vhk cloud)
|
|
351
|
+
|
|
352
|
+
`.vhk/` ํ๋ก์ ํธ ๋งฅ๋ฝ์ GitHub **secret gist** ๋ก ๋ฐฑ์
ยท๋ณต์ํฉ๋๋ค. ์ปดํจํฐ๋ฅผ ๋ฐ๊ฟ๋
|
|
353
|
+
๊ท์นยท๋งฅ๋ฝ์ด ๋ฐ๋ผ์ต๋๋ค. ๊ท๊ฒฉ์ [`docs/spec.md`](docs/spec.md) ์ฐธ์กฐ.
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
vhk cloud push # .vhk/ โ secret gist ๋ฐฑ์
(gist id ๋ .vhk/cloud.json ์ ์ ์ฅ)
|
|
357
|
+
vhk cloud pull # cloud.json ์ gist ์์ ๋ณต์
|
|
358
|
+
vhk cloud pull <gistId> # ์ ํ๊ฒฝ์์ gist id ๋ก ์ง์ ๋ณต์
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
- **์ธ์ฆ:** `gh` CLI ์ฌ์ฉ (`gh auth login`, gist ๊ถํ). ์ฝ๋ยท์ค์ ์ ํ ํฐ์ ์ ์ฅํ์ง ์์ต๋๋ค.
|
|
362
|
+
- **ํ๋ผ์ด๋ฒ์:** gist ๋ secret(๋น๊ณต๊ฐ). ๊ฐ์ธ ๋ฉ๋ชจ(`memory.json`)ยท์ฐธ๊ณ ๋งํฌ(`refs.json`)ยท
|
|
363
|
+
`HARD_STOP` ์ ๊ธฐ๋ณธ ์ ์ธ๋ฉ๋๋ค. ์ถ๊ฐ ์ ์ธ๋ ๋ฃจํธ `.vhkignore` ์ ํ ์ค์ฉ ์ ์ผ์ธ์.
|
|
364
|
+
|
|
345
365
|
## ์์ฐ์ด ์์
|
|
346
366
|
|
|
347
367
|
| ๋งํ๋ฉด | ์คํ |
|
|
@@ -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,22 @@ 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",
|
|
755
758
|
done: "\u{1F504} \uB9DE\uCD94\uAE30 \uC644\uB8CC!"
|
|
756
759
|
},
|
|
760
|
+
cloud: {
|
|
761
|
+
pushTitle: "\u2601\uFE0F .vhk \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 (gist \uC62C\uB9AC\uAE30)",
|
|
762
|
+
pullTitle: "\u2601\uFE0F .vhk \uD074\uB77C\uC6B0\uB4DC \uBCF5\uC6D0 (gist \uB0B4\uB9AC\uAE30)",
|
|
763
|
+
noGh: "gh CLI \uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
|
|
764
|
+
noAuth: "gh \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 (gist \uAD8C\uD55C).",
|
|
765
|
+
noVhkDir: ".vhk/ \uD3F4\uB354\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. vhk init \uB610\uB294 vhk context \uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694.",
|
|
766
|
+
nothingToSync: "\uBC31\uC5C5\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (.vhkignore \uB85C \uBAA8\uB450 \uC81C\uC678\uB428).",
|
|
767
|
+
noGistId: "\uBCF5\uC6D0\uD560 gist id \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
|
|
768
|
+
pushDone: "\u2705 \uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 \uC644\uB8CC",
|
|
769
|
+
pullDone: "\u2705 \uD074\uB77C\uC6B0\uB4DC \uBCF5\uC6D0 \uC644\uB8CC",
|
|
770
|
+
pushFail: "\u274C \uBC31\uC5C5 \uC2E4\uD328",
|
|
771
|
+
pullFail: "\u274C \uBCF5\uC6D0 \uC2E4\uD328"
|
|
772
|
+
},
|
|
757
773
|
ship: {
|
|
758
774
|
title: "\u{1F680} \uBC30\uD3EC \uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
759
775
|
checklist: "\u{1F4CB} \uBC30\uD3EC \uC804 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8",
|
|
@@ -2134,9 +2150,11 @@ async function startMcpServer() {
|
|
|
2134
2150
|
}
|
|
2135
2151
|
|
|
2136
2152
|
export {
|
|
2153
|
+
__toESM,
|
|
2137
2154
|
ko,
|
|
2138
2155
|
t,
|
|
2139
2156
|
printNextStep,
|
|
2157
|
+
require_ignore,
|
|
2140
2158
|
printSecurityWarnings,
|
|
2141
2159
|
filterTrackedPaths,
|
|
2142
2160
|
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-3DV7AEN4.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
|
|
@@ -1579,6 +1697,27 @@ function toCursorrules(sections, projectName) {
|
|
|
1579
1697
|
}
|
|
1580
1698
|
return lines.join("\n");
|
|
1581
1699
|
}
|
|
1700
|
+
function toWindsurfrules(sections, projectName) {
|
|
1701
|
+
const codingSections = sections.filter(
|
|
1702
|
+
(s) => CURSORRULES_KEYS.some((k) => s.title.includes(k))
|
|
1703
|
+
);
|
|
1704
|
+
const lines = [
|
|
1705
|
+
`# ${projectName} \u2014 Windsurf Rules`,
|
|
1706
|
+
"",
|
|
1707
|
+
"> \uCF54\uB529/\uB514\uC790\uC778 \uC804\uC6A9. \uAE30\uB85D/\uC6B4\uC601 \u2192 CLAUDE.md \uCC38\uC870.",
|
|
1708
|
+
"> \u26A1 \uC774 \uD30C\uC77C\uC740 RULES.md\uC5D0\uC11C \uC790\uB3D9 \uC0DD\uC131\uB428 (vhk sync). \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0.",
|
|
1709
|
+
"",
|
|
1710
|
+
"## \uD544\uC218 \uCC38\uC870",
|
|
1711
|
+
"- docs/PRD.md \xB7 docs/ARCHITECTURE.md \xB7 CLAUDE.md \xB7 RULES.md",
|
|
1712
|
+
""
|
|
1713
|
+
];
|
|
1714
|
+
for (const section of codingSections) {
|
|
1715
|
+
lines.push(`## ${section.title}`);
|
|
1716
|
+
lines.push(section.content);
|
|
1717
|
+
lines.push("");
|
|
1718
|
+
}
|
|
1719
|
+
return lines.join("\n");
|
|
1720
|
+
}
|
|
1582
1721
|
function toClaudeMd(sections, existing) {
|
|
1583
1722
|
const recordSections = sections.filter(
|
|
1584
1723
|
(s) => CLAUDE_MD_KEYS.some((k) => s.title.includes(k))
|
|
@@ -1638,9 +1777,12 @@ ${ko.sync.title}
|
|
|
1638
1777
|
- **\uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8:** ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`;
|
|
1639
1778
|
fs5.writeFileSync(claudePath, toClaudeMd(sections, existingClaude), "utf-8");
|
|
1640
1779
|
console.log(chalk5.green(` ${ko.sync.claudeDone}`));
|
|
1780
|
+
const windsurfPath = path6.join(cwd, ".windsurfrules");
|
|
1781
|
+
fs5.writeFileSync(windsurfPath, toWindsurfrules(sections, projectName), "utf-8");
|
|
1782
|
+
console.log(chalk5.green(` ${ko.sync.windsurfDone}`));
|
|
1641
1783
|
console.log(chalk5.bold.green(`
|
|
1642
1784
|
${ko.sync.done}`));
|
|
1643
|
-
console.log(chalk5.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md (\uC790\uB3D9 \uC0DD\uC131)"));
|
|
1785
|
+
console.log(chalk5.dim(" RULES.md (\uC6D0\uBCF8) \u2192 .cursorrules + CLAUDE.md + .windsurfrules (\uC790\uB3D9 \uC0DD\uC131)"));
|
|
1644
1786
|
console.log(chalk5.dim(" \uADDC\uCE59 \uBCC0\uACBD\uC740 \uD56D\uC0C1 RULES.md\uC5D0\uC11C\uB9CC \uD558\uC138\uC694."));
|
|
1645
1787
|
printNextStep({
|
|
1646
1788
|
message: "\uADDC\uCE59 \uB3D9\uAE30\uD654 \uC644\uB8CC! \uC774\uC81C Cursor\uAC00 \uC0C8 \uADDC\uCE59\uC744 \uB530\uB985\uB2C8\uB2E4.",
|
|
@@ -4361,6 +4503,211 @@ ${ko.start.allDone}
|
|
|
4361
4503
|
});
|
|
4362
4504
|
}
|
|
4363
4505
|
|
|
4506
|
+
// src/commands/cloud.ts
|
|
4507
|
+
import fs13 from "fs";
|
|
4508
|
+
import path14 from "path";
|
|
4509
|
+
import chalk26 from "chalk";
|
|
4510
|
+
|
|
4511
|
+
// src/lib/vhk-cloud.ts
|
|
4512
|
+
var import_ignore = __toESM(require_ignore(), 1);
|
|
4513
|
+
import fs12 from "fs";
|
|
4514
|
+
import path13 from "path";
|
|
4515
|
+
var DEFAULT_CLOUD_EXCLUDES = [
|
|
4516
|
+
"memory.json",
|
|
4517
|
+
// ๊ฐ์ธ ์์ฌ๊ฒฐ์ ๋ฉ๋ชจ
|
|
4518
|
+
"refs.json",
|
|
4519
|
+
// ๊ฐ์ธ ์ฐธ๊ณ ๋งํฌ
|
|
4520
|
+
"HARD_STOP",
|
|
4521
|
+
// ๋ก์ปฌ ์์ ์ ํธ
|
|
4522
|
+
"cloud.json",
|
|
4523
|
+
// gist ํฌ์ธํฐ (๋ฐฑ์
๋์ ์๋)
|
|
4524
|
+
".gitignore"
|
|
4525
|
+
// .vhk/ ๋ด๋ถ gitignore
|
|
4526
|
+
];
|
|
4527
|
+
var VHK_DIR2 = ".vhk";
|
|
4528
|
+
var CLOUD_CONFIG_FILE = "cloud.json";
|
|
4529
|
+
function loadVhkignore(rootDir) {
|
|
4530
|
+
const ig = (0, import_ignore.default)();
|
|
4531
|
+
ig.add(DEFAULT_CLOUD_EXCLUDES);
|
|
4532
|
+
const ignorePath = path13.join(rootDir, ".vhkignore");
|
|
4533
|
+
if (fs12.existsSync(ignorePath)) {
|
|
4534
|
+
ig.add(fs12.readFileSync(ignorePath, "utf-8"));
|
|
4535
|
+
}
|
|
4536
|
+
return ig;
|
|
4537
|
+
}
|
|
4538
|
+
function collectVhkFiles(rootDir, ig = loadVhkignore(rootDir)) {
|
|
4539
|
+
const vhkDir = path13.join(rootDir, VHK_DIR2);
|
|
4540
|
+
let entries;
|
|
4541
|
+
try {
|
|
4542
|
+
entries = fs12.readdirSync(vhkDir, { withFileTypes: true });
|
|
4543
|
+
} catch {
|
|
4544
|
+
return [];
|
|
4545
|
+
}
|
|
4546
|
+
return entries.filter((e) => e.isFile()).map((e) => e.name).filter((name) => !ig.ignores(name)).sort();
|
|
4547
|
+
}
|
|
4548
|
+
function readCloudConfig(rootDir) {
|
|
4549
|
+
const p = path13.join(rootDir, VHK_DIR2, CLOUD_CONFIG_FILE);
|
|
4550
|
+
if (!fs12.existsSync(p)) return null;
|
|
4551
|
+
try {
|
|
4552
|
+
const parsed = JSON.parse(fs12.readFileSync(p, "utf-8"));
|
|
4553
|
+
if (parsed && typeof parsed.gistId === "string" && parsed.gistId) {
|
|
4554
|
+
return { gistId: parsed.gistId };
|
|
4555
|
+
}
|
|
4556
|
+
return null;
|
|
4557
|
+
} catch {
|
|
4558
|
+
return null;
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
function writeCloudConfig(rootDir, config) {
|
|
4562
|
+
const vhkDir = path13.join(rootDir, VHK_DIR2);
|
|
4563
|
+
fs12.mkdirSync(vhkDir, { recursive: true });
|
|
4564
|
+
const p = path13.join(vhkDir, CLOUD_CONFIG_FILE);
|
|
4565
|
+
fs12.writeFileSync(p, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
// src/commands/cloud.ts
|
|
4569
|
+
function ensureGhReady() {
|
|
4570
|
+
const ver = safeExecFile("gh", ["--version"]);
|
|
4571
|
+
if (!ver.ok) {
|
|
4572
|
+
console.log(chalk26.red(` ${ko.cloud.noGh}`));
|
|
4573
|
+
console.log(chalk26.dim(" \uC124\uCE58: https://cli.github.com/ (\uC124\uCE58 \uD6C4 `gh auth login`)"));
|
|
4574
|
+
return false;
|
|
4575
|
+
}
|
|
4576
|
+
const auth = safeExecFile("gh", ["auth", "status"]);
|
|
4577
|
+
if (!auth.ok) {
|
|
4578
|
+
console.log(chalk26.red(` ${ko.cloud.noAuth}`));
|
|
4579
|
+
console.log(chalk26.dim(" \uC2E4\uD589: gh auth login (gist \uAD8C\uD55C \uD544\uC694)"));
|
|
4580
|
+
return false;
|
|
4581
|
+
}
|
|
4582
|
+
return true;
|
|
4583
|
+
}
|
|
4584
|
+
function parseGistId(output) {
|
|
4585
|
+
const match = output.match(/gist\.github\.com\/(?:[^/]+\/)?([0-9a-f]+)/i);
|
|
4586
|
+
if (match) return match[1];
|
|
4587
|
+
const trimmed = output.trim();
|
|
4588
|
+
if (/^[0-9a-f]{8,}$/i.test(trimmed)) return trimmed;
|
|
4589
|
+
return null;
|
|
4590
|
+
}
|
|
4591
|
+
async function cloudPush() {
|
|
4592
|
+
console.log(chalk26.bold(`
|
|
4593
|
+
${ko.cloud.pushTitle}
|
|
4594
|
+
`));
|
|
4595
|
+
const cwd = process.cwd();
|
|
4596
|
+
if (!fs13.existsSync(path14.join(cwd, VHK_DIR2))) {
|
|
4597
|
+
console.log(chalk26.yellow(` ${ko.cloud.noVhkDir}`));
|
|
4598
|
+
return;
|
|
4599
|
+
}
|
|
4600
|
+
const files = collectVhkFiles(cwd);
|
|
4601
|
+
if (files.length === 0) {
|
|
4602
|
+
console.log(chalk26.yellow(` ${ko.cloud.nothingToSync}`));
|
|
4603
|
+
return;
|
|
4604
|
+
}
|
|
4605
|
+
if (!ensureGhReady()) {
|
|
4606
|
+
process.exitCode = 1;
|
|
4607
|
+
return;
|
|
4608
|
+
}
|
|
4609
|
+
const filePaths = files.map((f) => path14.join(cwd, VHK_DIR2, f));
|
|
4610
|
+
console.log(chalk26.dim(` \u{1F4E6} \uBC31\uC5C5 \uB300\uC0C1 ${files.length}\uAC1C: ${files.join(", ")}
|
|
4611
|
+
`));
|
|
4612
|
+
const existing = readCloudConfig(cwd);
|
|
4613
|
+
const desc = `vhk .vhk backup \u2014 ${path14.basename(cwd)}`;
|
|
4614
|
+
if (existing) {
|
|
4615
|
+
const gistFiles = listGistFiles(existing.gistId);
|
|
4616
|
+
for (let i = 0; i < files.length; i++) {
|
|
4617
|
+
const name = files[i];
|
|
4618
|
+
const src = filePaths[i];
|
|
4619
|
+
const args = gistFiles.includes(name) ? ["gist", "edit", existing.gistId, "-f", name, src] : ["gist", "edit", existing.gistId, "-a", src];
|
|
4620
|
+
const res2 = safeExecFile("gh", args);
|
|
4621
|
+
if (!res2.ok) {
|
|
4622
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail}: ${name}`));
|
|
4623
|
+
console.log(chalk26.dim(` ${res2.err}`));
|
|
4624
|
+
process.exitCode = 1;
|
|
4625
|
+
return;
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pushDone}`));
|
|
4629
|
+
console.log(chalk26.dim(` gist: ${existing.gistId} (\uAC31\uC2E0)`));
|
|
4630
|
+
printPushNext();
|
|
4631
|
+
return;
|
|
4632
|
+
}
|
|
4633
|
+
const res = safeExecFile("gh", ["gist", "create", "--desc", desc, ...filePaths]);
|
|
4634
|
+
if (!res.ok) {
|
|
4635
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail}`));
|
|
4636
|
+
console.log(chalk26.dim(` ${res.err || res.out}`));
|
|
4637
|
+
process.exitCode = 1;
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
const gistId = parseGistId(res.out);
|
|
4641
|
+
if (!gistId) {
|
|
4642
|
+
console.log(chalk26.red(` ${ko.cloud.pushFail} \u2014 gist id \uD30C\uC2F1 \uC2E4\uD328`));
|
|
4643
|
+
console.log(chalk26.dim(` \uCD9C\uB825: ${res.out}`));
|
|
4644
|
+
process.exitCode = 1;
|
|
4645
|
+
return;
|
|
4646
|
+
}
|
|
4647
|
+
writeCloudConfig(cwd, { gistId });
|
|
4648
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pushDone}`));
|
|
4649
|
+
console.log(chalk26.dim(` gist: ${gistId} (\uC2E0\uADDC, secret) \u2192 .vhk/cloud.json \uC800\uC7A5`));
|
|
4650
|
+
printPushNext();
|
|
4651
|
+
}
|
|
4652
|
+
async function cloudPull(gistIdArg) {
|
|
4653
|
+
console.log(chalk26.bold(`
|
|
4654
|
+
${ko.cloud.pullTitle}
|
|
4655
|
+
`));
|
|
4656
|
+
const cwd = process.cwd();
|
|
4657
|
+
const gistId = gistIdArg || readCloudConfig(cwd)?.gistId;
|
|
4658
|
+
if (!gistId) {
|
|
4659
|
+
console.log(chalk26.yellow(` ${ko.cloud.noGistId}`));
|
|
4660
|
+
console.log(chalk26.dim(" \uC0AC\uC6A9\uBC95: vhk cloud pull <gistId> (\uB610\uB294 cloud.json \uC774 \uC788\uB294 \uACF3\uC5D0\uC11C \uC2E4\uD589)"));
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
if (!ensureGhReady()) {
|
|
4664
|
+
process.exitCode = 1;
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4667
|
+
const names = listGistFiles(gistId);
|
|
4668
|
+
if (names.length === 0) {
|
|
4669
|
+
console.log(chalk26.red(` ${ko.cloud.pullFail} \u2014 gist \uBE44\uC5C8\uAC70\uB098 \uC811\uADFC \uBD88\uAC00: ${gistId}`));
|
|
4670
|
+
process.exitCode = 1;
|
|
4671
|
+
return;
|
|
4672
|
+
}
|
|
4673
|
+
const vhkDir = path14.join(cwd, VHK_DIR2);
|
|
4674
|
+
fs13.mkdirSync(vhkDir, { recursive: true });
|
|
4675
|
+
let restored = 0;
|
|
4676
|
+
for (const name of names) {
|
|
4677
|
+
const res = safeExecFile("gh", ["gist", "view", gistId, "-f", name, "--raw"]);
|
|
4678
|
+
if (!res.ok) {
|
|
4679
|
+
console.log(chalk26.red(` ${ko.cloud.pullFail}: ${name}`));
|
|
4680
|
+
console.log(chalk26.dim(` ${res.err}`));
|
|
4681
|
+
continue;
|
|
4682
|
+
}
|
|
4683
|
+
fs13.writeFileSync(path14.join(vhkDir, name), ensureTrailingNewline(res.out), "utf-8");
|
|
4684
|
+
restored++;
|
|
4685
|
+
}
|
|
4686
|
+
writeCloudConfig(cwd, { gistId });
|
|
4687
|
+
console.log(chalk26.green.bold(` ${ko.cloud.pullDone}`));
|
|
4688
|
+
console.log(chalk26.dim(` ${restored}\uAC1C \uD30C\uC77C \uBCF5\uC6D0 (gist: ${gistId})`));
|
|
4689
|
+
printNextStep({
|
|
4690
|
+
message: "\uD074\uB77C\uC6B0\uB4DC\uC5D0\uC11C .vhk/ \uBCF5\uC6D0 \uC644\uB8CC!",
|
|
4691
|
+
command: "vhk \uB9E5\uB77D",
|
|
4692
|
+
cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uBCF4\uC5EC\uC918"
|
|
4693
|
+
});
|
|
4694
|
+
}
|
|
4695
|
+
function listGistFiles(gistId) {
|
|
4696
|
+
const res = safeExecFile("gh", ["gist", "view", gistId, "--files"]);
|
|
4697
|
+
if (!res.ok) return [];
|
|
4698
|
+
return res.out.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
4699
|
+
}
|
|
4700
|
+
function ensureTrailingNewline(s) {
|
|
4701
|
+
return s.endsWith("\n") ? s : s + "\n";
|
|
4702
|
+
}
|
|
4703
|
+
function printPushNext() {
|
|
4704
|
+
printNextStep({
|
|
4705
|
+
message: "\uD074\uB77C\uC6B0\uB4DC \uBC31\uC5C5 \uC644\uB8CC! \uB2E4\uB978 \uD658\uACBD\uC5D0\uC11C vhk cloud pull \uB85C \uBCF5\uC6D0\uD558\uC138\uC694.",
|
|
4706
|
+
command: "vhk cloud pull",
|
|
4707
|
+
cursorHint: "\uB2E4\uB978 \uCEF4\uD4E8\uD130\uC5D0\uC11C .vhk \uBCF5\uC6D0\uD574\uC918"
|
|
4708
|
+
});
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4364
4711
|
// src/lib/nlp-run.ts
|
|
4365
4712
|
async function dispatchNlpRoute(route, input) {
|
|
4366
4713
|
switch (route.command) {
|
|
@@ -4429,6 +4776,10 @@ async function dispatchNlpRoute(route, input) {
|
|
|
4429
4776
|
return memoryList();
|
|
4430
4777
|
case "brief":
|
|
4431
4778
|
return brief();
|
|
4779
|
+
case "cloud-push":
|
|
4780
|
+
return cloudPush();
|
|
4781
|
+
case "cloud-pull":
|
|
4782
|
+
return cloudPull();
|
|
4432
4783
|
case "goal": {
|
|
4433
4784
|
const sub = route.args?.[0];
|
|
4434
4785
|
if (sub === "next") return goalNext();
|
|
@@ -4441,14 +4792,14 @@ async function dispatchNlpRoute(route, input) {
|
|
|
4441
4792
|
async function runNaturalLanguageRoute(input) {
|
|
4442
4793
|
const route = routeNaturalLanguage(input);
|
|
4443
4794
|
if (!route) {
|
|
4444
|
-
console.log(
|
|
4795
|
+
console.log(chalk27.yellow(`
|
|
4445
4796
|
\u2753 "${input}" \u2014 ${ko.nlp.notMatched}
|
|
4446
4797
|
`));
|
|
4447
4798
|
return;
|
|
4448
4799
|
}
|
|
4449
4800
|
console.log("");
|
|
4450
|
-
console.log(
|
|
4451
|
-
console.log(
|
|
4801
|
+
console.log(chalk27.cyan(` \u{1F4AC} "${input}"`));
|
|
4802
|
+
console.log(chalk27.cyan(` \u2192 ${route.explanation}`));
|
|
4452
4803
|
if (route.confidence === "low") {
|
|
4453
4804
|
const { confirm } = await inquirer11.prompt([{
|
|
4454
4805
|
type: "confirm",
|
|
@@ -4457,7 +4808,7 @@ async function runNaturalLanguageRoute(input) {
|
|
|
4457
4808
|
default: true
|
|
4458
4809
|
}]);
|
|
4459
4810
|
if (!confirm) {
|
|
4460
|
-
console.log(
|
|
4811
|
+
console.log(chalk27.dim(` ${ko.nlp.menuHint}`));
|
|
4461
4812
|
return;
|
|
4462
4813
|
}
|
|
4463
4814
|
}
|
|
@@ -4466,77 +4817,77 @@ async function runNaturalLanguageRoute(input) {
|
|
|
4466
4817
|
}
|
|
4467
4818
|
|
|
4468
4819
|
// src/commands/agent.ts
|
|
4469
|
-
import
|
|
4820
|
+
import chalk28 from "chalk";
|
|
4470
4821
|
function activeGoalId() {
|
|
4471
4822
|
const goals = listGoals("goals");
|
|
4472
4823
|
const id = selectActiveId(goals);
|
|
4473
4824
|
return id ?? void 0;
|
|
4474
4825
|
}
|
|
4475
4826
|
async function blocker(description) {
|
|
4476
|
-
console.log(
|
|
4827
|
+
console.log(chalk28.bold(`
|
|
4477
4828
|
${ko.agent.blockerTitle}
|
|
4478
4829
|
`));
|
|
4479
4830
|
if (!description || !description.trim()) {
|
|
4480
|
-
console.log(
|
|
4481
|
-
console.log(
|
|
4831
|
+
console.log(chalk28.red(" \u274C \uBE14\uB85C\uCEE4 \uC124\uBA85\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
4832
|
+
console.log(chalk28.dim(' \uC608: vhk blocker "tsc \uC5D0\uB7EC \u2014 simple-git \uD0C0\uC785 \uD638\uD658"'));
|
|
4482
4833
|
process.exitCode = 1;
|
|
4483
4834
|
return;
|
|
4484
4835
|
}
|
|
4485
4836
|
const goalId = activeGoalId();
|
|
4486
4837
|
const r = appendBlocker(description, goalId);
|
|
4487
|
-
console.log(
|
|
4838
|
+
console.log(chalk28.green(` \u2705 blocker \uAE30\uB85D (\uD604\uC7AC \uD65C\uC131 ${r.count}\uAC74)`));
|
|
4488
4839
|
if (r.hardStopTripped) {
|
|
4489
|
-
console.log(
|
|
4490
|
-
console.log(
|
|
4840
|
+
console.log(chalk28.red.bold(" \u{1F6D1} HARD_STOP \uC790\uB3D9 \uC0DD\uC131 \u2014 \uBAA8\uB4E0 \uC790\uB3D9\uD654 \uC911\uB2E8."));
|
|
4841
|
+
console.log(chalk28.yellow(" \uC0AC\uB78C \uAC80\uD1A0 \uD6C4 `vhk resume --confirm` \uC73C\uB85C\uB9CC \uD574\uC81C."));
|
|
4491
4842
|
process.exitCode = 2;
|
|
4492
4843
|
}
|
|
4493
4844
|
}
|
|
4494
4845
|
async function learn(lesson) {
|
|
4495
|
-
console.log(
|
|
4846
|
+
console.log(chalk28.bold(`
|
|
4496
4847
|
${ko.agent.learnTitle}
|
|
4497
4848
|
`));
|
|
4498
4849
|
if (!lesson || !lesson.trim()) {
|
|
4499
|
-
console.log(
|
|
4500
|
-
console.log(
|
|
4850
|
+
console.log(chalk28.red(" \u274C \uAD50\uD6C8 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694."));
|
|
4851
|
+
console.log(chalk28.dim(' \uC608: vhk learn "PowerShell \uC5D0\uC11C\uB294 ; \uC0AC\uC6A9 (&& \uBBF8\uC9C0\uC6D0)"'));
|
|
4501
4852
|
process.exitCode = 1;
|
|
4502
4853
|
return;
|
|
4503
4854
|
}
|
|
4504
4855
|
const goalId = activeGoalId();
|
|
4505
4856
|
appendLearning(lesson, goalId);
|
|
4506
|
-
console.log(
|
|
4857
|
+
console.log(chalk28.green(" \u2705 learnings.md append."));
|
|
4507
4858
|
console.log(
|
|
4508
|
-
|
|
4859
|
+
chalk28.dim(" \uACB0\uC815\uC0AC\uD56D(decision)\uC740 `vhk memory add` \uB85C \uBCC4\uB3C4 \uAE30\uB85D \u2014 SoT \uBD84\uB9AC.")
|
|
4509
4860
|
);
|
|
4510
4861
|
}
|
|
4511
4862
|
async function resume(opts = {}) {
|
|
4512
|
-
console.log(
|
|
4863
|
+
console.log(chalk28.bold(`
|
|
4513
4864
|
${ko.agent.resumeTitle}
|
|
4514
4865
|
`));
|
|
4515
4866
|
if (!isHardStopActive()) {
|
|
4516
|
-
console.log(
|
|
4867
|
+
console.log(chalk28.dim(" HARD_STOP \uD65C\uC131 \uC544\uB2D8 \u2014 \uD560 \uC77C \uC5C6\uC74C."));
|
|
4517
4868
|
return;
|
|
4518
4869
|
}
|
|
4519
4870
|
const reason = readHardStopReason();
|
|
4520
4871
|
if (reason) {
|
|
4521
|
-
console.log(
|
|
4522
|
-
console.log(
|
|
4872
|
+
console.log(chalk28.yellow(" \u{1F4CB} HARD_STOP \uC0AC\uC720:"));
|
|
4873
|
+
console.log(chalk28.dim(` ${reason.split("\n").join("\n ")}`));
|
|
4523
4874
|
console.log("");
|
|
4524
4875
|
}
|
|
4525
4876
|
if (!opts.confirm) {
|
|
4526
4877
|
console.log(
|
|
4527
|
-
|
|
4878
|
+
chalk28.red(
|
|
4528
4879
|
" \u274C --confirm \uD50C\uB798\uADF8 \uC5C6\uC774\uB294 \uD574\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (\uC790\uB3D9 \uD638\uCD9C \uAE08\uC9C0)."
|
|
4529
4880
|
)
|
|
4530
4881
|
);
|
|
4531
|
-
console.log(
|
|
4882
|
+
console.log(chalk28.yellow(" \uC0AC\uC720\uB97C \uD655\uC778\uD55C \uD6C4 \uB2E4\uC2DC: vhk resume --confirm"));
|
|
4532
4883
|
process.exitCode = 1;
|
|
4533
4884
|
return;
|
|
4534
4885
|
}
|
|
4535
4886
|
const removed = clearHardStop();
|
|
4536
4887
|
if (removed) {
|
|
4537
|
-
console.log(
|
|
4888
|
+
console.log(chalk28.green(" \u2705 HARD_STOP \uD574\uC81C. \uC790\uB3D9\uD654 \uC7AC\uAC1C \uAC00\uB2A5."));
|
|
4538
4889
|
} else {
|
|
4539
|
-
console.log(
|
|
4890
|
+
console.log(chalk28.dim(" \uD30C\uC77C\uC774 \uC774\uBBF8 \uC5C6\uC74C \u2014 no-op."));
|
|
4540
4891
|
}
|
|
4541
4892
|
}
|
|
4542
4893
|
|
|
@@ -4612,6 +4963,15 @@ program.command("check").alias("\uC810\uAC80").alias("\uB9B0\uD2B8").option("--g
|
|
|
4612
4963
|
});
|
|
4613
4964
|
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
4965
|
secureCmd.command("scan").alias("\uC2A4\uCE94").description("\uC2DC\uD06C\uB9BF/\uD0A4 \uC720\uCD9C \uC2A4\uCE94").action(secure);
|
|
4966
|
+
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(() => {
|
|
4967
|
+
cloudCmd.help();
|
|
4968
|
+
});
|
|
4969
|
+
cloudCmd.command("push").alias("\uC62C\uB9AC\uAE30").description(".vhk/ \uB97C secret gist \uB85C \uBC31\uC5C5").action(async () => {
|
|
4970
|
+
await cloudPush();
|
|
4971
|
+
});
|
|
4972
|
+
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) => {
|
|
4973
|
+
await cloudPull(gistId);
|
|
4974
|
+
});
|
|
4615
4975
|
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
4976
|
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
4977
|
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