metheus-governance-mcp-cli 0.2.65 → 0.2.66
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 +3 -0
- package/lib/bot-commands.mjs +55 -5
- package/lib/selftest-bot-commands.mjs +119 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,6 +227,9 @@ Behavior:
|
|
|
227
227
|
- `bot setup` asks for `Telegram / Slack / KakaoTalk` first, then prompts with numbered actions.
|
|
228
228
|
- `bot add` without flags starts a guided question flow: provider -> server bot -> local bot key -> token -> verify -> role/AI binding -> default bot choice.
|
|
229
229
|
- `bot edit` without flags starts a guided numbered flow: provider -> bot entry -> guided edit -> step-by-step field choices.
|
|
230
|
+
- `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
|
|
231
|
+
- `bot verify` without flags starts a guided numbered flow: provider -> bot entry -> output format.
|
|
232
|
+
- `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
|
|
230
233
|
- Telegram supports named local bot entries with:
|
|
231
234
|
- `SERVER_BOT_ID`
|
|
232
235
|
- `USERNAME`
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -182,6 +182,26 @@ async function promptYesNo(ui, promptText, defaultValue = true) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
async function promptConfirmChoice(
|
|
186
|
+
ui,
|
|
187
|
+
title,
|
|
188
|
+
{
|
|
189
|
+
confirmLabel = "Confirm",
|
|
190
|
+
confirmDescription = "",
|
|
191
|
+
cancelLabel = "Cancel",
|
|
192
|
+
cancelDescription = "",
|
|
193
|
+
defaultValue = "confirm",
|
|
194
|
+
} = {},
|
|
195
|
+
) {
|
|
196
|
+
const options = [
|
|
197
|
+
{ value: "confirm", label: confirmLabel, description: confirmDescription },
|
|
198
|
+
{ value: "cancel", label: cancelLabel, description: cancelDescription },
|
|
199
|
+
];
|
|
200
|
+
const defaultIndex = defaultValue === "cancel" ? 1 : 0;
|
|
201
|
+
const selected = await promptChoice(ui, title, options, { defaultIndex });
|
|
202
|
+
return selected?.value === "confirm";
|
|
203
|
+
}
|
|
204
|
+
|
|
185
205
|
function formatChoiceLabel(option) {
|
|
186
206
|
return `${String(option.label || option.value || "").trim()}${option.description ? ` - ${option.description}` : ""}`;
|
|
187
207
|
}
|
|
@@ -1262,7 +1282,13 @@ async function removeTelegramBot(ui, deps) {
|
|
|
1262
1282
|
const parsed = { ...state.parsed };
|
|
1263
1283
|
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select Telegram bot entry to remove");
|
|
1264
1284
|
if (!selected) return;
|
|
1265
|
-
if (!await
|
|
1285
|
+
if (!await promptConfirmChoice(ui, `Remove Telegram bot "${selected.key}"?`, {
|
|
1286
|
+
confirmLabel: "Remove bot",
|
|
1287
|
+
confirmDescription: "delete this local Telegram bot entry",
|
|
1288
|
+
cancelLabel: "Cancel",
|
|
1289
|
+
cancelDescription: "keep the current local bot entry",
|
|
1290
|
+
defaultValue: "cancel",
|
|
1291
|
+
})) {
|
|
1266
1292
|
process.stdout.write("Cancelled.\n");
|
|
1267
1293
|
return;
|
|
1268
1294
|
}
|
|
@@ -1338,7 +1364,23 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1338
1364
|
}
|
|
1339
1365
|
}
|
|
1340
1366
|
}
|
|
1341
|
-
|
|
1367
|
+
const interactiveJsonChoice = (
|
|
1368
|
+
!boolFromRaw(flags.json, false)
|
|
1369
|
+
&& !boolFromRaw(flags["non-interactive"] ?? flags.yes, false)
|
|
1370
|
+
)
|
|
1371
|
+
? await promptChoice(
|
|
1372
|
+
ui,
|
|
1373
|
+
"Verification output format",
|
|
1374
|
+
[
|
|
1375
|
+
{ value: "text", label: "Text output (Recommended)", description: "human-readable summary" },
|
|
1376
|
+
{ value: "json", label: "JSON output", description: "machine-readable verification payload" },
|
|
1377
|
+
],
|
|
1378
|
+
{ defaultIndex: 0 },
|
|
1379
|
+
)
|
|
1380
|
+
: null;
|
|
1381
|
+
const outputAsJson = boolFromRaw(flags.json, false) || interactiveJsonChoice?.value === "json";
|
|
1382
|
+
|
|
1383
|
+
if (outputAsJson) {
|
|
1342
1384
|
process.stdout.write(
|
|
1343
1385
|
`${JSON.stringify({
|
|
1344
1386
|
ok: overallOK,
|
|
@@ -1594,9 +1636,7 @@ async function runBotVerify(ui, flags, deps) {
|
|
|
1594
1636
|
}
|
|
1595
1637
|
|
|
1596
1638
|
async function runBotSetDefault(ui, flags, deps) {
|
|
1597
|
-
const provider =
|
|
1598
|
-
? requireDependency(deps, "normalizeBotProvider")(flags.provider)
|
|
1599
|
-
: "telegram";
|
|
1639
|
+
const provider = await selectProvider(ui, flags.provider, deps);
|
|
1600
1640
|
if (provider !== "telegram") {
|
|
1601
1641
|
throw new Error("bot set-default currently supports only --provider telegram");
|
|
1602
1642
|
}
|
|
@@ -1609,6 +1649,16 @@ async function runBotSetDefault(ui, flags, deps) {
|
|
|
1609
1649
|
if (!selected) {
|
|
1610
1650
|
throw new Error("Telegram bot selector is required for set-default");
|
|
1611
1651
|
}
|
|
1652
|
+
if (!nonInteractive && !await promptConfirmChoice(ui, `Set "${selected.key}" as TELEGRAM_DEFAULT_BOT_KEY?`, {
|
|
1653
|
+
confirmLabel: "Set default bot",
|
|
1654
|
+
confirmDescription: "make this the default local Telegram bot entry",
|
|
1655
|
+
cancelLabel: "Cancel",
|
|
1656
|
+
cancelDescription: "leave the current default unchanged",
|
|
1657
|
+
defaultValue: "confirm",
|
|
1658
|
+
})) {
|
|
1659
|
+
process.stdout.write("Cancelled.\n");
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1612
1662
|
parsed.TELEGRAM_DEFAULT_BOT_KEY = selected.key;
|
|
1613
1663
|
const filePath = writeProviderEnvState("telegram", parsed, deps);
|
|
1614
1664
|
process.stdout.write(`Set TELEGRAM_DEFAULT_BOT_KEY=${selected.key} in ${filePath}\n`);
|
|
@@ -45,6 +45,45 @@ function readJSON(rawText) {
|
|
|
45
45
|
return JSON.parse(String(rawText || "").trim() || "{}");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function readTrailingJSON(rawText) {
|
|
49
|
+
const text = String(rawText || "");
|
|
50
|
+
const start = text.indexOf("{");
|
|
51
|
+
if (start < 0) {
|
|
52
|
+
return readJSON(text);
|
|
53
|
+
}
|
|
54
|
+
let depth = 0;
|
|
55
|
+
let inString = false;
|
|
56
|
+
let escaping = false;
|
|
57
|
+
for (let index = start; index < text.length; index += 1) {
|
|
58
|
+
const char = text[index];
|
|
59
|
+
if (inString) {
|
|
60
|
+
if (escaping) {
|
|
61
|
+
escaping = false;
|
|
62
|
+
} else if (char === "\\") {
|
|
63
|
+
escaping = true;
|
|
64
|
+
} else if (char === "\"") {
|
|
65
|
+
inString = false;
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (char === "\"") {
|
|
70
|
+
inString = true;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (char === "{") {
|
|
74
|
+
depth += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (char === "}") {
|
|
78
|
+
depth -= 1;
|
|
79
|
+
if (depth === 0) {
|
|
80
|
+
return readJSON(text.slice(start, index + 1));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return readJSON(text.slice(start));
|
|
85
|
+
}
|
|
86
|
+
|
|
48
87
|
function createMockServer() {
|
|
49
88
|
const serverBots = [
|
|
50
89
|
{
|
|
@@ -338,6 +377,50 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
338
377
|
`client=${String(editedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")} model=${String(editedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "")}`,
|
|
339
378
|
);
|
|
340
379
|
|
|
380
|
+
await runCLI({
|
|
381
|
+
cliPath,
|
|
382
|
+
args: ["bot", "set-default"],
|
|
383
|
+
env: {
|
|
384
|
+
...env,
|
|
385
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
386
|
+
"1", // provider: telegram
|
|
387
|
+
"1", // bot entry: main_test
|
|
388
|
+
"1", // confirm set default
|
|
389
|
+
]),
|
|
390
|
+
},
|
|
391
|
+
});
|
|
392
|
+
const guidedDefaultState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
393
|
+
push(
|
|
394
|
+
"bot_set_default_guided_selects_entry",
|
|
395
|
+
String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "main_test",
|
|
396
|
+
`default=${String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "")}`,
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
const guidedVerifyResult = await runCLI({
|
|
400
|
+
cliPath,
|
|
401
|
+
args: [
|
|
402
|
+
"bot", "verify",
|
|
403
|
+
"--base-url", baseURL,
|
|
404
|
+
"--timeout-seconds", "5",
|
|
405
|
+
],
|
|
406
|
+
env: {
|
|
407
|
+
...env,
|
|
408
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
409
|
+
"1", // provider: telegram
|
|
410
|
+
"1", // bot entry: main_test
|
|
411
|
+
"2", // output format: json
|
|
412
|
+
]),
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
const guidedVerifyPayload = readTrailingJSON(guidedVerifyResult.stdout);
|
|
416
|
+
push(
|
|
417
|
+
"bot_verify_guided_can_emit_json",
|
|
418
|
+
guidedVerifyPayload.ok === true
|
|
419
|
+
&& safeObject(guidedVerifyPayload.serverBinding).ok === true
|
|
420
|
+
&& String(guidedVerifyPayload.client || "") === "claude",
|
|
421
|
+
`verify=${String(guidedVerifyPayload.ok)} server=${String(safeObject(guidedVerifyPayload.serverBinding).detail || "")}`,
|
|
422
|
+
);
|
|
423
|
+
|
|
341
424
|
await runCLI({
|
|
342
425
|
cliPath,
|
|
343
426
|
args: [
|
|
@@ -435,16 +518,49 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
435
518
|
`client=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_MODEL || "")}`,
|
|
436
519
|
);
|
|
437
520
|
|
|
521
|
+
const guidedRemoveBeforeList = await runCLI({
|
|
522
|
+
cliPath,
|
|
523
|
+
args: [
|
|
524
|
+
"bot", "list",
|
|
525
|
+
"--provider", "telegram",
|
|
526
|
+
"--json", "true",
|
|
527
|
+
],
|
|
528
|
+
env,
|
|
529
|
+
});
|
|
530
|
+
const guidedRemoveBeforePayload = ensureArray(readJSON(guidedRemoveBeforeList.stdout));
|
|
531
|
+
const guidedRemoveBeforeEntry = safeObject(guidedRemoveBeforePayload[0]);
|
|
532
|
+
const guidedRemoveEntries = ensureArray(guidedRemoveBeforeEntry.entries);
|
|
533
|
+
const explicitEntryIndex = guidedRemoveEntries.findIndex((entry) => String(safeObject(entry).key || "") === "explicit_test");
|
|
534
|
+
|
|
438
535
|
await runCLI({
|
|
536
|
+
cliPath,
|
|
537
|
+
args: ["bot", "remove"],
|
|
538
|
+
env: {
|
|
539
|
+
...env,
|
|
540
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
541
|
+
"1", // provider: telegram
|
|
542
|
+
String(explicitEntryIndex + 1), // bot entry: explicit_test
|
|
543
|
+
"1", // confirm remove
|
|
544
|
+
]),
|
|
545
|
+
},
|
|
546
|
+
});
|
|
547
|
+
const guidedRemoveList = await runCLI({
|
|
439
548
|
cliPath,
|
|
440
549
|
args: [
|
|
441
|
-
"bot", "
|
|
550
|
+
"bot", "list",
|
|
442
551
|
"--provider", "telegram",
|
|
443
|
-
"--
|
|
444
|
-
"--non-interactive", "true",
|
|
552
|
+
"--json", "true",
|
|
445
553
|
],
|
|
446
554
|
env,
|
|
447
555
|
});
|
|
556
|
+
const guidedRemovePayload = ensureArray(readJSON(guidedRemoveList.stdout));
|
|
557
|
+
const guidedRemoveEntry = safeObject(guidedRemovePayload[0]);
|
|
558
|
+
push(
|
|
559
|
+
"bot_remove_guided_deletes_selected_entry",
|
|
560
|
+
explicitEntryIndex >= 0
|
|
561
|
+
&& ensureArray(guidedRemoveEntry.entries).length === 0,
|
|
562
|
+
`entries=${String(ensureArray(guidedRemoveEntry.entries).length)} selected=${String(explicitEntryIndex + 1)}`,
|
|
563
|
+
);
|
|
448
564
|
|
|
449
565
|
const migratedEnv = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
450
566
|
migratedEnv.TELEGRAM_BOT_TOKEN = "legacy-selftest-token";
|