@byh3071/vhk 0.7.1 โ†’ 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  ---
2
2
  id: vhk-readme
3
3
  date: 2026-05-24
4
- tags: [vhk, cli, readme, v0.6.0]
4
+ tags: [vhk, cli, readme, v0.8.0]
5
5
  ---
6
6
 
7
7
  # ๐Ÿ”ง VHK โ€” Vibe Harness Kit
8
8
 
9
- > AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ๋ถ€๋ฆฌ๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•œ **ํ•œ๊ตญ์–ด ํ’€์‚ฌ์ดํด CLI** (v0.6.0)
9
+ > AI ์ฝ”๋”ฉ ์—์ด์ „ํŠธ๋ฅผ ๋ถ€๋ฆฌ๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•œ **ํ•œ๊ตญ์–ด ํ’€์‚ฌ์ดํด CLI** (v0.8.0)
10
10
  >
11
11
  > ๐Ÿฝ๏ธ **VHK๋Š” VHK๋กœ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ๋จ** โ€” ์ด ๋ ˆํฌ์˜ `docs/`, `CLAUDE.md`, `.cursorrules`๋„ `vhk init`์ด ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
12
12
 
@@ -95,6 +95,10 @@ vhk ๊ธฐํš ๋๋‚ฌ๊ณ  ๋ฐ”๋กœ ์‹œ์ž‘
95
95
  | `vhk env` | `ํ™˜๊ฒฝ๋ณ€์ˆ˜` | `.env` โ†’ `.env.example` ๋™๊ธฐํ™” + `.gitignore`์— `.env` ์ž๋™ ์ถ”๊ฐ€ |
96
96
  | `vhk env-check` | `ํ™˜๊ฒฝ๋ณ€์ˆ˜์ ๊ฒ€` | `.env.example` ๊ธฐ์ค€ ๋ˆ„๋ฝ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฒ€์‚ฌ |
97
97
  | `vhk publish` | `์ถœ์‹œ` | npm ๋ฐฐํฌ ์ž๋™ํ™” (๋ฒ„์ „ ๋ฒ”ํ”„ โ†’ ๋นŒ๋“œ โ†’ ํ…Œ์ŠคํŠธ โ†’ publish โ†’ git tag) |
98
+ | `vhk design` | `๋””์ž์ธ` | ๋””์ž์ธ ํ† ํฐ ์ƒ์„ฑ (Tailwind config ๋˜๋Š” CSS ๋ณ€์ˆ˜) |
99
+ | `vhk design-palette` | `ํŒ”๋ ˆํŠธ` | ์ปฌ๋Ÿฌ ํŒ”๋ ˆํŠธ ํ”„๋ฆฌ์…‹ ์„ ํƒ + ์ ์šฉ |
100
+ | `vhk theme` | `ํ…Œ๋งˆ` | ๋‹คํฌ/๋ผ์ดํŠธ ๋ชจ๋“œ CSS + ํ† ๊ธ€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ƒ์„ฑ |
101
+ | `vhk ref` | `๋ ˆํผ๋Ÿฐ์Šค` | ๋ ˆํผ๋Ÿฐ์Šค URL ๊ด€๋ฆฌ (`add` / `list` / `open`) |
98
102
 
99
103
  ### init ์˜ต์…˜
100
104
 
@@ -129,6 +133,31 @@ MCP ์„œ๋ฒ„๋ฅผ ์ˆ˜๋™์œผ๋กœ ๋„์šฐ๋ ค๋ฉด:
129
133
  vhk mcp # stdio ์„œ๋ฒ„ ์‹œ์ž‘ (Cursor๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ)
130
134
  ```
131
135
 
136
+ ## v0.8.0 ํ•˜์ด๋ผ์ดํŠธ
137
+
138
+ | ๊ธฐ๋Šฅ | ์„ค๋ช… |
139
+ |------|------|
140
+ | **design** | ํŒ”๋ ˆํŠธ ํ”„๋ฆฌ์…‹ 4์ข…(Minimal/Vibrant/Corporate/Pastel) ์„ ํƒ โ†’ `src/styles/tokens.css` ๋˜๋Š” `src/styles/vhk-colors.ts` (Tailwind config๊ฐ€ ์žˆ์œผ๋ฉด TS) ์ƒ์„ฑ |
141
+ | **theme** | `src/styles/theme.css` (๋‹คํฌ/๋ผ์ดํŠธ + `prefers-color-scheme` + `data-theme` ์…€๋ ‰ํ„ฐ) + `src/lib/theme-toggle.ts` (`getTheme`/`setTheme`/`toggleTheme`/`initTheme`) ์ƒ์„ฑ |
142
+ | **ref** | `.vhk/refs.json` ๊ธฐ๋ฐ˜ ๋ ˆํผ๋Ÿฐ์Šค URL ๊ด€๋ฆฌ. `ref add <url> --memo "..."` / `ref list` / `ref open <๋ฒˆํ˜ธ>` (Windows/macOS/Linux ๋ธŒ๋ผ์šฐ์ € ์ž๋™ ์˜คํ”ˆ) |
143
+ | **์ž์—ฐ์–ด ํ™•์žฅ** | `"๋””์ž์ธ ํ† ํฐ ๋งŒ๋“ค์–ด์ค˜"` / `"ํŒ”๋ ˆํŠธ ๊ณจ๋ผ์ค˜"` / `"๋‹คํฌ ๋ชจ๋“œ ์ ์šฉ"` / `"๋ ˆํผ๋Ÿฐ์Šค ๋ณด์—ฌ์ค˜"` ์ธ์‹. `ref add`/`open`์€ ์ธ์ž ์ถ”์ถœ ์ธํ”„๋ผ๊ฐ€ ์—†์–ด ์˜๋„์ ์œผ๋กœ NL ๋ฐฐ์ œ โ€” commander ์„œ๋ธŒ์ปค๋งจ๋“œ๋งŒ ์‚ฌ์šฉ |
144
+
145
+ ```powershell
146
+ vhk design # ํŒ”๋ ˆํŠธ ์„ ํƒ โ†’ src/styles/tokens.css ๋˜๋Š” vhk-colors.ts
147
+ vhk theme # src/styles/theme.css + src/lib/theme-toggle.ts
148
+ vhk ref add https://example.com --memo "์ฐธ๊ณ  ์‚ฌ์ดํŠธ"
149
+ vhk ref list # ์ €์žฅ๋œ ๋ ˆํผ๋Ÿฐ์Šค ๋ชฉ๋ก
150
+ vhk ref open 1 # 1๋ฒˆ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๋ธŒ๋ผ์šฐ์ €๋กœ ์—ด๊ธฐ
151
+ ```
152
+
153
+ ## v0.7.0 ํ•˜์ด๋ผ์ดํŠธ
154
+
155
+ | ๊ธฐ๋Šฅ | ์„ค๋ช… |
156
+ |------|------|
157
+ | **deploy** | Vercel / Netlify / Cloudflare Workers ์ž๋™ ๊ฐ์ง€ + ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ |
158
+ | **env / env-check** | `.env` โ†’ `.env.example` ๋™๊ธฐํ™” + ๋ˆ„๋ฝ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฒ€์‚ฌ. MCP ๋„๊ตฌ๋กœ๋„ ๋…ธ์ถœ (v0.7.1) |
159
+ | **publish** | semver ๋ฒ”ํ”„ + ๋นŒ๋“œ + ํ…Œ์ŠคํŠธ + `npm publish` + git tag ์ž๋™ํ™” |
160
+
132
161
  ## v0.6.0 ํ•˜์ด๋ผ์ดํŠธ
133
162
 
134
163
  | ๊ธฐ๋Šฅ | ์„ค๋ช… |
@@ -191,6 +220,10 @@ vhk mcp # stdio ์„œ๋ฒ„ ์‹œ์ž‘ (Cursor๊ฐ€ ์ž๋™์œผ๋กœ ํ˜ธ์ถœ)
191
220
  | ๋ณด์•ˆ ์Šค์บ” ๋Œ๋ ค | `vhk ๋ณด์•ˆ` |
192
221
  | ๋ฐฐํฌํ•˜๊ณ  ์‹ถ์–ด | `vhk ๋ฐฐํฌ` |
193
222
  | ๋ญ”๊ฐ€ ์•ˆ ๋ผ | `vhk doctor` |
223
+ | ๋””์ž์ธ ํ† ํฐ ๋งŒ๋“ค์–ด์ค˜ | `vhk design` |
224
+ | ํŒ”๋ ˆํŠธ ๊ณจ๋ผ์ค˜ | `vhk design-palette` |
225
+ | ๋‹คํฌ ๋ชจ๋“œ ์ ์šฉ | `vhk theme` |
226
+ | ๋ ˆํผ๋Ÿฐ์Šค ๋ณด์—ฌ์ค˜ | `vhk ref` (list) |
194
227
 
195
228
  ## ํŠน์ง•
196
229
 
@@ -272,6 +272,17 @@ var ko = {
272
272
  changelogNoUnreleased: "CHANGELOG.md\uC5D0 [Unreleased] \uC139\uC158\uC774 \uC5C6\uC5B4 \uC790\uB3D9 \uAC31\uC2E0\uC744 \uC2A4\uD0B5\uD588\uC5B4\uC694",
273
273
  changelogMissing: "CHANGELOG.md\uAC00 \uC5C6\uC5B4\uC694. \uB9CC\uB4E4\uBA74 ship\uC774 \uC790\uB3D9\uC73C\uB85C [Unreleased] \u2192 \uBC84\uC804 \uC139\uC158\uC73C\uB85C \uC62E\uACA8\uC90D\uB2C8\uB2E4."
274
274
  },
275
+ design: {
276
+ title: "\uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131",
277
+ selectPalette: "\uCEEC\uB7EC \uD314\uB808\uD2B8\uB97C \uC120\uD0DD\uD558\uC138\uC694:"
278
+ },
279
+ theme: {
280
+ title: "\uD14C\uB9C8 \uC124\uC815 (\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC)"
281
+ },
282
+ ref: {
283
+ addTitle: "\uB808\uD37C\uB7F0\uC2A4 \uCD94\uAC00",
284
+ listTitle: "\uB808\uD37C\uB7F0\uC2A4 \uBAA9\uB85D"
285
+ },
275
286
  mcp: {
276
287
  initTitle: "Cursor MCP \uC5F0\uB3D9 \uC124\uC815",
277
288
  serverStarted: "VHK MCP \uC11C\uBC84 \uC2DC\uC791\uB428"
@@ -431,9 +442,16 @@ function platformCmd(cmd) {
431
442
  }
432
443
  return cmd;
433
444
  }
445
+ function resolveCmd(cmd, args) {
446
+ if (process.platform === "win32" && SHIM_BINARIES.has(cmd)) {
447
+ return { bin: "cmd.exe", argv: ["/d", "/s", "/c", `${cmd}.cmd`, ...args] };
448
+ }
449
+ return { bin: platformCmd(cmd), argv: args };
450
+ }
434
451
  function safeExecFile(cmd, args) {
452
+ const { bin, argv } = resolveCmd(cmd, args);
435
453
  try {
436
- const out = execFileSync(platformCmd(cmd), args, {
454
+ const out = execFileSync(bin, argv, {
437
455
  encoding: "utf-8",
438
456
  stdio: ["pipe", "pipe", "pipe"]
439
457
  }).toString();
@@ -444,8 +462,9 @@ function safeExecFile(cmd, args) {
444
462
  }
445
463
  }
446
464
  function safeExecFileStream(cmd, args) {
465
+ const { bin, argv } = resolveCmd(cmd, args);
447
466
  try {
448
- execFileSync(platformCmd(cmd), args, {
467
+ execFileSync(bin, argv, {
449
468
  encoding: "utf-8",
450
469
  stdio: "inherit"
451
470
  });
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  safeExecFileStream,
11
11
  startMcpServer,
12
12
  t
13
- } from "./chunk-3HHU7V77.js";
13
+ } from "./chunk-X3CIIDO2.js";
14
14
 
15
15
  // node_modules/.pnpm/ignore@7.0.5/node_modules/ignore/index.js
16
16
  var require_ignore = __commonJS({
@@ -310,7 +310,7 @@ var require_ignore = __commonJS({
310
310
  // path matching.
311
311
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
312
312
  // @returns {TestResult} true if a file is ignored
313
- test(path15, checkUnignored, mode) {
313
+ test(path16, checkUnignored, mode) {
314
314
  let ignored = false;
315
315
  let unignored = false;
316
316
  let matchedRule;
@@ -319,7 +319,7 @@ var require_ignore = __commonJS({
319
319
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
320
320
  return;
321
321
  }
322
- const matched = rule[mode].test(path15);
322
+ const matched = rule[mode].test(path16);
323
323
  if (!matched) {
324
324
  return;
325
325
  }
@@ -340,17 +340,17 @@ var require_ignore = __commonJS({
340
340
  var throwError = (message, Ctor) => {
341
341
  throw new Ctor(message);
342
342
  };
343
- var checkPath = (path15, originalPath, doThrow) => {
344
- if (!isString(path15)) {
343
+ var checkPath = (path16, originalPath, doThrow) => {
344
+ if (!isString(path16)) {
345
345
  return doThrow(
346
346
  `path must be a string, but got \`${originalPath}\``,
347
347
  TypeError
348
348
  );
349
349
  }
350
- if (!path15) {
350
+ if (!path16) {
351
351
  return doThrow(`path must not be empty`, TypeError);
352
352
  }
353
- if (checkPath.isNotRelative(path15)) {
353
+ if (checkPath.isNotRelative(path16)) {
354
354
  const r = "`path.relative()`d";
355
355
  return doThrow(
356
356
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -359,7 +359,7 @@ var require_ignore = __commonJS({
359
359
  }
360
360
  return true;
361
361
  };
362
- var isNotRelative = (path15) => REGEX_TEST_INVALID_PATH.test(path15);
362
+ var isNotRelative = (path16) => REGEX_TEST_INVALID_PATH.test(path16);
363
363
  checkPath.isNotRelative = isNotRelative;
364
364
  checkPath.convert = (p) => p;
365
365
  var Ignore = class {
@@ -389,19 +389,19 @@ var require_ignore = __commonJS({
389
389
  }
390
390
  // @returns {TestResult}
391
391
  _test(originalPath, cache, checkUnignored, slices) {
392
- const path15 = originalPath && checkPath.convert(originalPath);
392
+ const path16 = originalPath && checkPath.convert(originalPath);
393
393
  checkPath(
394
- path15,
394
+ path16,
395
395
  originalPath,
396
396
  this._strictPathCheck ? throwError : RETURN_FALSE
397
397
  );
398
- return this._t(path15, cache, checkUnignored, slices);
398
+ return this._t(path16, cache, checkUnignored, slices);
399
399
  }
400
- checkIgnore(path15) {
401
- if (!REGEX_TEST_TRAILING_SLASH.test(path15)) {
402
- return this.test(path15);
400
+ checkIgnore(path16) {
401
+ if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
402
+ return this.test(path16);
403
403
  }
404
- const slices = path15.split(SLASH).filter(Boolean);
404
+ const slices = path16.split(SLASH).filter(Boolean);
405
405
  slices.pop();
406
406
  if (slices.length) {
407
407
  const parent = this._t(
@@ -414,18 +414,18 @@ var require_ignore = __commonJS({
414
414
  return parent;
415
415
  }
416
416
  }
417
- return this._rules.test(path15, false, MODE_CHECK_IGNORE);
417
+ return this._rules.test(path16, false, MODE_CHECK_IGNORE);
418
418
  }
419
- _t(path15, cache, checkUnignored, slices) {
420
- if (path15 in cache) {
421
- return cache[path15];
419
+ _t(path16, cache, checkUnignored, slices) {
420
+ if (path16 in cache) {
421
+ return cache[path16];
422
422
  }
423
423
  if (!slices) {
424
- slices = path15.split(SLASH).filter(Boolean);
424
+ slices = path16.split(SLASH).filter(Boolean);
425
425
  }
426
426
  slices.pop();
427
427
  if (!slices.length) {
428
- return cache[path15] = this._rules.test(path15, checkUnignored, MODE_IGNORE);
428
+ return cache[path16] = this._rules.test(path16, checkUnignored, MODE_IGNORE);
429
429
  }
430
430
  const parent = this._t(
431
431
  slices.join(SLASH) + SLASH,
@@ -433,29 +433,29 @@ var require_ignore = __commonJS({
433
433
  checkUnignored,
434
434
  slices
435
435
  );
436
- return cache[path15] = parent.ignored ? parent : this._rules.test(path15, checkUnignored, MODE_IGNORE);
436
+ return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
437
437
  }
438
- ignores(path15) {
439
- return this._test(path15, this._ignoreCache, false).ignored;
438
+ ignores(path16) {
439
+ return this._test(path16, this._ignoreCache, false).ignored;
440
440
  }
441
441
  createFilter() {
442
- return (path15) => !this.ignores(path15);
442
+ return (path16) => !this.ignores(path16);
443
443
  }
444
444
  filter(paths) {
445
445
  return makeArray(paths).filter(this.createFilter());
446
446
  }
447
447
  // @returns {TestResult}
448
- test(path15) {
449
- return this._test(path15, this._testCache, true);
448
+ test(path16) {
449
+ return this._test(path16, this._testCache, true);
450
450
  }
451
451
  };
452
452
  var factory = (options) => new Ignore(options);
453
- var isPathValid = (path15) => checkPath(path15 && checkPath.convert(path15), path15, RETURN_FALSE);
453
+ var isPathValid = (path16) => checkPath(path16 && checkPath.convert(path16), path16, RETURN_FALSE);
454
454
  var setupWindows = () => {
455
455
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
456
456
  checkPath.convert = makePosix;
457
457
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
458
- checkPath.isNotRelative = (path15) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path15) || isNotRelative(path15);
458
+ checkPath.isNotRelative = (path16) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path16) || isNotRelative(path16);
459
459
  };
460
460
  if (
461
461
  // Detect `process` so that it can run in browsers.
@@ -472,7 +472,10 @@ var require_ignore = __commonJS({
472
472
 
473
473
  // src/index.ts
474
474
  import { Command, Help } from "commander";
475
- import inquirer10 from "inquirer";
475
+ import inquirer12 from "inquirer";
476
+ import fs16 from "fs";
477
+ import path15 from "path";
478
+ import { fileURLToPath as fileURLToPath3 } from "url";
476
479
 
477
480
  // src/lib/nlp-router.ts
478
481
  function normalize(input) {
@@ -508,7 +511,7 @@ var RULES = [
508
511
  command: "init",
509
512
  explanation: "\uD504\uB85C\uC81D\uD2B8 \uC2DC\uC791 (vhk \uC2DC\uC791)",
510
513
  confidence: "high",
511
- test: (t2) => /ํ”„๋กœ์ ํŠธ.*(๋งŒ๋“ค|์‹œ์ž‘)|ํด๋”.*๋งŒ๋“ค|๋งŒ๋“ค๊ณ \s*์‹ถ|ํ•˜๋„ค์Šค|์ดˆ๊ธฐํ™”/.test(t2) || /^์‹œ์ž‘$/.test(t2)
514
+ test: (t2) => (/ํ”„๋กœ์ ํŠธ.*(๋งŒ๋“ค|์‹œ์ž‘)|ํด๋”.*๋งŒ๋“ค|๋งŒ๋“ค๊ณ \s*์‹ถ|ํ•˜๋„ค์Šค|์ดˆ๊ธฐํ™”/.test(t2) || /^์‹œ์ž‘$/.test(t2)) && !/๋””์ž์ธ|design|ํŒ”๋ ˆํŠธ|palette|ํ…Œ๋งˆ|theme|๋ ˆํผ๋Ÿฐ์Šค|reference|๋‹คํฌ\s*๋ชจ๋“œ|๋ผ์ดํŠธ\s*๋ชจ๋“œ|์ƒ‰์ƒ\s*๋ชจ๋“œ/.test(t2)
512
515
  },
513
516
  {
514
517
  command: "mcp-init",
@@ -516,6 +519,30 @@ var RULES = [
516
519
  confidence: "high",
517
520
  test: (t2) => /mcp.*(์„ค์ •|์—ฐ๋™|์ดˆ๊ธฐ|init)|์ปค์„œ.*(์—ฐ๋™|์„ค์ •|mcp)|cursor.*mcp/.test(t2)
518
521
  },
522
+ {
523
+ command: "design-palette",
524
+ explanation: "\uCEEC\uB7EC \uD314\uB808\uD2B8 \uC120\uD0DD (vhk design-palette)",
525
+ confidence: "high",
526
+ test: (t2) => /ํŒ”๋ ˆํŠธ|palette|์ปฌ๋Ÿฌ\s*(๊ณ |์„ ํƒ|๋ฐ”๊ฟ”|๋ณ€๊ฒฝ)|์ƒ‰์ƒ\s*(๊ณ |์„ ํƒ|๋ณ€๊ฒฝ)|์ƒ‰๊น”\s*์„ ํƒ/.test(t2)
527
+ },
528
+ {
529
+ command: "design",
530
+ explanation: "\uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131 (vhk design)",
531
+ confidence: "high",
532
+ test: (t2) => /๋””์ž์ธ\s*(ํ† ํฐ|์‹œ์Šคํ…œ|๋งŒ๋“ค|์ƒ์„ฑ|์…‹์—…|์„ค์ •)|design\s*(token|system|setup)|ํ† ํฐ\s*๋งŒ๋“ค|css\s*๋ณ€์ˆ˜.*๋งŒ๋“ค|tailwind\s*(์ปฌ๋Ÿฌ|์„ค์ •)/.test(t2) && !/๋ฐฐํฌ|deploy|vercel|netlify|cloudflare|wrangler|์ถœ์‹œ|publish|npm/.test(t2)
533
+ },
534
+ {
535
+ command: "theme",
536
+ explanation: "\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uD14C\uB9C8 \uC801\uC6A9 (vhk theme)",
537
+ confidence: "high",
538
+ test: (t2) => /ํ…Œ๋งˆ(?!\s*(ํŒŒ์ผ|์ด๋ฆ„))|theme|๋‹คํฌ\s*๋ชจ๋“œ|๋ผ์ดํŠธ\s*๋ชจ๋“œ|dark\s*mode|light\s*mode|์ƒ‰์ƒ\s*๋ชจ๋“œ|๋ชจ๋“œ\s*์ „ํ™˜/.test(t2) && !/๋ณด์•ˆ|์‹œํฌ๋ฆฟ|๋น„๋ฐ€|ํ‚ค\s*์œ ์ถœ|secure|scan|์Šค์บ”|๋ฐฐํฌ|deploy/.test(t2)
539
+ },
540
+ {
541
+ command: "ref",
542
+ explanation: "\uB808\uD37C\uB7F0\uC2A4 \uBAA9\uB85D (vhk ref list)",
543
+ confidence: "high",
544
+ test: (t2) => /^๋ ˆํผ๋Ÿฐ์Šค$|^ref$|๋ ˆํผ๋Ÿฐ์Šค.*(๋ณด|๋ชฉ๋ก|ํ™•์ธ|์žˆ|๋ญ)|์ฐธ๊ณ \s*(์‚ฌ์ดํŠธ|๋ชฉ๋ก|๋งํฌ)|reference.*list/.test(t2) && !/(add|์ถ”๊ฐ€|open|์—ด|https?:\/\/)/.test(t2)
545
+ },
519
546
  {
520
547
  command: "secure",
521
548
  explanation: "\uBCF4\uC548 \uC2A4\uCE94 (vhk \uBCF4\uC548)",
@@ -674,6 +701,14 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
674
701
  "publish",
675
702
  "\uCD9C\uC2DC",
676
703
  "\uCD9C\uD558",
704
+ "design",
705
+ "\uB514\uC790\uC778",
706
+ "design-palette",
707
+ "\uD314\uB808\uD2B8",
708
+ "theme",
709
+ "\uD14C\uB9C8",
710
+ "ref",
711
+ "\uB808\uD37C\uB7F0\uC2A4",
677
712
  "help"
678
713
  ]);
679
714
  function isOptionToken(token) {
@@ -697,8 +732,8 @@ function detectNaturalLanguageInput(argv) {
697
732
  }
698
733
 
699
734
  // src/lib/nlp-run.ts
700
- import chalk18 from "chalk";
701
- import inquirer9 from "inquirer";
735
+ import chalk21 from "chalk";
736
+ import inquirer11 from "inquirer";
702
737
 
703
738
  // src/commands/gate.ts
704
739
  import inquirer from "inquirer";
@@ -3535,17 +3570,21 @@ async function publish() {
3535
3570
  console.log(chalk17.gray("\uCDE8\uC18C\uB428. \uBC84\uC804\uC774 \uC6D0\uB798\uB300\uB85C \uBCF5\uAD6C\uB429\uB2C8\uB2E4."));
3536
3571
  return;
3537
3572
  }
3538
- const pubSpinner = ora2(t("publish.publishing")).start();
3539
- const pubResult = safeExecFile("npm", ["publish", "--access", "public"]);
3573
+ console.log(chalk17.cyan(`
3574
+ \u{1F4E4} ${t("publish.publishing")}`));
3575
+ console.log(chalk17.gray(" 2FA \uD65C\uC131\uD654 \uC2DC: OTP 6\uC790\uB9AC \uC785\uB825 \uB610\uB294 \uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D URL \uD074\uB9AD (Windows Hello / PIN \uC9C0\uC6D0)"));
3576
+ const pubResult = safeExecFileStream("npm", ["publish", "--access", "public"]);
3540
3577
  if (!pubResult.ok) {
3541
- pubSpinner.fail(t("publish.publishFailed"));
3578
+ console.log(chalk17.red(`
3579
+ \u2716 ${t("publish.publishFailed")}`));
3542
3580
  console.log(chalk17.red(pubResult.err.slice(0, 500)));
3543
3581
  pkg.version = currentVersion;
3544
3582
  writeFileSync2("package.json", JSON.stringify(pkg, null, 2) + "\n", "utf-8");
3545
3583
  console.log(chalk17.gray(`\u{1F4E6} package.json \uBC84\uC804\uC744 v${currentVersion}\uB85C \uBCF5\uAD6C\uD588\uC2B5\uB2C8\uB2E4.`));
3546
3584
  return;
3547
3585
  }
3548
- pubSpinner.succeed(t("publish.publishSuccess"));
3586
+ console.log(chalk17.green(`
3587
+ \u2714 ${t("publish.publishSuccess")}`));
3549
3588
  const addResult = safeExecFile("git", ["add", "package.json"]);
3550
3589
  if (addResult.ok) {
3551
3590
  safeExecFile("git", ["commit", "-m", `chore: release v${newVersion}`]);
@@ -3571,6 +3610,329 @@ async function publish() {
3571
3610
  });
3572
3611
  }
3573
3612
 
3613
+ // src/commands/design.ts
3614
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
3615
+ import chalk18 from "chalk";
3616
+ import inquirer9 from "inquirer";
3617
+ var PALETTES = [
3618
+ {
3619
+ name: "Minimal",
3620
+ colors: {
3621
+ primary: "#1a1a1a",
3622
+ secondary: "#6b7280",
3623
+ accent: "#3b82f6",
3624
+ background: "#ffffff",
3625
+ surface: "#f9fafb",
3626
+ text: "#111827",
3627
+ muted: "#9ca3af"
3628
+ }
3629
+ },
3630
+ {
3631
+ name: "Vibrant",
3632
+ colors: {
3633
+ primary: "#7c3aed",
3634
+ secondary: "#ec4899",
3635
+ accent: "#f59e0b",
3636
+ background: "#ffffff",
3637
+ surface: "#faf5ff",
3638
+ text: "#1e1b4b",
3639
+ muted: "#8b5cf6"
3640
+ }
3641
+ },
3642
+ {
3643
+ name: "Corporate",
3644
+ colors: {
3645
+ primary: "#1e40af",
3646
+ secondary: "#0f766e",
3647
+ accent: "#ca8a04",
3648
+ background: "#ffffff",
3649
+ surface: "#f0f9ff",
3650
+ text: "#0f172a",
3651
+ muted: "#64748b"
3652
+ }
3653
+ },
3654
+ {
3655
+ name: "Pastel",
3656
+ colors: {
3657
+ primary: "#a78bfa",
3658
+ secondary: "#f9a8d4",
3659
+ accent: "#fcd34d",
3660
+ background: "#fffbeb",
3661
+ surface: "#fef3c7",
3662
+ text: "#44403c",
3663
+ muted: "#a8a29e"
3664
+ }
3665
+ }
3666
+ ];
3667
+ function hasTailwind() {
3668
+ return existsSync4("tailwind.config.js") || existsSync4("tailwind.config.ts") || existsSync4("tailwind.config.mjs") || existsSync4("tailwind.config.cjs");
3669
+ }
3670
+ function generateCSSTokens(palette) {
3671
+ const lines = Object.entries(palette.colors).map(([key, value]) => ` --color-${key}: ${value};`).join("\n");
3672
+ return `:root {
3673
+ ${lines}
3674
+ }
3675
+ `;
3676
+ }
3677
+ function generateTailwindExtend(palette) {
3678
+ const entries = Object.entries(palette.colors).map(([key, value]) => ` '${key}': '${value}',`).join("\n");
3679
+ return `// vhk design \u2014 Tailwind config \uD655\uC7A5\uC6A9 \uCEEC\uB7EC \uD1A0\uD070
3680
+ // tailwind.config\uC758 theme.extend.colors\uC5D0 spread \uD558\uC138\uC694.
3681
+ const vhkColors = {
3682
+ ${entries}
3683
+ }
3684
+
3685
+ export default vhkColors
3686
+ `;
3687
+ }
3688
+ async function design() {
3689
+ console.log(chalk18.bold("\n\u{1F3A8} " + t("design.title")));
3690
+ console.log(chalk18.gray("\u2500".repeat(40)));
3691
+ const { paletteIndex } = await inquirer9.prompt([
3692
+ {
3693
+ type: "list",
3694
+ name: "paletteIndex",
3695
+ message: t("design.selectPalette"),
3696
+ choices: PALETTES.map((p, i) => ({
3697
+ name: `${p.name} \u2014 primary ${p.colors.primary}`,
3698
+ value: i
3699
+ }))
3700
+ }
3701
+ ]);
3702
+ const palette = PALETTES[paletteIndex];
3703
+ console.log(chalk18.cyan(`
3704
+ \u{1F3A8} \uC120\uD0DD\uB41C \uD314\uB808\uD2B8: ${palette.name}`));
3705
+ const targetPath = hasTailwind() ? "src/styles/vhk-colors.ts" : "src/styles/tokens.css";
3706
+ const content = hasTailwind() ? generateTailwindExtend(palette) : generateCSSTokens(palette);
3707
+ if (existsSync4(targetPath)) {
3708
+ const { overwrite } = await inquirer9.prompt([{
3709
+ type: "confirm",
3710
+ name: "overwrite",
3711
+ message: `${targetPath} \uC774\uBBF8 \uC788\uC5B4\uC694. \uB36E\uC5B4\uC4F8\uAE4C\uC694?`,
3712
+ default: false
3713
+ }]);
3714
+ if (!overwrite) {
3715
+ console.log(chalk18.yellow("\n\u23ED\uFE0F \uC0DD\uC131 \uCDE8\uC18C \u2014 \uAE30\uC874 \uD30C\uC77C \uC720\uC9C0."));
3716
+ return;
3717
+ }
3718
+ }
3719
+ mkdirSync2("src/styles", { recursive: true });
3720
+ writeFileSync3(targetPath, content, "utf-8");
3721
+ if (hasTailwind()) {
3722
+ console.log(chalk18.green("\n\u2705 src/styles/vhk-colors.ts \uC0DD\uC131"));
3723
+ console.log(chalk18.gray(" tailwind.config\uC758 extend.colors\uC5D0 import \uD574\uC11C \uC0AC\uC6A9\uD558\uC138\uC694."));
3724
+ } else {
3725
+ console.log(chalk18.green("\n\u2705 src/styles/tokens.css \uC0DD\uC131"));
3726
+ console.log(chalk18.gray(" HTML\uC5D0 <link>\uB85C \uCD94\uAC00\uD558\uAC70\uB098 CSS\uC5D0\uC11C @import \uD558\uC138\uC694."));
3727
+ }
3728
+ console.log(chalk18.bold("\n\u{1F308} \uCEEC\uB7EC \uBBF8\uB9AC\uBCF4\uAE30:"));
3729
+ for (const [key, value] of Object.entries(palette.colors)) {
3730
+ console.log(` ${key.padEnd(12)} ${value}`);
3731
+ }
3732
+ printNextStep({
3733
+ message: "\uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131 \uC644\uB8CC!",
3734
+ command: "vhk theme",
3735
+ cursorHint: "\uD14C\uB9C8 \uC124\uC815\uD574\uC918"
3736
+ });
3737
+ }
3738
+ async function designPalette() {
3739
+ await design();
3740
+ }
3741
+
3742
+ // src/commands/theme.ts
3743
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
3744
+ import chalk19 from "chalk";
3745
+ import inquirer10 from "inquirer";
3746
+ function generateDarkCSS() {
3747
+ return `/* vhk theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS \uBCC0\uC218 */
3748
+
3749
+ @media (prefers-color-scheme: dark) {
3750
+ :root {
3751
+ --color-background: #0f172a;
3752
+ --color-surface: #1e293b;
3753
+ --color-text: #f1f5f9;
3754
+ --color-muted: #64748b;
3755
+ }
3756
+ }
3757
+
3758
+ [data-theme="dark"] {
3759
+ --color-background: #0f172a;
3760
+ --color-surface: #1e293b;
3761
+ --color-text: #f1f5f9;
3762
+ --color-muted: #64748b;
3763
+ }
3764
+
3765
+ [data-theme="light"] {
3766
+ --color-background: #ffffff;
3767
+ --color-surface: #f9fafb;
3768
+ --color-text: #111827;
3769
+ --color-muted: #9ca3af;
3770
+ }
3771
+ `;
3772
+ }
3773
+ function generateToggleUtil() {
3774
+ return `// vhk theme \u2014 \uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC \uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0
3775
+
3776
+ export function getTheme(): 'light' | 'dark' {
3777
+ if (typeof window === 'undefined') return 'light'
3778
+ const stored = localStorage.getItem('vhk-theme') as 'light' | 'dark' | null
3779
+ if (stored === 'light' || stored === 'dark') return stored
3780
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
3781
+ }
3782
+
3783
+ export function setTheme(theme: 'light' | 'dark'): void {
3784
+ if (typeof document === 'undefined') return
3785
+ document.documentElement.setAttribute('data-theme', theme)
3786
+ localStorage.setItem('vhk-theme', theme)
3787
+ }
3788
+
3789
+ export function toggleTheme(): 'light' | 'dark' {
3790
+ const next = getTheme() === 'light' ? 'dark' : 'light'
3791
+ setTheme(next)
3792
+ return next
3793
+ }
3794
+
3795
+ export function initTheme(): void {
3796
+ setTheme(getTheme())
3797
+ }
3798
+ `;
3799
+ }
3800
+ async function theme() {
3801
+ console.log(chalk19.bold("\n\u{1F319} " + t("theme.title")));
3802
+ console.log(chalk19.gray("\u2500".repeat(40)));
3803
+ const cssPath = "src/styles/theme.css";
3804
+ const togglePath = "src/lib/theme-toggle.ts";
3805
+ const conflicts = [cssPath, togglePath].filter((p) => existsSync5(p));
3806
+ if (conflicts.length > 0) {
3807
+ const { overwrite } = await inquirer10.prompt([{
3808
+ type: "confirm",
3809
+ name: "overwrite",
3810
+ message: `\uB2E4\uC74C \uD30C\uC77C\uC774 \uC774\uBBF8 \uC788\uC5B4\uC694. \uB36E\uC5B4\uC4F8\uAE4C\uC694?
3811
+ ${conflicts.join("\n ")}`,
3812
+ default: false
3813
+ }]);
3814
+ if (!overwrite) {
3815
+ console.log(chalk19.yellow("\n\u23ED\uFE0F \uC0DD\uC131 \uCDE8\uC18C \u2014 \uAE30\uC874 \uD30C\uC77C \uC720\uC9C0."));
3816
+ return;
3817
+ }
3818
+ }
3819
+ mkdirSync3("src/styles", { recursive: true });
3820
+ mkdirSync3("src/lib", { recursive: true });
3821
+ writeFileSync4(cssPath, generateDarkCSS(), "utf-8");
3822
+ console.log(chalk19.green("\n\u2705 src/styles/theme.css \uC0DD\uC131 (\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC)"));
3823
+ writeFileSync4(togglePath, generateToggleUtil(), "utf-8");
3824
+ console.log(chalk19.green("\u2705 src/lib/theme-toggle.ts \uC0DD\uC131 (\uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0)"));
3825
+ console.log(chalk19.bold("\n\u{1F4D6} \uC0AC\uC6A9\uBC95:"));
3826
+ console.log(chalk19.gray(" 1. theme.css\uB97C \uAE00\uB85C\uBC8C \uC2A4\uD0C0\uC77C\uC5D0 \uCD94\uAC00"));
3827
+ console.log(chalk19.gray(' 2. import { initTheme, toggleTheme } from "./lib/theme-toggle"'));
3828
+ console.log(chalk19.gray(" 3. \uC571 \uC9C4\uC785\uC810\uC5D0\uC11C initTheme() \uD638\uCD9C"));
3829
+ console.log(chalk19.gray(" 4. \uD1A0\uAE00 \uBC84\uD2BC\uC5D0\uC11C toggleTheme() \uD638\uCD9C"));
3830
+ printNextStep({
3831
+ message: "\uD14C\uB9C8 \uC124\uC815 \uC644\uB8CC!",
3832
+ command: "vhk ref list",
3833
+ cursorHint: "\uB808\uD37C\uB7F0\uC2A4 \uD655\uC778\uD574\uC918"
3834
+ });
3835
+ }
3836
+
3837
+ // src/commands/ref.ts
3838
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync5 } from "fs";
3839
+ import chalk20 from "chalk";
3840
+ var REFS_PATH = ".vhk/refs.json";
3841
+ function loadRefs() {
3842
+ if (!existsSync6(REFS_PATH)) return [];
3843
+ try {
3844
+ const raw = readFileSync3(REFS_PATH, "utf-8");
3845
+ const parsed = JSON.parse(raw);
3846
+ return Array.isArray(parsed) ? parsed : [];
3847
+ } catch {
3848
+ return [];
3849
+ }
3850
+ }
3851
+ function saveRefs(refs) {
3852
+ mkdirSync4(".vhk", { recursive: true });
3853
+ writeFileSync5(REFS_PATH, JSON.stringify(refs, null, 2) + "\n", "utf-8");
3854
+ }
3855
+ async function refAdd(url, memo = "") {
3856
+ console.log(chalk20.bold("\n\u{1F517} " + t("ref.addTitle")));
3857
+ console.log(chalk20.gray("\u2500".repeat(40)));
3858
+ if (!url) {
3859
+ console.log(chalk20.red("\u274C URL\uC744 \uC785\uB825\uD574\uC8FC\uC138\uC694."));
3860
+ console.log(chalk20.gray(' \uC608: vhk ref add https://example.com --memo "\uCC38\uACE0 \uC0AC\uC774\uD2B8"'));
3861
+ return;
3862
+ }
3863
+ const refs = loadRefs();
3864
+ if (refs.some((r) => r.url === url)) {
3865
+ console.log(chalk20.yellow("\u26A0\uFE0F \uC774\uBBF8 \uC800\uC7A5\uB41C URL\uC785\uB2C8\uB2E4."));
3866
+ return;
3867
+ }
3868
+ refs.push({ url, memo, addedAt: (/* @__PURE__ */ new Date()).toISOString() });
3869
+ saveRefs(refs);
3870
+ console.log(chalk20.green(`
3871
+ \u2705 \uB808\uD37C\uB7F0\uC2A4 \uCD94\uAC00\uB428 (#${refs.length})`));
3872
+ console.log(chalk20.cyan(` ${url}`));
3873
+ if (memo) console.log(chalk20.gray(` \u{1F4DD} ${memo}`));
3874
+ printNextStep({
3875
+ message: "\uB808\uD37C\uB7F0\uC2A4 \uC800\uC7A5 \uC644\uB8CC!",
3876
+ command: "vhk ref list",
3877
+ cursorHint: "\uB808\uD37C\uB7F0\uC2A4 \uBAA9\uB85D \uBCF4\uC5EC\uC918"
3878
+ });
3879
+ }
3880
+ async function refList() {
3881
+ console.log(chalk20.bold("\n\u{1F4DA} " + t("ref.listTitle")));
3882
+ console.log(chalk20.gray("\u2500".repeat(40)));
3883
+ const refs = loadRefs();
3884
+ if (refs.length === 0) {
3885
+ console.log(chalk20.yellow("\n\u{1F4ED} \uC800\uC7A5\uB41C \uB808\uD37C\uB7F0\uC2A4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."));
3886
+ console.log(chalk20.gray(' vhk ref add <url> --memo "\uBA54\uBAA8"\uB85C \uCD94\uAC00\uD558\uC138\uC694.'));
3887
+ return;
3888
+ }
3889
+ console.log(chalk20.cyan(`
3890
+ \uCD1D ${refs.length}\uAC1C\uC758 \uB808\uD37C\uB7F0\uC2A4:
3891
+ `));
3892
+ refs.forEach((ref, index) => {
3893
+ const date = new Date(ref.addedAt).toLocaleDateString("ko-KR");
3894
+ console.log(chalk20.white(` [${index + 1}] ${ref.url}`));
3895
+ if (ref.memo) console.log(chalk20.gray(` \u{1F4DD} ${ref.memo}`));
3896
+ console.log(chalk20.gray(` \u{1F4C5} ${date}`));
3897
+ console.log("");
3898
+ });
3899
+ }
3900
+ async function refOpen(indexStr) {
3901
+ const refs = loadRefs();
3902
+ const idx = parseInt(indexStr, 10) - 1;
3903
+ if (Number.isNaN(idx) || idx < 0 || idx >= refs.length) {
3904
+ console.log(chalk20.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uBC88\uD638\uC785\uB2C8\uB2E4. (1~${refs.length || 0})`));
3905
+ return;
3906
+ }
3907
+ const ref = refs[idx];
3908
+ let parsed;
3909
+ try {
3910
+ parsed = new URL(ref.url);
3911
+ } catch {
3912
+ console.log(chalk20.red(`\u274C \uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 URL: ${ref.url}`));
3913
+ return;
3914
+ }
3915
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3916
+ console.log(chalk20.red(`\u274C http(s) URL\uB9CC \uC5F4 \uC218 \uC788\uC2B5\uB2C8\uB2E4 (${parsed.protocol})`));
3917
+ return;
3918
+ }
3919
+ console.log(chalk20.cyan(`
3920
+ \u{1F310} \uC5F4\uAE30: ${ref.url}`));
3921
+ let result;
3922
+ if (process.platform === "darwin") {
3923
+ result = safeExecFile("open", [ref.url]);
3924
+ } else if (process.platform === "win32") {
3925
+ result = safeExecFile("cmd.exe", ["/c", "start", "", ref.url]);
3926
+ } else {
3927
+ result = safeExecFile("xdg-open", [ref.url]);
3928
+ }
3929
+ if (result.ok) {
3930
+ console.log(chalk20.green("\u2705 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4."));
3931
+ } else {
3932
+ console.log(chalk20.yellow("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. URL\uC744 \uC9C1\uC811 \uBC29\uBB38\uD574\uC8FC\uC138\uC694."));
3933
+ }
3934
+ }
3935
+
3574
3936
  // src/lib/nlp-run.ts
3575
3937
  async function dispatchNlpRoute(route, input) {
3576
3938
  switch (route.command) {
@@ -3611,28 +3973,36 @@ async function dispatchNlpRoute(route, input) {
3611
3973
  return envCheck();
3612
3974
  case "publish":
3613
3975
  return publish();
3976
+ case "design":
3977
+ return design();
3978
+ case "design-palette":
3979
+ return designPalette();
3980
+ case "theme":
3981
+ return theme();
3982
+ case "ref":
3983
+ return refList();
3614
3984
  }
3615
3985
  }
3616
3986
  async function runNaturalLanguageRoute(input) {
3617
3987
  const route = routeNaturalLanguage(input);
3618
3988
  if (!route) {
3619
- console.log(chalk18.yellow(`
3989
+ console.log(chalk21.yellow(`
3620
3990
  \u2753 "${input}" \u2014 ${ko.nlp.notMatched}
3621
3991
  `));
3622
3992
  return;
3623
3993
  }
3624
3994
  console.log("");
3625
- console.log(chalk18.cyan(` \u{1F4AC} "${input}"`));
3626
- console.log(chalk18.cyan(` \u2192 ${route.explanation}`));
3995
+ console.log(chalk21.cyan(` \u{1F4AC} "${input}"`));
3996
+ console.log(chalk21.cyan(` \u2192 ${route.explanation}`));
3627
3997
  if (route.confidence === "low") {
3628
- const { confirm } = await inquirer9.prompt([{
3998
+ const { confirm } = await inquirer11.prompt([{
3629
3999
  type: "confirm",
3630
4000
  name: "confirm",
3631
4001
  message: `${route.explanation} \u2014 ${ko.nlp.matched}`,
3632
4002
  default: true
3633
4003
  }]);
3634
4004
  if (!confirm) {
3635
- console.log(chalk18.dim(` ${ko.nlp.menuHint}`));
4005
+ console.log(chalk21.dim(` ${ko.nlp.menuHint}`));
3636
4006
  return;
3637
4007
  }
3638
4008
  }
@@ -3641,6 +4011,20 @@ async function runNaturalLanguageRoute(input) {
3641
4011
  }
3642
4012
 
3643
4013
  // src/index.ts
4014
+ function getVersion() {
4015
+ const dir = path15.dirname(fileURLToPath3(import.meta.url));
4016
+ for (const pkgPath of [path15.join(dir, "../package.json"), path15.join(dir, "../../package.json")]) {
4017
+ try {
4018
+ if (fs16.existsSync(pkgPath)) {
4019
+ const pkg = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
4020
+ if (pkg.version) return pkg.version;
4021
+ }
4022
+ } catch {
4023
+ continue;
4024
+ }
4025
+ }
4026
+ return "0.0.0";
4027
+ }
3644
4028
  var program = new Command();
3645
4029
  var defaultHelp = new Help();
3646
4030
  var KO_ALIASES = {
@@ -3659,9 +4043,13 @@ var KO_ALIASES = {
3659
4043
  deploy: "\uBC30\uD3EC",
3660
4044
  env: "\uD658\uACBD\uBCC0\uC218",
3661
4045
  "env-check": "\uD658\uACBD\uBCC0\uC218\uC810\uAC80",
3662
- publish: "\uCD9C\uC2DC"
4046
+ publish: "\uCD9C\uC2DC",
4047
+ design: "\uB514\uC790\uC778",
4048
+ "design-palette": "\uD314\uB808\uD2B8",
4049
+ theme: "\uD14C\uB9C8",
4050
+ ref: "\uB808\uD37C\uB7F0\uC2A4"
3663
4051
  };
3664
- 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("0.7.1");
4052
+ 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());
3665
4053
  program.configureHelp({
3666
4054
  formatHelp(cmd, helper) {
3667
4055
  if (cmd.parent) {
@@ -3722,6 +4110,27 @@ program.command("env-check").alias("\uD658\uACBD\uBCC0\uC218\uC810\uAC80").descr
3722
4110
  program.command("publish").alias("\uCD9C\uC2DC").description("npm \uBC30\uD3EC (\uBC84\uC804 \uBC94\uD504 \u2192 \uBE4C\uB4DC \u2192 \uD14C\uC2A4\uD2B8 \u2192 publish)").action(async () => {
3723
4111
  await publish();
3724
4112
  });
4113
+ program.command("design").alias("\uB514\uC790\uC778").description("\uB514\uC790\uC778 \uD1A0\uD070 \uC0DD\uC131 (Tailwind config \uB610\uB294 CSS \uBCC0\uC218)").action(async () => {
4114
+ await design();
4115
+ });
4116
+ program.command("design-palette").alias("\uD314\uB808\uD2B8").description("\uCEEC\uB7EC \uD314\uB808\uD2B8 \uD504\uB9AC\uC14B \uC120\uD0DD + \uC801\uC6A9").action(async () => {
4117
+ await designPalette();
4118
+ });
4119
+ program.command("theme").alias("\uD14C\uB9C8").description("\uB2E4\uD06C/\uB77C\uC774\uD2B8 \uBAA8\uB4DC CSS + \uD1A0\uAE00 \uC720\uD2F8\uB9AC\uD2F0 \uC0DD\uC131").action(async () => {
4120
+ await theme();
4121
+ });
4122
+ var refCmd = program.command("ref").alias("\uB808\uD37C\uB7F0\uC2A4").description("\uB808\uD37C\uB7F0\uC2A4 URL \uAD00\uB9AC (add / list / open)").action(async () => {
4123
+ await refList();
4124
+ });
4125
+ refCmd.command("add <url>").option("--memo <memo>", "\uBA54\uBAA8 \uCD94\uAC00").description("\uB808\uD37C\uB7F0\uC2A4 URL \uCD94\uAC00").action(async (url, opts) => {
4126
+ await refAdd(url, opts.memo);
4127
+ });
4128
+ refCmd.command("list").alias("\uBAA9\uB85D").description("\uC800\uC7A5\uB41C \uB808\uD37C\uB7F0\uC2A4 \uBAA9\uB85D").action(async () => {
4129
+ await refList();
4130
+ });
4131
+ refCmd.command("open <index>").alias("\uC5F4\uAE30").description("\uB808\uD37C\uB7F0\uC2A4\uB97C \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC5F4\uAE30").action(async (index) => {
4132
+ await refOpen(index);
4133
+ });
3725
4134
  program.on("command:*", async (operands) => {
3726
4135
  const unknown = operands[0] ?? "";
3727
4136
  const rest = operands.slice(1);
@@ -3730,7 +4139,7 @@ program.on("command:*", async (operands) => {
3730
4139
  });
3731
4140
  program.action(async () => {
3732
4141
  console.log("\n\u{1F3AF} VHK \u2014 \uBC14\uC774\uBE0C\uCF54\uB529 \uD504\uB85C\uC81D\uD2B8 \uCF54\uCE58\n");
3733
- const { choice } = await inquirer10.prompt([{
4142
+ const { choice } = await inquirer12.prompt([{
3734
4143
  type: "list",
3735
4144
  name: "choice",
3736
4145
  message: "\uBB58 \uB3C4\uC640\uB4DC\uB9B4\uAE4C\uC694?",
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-3HHU7V77.js";
4
+ } from "../chunk-X3CIIDO2.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.7.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": "0.8.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
+ }