@byh3071/vhk 1.6.3 → 1.6.4
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-53RJHPP6.js → chunk-EJTVXWUZ.js} +1 -0
- package/dist/index.js +105 -75
- package/dist/mcp/index.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -35,9 +35,10 @@ import {
|
|
|
35
35
|
safeExecFile,
|
|
36
36
|
scanProjectForSecrets,
|
|
37
37
|
startMcpServer,
|
|
38
|
+
stripBom,
|
|
38
39
|
sync,
|
|
39
40
|
t
|
|
40
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-EJTVXWUZ.js";
|
|
41
42
|
|
|
42
43
|
// src/index.ts
|
|
43
44
|
import { Command, Help } from "commander";
|
|
@@ -504,7 +505,37 @@ import inquirer12 from "inquirer";
|
|
|
504
505
|
|
|
505
506
|
// src/commands/gate.ts
|
|
506
507
|
import inquirer from "inquirer";
|
|
508
|
+
import chalk2 from "chalk";
|
|
509
|
+
|
|
510
|
+
// src/lib/interactive.ts
|
|
507
511
|
import chalk from "chalk";
|
|
512
|
+
function isInteractive(opts) {
|
|
513
|
+
if (opts?.yes) return false;
|
|
514
|
+
if (process.env.VHK_FORCE_INTERACTIVE === "1") return true;
|
|
515
|
+
return !!process.stdin.isTTY;
|
|
516
|
+
}
|
|
517
|
+
async function promptOrDefault(ask, fallback, opts) {
|
|
518
|
+
if (!isInteractive(opts)) return fallback;
|
|
519
|
+
try {
|
|
520
|
+
return await ask();
|
|
521
|
+
} catch (err) {
|
|
522
|
+
if (isPromptAbortError(err)) return fallback;
|
|
523
|
+
throw err;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
function ensureInteractive(hint = "") {
|
|
527
|
+
if (isInteractive()) return true;
|
|
528
|
+
console.error(chalk.yellow(" \u26A0\uFE0F \uC774 \uBA85\uB839\uC740 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uBE44-TTY/\uD30C\uC774\uD504 \uD658\uACBD\uC5D0\uC11C\uB294 \uC2E4\uD589\uD560 \uC218 \uC5C6\uC5B4\uC694."));
|
|
529
|
+
if (hint) console.error(chalk.dim(` ${hint}`));
|
|
530
|
+
process.exitCode = 1;
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
function isPromptAbortError(err) {
|
|
534
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
535
|
+
return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/commands/gate.ts
|
|
508
539
|
var GATE_QUESTIONS = [
|
|
509
540
|
{ id: 1, stage: "\uBB38\uC81C \uC815\uC758", question: "\uC774 \uC544\uC774\uB514\uC5B4\uAC00 \uD574\uACB0\uD558\uB294 \uBB38\uC81C\uB97C \uD55C \uBB38\uC7A5\uC73C\uB85C \uB9D0\uD574\uBCF4\uC138\uC694.", failIf: "\uD55C \uBB38\uC7A5 \uBD88\uAC00 \u2192 \uBBF8\uC131\uC219", quick: true },
|
|
510
541
|
{ id: 2, stage: "\uD575\uC2EC \uAE30\uB2A5", question: "\uB531 1\uAC1C \uAE30\uB2A5\uB9CC \uACE0\uB974\uBA74?", failIf: "2\uAC1C \uC774\uC0C1 \u2192 \uBC94\uC704 \uCD08\uACFC", quick: true },
|
|
@@ -526,7 +557,8 @@ function judgeGate(failCount, holdCount) {
|
|
|
526
557
|
return "DROP";
|
|
527
558
|
}
|
|
528
559
|
async function gate() {
|
|
529
|
-
|
|
560
|
+
if (!ensureInteractive("\uC544\uC774\uB514\uC5B4 \uAC80\uC99D\uC740 \uB300\uD654\uD615 \uC9C8\uBB38\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. \uD130\uBBF8\uB110(PowerShell \uB4F1)\uC5D0\uC11C \uC9C1\uC811 \uC2E4\uD589\uD558\uC138\uC694. Git Bash \uBA74 VHK_FORCE_INTERACTIVE=1.")) return;
|
|
561
|
+
console.log(chalk2.bold(`
|
|
530
562
|
${ko.gate.title}
|
|
531
563
|
`));
|
|
532
564
|
const { mode: mode2 } = await inquirer.prompt([{
|
|
@@ -545,33 +577,33 @@ ${ko.gate.title}
|
|
|
545
577
|
name: "source",
|
|
546
578
|
message: ko.gate.skipSourcePrompt
|
|
547
579
|
}]);
|
|
548
|
-
console.log(
|
|
580
|
+
console.log(chalk2.green.bold(`
|
|
549
581
|
${ko.gate.skipGo}`));
|
|
550
|
-
console.log(
|
|
582
|
+
console.log(chalk2.dim(ko.gate.skipSourceLabel(source)));
|
|
551
583
|
return;
|
|
552
584
|
}
|
|
553
585
|
const questions = mode2 === "quick" ? GATE_QUESTIONS.filter((q) => q.quick) : GATE_QUESTIONS;
|
|
554
586
|
const total = questions.length;
|
|
555
587
|
const header = mode2 === "quick" ? ko.gate.quickHeader : ko.gate.fullHeader;
|
|
556
|
-
console.log(
|
|
588
|
+
console.log(chalk2.dim(`
|
|
557
589
|
${header} ${ko.gate.modeCountSuffix(total)}
|
|
558
590
|
`));
|
|
559
|
-
console.log(
|
|
591
|
+
console.log(chalk2.dim(`
|
|
560
592
|
${ko.gate.welcome}
|
|
561
593
|
`));
|
|
562
|
-
console.log(
|
|
594
|
+
console.log(chalk2.dim(` ${ko.gate.ideaHint}`));
|
|
563
595
|
const { idea } = await inquirer.prompt([
|
|
564
596
|
{ type: "input", name: "idea", message: ko.gate.idea }
|
|
565
597
|
]);
|
|
566
|
-
console.log(
|
|
598
|
+
console.log(chalk2.dim(` ${ko.gate.painPointHint}`));
|
|
567
599
|
const { painPoint } = await inquirer.prompt([
|
|
568
600
|
{ type: "input", name: "painPoint", message: ko.gate.painPoint }
|
|
569
601
|
]);
|
|
570
|
-
console.log(
|
|
602
|
+
console.log(chalk2.dim(` ${ko.gate.edgeHint}`));
|
|
571
603
|
const { edge } = await inquirer.prompt([
|
|
572
604
|
{ type: "input", name: "edge", message: ko.gate.edge }
|
|
573
605
|
]);
|
|
574
|
-
console.log(
|
|
606
|
+
console.log(chalk2.dim(`
|
|
575
607
|
${ko.gate.checklistStart}
|
|
576
608
|
`));
|
|
577
609
|
let failCount = 0;
|
|
@@ -579,7 +611,7 @@ ${ko.gate.checklistStart}
|
|
|
579
611
|
const results = [];
|
|
580
612
|
for (let i = 0; i < questions.length; i++) {
|
|
581
613
|
const q = questions[i];
|
|
582
|
-
if (q.hint) console.log(
|
|
614
|
+
if (q.hint) console.log(chalk2.dim(`${ko.gate.hintPrefix} ${q.hint}`));
|
|
583
615
|
const { answer } = await inquirer.prompt([{
|
|
584
616
|
type: "input",
|
|
585
617
|
name: "answer",
|
|
@@ -598,22 +630,22 @@ ${ko.gate.checklistStart}
|
|
|
598
630
|
if (status2 === "fail") failCount++;
|
|
599
631
|
if (status2 === "hold") holdCount++;
|
|
600
632
|
results.push({ id: q.id, stage: q.stage, status: status2, answer });
|
|
601
|
-
const icon = status2 === "pass" ?
|
|
633
|
+
const icon = status2 === "pass" ? chalk2.green(ko.gate.statusPassLine) : status2 === "hold" ? chalk2.yellow(ko.gate.statusHoldLine) : chalk2.red(ko.gate.statusFailLine);
|
|
602
634
|
console.log(icon);
|
|
603
635
|
}
|
|
604
|
-
console.log(
|
|
636
|
+
console.log(chalk2.bold(`
|
|
605
637
|
${ko.gate.verdictTitle}
|
|
606
638
|
`));
|
|
607
|
-
console.log(`${ko.gate.ideaLabel} ${
|
|
639
|
+
console.log(`${ko.gate.ideaLabel} ${chalk2.cyan(idea)}`);
|
|
608
640
|
console.log(`${ko.gate.painPointLabel} ${painPoint}`);
|
|
609
641
|
console.log(`${ko.gate.edgeLabel} ${edge}`);
|
|
610
642
|
console.log(`${ko.gate.countLine(failCount, holdCount, total)}
|
|
611
643
|
`);
|
|
612
644
|
const verdict = judgeGate(failCount, holdCount);
|
|
613
645
|
if (verdict === "GO") {
|
|
614
|
-
console.log(
|
|
646
|
+
console.log(chalk2.green.bold(ko.gate.go));
|
|
615
647
|
if (holdCount > 0) {
|
|
616
|
-
console.log(
|
|
648
|
+
console.log(chalk2.yellow(ko.gate.holdRemainHint));
|
|
617
649
|
}
|
|
618
650
|
printNextStep({
|
|
619
651
|
message: "\uC544\uC774\uB514\uC5B4 \uD1B5\uACFC! \uC774\uC81C \uD504\uB85C\uC81D\uD2B8\uB97C \uB9CC\uB4E4\uC5B4\uBCF4\uC138\uC694.",
|
|
@@ -621,20 +653,20 @@ ${ko.gate.verdictTitle}
|
|
|
621
653
|
cursorHint: "\uD504\uB85C\uC81D\uD2B8 \uB9CC\uB4E4\uC5B4\uC918"
|
|
622
654
|
});
|
|
623
655
|
} else if (verdict === "REFINE") {
|
|
624
|
-
console.log(
|
|
656
|
+
console.log(chalk2.yellow.bold(ko.gate.refine));
|
|
625
657
|
printNextStep({
|
|
626
658
|
message: "\uC870\uAE08 \uB354 \uB2E4\uB4EC\uC740 \uD6C4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uBCF4\uC138\uC694.",
|
|
627
659
|
command: "vhk \uAC80\uC99D",
|
|
628
660
|
cursorHint: "\uC544\uC774\uB514\uC5B4 \uB2E4\uC2DC \uAC80\uC99D\uD574\uC918"
|
|
629
661
|
});
|
|
630
662
|
} else {
|
|
631
|
-
console.log(
|
|
663
|
+
console.log(chalk2.red.bold(ko.gate.drop));
|
|
632
664
|
}
|
|
633
665
|
}
|
|
634
666
|
|
|
635
667
|
// src/commands/init.ts
|
|
636
668
|
import inquirer2 from "inquirer";
|
|
637
|
-
import
|
|
669
|
+
import chalk4 from "chalk";
|
|
638
670
|
import fs2 from "fs";
|
|
639
671
|
import path2 from "path";
|
|
640
672
|
|
|
@@ -956,13 +988,13 @@ function VHK_CONTEXT_SEED(name, type, stack) {
|
|
|
956
988
|
}
|
|
957
989
|
|
|
958
990
|
// src/utils/logger.ts
|
|
959
|
-
import
|
|
991
|
+
import chalk3 from "chalk";
|
|
960
992
|
var log = {
|
|
961
|
-
success: (msg) => console.log(
|
|
962
|
-
error: (msg) => console.log(
|
|
963
|
-
warn: (msg) => console.log(
|
|
964
|
-
info: (msg) => console.log(
|
|
965
|
-
step: (msg) => console.log(
|
|
993
|
+
success: (msg) => console.log(chalk3.green(`\u2705 ${msg}`)),
|
|
994
|
+
error: (msg) => console.log(chalk3.red(`\u274C ${msg}`)),
|
|
995
|
+
warn: (msg) => console.log(chalk3.yellow(`\u26A0\uFE0F ${msg}`)),
|
|
996
|
+
info: (msg) => console.log(chalk3.blue(`\u2139\uFE0F ${msg}`)),
|
|
997
|
+
step: (msg) => console.log(chalk3.bold(`
|
|
966
998
|
\u25B8 ${msg}`))
|
|
967
999
|
};
|
|
968
1000
|
|
|
@@ -1180,12 +1212,9 @@ function resolveType(type) {
|
|
|
1180
1212
|
}
|
|
1181
1213
|
return type;
|
|
1182
1214
|
}
|
|
1183
|
-
function isNonInteractive(options) {
|
|
1184
|
-
return Boolean(options.yes) || !process.stdin.isTTY || !process.stdout.isTTY;
|
|
1185
|
-
}
|
|
1186
1215
|
var DEFAULT_TYPE = PROJECT_TYPES[0].value;
|
|
1187
1216
|
async function collectAnswers(options, defaults = {}) {
|
|
1188
|
-
const noninteractive =
|
|
1217
|
+
const noninteractive = !isInteractive(options);
|
|
1189
1218
|
const prompts = [];
|
|
1190
1219
|
if (!noninteractive) {
|
|
1191
1220
|
if (!options.name && !defaults.name) {
|
|
@@ -1208,11 +1237,11 @@ async function collectAnswers(options, defaults = {}) {
|
|
|
1208
1237
|
async function init(options = {}) {
|
|
1209
1238
|
const skipGate = Boolean(options.skipGate || options.fromNotion);
|
|
1210
1239
|
if (skipGate) {
|
|
1211
|
-
console.log(
|
|
1240
|
+
console.log(chalk4.dim(`
|
|
1212
1241
|
${ko.init.skipGate}
|
|
1213
1242
|
`));
|
|
1214
1243
|
}
|
|
1215
|
-
console.log(
|
|
1244
|
+
console.log(chalk4.bold(`
|
|
1216
1245
|
${ko.init.title}
|
|
1217
1246
|
`));
|
|
1218
1247
|
printSecurityWarnings();
|
|
@@ -1238,11 +1267,11 @@ ${ko.init.title}
|
|
|
1238
1267
|
}
|
|
1239
1268
|
const detected = detectProjectStack(process.cwd());
|
|
1240
1269
|
const stack = detected ?? STACK_PRESETS[answers.type];
|
|
1241
|
-
if (detected) console.log(
|
|
1242
|
-
console.log(
|
|
1270
|
+
if (detected) console.log(chalk4.dim(" \u{1F50E} package.json \uC758\uC874\uC131\uC5D0\uC11C \uC2E4\uC81C \uC2A4\uD0DD \uAC10\uC9C0"));
|
|
1271
|
+
console.log(chalk4.dim(`
|
|
1243
1272
|
${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
1244
1273
|
`));
|
|
1245
|
-
if (
|
|
1274
|
+
if (isInteractive(options)) {
|
|
1246
1275
|
const { confirmStack } = await inquirer2.prompt([{
|
|
1247
1276
|
type: "confirm",
|
|
1248
1277
|
name: "confirmStack",
|
|
@@ -1256,7 +1285,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1256
1285
|
}
|
|
1257
1286
|
const cwd = process.cwd();
|
|
1258
1287
|
let adoptedRules = null;
|
|
1259
|
-
if (
|
|
1288
|
+
if (isInteractive(options) && !options.fromNotion) {
|
|
1260
1289
|
const existingRules = detectExistingRuleFiles(cwd);
|
|
1261
1290
|
if (existingRules.length > 0) {
|
|
1262
1291
|
const { adopt } = await inquirer2.prompt([{
|
|
@@ -1270,7 +1299,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1270
1299
|
}]);
|
|
1271
1300
|
if (adopt) {
|
|
1272
1301
|
adoptedRules = buildAdoptedRules(existingRules, answers.name);
|
|
1273
|
-
console.log(
|
|
1302
|
+
console.log(chalk4.dim(` ${ko.init.adoptPreview(existingRules.length)}`));
|
|
1274
1303
|
}
|
|
1275
1304
|
}
|
|
1276
1305
|
}
|
|
@@ -1280,7 +1309,7 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1280
1309
|
for (const [filePath, content] of Object.entries(files)) {
|
|
1281
1310
|
const fullPath = path2.join(cwd, filePath);
|
|
1282
1311
|
if (fileExists(fullPath)) {
|
|
1283
|
-
const overwrite =
|
|
1312
|
+
const overwrite = !isInteractive(options) ? false : (await inquirer2.prompt([{
|
|
1284
1313
|
type: "confirm",
|
|
1285
1314
|
name: "overwrite",
|
|
1286
1315
|
message: ko.init.overwrite(filePath),
|
|
@@ -1294,22 +1323,22 @@ ${ko.init.recommendedStack} ${stack.join(" + ")}
|
|
|
1294
1323
|
writeFile(fullPath, content);
|
|
1295
1324
|
log.success(filePath);
|
|
1296
1325
|
}
|
|
1297
|
-
await writeInitExtras(cwd,
|
|
1298
|
-
console.log(
|
|
1326
|
+
await writeInitExtras(cwd, !isInteractive(options));
|
|
1327
|
+
console.log(chalk4.bold.green(`
|
|
1299
1328
|
${ko.init.done}`));
|
|
1300
|
-
console.log(
|
|
1329
|
+
console.log(chalk4.dim(`
|
|
1301
1330
|
${ko.init.nextSteps}`));
|
|
1302
1331
|
if (options.fromNotion) {
|
|
1303
1332
|
console.log(` 1. ${ko.init.notionReviewHint}`);
|
|
1304
1333
|
console.log(` 2. ${ko.init.gitHintLabel}`);
|
|
1305
|
-
console.log(` ${
|
|
1334
|
+
console.log(` ${chalk4.cyan(ko.init.gitHintCommand)}`);
|
|
1306
1335
|
console.log(` 3. ${ko.init.startDev}
|
|
1307
1336
|
`);
|
|
1308
1337
|
} else {
|
|
1309
1338
|
console.log(` 1. ${ko.init.fillHint}`);
|
|
1310
1339
|
console.log(` 2. ${ko.init.prdHint}`);
|
|
1311
1340
|
console.log(` 3. ${ko.init.gitHintLabel}`);
|
|
1312
|
-
console.log(` ${
|
|
1341
|
+
console.log(` ${chalk4.cyan(ko.init.gitHintCommand)}`);
|
|
1313
1342
|
console.log(` 4. ${ko.init.startDev}
|
|
1314
1343
|
`);
|
|
1315
1344
|
}
|
|
@@ -1626,20 +1655,6 @@ function createAdrFile(cwd, title, context2, decision, consequences) {
|
|
|
1626
1655
|
return filePath;
|
|
1627
1656
|
}
|
|
1628
1657
|
|
|
1629
|
-
// src/lib/interactive.ts
|
|
1630
|
-
import chalk4 from "chalk";
|
|
1631
|
-
function ensureInteractive(hint = "") {
|
|
1632
|
-
if (process.stdin.isTTY) return true;
|
|
1633
|
-
console.error(chalk4.yellow(" \u26A0\uFE0F \uC774 \uBA85\uB839\uC740 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uBE44-TTY/\uD30C\uC774\uD504 \uD658\uACBD\uC5D0\uC11C\uB294 \uC2E4\uD589\uD560 \uC218 \uC5C6\uC5B4\uC694."));
|
|
1634
|
-
if (hint) console.error(chalk4.dim(` ${hint}`));
|
|
1635
|
-
process.exitCode = 1;
|
|
1636
|
-
return false;
|
|
1637
|
-
}
|
|
1638
|
-
function isPromptAbortError(err) {
|
|
1639
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1640
|
-
return /ERR_USE_AFTER_CLOSE|force closed|ExitPromptError|readline was closed|User force closed/i.test(msg);
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
1658
|
// src/lib/hard-stop-guard.ts
|
|
1644
1659
|
import chalk5 from "chalk";
|
|
1645
1660
|
|
|
@@ -2178,8 +2193,9 @@ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync,
|
|
|
2178
2193
|
import { join as join3 } from "path";
|
|
2179
2194
|
var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
2180
2195
|
function parseFrontmatter(content) {
|
|
2181
|
-
const
|
|
2182
|
-
|
|
2196
|
+
const normalized = stripBom(content);
|
|
2197
|
+
const m = normalized.match(FRONTMATTER_RE);
|
|
2198
|
+
if (!m) return { frontmatter: {}, body: normalized };
|
|
2183
2199
|
const fm = parseSimpleYaml(m[1]);
|
|
2184
2200
|
const body = (m[2] ?? "").replace(/^\r?\n+/, "");
|
|
2185
2201
|
return { frontmatter: fm, body };
|
|
@@ -3236,12 +3252,16 @@ async function save() {
|
|
|
3236
3252
|
if (severe.length > 5) {
|
|
3237
3253
|
console.log(chalk12.dim(` ... \uC678 ${severe.length - 5}\uAC74 (vhk \uBCF4\uC548 scan)`));
|
|
3238
3254
|
}
|
|
3239
|
-
const
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3255
|
+
const proceed = await promptOrDefault(
|
|
3256
|
+
async () => (await inquirer5.prompt([{
|
|
3257
|
+
type: "confirm",
|
|
3258
|
+
name: "proceed",
|
|
3259
|
+
message: t("save.secretsConfirm"),
|
|
3260
|
+
default: false
|
|
3261
|
+
}])).proceed,
|
|
3262
|
+
false
|
|
3263
|
+
// 비대화형 = 시크릿 커밋 안 함 (안전)
|
|
3264
|
+
);
|
|
3245
3265
|
if (!proceed) {
|
|
3246
3266
|
console.log(chalk12.gray(t("save.cancelled")));
|
|
3247
3267
|
return;
|
|
@@ -3259,12 +3279,15 @@ async function save() {
|
|
|
3259
3279
|
const name = line.substring(3);
|
|
3260
3280
|
console.log(` ${statusIcon(code)} ${name}`);
|
|
3261
3281
|
});
|
|
3262
|
-
const
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3282
|
+
const message = await promptOrDefault(
|
|
3283
|
+
async () => (await inquirer5.prompt([{
|
|
3284
|
+
type: "input",
|
|
3285
|
+
name: "message",
|
|
3286
|
+
message: t("save.commitMessage"),
|
|
3287
|
+
default: formatDefaultCommitMessage()
|
|
3288
|
+
}])).message,
|
|
3289
|
+
"chore: vhk save"
|
|
3290
|
+
);
|
|
3268
3291
|
const spinner = ora(t("save.saving")).start();
|
|
3269
3292
|
let didAdd = false;
|
|
3270
3293
|
try {
|
|
@@ -5393,7 +5416,8 @@ var HIGH_RISK_ACTIONS = [
|
|
|
5393
5416
|
"cloud-pull",
|
|
5394
5417
|
"resume",
|
|
5395
5418
|
"env-write",
|
|
5396
|
-
"delete"
|
|
5419
|
+
"delete",
|
|
5420
|
+
"restore"
|
|
5397
5421
|
];
|
|
5398
5422
|
var STRICT_EXTRA_ACTIONS = /* @__PURE__ */ new Set(["save", "sync"]);
|
|
5399
5423
|
var NL_GUARDED_ACTIONS = {
|
|
@@ -5404,7 +5428,8 @@ var NL_GUARDED_ACTIONS = {
|
|
|
5404
5428
|
"cloud-pull": "cloud-pull",
|
|
5405
5429
|
env: "env-write",
|
|
5406
5430
|
save: "save",
|
|
5407
|
-
sync: "sync"
|
|
5431
|
+
sync: "sync",
|
|
5432
|
+
restore: "restore"
|
|
5408
5433
|
};
|
|
5409
5434
|
function isHighRisk(action) {
|
|
5410
5435
|
return HIGH_RISK_ACTIONS.includes(action);
|
|
@@ -5426,6 +5451,11 @@ async function runGuarded(action, deps, run) {
|
|
|
5426
5451
|
return { outcome: { ran: true, guard, reason: "low-risk" }, result: await run() };
|
|
5427
5452
|
}
|
|
5428
5453
|
if (guard === "warn") {
|
|
5454
|
+
const canConfirm = deps.isTTY ?? !!process.stdin.isTTY;
|
|
5455
|
+
if (!deps.approved && !canConfirm) {
|
|
5456
|
+
log2(`\u26A0\uFE0F \uC704\uD5D8 \uC791\uC5C5(${action}) \u2014 lite \uC9C0\uB9CC \uBE44\uB300\uD654\uD615+\uBBF8\uC2B9\uC778 \u2192 \uC911\uB2E8. (--yes \uB85C \uC2B9\uC778)`);
|
|
5457
|
+
return { outcome: { ran: false, guard, reason: "lite-noninteractive-block" } };
|
|
5458
|
+
}
|
|
5429
5459
|
log2(`\u26A0\uFE0F \uC704\uD5D8 \uC791\uC5C5(${action}) \u2014 lite \uBAA8\uB4DC: \uACBD\uACE0\uB9CC \uD558\uACE0 \uC9C4\uD589\uD569\uB2C8\uB2E4.`);
|
|
5430
5460
|
return { outcome: { ran: true, guard, reason: "lite-warn" }, result: await run() };
|
|
5431
5461
|
}
|
|
@@ -5433,7 +5463,7 @@ async function runGuarded(action, deps, run) {
|
|
|
5433
5463
|
if (deps.approved === true) {
|
|
5434
5464
|
return { outcome: { ran: true, guard, reason: "approved" }, result: await run() };
|
|
5435
5465
|
}
|
|
5436
|
-
const tty = deps.isTTY ?? !!process.
|
|
5466
|
+
const tty = deps.isTTY ?? !!process.stdin.isTTY;
|
|
5437
5467
|
if (tty && deps.confirm) {
|
|
5438
5468
|
const ok = await deps.confirm();
|
|
5439
5469
|
if (ok) return { outcome: { ran: true, guard, reason: "confirmed" }, result: await run() };
|
|
@@ -5789,8 +5819,8 @@ program.command("save").alias("\uC800\uC7A5").option("--yes", "\uD655\uC778 \uC5
|
|
|
5789
5819
|
program.command("undo").alias("\uB418\uB3CC\uB9AC\uAE30").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC2E4\uD589 (\uC704\uD5D8 \uC791\uC5C5 \uBA85\uC2DC \uC2B9\uC778)").description("\uCD5C\uADFC \uCEE4\uBC0B \uB418\uB3CC\uB9AC\uAE30").action(async (opts) => {
|
|
5790
5820
|
await guardCliDefer("undo", opts?.yes === true, () => undo());
|
|
5791
5821
|
});
|
|
5792
|
-
program.command("restore").alias("\uBCF5\uC6D0").argument("[id]", "\uBCF5\uC6D0\uD560 \uBC31\uC5C5 id (\uC0DD\uB7B5 \uC2DC \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD)").description("sync \uBC31\uC5C5 \uBCF5\uC6D0 (.vhk/backups/ \u2014 \uC5B8\uCEE4\uBC0B \uB36E\uC5B4\uC4F0\uAE30 \uBCF5\uAD6C)").action(async (id) => {
|
|
5793
|
-
await restore(id);
|
|
5822
|
+
program.command("restore").alias("\uBCF5\uC6D0").argument("[id]", "\uBCF5\uC6D0\uD560 \uBC31\uC5C5 id (\uC0DD\uB7B5 \uC2DC \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD)").option("--yes", "\uD655\uC778 \uC5C6\uC774 \uC2E4\uD589 (\uC704\uD5D8 \uC791\uC5C5 \uBA85\uC2DC \uC2B9\uC778)").description("sync \uBC31\uC5C5 \uBCF5\uC6D0 (.vhk/backups/ \u2014 \uC5B8\uCEE4\uBC0B \uB36E\uC5B4\uC4F0\uAE30 \uBCF5\uAD6C)").action(async (id, opts) => {
|
|
5823
|
+
await guardCli("restore", opts?.yes === true, () => restore(id));
|
|
5794
5824
|
});
|
|
5795
5825
|
program.command("status").alias("\uC0C1\uD0DC").description("\uD504\uB85C\uC81D\uD2B8 \uC0C1\uD0DC \uB300\uC2DC\uBCF4\uB4DC").action(async () => {
|
|
5796
5826
|
await status();
|
package/dist/mcp/index.js
CHANGED
package/package.json
CHANGED