@byh3071/vhk 2.3.1 → 2.3.2
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/dist/{chunk-WQWPM364.js → chunk-OHGVVAKT.js} +87 -20
- package/dist/index.js +38 -37
- package/dist/mcp/index.js +1 -1
- package/package.json +72 -72
|
@@ -762,7 +762,12 @@ var ko = {
|
|
|
762
762
|
skipped: (p) => `\u23ED\uFE0F \uAC74\uB108\uB700: ${p} (\uB36E\uC5B4\uC4F0\uAE30 \uAC70\uBD80 \u2014 \uBC31\uC5C5\uB9CC \uBCF4\uAD00)`,
|
|
763
763
|
dryRunHeader: "\u{1F50E} \uBBF8\uB9AC\uBCF4\uAE30 (--dry-run) \u2014 \uC2E4\uC81C \uD30C\uC77C \uBCC0\uACBD \uC5C6\uC74C",
|
|
764
764
|
dryRunWouldWrite: (p, drift) => ` ${drift ? "\u270F\uFE0F \uBCC0\uACBD\uB428" : "\xB7 \uB3D9\uC77C"} : ${p}`,
|
|
765
|
-
nonTtyAuto: (n, id) => `\u{1F916} \uBE44\uB300\uD654\uD615(CI/\uC5D0\uC774\uC804\uD2B8) \u2014 ${n}\uAC1C \uBC31\uC5C5 \uD6C4 \uC9C4\uD589. \uBCF5\uC6D0: vhk restore ${id}
|
|
765
|
+
nonTtyAuto: (n, id) => `\u{1F916} \uBE44\uB300\uD654\uD615(CI/\uC5D0\uC774\uC804\uD2B8) \u2014 ${n}\uAC1C \uBC31\uC5C5 \uD6C4 \uC9C4\uD589. \uBCF5\uC6D0: vhk restore ${id}`,
|
|
766
|
+
// 배치1 — CLAUDE.md 를 vhk 마커(<!-- vhk:rules:start/end -->) 형식으로 1회 정리할 때의 안내.
|
|
767
|
+
// 사용자 섹션은 보존, RULES.md 기준 옛 자동생성 섹션만 재생성 교체(조용한 드롭 방지).
|
|
768
|
+
claudeMigrated: (preserved, removed) => `\u2139\uFE0F CLAUDE.md \uB97C vhk \uB9C8\uCEE4 \uD615\uC2DD\uC73C\uB85C \uC815\uB9AC\uD588\uC5B4\uC694 \u2014 \uB9C8\uCEE4 \uBC16 \uC0AC\uC6A9\uC790 \uC139\uC158\uC740 \uBCF4\uC874\uB429\uB2C8\uB2E4.` + (preserved.length ? `
|
|
769
|
+
\uBCF4\uC874\uB41C \uC0AC\uC6A9\uC790 \uC139\uC158 ${preserved.length}\uAC1C: ${preserved.join(", ")}` : "") + (removed.length ? `
|
|
770
|
+
RULES.md \uAE30\uC900\uC73C\uB85C \uC7AC\uC0DD\uC131\xB7\uAD50\uCCB4\uB41C \uC61B \uC790\uB3D9\uC0DD\uC131 \uC139\uC158 ${removed.length}\uAC1C: ${removed.join(", ")} (\uD544\uC694 \uC2DC .vhk/backups \uC5D0\uC11C \uBCF5\uAD6C)` : "")
|
|
766
771
|
},
|
|
767
772
|
restore: {
|
|
768
773
|
title: "\u{1F6DF} \uBC31\uC5C5 \uBCF5\uC6D0",
|
|
@@ -1378,29 +1383,80 @@ function toAntigravityRules(sections, projectName) {
|
|
|
1378
1383
|
return truncateForAntigravity(buildCodingDoc("Antigravity Rules", sections, projectName));
|
|
1379
1384
|
}
|
|
1380
1385
|
var CLAUDE_AUTOGEN_BANNER = "> \u26A1 \uC544\uB798 \uADDC\uCE59 \uC139\uC158\uC740 RULES.md\uC5D0\uC11C \uC790\uB3D9 \uC0DD\uC131\uB428 (vhk sync). \uC9C1\uC811 \uC218\uC815 \uAE08\uC9C0.";
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
const cleaned = existing.split("\n").filter((line) => line.trim() !== CLAUDE_AUTOGEN_BANNER).join("\n");
|
|
1386
|
-
const statusMatch = cleaned.match(/## 현재 상태[\s\S]*?(?=\n## |$)/);
|
|
1387
|
-
const statusSection = statusMatch ? statusMatch[0].trimEnd() : "";
|
|
1388
|
-
const header = cleaned.split("## ")[0].trim();
|
|
1389
|
-
const lines = [
|
|
1390
|
-
header,
|
|
1391
|
-
"",
|
|
1392
|
-
statusSection,
|
|
1393
|
-
"",
|
|
1394
|
-
CLAUDE_AUTOGEN_BANNER,
|
|
1395
|
-
""
|
|
1396
|
-
];
|
|
1386
|
+
var VHK_BLOCK_START = "<!-- vhk:rules:start -->";
|
|
1387
|
+
var VHK_BLOCK_END = "<!-- vhk:rules:end -->";
|
|
1388
|
+
function buildVhkBlock(recordSections) {
|
|
1389
|
+
const lines = [VHK_BLOCK_START, CLAUDE_AUTOGEN_BANNER, ""];
|
|
1397
1390
|
for (const section of recordSections) {
|
|
1398
1391
|
lines.push(`## ${section.title}`);
|
|
1399
1392
|
lines.push(section.content);
|
|
1400
1393
|
lines.push("");
|
|
1401
1394
|
}
|
|
1395
|
+
lines.push(VHK_BLOCK_END);
|
|
1402
1396
|
return lines.join("\n");
|
|
1403
1397
|
}
|
|
1398
|
+
function splitVhkBlock(existing) {
|
|
1399
|
+
const start = existing.indexOf(VHK_BLOCK_START);
|
|
1400
|
+
const end = existing.indexOf(VHK_BLOCK_END);
|
|
1401
|
+
if (start === -1 || end === -1 || end < start) return null;
|
|
1402
|
+
return {
|
|
1403
|
+
before: existing.slice(0, start),
|
|
1404
|
+
after: existing.slice(end + VHK_BLOCK_END.length)
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
function stripLegacyAutogen(existing) {
|
|
1408
|
+
const lines = existing.split("\n").filter((line) => {
|
|
1409
|
+
const t2 = line.trim();
|
|
1410
|
+
return t2 !== CLAUDE_AUTOGEN_BANNER && t2 !== VHK_BLOCK_START && t2 !== VHK_BLOCK_END;
|
|
1411
|
+
});
|
|
1412
|
+
const headerLines = [];
|
|
1413
|
+
const blocks = [];
|
|
1414
|
+
let cur = null;
|
|
1415
|
+
for (const line of lines) {
|
|
1416
|
+
if (line.startsWith("## ")) {
|
|
1417
|
+
if (cur) blocks.push(cur);
|
|
1418
|
+
cur = { title: line.slice(3).trim(), body: [line] };
|
|
1419
|
+
} else if (cur) {
|
|
1420
|
+
cur.body.push(line);
|
|
1421
|
+
} else {
|
|
1422
|
+
headerLines.push(line);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
if (cur) blocks.push(cur);
|
|
1426
|
+
const removed = [];
|
|
1427
|
+
const preserved = [];
|
|
1428
|
+
const keptBodies = [];
|
|
1429
|
+
for (const b of blocks) {
|
|
1430
|
+
if (CLAUDE_MD_KEYS.some((k) => b.title.includes(k))) {
|
|
1431
|
+
removed.push(b.title);
|
|
1432
|
+
} else {
|
|
1433
|
+
preserved.push(b.title);
|
|
1434
|
+
keptBodies.push(b.body.join("\n").trimEnd());
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const header = headerLines.join("\n").trim();
|
|
1438
|
+
const cleaned = [header, ...keptBodies].filter(Boolean).join("\n\n");
|
|
1439
|
+
return { cleaned, removed, preserved };
|
|
1440
|
+
}
|
|
1441
|
+
function claudeMdMigration(existing) {
|
|
1442
|
+
if (splitVhkBlock(existing)) return { migrated: false, removed: [], preserved: [] };
|
|
1443
|
+
const { removed, preserved } = stripLegacyAutogen(existing);
|
|
1444
|
+
return { migrated: true, removed, preserved };
|
|
1445
|
+
}
|
|
1446
|
+
function toClaudeMd(sections, existing) {
|
|
1447
|
+
const recordSections = sections.filter(
|
|
1448
|
+
(s) => CLAUDE_MD_KEYS.some((k) => s.title.includes(k))
|
|
1449
|
+
);
|
|
1450
|
+
const vhkBlock = buildVhkBlock(recordSections);
|
|
1451
|
+
const split = splitVhkBlock(existing);
|
|
1452
|
+
if (split) {
|
|
1453
|
+
const before = split.before.replace(/\s+$/, "");
|
|
1454
|
+
const after = split.after.replace(/^\s+/, "").replace(/\s+$/, "");
|
|
1455
|
+
return [before, vhkBlock, after].filter((s) => s.length > 0).join("\n\n") + "\n";
|
|
1456
|
+
}
|
|
1457
|
+
const { cleaned } = stripLegacyAutogen(existing);
|
|
1458
|
+
return [cleaned, vhkBlock].filter((s) => s.length > 0).join("\n\n") + "\n";
|
|
1459
|
+
}
|
|
1404
1460
|
function toAgentsMd(sections, projectName) {
|
|
1405
1461
|
const codingSections = sections.filter((s) => CURSORRULES_KEYS.some((k) => s.title.includes(k)));
|
|
1406
1462
|
const recordSections = sections.filter((s) => CLAUDE_MD_KEYS.some((k) => s.title.includes(k)));
|
|
@@ -1472,7 +1528,9 @@ function buildSyncPlan(rootDir, sections, projectName) {
|
|
|
1472
1528
|
newContent: claudeNew,
|
|
1473
1529
|
doneMessage: ko.sync.claudeDone,
|
|
1474
1530
|
exists: claudeExists,
|
|
1475
|
-
drift: claudeDrift
|
|
1531
|
+
drift: claudeDrift,
|
|
1532
|
+
// 기존 CLAUDE.md 가 있을 때만 마이그레이션 집계(첫 생성은 마이그레이션 아님). 추가 I/O 0 — 이미 읽은 existingClaude 재사용.
|
|
1533
|
+
migration: claudeExists ? claudeMdMigration(existingClaude) : void 0
|
|
1476
1534
|
});
|
|
1477
1535
|
return plan;
|
|
1478
1536
|
}
|
|
@@ -1483,6 +1541,7 @@ async function syncCore(rootDir, opts, confirmOverwrite) {
|
|
|
1483
1541
|
const plan = buildSyncPlan(rootDir, sections, projectName);
|
|
1484
1542
|
const firstSync = !fs4.existsSync(path4.join(rootDir, SYNCED_MARKER_REL));
|
|
1485
1543
|
const unmapped = findUnmappedSections(sections);
|
|
1544
|
+
const claudeMigration = plan.find((p) => p.path === "CLAUDE.md")?.migration;
|
|
1486
1545
|
if (opts.dryRun) {
|
|
1487
1546
|
return {
|
|
1488
1547
|
dryRun: true,
|
|
@@ -1493,7 +1552,8 @@ async function syncCore(rootDir, opts, confirmOverwrite) {
|
|
|
1493
1552
|
skipped: [],
|
|
1494
1553
|
truncated: [],
|
|
1495
1554
|
plan,
|
|
1496
|
-
unmapped
|
|
1555
|
+
unmapped,
|
|
1556
|
+
claudeMigration
|
|
1497
1557
|
};
|
|
1498
1558
|
}
|
|
1499
1559
|
const toBackup = plan.filter((p) => p.exists && (p.drift || firstSync)).map((p) => p.path);
|
|
@@ -1526,7 +1586,7 @@ async function syncCore(rootDir, opts, confirmOverwrite) {
|
|
|
1526
1586
|
fs4.mkdirSync(path4.join(rootDir, ".vhk"), { recursive: true });
|
|
1527
1587
|
fs4.writeFileSync(path4.join(rootDir, SYNCED_MARKER_REL), (/* @__PURE__ */ new Date()).toISOString() + "\n", "utf-8");
|
|
1528
1588
|
ensureVhkIgnored(rootDir, ".synced");
|
|
1529
|
-
return { dryRun: false, firstSync, backupId, backedUp, written, skipped, truncated, plan, unmapped };
|
|
1589
|
+
return { dryRun: false, firstSync, backupId, backedUp, written, skipped, truncated, plan, unmapped, claudeMigration };
|
|
1530
1590
|
}
|
|
1531
1591
|
async function sync(opts = {}) {
|
|
1532
1592
|
console.log(chalk3.bold(`
|
|
@@ -1575,6 +1635,13 @@ ${ko.sync.title}
|
|
|
1575
1635
|
)
|
|
1576
1636
|
);
|
|
1577
1637
|
}
|
|
1638
|
+
if (result.claudeMigration?.migrated) {
|
|
1639
|
+
console.log(
|
|
1640
|
+
chalk3.cyan(
|
|
1641
|
+
` ${ko.sync.claudeMigrated(result.claudeMigration.preserved, result.claudeMigration.removed)}`
|
|
1642
|
+
)
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1578
1645
|
if (result.dryRun) {
|
|
1579
1646
|
console.log(chalk3.cyan(`
|
|
1580
1647
|
${ko.sync.dryRunHeader}`));
|
package/dist/index.js
CHANGED
|
@@ -43,7 +43,7 @@ import {
|
|
|
43
43
|
stripBom,
|
|
44
44
|
sync,
|
|
45
45
|
t
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-OHGVVAKT.js";
|
|
47
47
|
|
|
48
48
|
// src/index.ts
|
|
49
49
|
import { Command, Help } from "commander";
|
|
@@ -516,6 +516,10 @@ var KNOWN_COMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
516
516
|
"\uAC80\uD1A0",
|
|
517
517
|
"mission",
|
|
518
518
|
"\uBBF8\uC158",
|
|
519
|
+
"pattern",
|
|
520
|
+
"\uD328\uD134",
|
|
521
|
+
"evolve",
|
|
522
|
+
"\uC9C4\uD654",
|
|
519
523
|
"help"
|
|
520
524
|
]);
|
|
521
525
|
function isOptionToken(token) {
|
|
@@ -6592,41 +6596,19 @@ function detectCandidates(mem, minFreq) {
|
|
|
6592
6596
|
processBucket(mem.successes, "reinforce", (e) => e.content ?? "");
|
|
6593
6597
|
return candidates.sort((a, b) => b.count - a.count || a.signal.localeCompare(b.signal));
|
|
6594
6598
|
}
|
|
6595
|
-
function
|
|
6596
|
-
|
|
6597
|
-
let
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
return `p${max + 1}`;
|
|
6603
|
-
}
|
|
6604
|
-
async function patternDetect(opts = {}) {
|
|
6605
|
-
const minFreq = opts.min !== void 0 ? parseInt(opts.min, 10) : MIN_TAG_FREQ;
|
|
6606
|
-
if (!Number.isFinite(minFreq) || minFreq < 1) {
|
|
6607
|
-
console.log(chalk33.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
|
|
6608
|
-
process.exitCode = 1;
|
|
6609
|
-
return;
|
|
6610
|
-
}
|
|
6611
|
-
const cwd = process.cwd();
|
|
6612
|
-
const loaded = loadForMutation(cwd);
|
|
6613
|
-
if (!loaded.ok) {
|
|
6614
|
-
console.log(chalk33.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAC10\uC9C0 \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874). \uBC31\uC5C5 \uD655\uC778 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694."));
|
|
6615
|
-
process.exitCode = 1;
|
|
6616
|
-
return;
|
|
6599
|
+
function reconcilePatterns(patterns, candidates, now) {
|
|
6600
|
+
let added = 0;
|
|
6601
|
+
let updated = 0;
|
|
6602
|
+
let maxId = 0;
|
|
6603
|
+
for (const p of patterns) {
|
|
6604
|
+
const m = p.id.match(/^p(\d+)$/);
|
|
6605
|
+
if (m) maxId = Math.max(maxId, Number(m[1]));
|
|
6617
6606
|
}
|
|
6618
|
-
const mem = loaded.mem;
|
|
6619
|
-
const candidates = detectCandidates(mem, minFreq);
|
|
6620
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6621
|
-
let added = 0, updated = 0;
|
|
6622
6607
|
for (const c of candidates) {
|
|
6623
6608
|
const sig = sigOf(c.kind, c.axis, c.signal);
|
|
6624
|
-
const
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
const fieldMatch = pp.kind === c.kind && pp.axis === c.axis && pp.signal === c.signal;
|
|
6628
|
-
return (sigMatch || fieldMatch) && pp.status !== "archived";
|
|
6629
|
-
});
|
|
6609
|
+
const matches = (pp) => pp._sig === sig || pp.kind === c.kind && pp.axis === c.axis && pp.signal === c.signal;
|
|
6610
|
+
if (patterns.some((p) => matches(p) && p.status === "archived")) continue;
|
|
6611
|
+
const existing = patterns.find((p) => matches(p) && p.status !== "archived");
|
|
6630
6612
|
if (existing) {
|
|
6631
6613
|
existing._sig = sig;
|
|
6632
6614
|
existing.count = c.count;
|
|
@@ -6635,8 +6617,8 @@ async function patternDetect(opts = {}) {
|
|
|
6635
6617
|
existing.tags = c.sourceTags;
|
|
6636
6618
|
updated++;
|
|
6637
6619
|
} else {
|
|
6638
|
-
|
|
6639
|
-
id:
|
|
6620
|
+
patterns.push({
|
|
6621
|
+
id: `p${++maxId}`,
|
|
6640
6622
|
kind: c.kind,
|
|
6641
6623
|
axis: c.axis,
|
|
6642
6624
|
signal: c.signal,
|
|
@@ -6647,11 +6629,30 @@ async function patternDetect(opts = {}) {
|
|
|
6647
6629
|
status: "active",
|
|
6648
6630
|
tags: c.sourceTags,
|
|
6649
6631
|
_sig: sig
|
|
6650
|
-
};
|
|
6651
|
-
mem.patterns.push(entry);
|
|
6632
|
+
});
|
|
6652
6633
|
added++;
|
|
6653
6634
|
}
|
|
6654
6635
|
}
|
|
6636
|
+
return { added, updated };
|
|
6637
|
+
}
|
|
6638
|
+
async function patternDetect(opts = {}) {
|
|
6639
|
+
const minFreq = opts.min !== void 0 ? parseInt(opts.min, 10) : MIN_TAG_FREQ;
|
|
6640
|
+
if (!Number.isFinite(minFreq) || minFreq < 1) {
|
|
6641
|
+
console.log(chalk33.red("\u274C --min \uC740 1 \uC774\uC0C1\uC758 \uC815\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4."));
|
|
6642
|
+
process.exitCode = 1;
|
|
6643
|
+
return;
|
|
6644
|
+
}
|
|
6645
|
+
const cwd = process.cwd();
|
|
6646
|
+
const loaded = loadForMutation(cwd);
|
|
6647
|
+
if (!loaded.ok) {
|
|
6648
|
+
console.log(chalk33.red("\u274C memory.json \uC190\uC0C1 \uC758\uC2EC \u2014 \uAC10\uC9C0 \uC911\uB2E8 (\uC6D0\uBCF8 \uBCF4\uC874). \uBC31\uC5C5 \uD655\uC778 \uD6C4 \uC7AC\uC2DC\uB3C4\uD558\uC138\uC694."));
|
|
6649
|
+
process.exitCode = 1;
|
|
6650
|
+
return;
|
|
6651
|
+
}
|
|
6652
|
+
const mem = loaded.mem;
|
|
6653
|
+
const candidates = detectCandidates(mem, minFreq);
|
|
6654
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6655
|
+
const { added, updated } = reconcilePatterns(mem.patterns, candidates, now);
|
|
6655
6656
|
if (added > 0 || updated > 0) {
|
|
6656
6657
|
writeMemory(cwd, mem);
|
|
6657
6658
|
}
|
package/dist/mcp/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@byh3071/vhk",
|
|
3
|
-
"version": "2.3.
|
|
4
|
-
"description": "Vibe Harness Kit — AI 코딩 도구·기기를 바꿔도 규칙·맥락이 따라가는 포터빌리티 CLI (sync: Cursor·Claude·Windsurf·Copilot·Antigravity / cloud 백업)",
|
|
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
|
-
"portability",
|
|
36
|
-
"ai-coding",
|
|
37
|
-
"cursor",
|
|
38
|
-
"claude",
|
|
39
|
-
"windsurf",
|
|
40
|
-
"copilot",
|
|
41
|
-
"context-sync"
|
|
42
|
-
],
|
|
43
|
-
"author": "byh3071 <byh3071@gmail.com>",
|
|
44
|
-
"license": "MIT",
|
|
45
|
-
"repository": {
|
|
46
|
-
"type": "git",
|
|
47
|
-
"url": "git+https://github.com/byh3071-cpu/vhk.git"
|
|
48
|
-
},
|
|
49
|
-
"engines": {
|
|
50
|
-
"node": ">=20"
|
|
51
|
-
},
|
|
52
|
-
"dependencies": {
|
|
53
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
54
|
-
"@notionhq/client": "^5.22.0",
|
|
55
|
-
"chalk": "^5.6.2",
|
|
56
|
-
"commander": "^14.0.3",
|
|
57
|
-
"handlebars": "^4.7.9",
|
|
58
|
-
"inquirer": "^9.3.8",
|
|
59
|
-
"ora": "^9.4.0",
|
|
60
|
-
"simple-git": "^3.36.0",
|
|
61
|
-
"zod": "^4.4.3"
|
|
62
|
-
},
|
|
63
|
-
"devDependencies": {
|
|
64
|
-
"@types/inquirer": "^9.0.9",
|
|
65
|
-
"@types/node": "^25.9.1",
|
|
66
|
-
"ignore": "^7.0.5",
|
|
67
|
-
"tsup": "^8.5.1",
|
|
68
|
-
"tsx": "^4.22.3",
|
|
69
|
-
"typescript": "^6.0.3",
|
|
70
|
-
"vitest": "^4.1.7"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@byh3071/vhk",
|
|
3
|
+
"version": "2.3.2",
|
|
4
|
+
"description": "Vibe Harness Kit — AI 코딩 도구·기기를 바꿔도 규칙·맥락이 따라가는 포터빌리티 CLI (sync: Cursor·Claude·Windsurf·Copilot·Antigravity / cloud 백업)",
|
|
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
|
+
"portability",
|
|
36
|
+
"ai-coding",
|
|
37
|
+
"cursor",
|
|
38
|
+
"claude",
|
|
39
|
+
"windsurf",
|
|
40
|
+
"copilot",
|
|
41
|
+
"context-sync"
|
|
42
|
+
],
|
|
43
|
+
"author": "byh3071 <byh3071@gmail.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/byh3071-cpu/vhk.git"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
54
|
+
"@notionhq/client": "^5.22.0",
|
|
55
|
+
"chalk": "^5.6.2",
|
|
56
|
+
"commander": "^14.0.3",
|
|
57
|
+
"handlebars": "^4.7.9",
|
|
58
|
+
"inquirer": "^9.3.8",
|
|
59
|
+
"ora": "^9.4.0",
|
|
60
|
+
"simple-git": "^3.36.0",
|
|
61
|
+
"zod": "^4.4.3"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/inquirer": "^9.0.9",
|
|
65
|
+
"@types/node": "^25.9.1",
|
|
66
|
+
"ignore": "^7.0.5",
|
|
67
|
+
"tsup": "^8.5.1",
|
|
68
|
+
"tsx": "^4.22.3",
|
|
69
|
+
"typescript": "^6.0.3",
|
|
70
|
+
"vitest": "^4.1.7"
|
|
71
|
+
}
|
|
72
|
+
}
|