@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 +35 -2
- package/dist/{chunk-3HHU7V77.js โ chunk-X3CIIDO2.js} +21 -2
- package/dist/index.js +454 -45
- package/dist/mcp/index.js +1 -1
- package/package.json +65 -65
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.
|
|
4
|
+
tags: [vhk, cli, readme, v0.8.0]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# ๐ง VHK โ Vibe Harness Kit
|
|
8
8
|
|
|
9
|
-
> AI ์ฝ๋ฉ ์์ด์ ํธ๋ฅผ ๋ถ๋ฆฌ๋ ์ฌ๋์ ์ํ **ํ๊ตญ์ด ํ์ฌ์ดํด CLI** (v0.
|
|
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(
|
|
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(
|
|
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-
|
|
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(
|
|
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(
|
|
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 = (
|
|
344
|
-
if (!isString(
|
|
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 (!
|
|
350
|
+
if (!path16) {
|
|
351
351
|
return doThrow(`path must not be empty`, TypeError);
|
|
352
352
|
}
|
|
353
|
-
if (checkPath.isNotRelative(
|
|
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 = (
|
|
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
|
|
392
|
+
const path16 = originalPath && checkPath.convert(originalPath);
|
|
393
393
|
checkPath(
|
|
394
|
-
|
|
394
|
+
path16,
|
|
395
395
|
originalPath,
|
|
396
396
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
397
397
|
);
|
|
398
|
-
return this._t(
|
|
398
|
+
return this._t(path16, cache, checkUnignored, slices);
|
|
399
399
|
}
|
|
400
|
-
checkIgnore(
|
|
401
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
402
|
-
return this.test(
|
|
400
|
+
checkIgnore(path16) {
|
|
401
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
|
|
402
|
+
return this.test(path16);
|
|
403
403
|
}
|
|
404
|
-
const slices =
|
|
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(
|
|
417
|
+
return this._rules.test(path16, false, MODE_CHECK_IGNORE);
|
|
418
418
|
}
|
|
419
|
-
_t(
|
|
420
|
-
if (
|
|
421
|
-
return cache[
|
|
419
|
+
_t(path16, cache, checkUnignored, slices) {
|
|
420
|
+
if (path16 in cache) {
|
|
421
|
+
return cache[path16];
|
|
422
422
|
}
|
|
423
423
|
if (!slices) {
|
|
424
|
-
slices =
|
|
424
|
+
slices = path16.split(SLASH).filter(Boolean);
|
|
425
425
|
}
|
|
426
426
|
slices.pop();
|
|
427
427
|
if (!slices.length) {
|
|
428
|
-
return cache[
|
|
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[
|
|
436
|
+
return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
|
|
437
437
|
}
|
|
438
|
-
ignores(
|
|
439
|
-
return this._test(
|
|
438
|
+
ignores(path16) {
|
|
439
|
+
return this._test(path16, this._ignoreCache, false).ignored;
|
|
440
440
|
}
|
|
441
441
|
createFilter() {
|
|
442
|
-
return (
|
|
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(
|
|
449
|
-
return this._test(
|
|
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 = (
|
|
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 = (
|
|
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
|
|
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
|
|
701
|
-
import
|
|
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
|
-
|
|
3539
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
3626
|
-
console.log(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
package/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@byh3071/vhk",
|
|
3
|
-
"version": "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
|
-
}
|
|
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
|
+
}
|