@byh3071/vhk 0.9.1 โ†’ 1.0.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 CHANGED
@@ -1,12 +1,14 @@
1
1
  ---
2
2
  id: vhk-readme
3
3
  date: 2026-05-24
4
- tags: [vhk, cli, readme, v0.9.0]
4
+ tags: [vhk, cli, readme, v1.0.0, ga]
5
5
  ---
6
6
 
7
7
  # ๐Ÿ”ง VHK โ€” Vibe Harness Kit
8
8
 
9
- > AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ๋ถ€๋ฆฌ๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•œ **ํ•œ๊ตญ์–ด ํ’€์‚ฌ์ดํด CLI** (v0.9.0)
9
+ > ๐ŸŽ‰ **v1.0.0 GA** โ€” ๋ฐ”์ด๋ธŒ์ฝ”๋”์˜ ์˜ฌ์ธ์› CLI. ๊ณต๊ฐœ API ์•ˆ์ •์„ฑ ๋ณด์žฅ.
10
+ >
11
+ > AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ๋ถ€๋ฆฌ๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•œ **ํ•œ๊ตญ์–ด ํ’€์‚ฌ์ดํด CLI** (v1.0.0)
10
12
  >
11
13
  > ๐Ÿฝ๏ธ **VHK๋Š” VHK๋กœ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ๋จ** โ€” ์ด ๋ ˆํฌ์˜ `docs/`, `CLAUDE.md`, `.cursorrules`๋„ `vhk init`์ด ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
12
14
 
@@ -100,9 +102,13 @@ vhk ๊ธฐํš ๋๋‚ฌ๊ณ  ๋ฐ”๋กœ ์‹œ์ž‘
100
102
  | `vhk theme` | `ํ…Œ๋งˆ` | ๋‹คํฌ/๋ผ์ดํŠธ ๋ชจ๋“œ CSS + ํ† ๊ธ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ƒ์„ฑ |
101
103
  | `vhk ref` | `๋ ˆํผ๋Ÿฐ์Šค` | ๋ ˆํผ๋Ÿฐ์Šค URL ๊ด€๋ฆฌ (`add` / `list` / `open`) |
102
104
  | `vhk harness` | `ํ•˜๋„ค์Šค` | ํ†ตํ•ฉ ํ’ˆ์งˆ ์ ๊ฒ€ (lint + type-check + test + build ์ˆœ์ฐจ ์‹คํ–‰ + ๋ฆฌํฌํŠธ) |
103
- | `vhk audit` | `๊ฐ์‚ฌ` | npm ๋ณด์•ˆ ์ทจ์•ฝ์  ๊ฐ์‚ฌ (`--fix`๋กœ ์ž๋™ ์ˆ˜์ •) |
105
+ | `vhk audit` | `๊ฐ์‚ฌ` | npm/pnpm/yarn ๋ณด์•ˆ ์ทจ์•ฝ์  ๊ฐ์‚ฌ (`--fix`๋กœ ์ž๋™ ์ˆ˜์ •, npm๋งŒ) |
104
106
  | `vhk migrate [target]` | `์ „ํ™˜` | ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ „ํ™˜ (`npm` / `yarn` / `pnpm`, lockfile + node_modules ์žฌ๊ตฌ์„ฑ) |
105
107
  | `vhk update` | `์—…๋ฐ์ดํŠธ` | VHK CLI ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์…€ํ”„ ์—…๋ฐ์ดํŠธ |
108
+ | `vhk context` | `๋งฅ๋ฝ` | ํ”„๋กœ์ ํŠธ ํŠธ๋ฆฌยท์ŠคํƒยทCLI ๋ช…๋ น ๋ชฉ๋ก์„ `.vhk/context.md`๋กœ ์ž๋™ ์ƒ์„ฑ (AI ์–ด์‹œ์Šคํ„ดํŠธ์šฉ) |
109
+ | `vhk context-show` | `๋งฅ๋ฝ๋ณด๊ธฐ` | ํ˜„์žฌ ์ปจํ…์ŠคํŠธ ํŒŒ์ผ ๋‚ด์šฉ ์ถœ๋ ฅ |
110
+ | `vhk memory` | `๊ธฐ์–ต` | ๊ฒฐ์ •์‚ฌํ•ญ ๊ธฐ์–ต ๊ด€๋ฆฌ (`add` / `list` / `remove`, `.vhk/memory.json` ๊ธฐ๋ฐ˜, ํƒœ๊ทธ ์ง€์›) |
111
+ | `vhk brief` | `๋ธŒ๋ฆฌํ•‘` | ํ”„๋กœ์ ํŠธ ์ •๋ณด + git ์ƒํƒœ + ๊ฒฐ์ •์‚ฌํ•ญ + ๋ ˆํผ๋Ÿฐ์Šค ํ†ตํ•ฉ ๋ณด๊ณ ์„œ `.vhk/brief.md` |
106
112
 
107
113
  ### init ์˜ต์…˜
108
114
 
@@ -137,6 +143,45 @@ MCP ์„œ๋ฒ„๋ฅผ ์ˆ˜๋™์œผ๋กœ ๋„์šฐ๋ ค๋ฉด:
137
143
  vhk mcp # stdio ์„œ๋ฒ„ ์‹œ์ž‘ (Cursor๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ)
138
144
  ```
139
145
 
146
+ ## v1.0.0 GA ํ•˜์ด๋ผ์ดํŠธ ๐ŸŽ‰
147
+
148
+ > **๊ณต๊ฐœ API ์•ˆ์ •์„ฑ ์•ฝ์†**. ๋ช…๋ น์–ด ์ด๋ฆ„, CLI ์ธ์ž, `.vhk/` ํŒŒ์ผ ํฌ๋งท์€ v2.0๊นŒ์ง€ breaking change ์—†์Œ.
149
+
150
+ | ๊ธฐ๋Šฅ | ์„ค๋ช… |
151
+ |------|------|
152
+ | **context** | ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ ํŠธ๋ฆฌ(3-depth) + ๊ธฐ์ˆ  ์Šคํƒ(Next/Nuxt/Vue/Svelte/TS/Tailwind/tsup/Vite/...) ์ž๋™ ๊ฐ์ง€ + 29๊ฐœ+ VHK ๋ช…๋ น์–ด ๋ชฉ๋ก์„ `.vhk/context.md` ๋งˆํฌ๋‹ค์šด์œผ๋กœ ์ƒ์„ฑ. AI ์–ด์‹œ์Šคํ„ดํŠธ๊ฐ€ ํ”„๋กœ์ ํŠธ ๋งฅ๋ฝ์„ ์ฆ‰์‹œ ํŒŒ์•… |
153
+ | **memory** | `.vhk/memory.json` ๊ฒฐ์ •์‚ฌํ•ญ ๊ธฐ์–ต ๊ด€๋ฆฌ. `add <content> --tags X,Y` / `list` / `remove <๋ฒˆํ˜ธ>`. NL์€ list๋งŒ (add/remove๋Š” ์ธ์ž ํ•„์ˆ˜ โ†’ commander ์ „์šฉ) |
154
+ | **brief** | ํ”„๋กœ์ ํŠธ ์ •๋ณด + git ์ƒํƒœ(๋ธŒ๋žœ์น˜ยท๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹ยท๋ฏธ์ปค๋ฐ‹ ๋ณ€๊ฒฝ) + ์ตœ๊ทผ ๊ฒฐ์ •์‚ฌํ•ญ + ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ํ•œ ํ™”๋ฉด์— + `.vhk/brief.md` ์ €์žฅ. `safeExecFile` ๊ธฐ๋ฐ˜ (Windows .cmd shim ์•ˆ์ „) |
155
+ | **์ž์—ฐ์–ด ํ™•์žฅ** | `"๋งฅ๋ฝ ๋งŒ๋“ค์–ด์ค˜"` โ†’ context ยท `"์ปจํ…์ŠคํŠธ ๋ณด์—ฌ์ค˜"` โ†’ context-show ยท `"๊ธฐ์–ต ๋ชฉ๋ก"` โ†’ memory ยท `"ํ”„๋กœ์ ํŠธ ๋ธŒ๋ฆฌํ•‘ ๋งŒ๋“ค์–ด์ค˜"` / `"์ƒํƒœ ์š”์•ฝ"` โ†’ brief |
156
+
157
+ ```powershell
158
+ vhk context # .vhk/context.md (ํŠธ๋ฆฌ + ์Šคํƒ + ๋ช…๋ น ๋ชฉ๋ก)
159
+ vhk memory add "API๋Š” tRPC ์‚ฌ์šฉ" --tags decision,arch
160
+ vhk memory list
161
+ vhk brief # ์ฝ˜์†” ์ถœ๋ ฅ + .vhk/brief.md
162
+ ```
163
+
164
+ ### Cursor ๊ถŒ์žฅ ์‹œํ€€์Šค (v1.0 GA)
165
+
166
+ ```text
167
+ vhk init # ํ”„๋กœ์ ํŠธ ์…‹์—…
168
+ vhk design + theme # ๋””์ž์ธ ์‹œ์Šคํ…œ
169
+ vhk context # AI ๋งฅ๋ฝ ํŒŒ์ผ ์ƒ์„ฑ
170
+ ... ๊ฐœ๋ฐœ ...
171
+ vhk memory add "<๊ฒฐ์ •>" # ๊ฒฐ์ • ๋ˆ„์ 
172
+ vhk brief # ์„ธ์…˜ ์ข…๋ฃŒ ์‹œ ์ƒํƒœ ๋ณด๊ณ ์„œ
173
+ ๋‹ค์Œ ์„ธ์…˜ ์‹œ์ž‘: "์ปจํ…์ŠคํŠธ ๋ณด์—ฌ์ค˜" โ†’ ์–ด์ œ ๋งฅ๋ฝ ๋ณต์›
174
+ ```
175
+
176
+ ### v1.0.0 GA ์ •์ฑ…
177
+
178
+ - **๊ณต๊ฐœ API ์•ˆ์ •์„ฑ**: ๋ช…๋ น์–ด ์ด๋ฆ„, CLI ์ธ์ž, `.vhk/` ํŒŒ์ผ ํฌ๋งท์€ v2.0๊นŒ์ง€ breaking change ์—†์Œ
179
+ - **deprecation ์ ˆ์ฐจ**: ๋ช…๋ น์–ด/์˜ต์…˜ ์ œ๊ฑฐ ์ „ 1๊ฐœ ๋งˆ์ด๋„ˆ ๋ฒ„์ „(1.x.0)์—์„œ deprecation ๊ฒฝ๊ณ 
180
+ - **i18n ํ‚ค**: `ko.ts`์˜ `t()` ํ‚ค ์ด๋ฆ„์€ ์•ˆ์ •. ์‹ ๊ทœ ํ‚ค ๋ˆ„์ , ๊ธฐ์กด ํ‚ค ๋ฏธ์ œ๊ฑฐ
181
+ - **MCP ์„œ๋ฒ„ ๋„๊ตฌ**: 8๊ฐœ ๋„๊ตฌ(save/undo/status/diff/ship/doctor/check/recap) ์ธํ„ฐํŽ˜์ด์Šค ์•ˆ์ •
182
+
183
+ > **`vhk memory` vs Claude Code `auto memory`** โ€” `vhk memory`๋Š” **ํ”„๋กœ์ ํŠธ ๋‹จ์œ„** ๊ฒฐ์ •์‚ฌํ•ญ(`.vhk/memory.json`, ํŒ€ ๊ณต์œ ). Claude Code์˜ `auto memory`๋Š” **์‚ฌ์šฉ์ž ๋‹จ์œ„** (`~/.claude/projects/.../memory/`, ๊ฐœ์ธ ์ปจํ…์ŠคํŠธ). ๋‘˜์€ ๋ณ„๊ฐœ.
184
+
140
185
  ## v0.9.0 ํ•˜์ด๋ผ์ดํŠธ
141
186
 
142
187
  | ๊ธฐ๋Šฅ | ์„ค๋ช… |
@@ -250,6 +295,10 @@ vhk ref open 1 # 1๋ฒˆ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ธŒ๋ผ์šฐ์ €๋กœ ์—ด๊ธฐ
250
295
  | ๋ณด์•ˆ ๊ฐ์‚ฌ ํ•ด์ค˜ / ์ทจ์•ฝ์  ํ™•์ธ | `vhk audit` |
251
296
  | ํŒจํ‚ค์ง€ ๋งค๋‹ˆ์ € ์ „ํ™˜ | `vhk migrate` |
252
297
  | vhk ์—…๋ฐ์ดํŠธ ํ•ด์ค˜ | `vhk update` |
298
+ | ๋งฅ๋ฝ ๋งŒ๋“ค์–ด์ค˜ / ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ | `vhk context` |
299
+ | ์ปจํ…์ŠคํŠธ ๋ณด์—ฌ์ค˜ / ๋งฅ๋ฝ ๋ณด์—ฌ์ค˜ | `vhk context-show` |
300
+ | ๊ธฐ์–ต ๋ชฉ๋ก / ๊ฒฐ์ •์‚ฌํ•ญ ํ™•์ธ | `vhk memory` (list) |
301
+ | ํ”„๋กœ์ ํŠธ ๋ธŒ๋ฆฌํ•‘ / ์ƒํƒœ ์š”์•ฝ | `vhk brief` |
253
302
 
254
303
  ## ํŠน์ง•
255
304
 
@@ -283,6 +283,10 @@ var ko = {
283
283
  addTitle: "\uB808\uD37C\uB7F0\uC2A4 \uCD94\uAC00",
284
284
  listTitle: "\uB808\uD37C\uB7F0\uC2A4 \uBAA9\uB85D"
285
285
  },
286
+ memory: {
287
+ addTitle: "\uAE30\uC5B5 \uCD94\uAC00",
288
+ listTitle: "\uAE30\uC5B5 \uBAA9\uB85D"
289
+ },
286
290
  mcp: {
287
291
  initTitle: "Cursor MCP \uC5F0\uB3D9 \uC124\uC815",
288
292
  serverStarted: "VHK MCP \uC11C\uBC84 \uC2DC\uC791\uB428"
@@ -323,6 +327,13 @@ var ko = {
323
327
  },
324
328
  update: {
325
329
  title: "VHK CLI \uC5C5\uB370\uC774\uD2B8"
330
+ },
331
+ context: {
332
+ title: "\uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8 \uC0DD\uC131",
333
+ showTitle: "\uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C"
334
+ },
335
+ brief: {
336
+ title: "\uD504\uB85C\uC81D\uD2B8 \uBE0C\uB9AC\uD551"
326
337
  }
327
338
  };
328
339
  function lookup(path) {
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  safeExecFileStream,
11
11
  startMcpServer,
12
12
  t
13
- } from "./chunk-UPXCLOBF.js";
13
+ } from "./chunk-7NGBIIA3.js";
14
14
 
15
15
  // node_modules/.pnpm/ignore@7.0.5/node_modules/ignore/index.js
16
16
  var require_ignore = __commonJS({
@@ -473,7 +473,7 @@ var require_ignore = __commonJS({
473
473
  // src/index.ts
474
474
  import { Command, Help } from "commander";
475
475
  import inquirer14 from "inquirer";
476
- import fs16 from "fs";
476
+ import fs15 from "fs";
477
477
  import path15 from "path";
478
478
  import { fileURLToPath as fileURLToPath4 } from "url";
479
479
 
@@ -511,7 +511,7 @@ var RULES = [
511
511
  command: "init",
512
512
  explanation: "\uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 (vhk \uC2DC\uC791)",
513
513
  confidence: "high",
514
- test: (t2) => (/ํ”„๋กœ์ ํŠธ.*(๋งŒ๋“ค|์‹œ์ž‘)|ํด๋”.*๋งŒ๋“ค|๋งŒ๋“ค๊ณ \s*์‹ถ|ํ•˜๋„ค์Šค|์ดˆ๊ธฐํ™”/.test(t2) || /^์‹œ์ž‘$/.test(t2)) && !/๋””์ž์ธ|design|ํŒ”๋ ˆํŠธ|palette|ํ…Œ๋งˆ|theme|๋ ˆํผ๋Ÿฐ์Šค|reference|๋‹คํฌ\s*๋ชจ๋“œ|๋ผ์ดํŠธ\s*๋ชจ๋“œ|์ƒ‰์ƒ\s*๋ชจ๋“œ/.test(t2)
514
+ test: (t2) => (/ํ”„๋กœ์ ํŠธ.*(๋งŒ๋“ค|์‹œ์ž‘)|ํด๋”.*๋งŒ๋“ค|๋งŒ๋“ค๊ณ \s*์‹ถ|ํ•˜๋„ค์Šค|์ดˆ๊ธฐํ™”/.test(t2) || /^์‹œ์ž‘$/.test(t2)) && !/๋””์ž์ธ|design|ํŒ”๋ ˆํŠธ|palette|ํ…Œ๋งˆ|theme|๋ ˆํผ๋Ÿฐ์Šค|reference|๋‹คํฌ\s*๋ชจ๋“œ|๋ผ์ดํŠธ\s*๋ชจ๋“œ|์ƒ‰์ƒ\s*๋ชจ๋“œ|๋ธŒ๋ฆฌํ•‘|brief|์ปจํ…์ŠคํŠธ|context|๋งฅ๋ฝ|๊ธฐ์–ต|memory/.test(t2)
515
515
  },
516
516
  {
517
517
  command: "mcp-init",
@@ -567,6 +567,30 @@ var RULES = [
567
567
  confidence: "high",
568
568
  test: (t2) => /์—…๋ฐ์ดํŠธ|update|๋ฒ„์ „\s*์—…|์ตœ์‹ \s*๋ฒ„์ „|์…€ํ”„\s*์—…๋ฐ์ดํŠธ|vhk.*์ตœ์‹ |vhk.*์—…๋ฐ์ดํŠธ/.test(t2)
569
569
  },
570
+ {
571
+ command: "context-show",
572
+ explanation: "\uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C \uBCF4\uAE30 (vhk context-show)",
573
+ confidence: "high",
574
+ test: (t2) => /๋งฅ๋ฝ\s*(๋ณด|ํ™•์ธ|๋ณด์—ฌ)|์ปจํ…์ŠคํŠธ\s*(๋ณด|ํ™•์ธ|๋ณด์—ฌ)|context\s*show/.test(t2)
575
+ },
576
+ {
577
+ command: "context",
578
+ explanation: "\uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uC0DD\uC131 (vhk context)",
579
+ confidence: "high",
580
+ test: (t2) => /(^๋งฅ๋ฝ$|^์ปจํ…์ŠคํŠธ$|^context$|๋งฅ๋ฝ\s*(๋งŒ๋“ค|์ƒ์„ฑ|๊ฐฑ์‹ |์—…๋ฐ์ดํŠธ)|์ปจํ…์ŠคํŠธ\s*(๋งŒ๋“ค|์ƒ์„ฑ|๊ฐฑ์‹ |์—…๋ฐ์ดํŠธ)|ํ”„๋กœ์ ํŠธ\s*๋งฅ๋ฝ|ํ”„๋กœ์ ํŠธ\s*์ •๋ณด\s*์ƒ์„ฑ)/.test(t2) && !/๋ณด|ํ™•์ธ|๋ณด์—ฌ|show/.test(t2)
581
+ },
582
+ {
583
+ command: "memory",
584
+ explanation: "\uAE30\uC5B5 \uBAA9\uB85D \uC870\uD68C (vhk memory list)",
585
+ confidence: "high",
586
+ test: (t2) => /^๊ธฐ์–ต$|๊ธฐ์–ต\s*(๋ชฉ๋ก|๋ณด|ํ™•์ธ|๋ญ)|memory.*list|๊ฒฐ์ •์‚ฌํ•ญ\s*(๋ชฉ๋ก|ํ™•์ธ|๋ณด์—ฌ)/.test(t2) && !/(์ถ”๊ฐ€|add|์‚ญ์ œ|remove|์ €์žฅ|๊ธฐ๋กํ•ด)/.test(t2)
587
+ },
588
+ {
589
+ command: "brief",
590
+ explanation: "\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uC694\uC57D (vhk brief)",
591
+ confidence: "high",
592
+ test: (t2) => /๋ธŒ๋ฆฌํ•‘|brief|์ƒํƒœ\s*์š”์•ฝ|ํ”„๋กœ์ ํŠธ\s*์š”์•ฝ|์š”์•ฝ\s*(๋ณด๊ณ |๋ฆฌํฌํŠธ|๋ณด์—ฌ|๋งŒ๋“ค)|๋ณด๊ณ ์„œ\s*(๋งŒ๋“ค|์ƒ์„ฑ|๋ณด์—ฌ)/.test(t2)
593
+ },
570
594
  {
571
595
  command: "secure",
572
596
  explanation: "\uBCF4\uC548 \uC2A4\uCE94 (vhk \uBCF4\uC548)",
@@ -741,6 +765,14 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
741
765
  "\uC804\uD658",
742
766
  "update",
743
767
  "\uC5C5\uB370\uC774\uD2B8",
768
+ "context",
769
+ "\uB9E5\uB77D",
770
+ "context-show",
771
+ "\uB9E5\uB77D\uBCF4\uAE30",
772
+ "memory",
773
+ "\uAE30\uC5B5",
774
+ "brief",
775
+ "\uBE0C\uB9AC\uD551",
744
776
  "help"
745
777
  ]);
746
778
  function isOptionToken(token) {
@@ -764,7 +796,7 @@ function detectNaturalLanguageInput(argv) {
764
796
  }
765
797
 
766
798
  // src/lib/nlp-run.ts
767
- import chalk25 from "chalk";
799
+ import chalk28 from "chalk";
768
800
  import inquirer13 from "inquirer";
769
801
 
770
802
  // src/commands/gate.ts
@@ -1690,7 +1722,7 @@ function nextAdrNumber(adrDir) {
1690
1722
  function slugify(title) {
1691
1723
  return title.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9๊ฐ€-ํžฃ-]/g, "").slice(0, 40) || "decision";
1692
1724
  }
1693
- function createAdrFile(cwd, title, context, decision, consequences) {
1725
+ function createAdrFile(cwd, title, context2, decision, consequences) {
1694
1726
  const adrDir = path5.join(cwd, "docs", "adr");
1695
1727
  if (!fs4.existsSync(adrDir)) fs4.mkdirSync(adrDir, { recursive: true });
1696
1728
  const num = nextAdrNumber(adrDir);
@@ -1708,7 +1740,7 @@ function createAdrFile(cwd, title, context, decision, consequences) {
1708
1740
  `# ADR-${String(num).padStart(3, "0")}: ${title}`,
1709
1741
  "",
1710
1742
  "## \uB9E5\uB77D (Context)",
1711
- context,
1743
+ context2,
1712
1744
  "",
1713
1745
  "## \uACB0\uC815 (Decision)",
1714
1746
  decision,
@@ -3136,17 +3168,17 @@ ${t("undo.recentHeader")}`));
3136
3168
 
3137
3169
  // src/commands/status.ts
3138
3170
  import { execFileSync as execFileSync4 } from "child_process";
3139
- import fs15 from "fs";
3171
+ import fs14 from "fs";
3140
3172
  import path14 from "path";
3141
3173
  import chalk13 from "chalk";
3142
3174
 
3143
3175
  // src/lib/read-json.ts
3144
- import fs14 from "fs";
3176
+ import { readFileSync } from "fs";
3145
3177
  function stripBom(text) {
3146
3178
  return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
3147
3179
  }
3148
3180
  function readJsonFile(filePath) {
3149
- const raw = stripBom(fs14.readFileSync(filePath, "utf-8"));
3181
+ const raw = stripBom(readFileSync(filePath, "utf-8"));
3150
3182
  return JSON.parse(raw);
3151
3183
  }
3152
3184
 
@@ -3189,7 +3221,7 @@ function parseRecentCommitLines(logOutput) {
3189
3221
  }
3190
3222
  function readProjectPackage(cwd = process.cwd()) {
3191
3223
  const pkgPath = path14.join(cwd, "package.json");
3192
- if (!fs15.existsSync(pkgPath)) return null;
3224
+ if (!fs14.existsSync(pkgPath)) return null;
3193
3225
  try {
3194
3226
  const pkg = readJsonFile(pkgPath);
3195
3227
  if (!pkg.name && !pkg.version) return null;
@@ -3358,7 +3390,7 @@ ${t("diff.summaryHeader")}`));
3358
3390
  }
3359
3391
 
3360
3392
  // src/commands/mcp-init.ts
3361
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3393
+ import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
3362
3394
  import { join } from "path";
3363
3395
  import { fileURLToPath as fileURLToPath2 } from "url";
3364
3396
  import chalk15 from "chalk";
@@ -3366,7 +3398,7 @@ function resolveVhkMcpPath() {
3366
3398
  try {
3367
3399
  const pkgPath = join(process.cwd(), "package.json");
3368
3400
  if (existsSync(pkgPath)) {
3369
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
3401
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
3370
3402
  if (pkg.name === "@byh3071/vhk") {
3371
3403
  return join(process.cwd(), "dist", "mcp", "index.js");
3372
3404
  }
@@ -3395,7 +3427,7 @@ async function mcpInit() {
3395
3427
  let config;
3396
3428
  if (existsSync(configPath)) {
3397
3429
  try {
3398
- const parsed = JSON.parse(readFileSync(configPath, "utf-8"));
3430
+ const parsed = JSON.parse(readFileSync2(configPath, "utf-8"));
3399
3431
  config = {
3400
3432
  mcpServers: { ...parsed.mcpServers ?? {}, vhk: vhkEntry }
3401
3433
  };
@@ -3518,7 +3550,7 @@ ${t("deploy.deploying")}
3518
3550
  }
3519
3551
 
3520
3552
  // src/commands/publish.ts
3521
- import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
3553
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3522
3554
  import chalk17 from "chalk";
3523
3555
  import inquirer8 from "inquirer";
3524
3556
  import ora2 from "ora";
@@ -3542,7 +3574,7 @@ async function publish() {
3542
3574
  }
3543
3575
  let pkg;
3544
3576
  try {
3545
- pkg = JSON.parse(readFileSync2("package.json", "utf-8"));
3577
+ pkg = JSON.parse(readFileSync3("package.json", "utf-8"));
3546
3578
  } catch {
3547
3579
  console.log(chalk17.red("\u274C package.json \uD30C\uC2F1 \uC2E4\uD328"));
3548
3580
  return;
@@ -3867,13 +3899,13 @@ async function theme() {
3867
3899
  }
3868
3900
 
3869
3901
  // src/commands/ref.ts
3870
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync5 } from "fs";
3902
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
3871
3903
  import chalk20 from "chalk";
3872
3904
  var REFS_PATH = ".vhk/refs.json";
3873
3905
  function loadRefs() {
3874
3906
  if (!existsSync6(REFS_PATH)) return [];
3875
3907
  try {
3876
- const raw = readFileSync3(REFS_PATH, "utf-8");
3908
+ const raw = readFileSync4(REFS_PATH, "utf-8");
3877
3909
  const parsed = JSON.parse(raw);
3878
3910
  return Array.isArray(parsed) ? parsed : [];
3879
3911
  } catch {
@@ -3966,7 +3998,7 @@ async function refOpen(indexStr) {
3966
3998
  }
3967
3999
 
3968
4000
  // src/commands/harness.ts
3969
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
4001
+ import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
3970
4002
  import chalk21 from "chalk";
3971
4003
  import ora3 from "ora";
3972
4004
  function detectPM() {
@@ -3981,7 +4013,7 @@ function detectChecks() {
3981
4013
  const checks = [];
3982
4014
  let pkg = {};
3983
4015
  try {
3984
- pkg = JSON.parse(readFileSync4("package.json", "utf-8"));
4016
+ pkg = JSON.parse(readFileSync5("package.json", "utf-8"));
3985
4017
  } catch {
3986
4018
  return checks;
3987
4019
  }
@@ -4251,7 +4283,7 @@ async function migrate(target) {
4251
4283
 
4252
4284
  // src/commands/update.ts
4253
4285
  import { execSync as execSync3 } from "child_process";
4254
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
4286
+ import { existsSync as existsSync10, readFileSync as readFileSync6 } from "fs";
4255
4287
  import { dirname, join as join2 } from "path";
4256
4288
  import { fileURLToPath as fileURLToPath3 } from "url";
4257
4289
  import chalk24 from "chalk";
@@ -4262,7 +4294,7 @@ function getCurrentVersion() {
4262
4294
  for (const pkgPath of [join2(dir, "../package.json"), join2(dir, "../../package.json")]) {
4263
4295
  try {
4264
4296
  if (existsSync10(pkgPath)) {
4265
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
4297
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
4266
4298
  if (pkg.version) return pkg.version;
4267
4299
  }
4268
4300
  } catch {
@@ -4326,6 +4358,369 @@ async function update() {
4326
4358
  }
4327
4359
  }
4328
4360
 
4361
+ // src/commands/context.ts
4362
+ import {
4363
+ existsSync as existsSync11,
4364
+ mkdirSync as mkdirSync5,
4365
+ readFileSync as readFileSync7,
4366
+ readdirSync,
4367
+ statSync,
4368
+ writeFileSync as writeFileSync6
4369
+ } from "fs";
4370
+ import { join as join3 } from "path";
4371
+ import chalk25 from "chalk";
4372
+ var CONTEXT_PATH = ".vhk/context.md";
4373
+ var IGNORE_DIRS2 = /* @__PURE__ */ new Set([
4374
+ "node_modules",
4375
+ ".git",
4376
+ "dist",
4377
+ ".next",
4378
+ ".nuxt",
4379
+ ".output",
4380
+ "coverage",
4381
+ ".cache",
4382
+ ".turbo",
4383
+ ".vhk"
4384
+ ]);
4385
+ function buildTree(dir, prefix = "", maxDepth = 3, depth = 0) {
4386
+ if (depth >= maxDepth) return [];
4387
+ const lines = [];
4388
+ try {
4389
+ const entries = readdirSync(dir);
4390
+ const filtered = entries.filter(
4391
+ (e) => (!e.startsWith(".") || e === ".env.example") && !IGNORE_DIRS2.has(e)
4392
+ );
4393
+ filtered.forEach((entry, index) => {
4394
+ const isLast = index === filtered.length - 1;
4395
+ const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4396
+ const fullPath = join3(dir, entry);
4397
+ const stat = statSync(fullPath);
4398
+ const isDir = stat.isDirectory();
4399
+ lines.push(`${prefix}${connector}${entry}${isDir ? "/" : ""}`);
4400
+ if (isDir) {
4401
+ const nextPrefix = prefix + (isLast ? " " : "\u2502 ");
4402
+ lines.push(...buildTree(fullPath, nextPrefix, maxDepth, depth + 1));
4403
+ }
4404
+ });
4405
+ } catch {
4406
+ }
4407
+ return lines;
4408
+ }
4409
+ function extractTechStack() {
4410
+ const stack = {};
4411
+ try {
4412
+ const pkg = readJsonFile("package.json");
4413
+ const all = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
4414
+ if (all.next) stack["\uD504\uB808\uC784\uC6CC\uD06C"] = `Next.js ${all.next}`;
4415
+ else if (all.nuxt) stack["\uD504\uB808\uC784\uC6CC\uD06C"] = `Nuxt ${all.nuxt}`;
4416
+ else if (all.react) stack["\uD504\uB808\uC784\uC6CC\uD06C"] = `React ${all.react}`;
4417
+ else if (all.vue) stack["\uD504\uB808\uC784\uC6CC\uD06C"] = `Vue ${all.vue}`;
4418
+ else if (all.svelte) stack["\uD504\uB808\uC784\uC6CC\uD06C"] = `Svelte ${all.svelte}`;
4419
+ if (all.typescript) stack["\uC5B8\uC5B4"] = `TypeScript ${all.typescript}`;
4420
+ if (all.tailwindcss) stack["\uC2A4\uD0C0\uC77C"] = `Tailwind CSS ${all.tailwindcss}`;
4421
+ if (all.tsup) stack["\uBE4C\uB4DC"] = "tsup";
4422
+ else if (all.vite) stack["\uBE4C\uB4DC"] = `Vite ${all.vite}`;
4423
+ else if (all.webpack) stack["\uBE4C\uB4DC"] = "webpack";
4424
+ if (all.vitest) stack["\uD14C\uC2A4\uD2B8"] = "vitest";
4425
+ else if (all.jest) stack["\uD14C\uC2A4\uD2B8"] = "jest";
4426
+ if (all.commander) stack["CLI"] = "commander";
4427
+ if (all.inquirer) stack["\uC778\uD130\uB799\uD2F0\uBE0C"] = "inquirer";
4428
+ if (existsSync11("pnpm-lock.yaml")) stack["\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800"] = "pnpm";
4429
+ else if (existsSync11("yarn.lock")) stack["\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800"] = "yarn";
4430
+ else stack["\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800"] = "npm";
4431
+ if (pkg.name) stack["\uD328\uD0A4\uC9C0 \uC774\uB984"] = pkg.name;
4432
+ if (pkg.version) stack["\uBC84\uC804"] = pkg.version;
4433
+ } catch {
4434
+ }
4435
+ return stack;
4436
+ }
4437
+ function getVhkCommands() {
4438
+ return [
4439
+ "gate \u2014 \uC544\uC774\uB514\uC5B4 \uAC80\uC99D",
4440
+ "init \u2014 \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654",
4441
+ "recap \u2014 \uC138\uC158 \uC694\uC57D \uC800\uC7A5",
4442
+ "sync \u2014 \uADDC\uCE59 \uD30C\uC77C \uB3D9\uAE30\uD654",
4443
+ "check \u2014 \uADDC\uCE59 \uC810\uAC80",
4444
+ "secure \u2014 \uBCF4\uC548 \uC2A4\uCE94",
4445
+ "ship \u2014 \uBC30\uD3EC \uCCB4\uD06C + \uD68C\uACE0",
4446
+ "doctor \u2014 \uD658\uACBD \uC9C4\uB2E8",
4447
+ "save \u2014 git \uC800\uC7A5 (add+commit+push)",
4448
+ "undo \u2014 \uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30",
4449
+ "status \u2014 git \uC0C1\uD0DC \uD655\uC778",
4450
+ "diff \u2014 git \uBCC0\uACBD \uC0AC\uD56D \uC694\uC57D",
4451
+ "deploy \u2014 \uD504\uB85C\uB355\uC158 \uBC30\uD3EC",
4452
+ "env \u2014 \uD658\uACBD\uBCC0\uC218 \uAD00\uB9AC",
4453
+ "publish \u2014 npm \uBC30\uD3EC \uC790\uB3D9\uD654",
4454
+ "design \u2014 \uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131",
4455
+ "design-palette \u2014 \uCEEC\uB7EC \uD314\uB808\uD2B8 \uC120\uD0DD",
4456
+ "theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC",
4457
+ "ref add|list|open \u2014 \uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC",
4458
+ "harness \u2014 \uD1B5\uD569 \uD488\uC9C8 \uC810\uAC80",
4459
+ "audit \u2014 \uBCF4\uC548 \uCDE8\uC57D\uC810 \uAC10\uC0AC",
4460
+ "migrate \u2014 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 \uC804\uD658",
4461
+ "update \u2014 VHK CLI \uC140\uD504 \uC5C5\uB370\uC774\uD2B8",
4462
+ "context \u2014 \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uC0DD\uC131",
4463
+ "context-show \u2014 \uB9E5\uB77D \uD30C\uC77C \uBCF4\uAE30",
4464
+ "memory add|list|remove \u2014 \uACB0\uC815\uC0AC\uD56D \uAE30\uC5B5",
4465
+ "brief \u2014 \uD504\uB85C\uC81D\uD2B8 \uC694\uC57D \uBCF4\uACE0\uC11C",
4466
+ "mcp \u2014 MCP \uC11C\uBC84 \uC2DC\uC791",
4467
+ "mcp-init \u2014 Cursor MCP \uC124\uC815"
4468
+ ];
4469
+ }
4470
+ async function context() {
4471
+ console.log(chalk25.bold("\n\u{1F9E0} " + t("context.title")));
4472
+ console.log(chalk25.gray("\u2500".repeat(40)));
4473
+ const stack = extractTechStack();
4474
+ const tree = buildTree(".").join("\n");
4475
+ const commands = getVhkCommands();
4476
+ const lines = [];
4477
+ lines.push("# \uD504\uB85C\uC81D\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8");
4478
+ lines.push("");
4479
+ lines.push("> \uC774 \uD30C\uC77C\uC740 `vhk context`\uB85C \uC790\uB3D9 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
4480
+ lines.push("> AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC5D0\uAC8C \uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D\uC744 \uC81C\uACF5\uD569\uB2C8\uB2E4.");
4481
+ lines.push("");
4482
+ lines.push("## \uAE30\uC220 \uC2A4\uD0DD");
4483
+ lines.push("");
4484
+ for (const [key, value] of Object.entries(stack)) {
4485
+ lines.push(`- **${key}**: ${value}`);
4486
+ }
4487
+ lines.push("");
4488
+ lines.push("## \uB514\uB809\uD1A0\uB9AC \uAD6C\uC870");
4489
+ lines.push("");
4490
+ lines.push("```");
4491
+ lines.push(tree);
4492
+ lines.push("```");
4493
+ lines.push("");
4494
+ lines.push("## VHK CLI \uBA85\uB839\uC5B4");
4495
+ lines.push("");
4496
+ for (const cmd of commands) {
4497
+ lines.push(`- \`vhk ${cmd}\``);
4498
+ }
4499
+ lines.push("");
4500
+ if (existsSync11(".vhk/memory.json")) {
4501
+ try {
4502
+ const memories = readJsonFile(
4503
+ ".vhk/memory.json"
4504
+ );
4505
+ if (Array.isArray(memories) && memories.length > 0) {
4506
+ lines.push("## \uC800\uC7A5\uB41C \uACB0\uC815\uC0AC\uD56D");
4507
+ lines.push("");
4508
+ for (const m of memories) {
4509
+ const date = new Date(m.addedAt).toLocaleDateString("ko-KR");
4510
+ lines.push(`- ${m.content} _(${date})_`);
4511
+ }
4512
+ lines.push("");
4513
+ }
4514
+ } catch {
4515
+ }
4516
+ }
4517
+ lines.push("---");
4518
+ lines.push("");
4519
+ lines.push(`_\uC0DD\uC131: ${(/* @__PURE__ */ new Date()).toLocaleString("ko-KR")}_`);
4520
+ lines.push("");
4521
+ mkdirSync5(".vhk", { recursive: true });
4522
+ writeFileSync6(CONTEXT_PATH, lines.join("\n"), "utf-8");
4523
+ console.log(chalk25.green(`
4524
+ \u2705 ${CONTEXT_PATH} \uC0DD\uC131 \uC644\uB8CC!`));
4525
+ console.log(chalk25.gray(` \uAE30\uC220 \uC2A4\uD0DD ${Object.keys(stack).length}\uAC1C \uAC10\uC9C0`));
4526
+ console.log(chalk25.gray(" AI \uC5B4\uC2DC\uC2A4\uD134\uD2B8\uC5D0\uAC8C \uC774 \uD30C\uC77C\uC744 \uCC38\uC870\uD558\uAC8C \uD558\uC138\uC694."));
4527
+ printNextStep({
4528
+ message: "\uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC!",
4529
+ command: "vhk context-show",
4530
+ cursorHint: "\uCEE8\uD14D\uC2A4\uD2B8 \uBCF4\uC5EC\uC918"
4531
+ });
4532
+ }
4533
+ async function contextShow() {
4534
+ console.log(chalk25.bold("\n\u{1F4C4} " + t("context.showTitle")));
4535
+ console.log(chalk25.gray("\u2500".repeat(40)));
4536
+ if (!existsSync11(CONTEXT_PATH)) {
4537
+ console.log(chalk25.yellow("\n\u26A0\uFE0F \uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
4538
+ console.log(chalk25.gray(" vhk context\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694."));
4539
+ return;
4540
+ }
4541
+ const content = readFileSync7(CONTEXT_PATH, "utf-8");
4542
+ console.log("\n" + content);
4543
+ }
4544
+
4545
+ // src/commands/memory.ts
4546
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
4547
+ import chalk26 from "chalk";
4548
+ var MEMORY_PATH = ".vhk/memory.json";
4549
+ function loadMemories() {
4550
+ if (!existsSync12(MEMORY_PATH)) return [];
4551
+ try {
4552
+ const parsed = readJsonFile(MEMORY_PATH);
4553
+ return Array.isArray(parsed) ? parsed : [];
4554
+ } catch {
4555
+ return [];
4556
+ }
4557
+ }
4558
+ function saveMemories(memories) {
4559
+ mkdirSync6(".vhk", { recursive: true });
4560
+ writeFileSync7(MEMORY_PATH, JSON.stringify(memories, null, 2) + "\n", "utf-8");
4561
+ }
4562
+ async function memoryAdd(content, tags) {
4563
+ console.log(chalk26.bold("\n\u{1F9E0} " + t("memory.addTitle")));
4564
+ console.log(chalk26.gray("\u2500".repeat(40)));
4565
+ if (!content) {
4566
+ console.log(chalk26.red("\u274C \uAE30\uC5B5\uD560 \uB0B4\uC6A9\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694."));
4567
+ console.log(chalk26.gray(' \uC608: vhk memory add "API\uB294 tRPC \uC0AC\uC6A9\uD558\uAE30\uB85C \uACB0\uC815"'));
4568
+ return;
4569
+ }
4570
+ const memories = loadMemories();
4571
+ memories.push({
4572
+ content,
4573
+ addedAt: (/* @__PURE__ */ new Date()).toISOString(),
4574
+ tags: tags && tags.length > 0 ? tags : []
4575
+ });
4576
+ saveMemories(memories);
4577
+ console.log(chalk26.green(`
4578
+ \u2705 \uAE30\uC5B5 \uC800\uC7A5\uB428 (#${memories.length})`));
4579
+ console.log(chalk26.cyan(` \u{1F4DD} ${content}`));
4580
+ printNextStep({
4581
+ message: "\uAE30\uC5B5 \uC800\uC7A5 \uC644\uB8CC!",
4582
+ command: "vhk memory list",
4583
+ cursorHint: "\uAE30\uC5B5 \uBAA9\uB85D \uBCF4\uC5EC\uC918"
4584
+ });
4585
+ }
4586
+ async function memoryList() {
4587
+ console.log(chalk26.bold("\n\u{1F9E0} " + t("memory.listTitle")));
4588
+ console.log(chalk26.gray("\u2500".repeat(40)));
4589
+ const memories = loadMemories();
4590
+ if (memories.length === 0) {
4591
+ console.log(chalk26.yellow("\n\u{1F4ED} \uC800\uC7A5\uB41C \uAE30\uC5B5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
4592
+ console.log(chalk26.gray(' vhk memory add "\uB0B4\uC6A9"\uC73C\uB85C \uCD94\uAC00\uD558\uC138\uC694.'));
4593
+ return;
4594
+ }
4595
+ console.log(chalk26.cyan(`
4596
+ \uCD1D ${memories.length}\uAC1C\uC758 \uAE30\uC5B5:
4597
+ `));
4598
+ memories.forEach((m, index) => {
4599
+ const date = new Date(m.addedAt).toLocaleDateString("ko-KR");
4600
+ console.log(chalk26.white(` [${index + 1}] ${m.content}`));
4601
+ if (m.tags && m.tags.length > 0) {
4602
+ console.log(chalk26.blue(` \u{1F3F7}\uFE0F ${m.tags.join(", ")}`));
4603
+ }
4604
+ console.log(chalk26.gray(` \u{1F4C5} ${date}`));
4605
+ console.log("");
4606
+ });
4607
+ }
4608
+ async function memoryRemove(indexStr) {
4609
+ const memories = loadMemories();
4610
+ const idx = parseInt(indexStr, 10) - 1;
4611
+ if (Number.isNaN(idx) || idx < 0 || idx >= memories.length) {
4612
+ console.log(chalk26.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBC88\uD638\uC785\uB2C8\uB2E4. (1~${memories.length || 0})`));
4613
+ return;
4614
+ }
4615
+ const removed = memories.splice(idx, 1)[0];
4616
+ saveMemories(memories);
4617
+ console.log(chalk26.green("\n\u2705 \uAE30\uC5B5 \uC0AD\uC81C\uB428:"));
4618
+ console.log(chalk26.gray(` ${removed.content}`));
4619
+ }
4620
+
4621
+ // src/commands/brief.ts
4622
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, writeFileSync as writeFileSync8 } from "fs";
4623
+ import chalk27 from "chalk";
4624
+ var BRIEF_PATH = ".vhk/brief.md";
4625
+ function git2(args) {
4626
+ const result = safeExecFile("git", args);
4627
+ return result.ok ? result.out : "";
4628
+ }
4629
+ async function brief() {
4630
+ console.log(chalk27.bold("\n\u{1F4CB} " + t("brief.title")));
4631
+ console.log(chalk27.gray("\u2500".repeat(40)));
4632
+ const lines = [];
4633
+ lines.push("# \uD504\uB85C\uC81D\uD2B8 \uBE0C\uB9AC\uD551");
4634
+ lines.push("");
4635
+ lines.push(`> \uC0DD\uC131: ${(/* @__PURE__ */ new Date()).toLocaleString("ko-KR")}`);
4636
+ lines.push("");
4637
+ try {
4638
+ const pkg = readJsonFile("package.json");
4639
+ lines.push("## \uD504\uB85C\uC81D\uD2B8 \uC815\uBCF4");
4640
+ lines.push("");
4641
+ lines.push(`- **\uC774\uB984**: ${pkg.name ?? "\uBBF8\uC815"}`);
4642
+ lines.push(`- **\uBC84\uC804**: ${pkg.version ?? "\uBBF8\uC815"}`);
4643
+ lines.push(`- **\uC124\uBA85**: ${pkg.description ?? "\uC5C6\uC74C"}`);
4644
+ const deps = Object.keys(pkg.dependencies ?? {}).length;
4645
+ const devDeps = Object.keys(pkg.devDependencies ?? {}).length;
4646
+ lines.push(`- **\uC758\uC874\uC131**: ${deps}\uAC1C (dev: ${devDeps}\uAC1C)`);
4647
+ lines.push("");
4648
+ } catch {
4649
+ lines.push("## \uD504\uB85C\uC81D\uD2B8 \uC815\uBCF4");
4650
+ lines.push("");
4651
+ lines.push("\u26A0\uFE0F package.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.");
4652
+ lines.push("");
4653
+ }
4654
+ const branch = git2(["branch", "--show-current"]);
4655
+ const lastCommit = git2(["log", "-1", "--pretty=format:%h %s (%cr)"]);
4656
+ const uncommitted = git2(["status", "--porcelain"]);
4657
+ const totalCommits = git2(["rev-list", "--count", "HEAD"]);
4658
+ lines.push("## Git \uC0C1\uD0DC");
4659
+ lines.push("");
4660
+ lines.push(`- **\uD604\uC7AC \uBE0C\uB79C\uCE58**: ${branch || "\uC54C \uC218 \uC5C6\uC74C"}`);
4661
+ lines.push(`- **\uB9C8\uC9C0\uB9C9 \uCEE4\uBC0B**: ${lastCommit || "\uC5C6\uC74C"}`);
4662
+ lines.push(`- **\uCD1D \uCEE4\uBC0B \uC218**: ${totalCommits || "\uC54C \uC218 \uC5C6\uC74C"}`);
4663
+ lines.push(
4664
+ `- **\uBBF8\uCEE4\uBC0B \uBCC0\uACBD**: ${uncommitted ? `${uncommitted.split("\n").length}\uAC1C \uD30C\uC77C` : "\uC5C6\uC74C \u2705"}`
4665
+ );
4666
+ lines.push("");
4667
+ if (existsSync13(".vhk/memory.json")) {
4668
+ try {
4669
+ const memories = readJsonFile(".vhk/memory.json");
4670
+ if (Array.isArray(memories) && memories.length > 0) {
4671
+ lines.push(`## \uC800\uC7A5\uB41C \uACB0\uC815\uC0AC\uD56D (${memories.length}\uAC1C)`);
4672
+ lines.push("");
4673
+ for (const m of memories.slice(-5)) {
4674
+ lines.push(`- ${m.content}`);
4675
+ }
4676
+ if (memories.length > 5) {
4677
+ lines.push(`- ... \uC678 ${memories.length - 5}\uAC1C`);
4678
+ }
4679
+ lines.push("");
4680
+ }
4681
+ } catch {
4682
+ }
4683
+ }
4684
+ if (existsSync13(".vhk/refs.json")) {
4685
+ try {
4686
+ const refs = readJsonFile(".vhk/refs.json");
4687
+ if (Array.isArray(refs) && refs.length > 0) {
4688
+ lines.push(`## \uB808\uD37C\uB7F0\uC2A4 (${refs.length}\uAC1C)`);
4689
+ lines.push("");
4690
+ for (const r of refs.slice(-3)) {
4691
+ const label = r.memo && r.memo.length > 0 ? r.memo : r.url;
4692
+ lines.push(`- [${label}](${r.url})`);
4693
+ }
4694
+ lines.push("");
4695
+ }
4696
+ } catch {
4697
+ }
4698
+ }
4699
+ lines.push("## \uB2E4\uC74C \uB2E8\uACC4 \uC81C\uC548");
4700
+ lines.push("");
4701
+ const steps = [];
4702
+ if (uncommitted) steps.push("\uBBF8\uCEE4\uBC0B \uBCC0\uACBD \uC0AC\uD56D\uC744 \uCEE4\uBC0B\uD558\uC138\uC694: `vhk save`");
4703
+ steps.push("\uD488\uC9C8 \uC810\uAC80 \uC2E4\uD589: `vhk harness`");
4704
+ steps.push("\uBCF4\uC548 \uAC10\uC0AC: `vhk audit`");
4705
+ steps.push("\uCEE8\uD14D\uC2A4\uD2B8 \uAC31\uC2E0: `vhk context`");
4706
+ steps.forEach((s, i) => lines.push(`${i + 1}. ${s}`));
4707
+ lines.push("");
4708
+ lines.push("---");
4709
+ lines.push("");
4710
+ lines.push("_VHK CLI \uBE0C\uB9AC\uD551_");
4711
+ lines.push("");
4712
+ mkdirSync7(".vhk", { recursive: true });
4713
+ writeFileSync8(BRIEF_PATH, lines.join("\n"), "utf-8");
4714
+ console.log("\n" + lines.join("\n"));
4715
+ console.log(chalk27.green(`
4716
+ \u2705 ${BRIEF_PATH} \uC800\uC7A5 \uC644\uB8CC`));
4717
+ printNextStep({
4718
+ message: "\uBE0C\uB9AC\uD551 \uC0DD\uC131 \uC644\uB8CC!",
4719
+ command: "vhk context",
4720
+ cursorHint: "\uCEE8\uD14D\uC2A4\uD2B8 \uC5C5\uB370\uC774\uD2B8\uD574\uC918"
4721
+ });
4722
+ }
4723
+
4329
4724
  // src/lib/nlp-run.ts
4330
4725
  async function dispatchNlpRoute(route, input) {
4331
4726
  switch (route.command) {
@@ -4382,19 +4777,27 @@ async function dispatchNlpRoute(route, input) {
4382
4777
  return migrate();
4383
4778
  case "update":
4384
4779
  return update();
4780
+ case "context":
4781
+ return context();
4782
+ case "context-show":
4783
+ return contextShow();
4784
+ case "memory":
4785
+ return memoryList();
4786
+ case "brief":
4787
+ return brief();
4385
4788
  }
4386
4789
  }
4387
4790
  async function runNaturalLanguageRoute(input) {
4388
4791
  const route = routeNaturalLanguage(input);
4389
4792
  if (!route) {
4390
- console.log(chalk25.yellow(`
4793
+ console.log(chalk28.yellow(`
4391
4794
  \u2753 "${input}" \u2014 ${ko.nlp.notMatched}
4392
4795
  `));
4393
4796
  return;
4394
4797
  }
4395
4798
  console.log("");
4396
- console.log(chalk25.cyan(` \u{1F4AC} "${input}"`));
4397
- console.log(chalk25.cyan(` \u2192 ${route.explanation}`));
4799
+ console.log(chalk28.cyan(` \u{1F4AC} "${input}"`));
4800
+ console.log(chalk28.cyan(` \u2192 ${route.explanation}`));
4398
4801
  if (route.confidence === "low") {
4399
4802
  const { confirm } = await inquirer13.prompt([{
4400
4803
  type: "confirm",
@@ -4403,7 +4806,7 @@ async function runNaturalLanguageRoute(input) {
4403
4806
  default: true
4404
4807
  }]);
4405
4808
  if (!confirm) {
4406
- console.log(chalk25.dim(` ${ko.nlp.menuHint}`));
4809
+ console.log(chalk28.dim(` ${ko.nlp.menuHint}`));
4407
4810
  return;
4408
4811
  }
4409
4812
  }
@@ -4416,8 +4819,8 @@ function getVersion() {
4416
4819
  const dir = path15.dirname(fileURLToPath4(import.meta.url));
4417
4820
  for (const pkgPath of [path15.join(dir, "../package.json"), path15.join(dir, "../../package.json")]) {
4418
4821
  try {
4419
- if (fs16.existsSync(pkgPath)) {
4420
- const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
4822
+ if (fs15.existsSync(pkgPath)) {
4823
+ const pkg = JSON.parse(fs15.readFileSync(pkgPath, "utf-8"));
4421
4824
  if (pkg.version) return pkg.version;
4422
4825
  }
4423
4826
  } catch {
@@ -4452,7 +4855,11 @@ var KO_ALIASES = {
4452
4855
  harness: "\uD558\uB124\uC2A4",
4453
4856
  audit: "\uAC10\uC0AC",
4454
4857
  migrate: "\uC804\uD658",
4455
- update: "\uC5C5\uB370\uC774\uD2B8"
4858
+ update: "\uC5C5\uB370\uC774\uD2B8",
4859
+ context: "\uB9E5\uB77D",
4860
+ "context-show": "\uB9E5\uB77D\uBCF4\uAE30",
4861
+ memory: "\uAE30\uC5B5",
4862
+ brief: "\uBE0C\uB9AC\uD551"
4456
4863
  };
4457
4864
  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(getVersion());
4458
4865
  program.configureHelp({
@@ -4548,6 +4955,28 @@ program.command("migrate [target]").alias("\uC804\uD658").description("\uD328\uD
4548
4955
  program.command("update").alias("\uC5C5\uB370\uC774\uD2B8").description("VHK CLI \uCD5C\uC2E0 \uBC84\uC804 \uC5C5\uB370\uC774\uD2B8").action(async () => {
4549
4956
  await update();
4550
4957
  });
4958
+ program.command("context").alias("\uB9E5\uB77D").description("\uD504\uB85C\uC81D\uD2B8 \uB9E5\uB77D \uD30C\uC77C \uC0DD\uC131 (.vhk/context.md)").action(async () => {
4959
+ await context();
4960
+ });
4961
+ program.command("context-show").alias("\uB9E5\uB77D\uBCF4\uAE30").description("\uD604\uC7AC \uCEE8\uD14D\uC2A4\uD2B8 \uD30C\uC77C \uB0B4\uC6A9 \uCD9C\uB825").action(async () => {
4962
+ await contextShow();
4963
+ });
4964
+ var memoryCmd = program.command("memory").alias("\uAE30\uC5B5").description("\uACB0\uC815\uC0AC\uD56D \uAE30\uC5B5 \uAD00\uB9AC (add / list / remove)").action(async () => {
4965
+ await memoryList();
4966
+ });
4967
+ memoryCmd.command("add <content>").option("--tags <tags>", "\uD0DC\uADF8 (\uC27C\uD45C \uAD6C\uBD84)").description("\uACB0\uC815\uC0AC\uD56D \uAE30\uC5B5 \uC800\uC7A5").action(async (content, opts) => {
4968
+ const tags = opts.tags ? opts.tags.split(",").map((s) => s.trim()) : void 0;
4969
+ await memoryAdd(content, tags);
4970
+ });
4971
+ memoryCmd.command("list").alias("\uBAA9\uB85D").description("\uC800\uC7A5\uB41C \uAE30\uC5B5 \uBAA9\uB85D").action(async () => {
4972
+ await memoryList();
4973
+ });
4974
+ memoryCmd.command("remove <index>").alias("\uC0AD\uC81C").description("\uAE30\uC5B5 \uC0AD\uC81C (1\uBD80\uD130 \uC2DC\uC791\uD558\uB294 \uBC88\uD638)").action(async (index) => {
4975
+ await memoryRemove(index);
4976
+ });
4977
+ program.command("brief").alias("\uBE0C\uB9AC\uD551").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uC694\uC57D \uBCF4\uACE0\uC11C \uC0DD\uC131 (.vhk/brief.md)").action(async () => {
4978
+ await brief();
4979
+ });
4551
4980
  program.on("command:*", async (operands) => {
4552
4981
  const unknown = operands[0] ?? "";
4553
4982
  const rest = operands.slice(1);
package/dist/mcp/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startMcpServer
4
- } from "../chunk-UPXCLOBF.js";
4
+ } from "../chunk-7NGBIIA3.js";
5
5
 
6
6
  // src/mcp/index.ts
7
7
  startMcpServer().catch((err) => {
package/package.json CHANGED
@@ -1,65 +1,65 @@
1
- {
2
- "name": "@byh3071/vhk",
3
- "version": "0.9.1",
4
- "description": "Vibe Harness Kit โ€” ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ํ’€์‚ฌ์ดํด CLI",
5
- "bin": {
6
- "vhk": "dist/index.js",
7
- "vhk-mcp": "dist/mcp/index.js"
8
- },
9
- "type": "module",
10
- "scripts": {
11
- "dev": "tsx src/index.ts",
12
- "build": "tsup",
13
- "test": "vitest",
14
- "test:run": "vitest --run",
15
- "prepublishOnly": "pnpm build && pnpm test:run",
16
- "save": "vhk save",
17
- "check": "vhk check",
18
- "scan": "vhk secure scan",
19
- "recap": "vhk recap",
20
- "ship": "vhk ship",
21
- "doctor": "vhk doctor"
22
- },
23
- "files": [
24
- "dist",
25
- "README.md",
26
- "LICENSE"
27
- ],
28
- "keywords": [
29
- "vibe-coding",
30
- "harness",
31
- "cli",
32
- "scaffold",
33
- "session-log",
34
- "rules-sync"
35
- ],
36
- "author": "byh3071 <byh3071@gmail.com>",
37
- "license": "MIT",
38
- "repository": {
39
- "type": "git",
40
- "url": "git+https://github.com/byh3071-cpu/vhk.git"
41
- },
42
- "engines": {
43
- "node": ">=20"
44
- },
45
- "dependencies": {
46
- "@modelcontextprotocol/sdk": "^1.29.0",
47
- "@notionhq/client": "^5.22.0",
48
- "chalk": "^5.6.2",
49
- "commander": "^14.0.3",
50
- "handlebars": "^4.7.9",
51
- "inquirer": "^9.3.8",
52
- "ora": "^9.4.0",
53
- "simple-git": "^3.36.0",
54
- "zod": "^4.4.3"
55
- },
56
- "devDependencies": {
57
- "@types/inquirer": "^9.0.9",
58
- "@types/node": "^25.9.1",
59
- "ignore": "^7.0.5",
60
- "tsup": "^8.5.1",
61
- "tsx": "^4.22.3",
62
- "typescript": "^6.0.3",
63
- "vitest": "^4.1.7"
64
- }
65
- }
1
+ {
2
+ "name": "@byh3071/vhk",
3
+ "version": "1.0.0",
4
+ "description": "Vibe Harness Kit โ€” ๋ฐ”์ด๋ธŒ์ฝ”๋”ฉ ํ’€์‚ฌ์ดํด CLI",
5
+ "bin": {
6
+ "vhk": "dist/index.js",
7
+ "vhk-mcp": "dist/mcp/index.js"
8
+ },
9
+ "type": "module",
10
+ "scripts": {
11
+ "dev": "tsx src/index.ts",
12
+ "build": "tsup",
13
+ "test": "vitest",
14
+ "test:run": "vitest --run",
15
+ "prepublishOnly": "pnpm build && pnpm test:run",
16
+ "save": "vhk save",
17
+ "check": "vhk check",
18
+ "scan": "vhk secure scan",
19
+ "recap": "vhk recap",
20
+ "ship": "vhk ship",
21
+ "doctor": "vhk doctor"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "keywords": [
29
+ "vibe-coding",
30
+ "harness",
31
+ "cli",
32
+ "scaffold",
33
+ "session-log",
34
+ "rules-sync"
35
+ ],
36
+ "author": "byh3071 <byh3071@gmail.com>",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/byh3071-cpu/vhk.git"
41
+ },
42
+ "engines": {
43
+ "node": ">=20"
44
+ },
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.29.0",
47
+ "@notionhq/client": "^5.22.0",
48
+ "chalk": "^5.6.2",
49
+ "commander": "^14.0.3",
50
+ "handlebars": "^4.7.9",
51
+ "inquirer": "^9.3.8",
52
+ "ora": "^9.4.0",
53
+ "simple-git": "^3.36.0",
54
+ "zod": "^4.4.3"
55
+ },
56
+ "devDependencies": {
57
+ "@types/inquirer": "^9.0.9",
58
+ "@types/node": "^25.9.1",
59
+ "ignore": "^7.0.5",
60
+ "tsup": "^8.5.1",
61
+ "tsx": "^4.22.3",
62
+ "typescript": "^6.0.3",
63
+ "vitest": "^4.1.7"
64
+ }
65
+ }