metheus-governance-mcp-cli 0.2.64 → 0.2.65
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 +6 -3
- package/lib/bot-commands.mjs +273 -40
- package/lib/selftest-bot-commands.mjs +101 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -213,6 +213,7 @@ Direct commands:
|
|
|
213
213
|
metheus-governance-mcp-cli bot list
|
|
214
214
|
metheus-governance-mcp-cli bot show --provider telegram --bot-key main
|
|
215
215
|
metheus-governance-mcp-cli bot add --provider telegram
|
|
216
|
+
metheus-governance-mcp-cli bot edit
|
|
216
217
|
metheus-governance-mcp-cli bot edit --provider telegram
|
|
217
218
|
metheus-governance-mcp-cli bot remove --provider telegram
|
|
218
219
|
metheus-governance-mcp-cli bot set-default --provider telegram --bot-key main
|
|
@@ -224,6 +225,8 @@ metheus-governance-mcp-cli bot verify --provider telegram --bot-key main
|
|
|
224
225
|
Behavior:
|
|
225
226
|
|
|
226
227
|
- `bot setup` asks for `Telegram / Slack / KakaoTalk` first, then prompts with numbered actions.
|
|
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
|
+
- `bot edit` without flags starts a guided numbered flow: provider -> bot entry -> guided edit -> step-by-step field choices.
|
|
227
230
|
- Telegram supports named local bot entries with:
|
|
228
231
|
- `SERVER_BOT_ID`
|
|
229
232
|
- `USERNAME`
|
|
@@ -244,10 +247,10 @@ Non-interactive examples:
|
|
|
244
247
|
|
|
245
248
|
```bash
|
|
246
249
|
metheus-governance-mcp-cli bot global --provider telegram --non-interactive true --api-base-url http://127.0.0.1:8999/telegram --auto-clear-webhook false --allowed-updates message,edited_message,channel_post
|
|
247
|
-
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --bot-key main --bot-id <server_bot_uuid> --token <telegram_bot_token> --role-profile monitor --client codex --permission-mode read_only --reasoning-effort low --default true
|
|
248
|
-
metheus-governance-mcp-cli bot edit --provider telegram --bot-key main --non-interactive true --client claude --model claude-
|
|
250
|
+
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --bot-key main --server-bot-id <server_bot_uuid> --username <telegram_username> --token <telegram_bot_token> --role-profile monitor --ai-client codex --ai-model gpt-5-codex --ai-permission-mode read_only --ai-reasoning-effort low --default true
|
|
251
|
+
metheus-governance-mcp-cli bot edit --provider telegram --bot-key main --non-interactive true --ai-client claude --ai-model claude-sonnet --ai-permission-mode workspace_write --ai-reasoning-effort medium
|
|
249
252
|
metheus-governance-mcp-cli bot set-default --provider telegram --bot-key main --non-interactive true
|
|
250
|
-
metheus-governance-mcp-cli bot migrate --provider telegram --bot-key main --bot-id <server_bot_uuid> --bot-name <telegram_username> --role-profile monitor --client codex --permission-mode read_only --reasoning-effort low --non-interactive true
|
|
253
|
+
metheus-governance-mcp-cli bot migrate --provider telegram --bot-key main --server-bot-id <server_bot_uuid> --bot-name <telegram_username> --role-profile monitor --ai-client codex --ai-permission-mode read_only --ai-reasoning-effort low --non-interactive true
|
|
251
254
|
metheus-governance-mcp-cli bot remove --provider telegram --bot-key main --non-interactive true
|
|
252
255
|
metheus-governance-mcp-cli bot verify --provider telegram --bot-key main --json true
|
|
253
256
|
```
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -43,6 +43,35 @@ function firstNonEmptyString(values) {
|
|
|
43
43
|
return "";
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function hasOwnFlag(flags, key) {
|
|
47
|
+
return Object.prototype.hasOwnProperty.call(safeObject(flags), key);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getServerBotIDFlag(flags) {
|
|
51
|
+
const parsedFlags = safeObject(flags);
|
|
52
|
+
return firstNonEmptyString([parsedFlags["server-bot-id"], parsedFlags["bot-id"]]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getAIClientFlag(flags) {
|
|
56
|
+
const parsedFlags = safeObject(flags);
|
|
57
|
+
return firstNonEmptyString([parsedFlags["ai-client"], parsedFlags.client]);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getAIModelFlag(flags) {
|
|
61
|
+
const parsedFlags = safeObject(flags);
|
|
62
|
+
return firstNonEmptyString([parsedFlags["ai-model"], parsedFlags.model]);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getAIPermissionModeFlag(flags) {
|
|
66
|
+
const parsedFlags = safeObject(flags);
|
|
67
|
+
return firstNonEmptyString([parsedFlags["ai-permission-mode"], parsedFlags["permission-mode"]]);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getAIReasoningEffortFlag(flags) {
|
|
71
|
+
const parsedFlags = safeObject(flags);
|
|
72
|
+
return firstNonEmptyString([parsedFlags["ai-reasoning-effort"], parsedFlags["reasoning-effort"]]);
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
function maskSecret(rawValue) {
|
|
47
76
|
const text = String(rawValue || "").trim();
|
|
48
77
|
if (!text) return "";
|
|
@@ -76,8 +105,8 @@ function printBotUsage(deps) {
|
|
|
76
105
|
` ${cliName} bot setup`,
|
|
77
106
|
` ${cliName} bot list [--provider <telegram|slack|kakaotalk>] [--json <true|false>]`,
|
|
78
107
|
` ${cliName} bot show [--provider <telegram|slack|kakaotalk>] [--bot-key <key>] [--bot-id <uuid>] [--bot-name <name>] [--json <true|false>]`,
|
|
79
|
-
` ${cliName} bot add [--provider <telegram|slack|kakaotalk>] [--non-interactive <true|false>] [--
|
|
80
|
-
` ${cliName} bot edit [--provider <telegram|slack|kakaotalk>] [--non-interactive <true|false>] [--bot-key <key>]`,
|
|
108
|
+
` ${cliName} bot add [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>] [--non-interactive <true|false>] [--bot-key <key>] [--server-bot-id <uuid>] [--username <name>] [--token <token>] [--role-profile <name>] [--ai-client <name>] [--ai-model <name>] [--ai-permission-mode <mode>] [--ai-reasoning-effort <level>] [--default <true|false>] [--verify <true|false>]`,
|
|
109
|
+
` ${cliName} bot edit [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>] [--non-interactive <true|false>] [--bot-key <key>] [--server-bot-id <uuid>] [--username <name>] [--token <token>] [--role-profile <name>] [--ai-client <name>] [--ai-model <name>] [--ai-permission-mode <mode>] [--ai-reasoning-effort <level>]`,
|
|
81
110
|
` ${cliName} bot remove [--provider <telegram|slack|kakaotalk>] [--non-interactive <true|false>] [--bot-key <key>]`,
|
|
82
111
|
` ${cliName} bot set-default --provider telegram [--bot-key <key>] [--non-interactive <true|false>]`,
|
|
83
112
|
` ${cliName} bot migrate --provider telegram [--bot-key <key>] [--bot-id <uuid>] [--bot-name <name>] [--keep-legacy-token <true|false>] [--non-interactive <true|false>]`,
|
|
@@ -89,6 +118,27 @@ function printBotUsage(deps) {
|
|
|
89
118
|
}
|
|
90
119
|
|
|
91
120
|
function createPrompter() {
|
|
121
|
+
const scriptedPromptAnswersRaw = String(process.env.METHEUS_SCRIPTED_PROMPT_ANSWERS || "").trim();
|
|
122
|
+
if (scriptedPromptAnswersRaw) {
|
|
123
|
+
let scriptedAnswers = [];
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(scriptedPromptAnswersRaw);
|
|
126
|
+
scriptedAnswers = ensureArray(parsed).map((value) => String(value ?? ""));
|
|
127
|
+
} catch {
|
|
128
|
+
scriptedAnswers = scriptedPromptAnswersRaw.split(/\r?\n/).map((value) => String(value ?? ""));
|
|
129
|
+
}
|
|
130
|
+
let answerIndex = 0;
|
|
131
|
+
return {
|
|
132
|
+
ask(promptText) {
|
|
133
|
+
process.stdout.write(promptText);
|
|
134
|
+
const answer = answerIndex < scriptedAnswers.length ? scriptedAnswers[answerIndex] : "";
|
|
135
|
+
answerIndex += 1;
|
|
136
|
+
process.stdout.write(`${answer}\n`);
|
|
137
|
+
return Promise.resolve(String(answer || ""));
|
|
138
|
+
},
|
|
139
|
+
close() {},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
92
142
|
return {
|
|
93
143
|
ask(promptText) {
|
|
94
144
|
return new Promise((resolve) => {
|
|
@@ -163,6 +213,19 @@ async function promptChoice(ui, title, options, { defaultIndex = 0, allowCancel
|
|
|
163
213
|
}
|
|
164
214
|
}
|
|
165
215
|
|
|
216
|
+
async function promptKeepChangeClear(ui, title, { allowClear = true, defaultValue = "keep" } = {}) {
|
|
217
|
+
const options = [
|
|
218
|
+
{ value: "keep", label: "Keep current value" },
|
|
219
|
+
{ value: "change", label: "Change value" },
|
|
220
|
+
];
|
|
221
|
+
if (allowClear) {
|
|
222
|
+
options.push({ value: "clear", label: "Clear value" });
|
|
223
|
+
}
|
|
224
|
+
const defaultIndex = Math.max(0, options.findIndex((option) => option.value === defaultValue));
|
|
225
|
+
const selected = await promptChoice(ui, title, options, { defaultIndex });
|
|
226
|
+
return selected?.value || "keep";
|
|
227
|
+
}
|
|
228
|
+
|
|
166
229
|
function loadProviderEnvState(provider, deps) {
|
|
167
230
|
const ensureTemplate = requireDependency(deps, "ensureProviderEnvTemplate");
|
|
168
231
|
const filePathResolver = requireDependency(deps, "providerEnvFilePath");
|
|
@@ -399,6 +462,175 @@ function findTelegramEntryByFlags(parsedEnv, flags, deps) {
|
|
|
399
462
|
return null;
|
|
400
463
|
}
|
|
401
464
|
|
|
465
|
+
function saveTelegramBotEdit(parsed, selected, current, deps) {
|
|
466
|
+
let nextParsed = parsed;
|
|
467
|
+
if (current.key !== selected.key) {
|
|
468
|
+
nextParsed = removeTelegramEntry(nextParsed, selected.key);
|
|
469
|
+
}
|
|
470
|
+
nextParsed = upsertTelegramEntry(nextParsed, current);
|
|
471
|
+
if (String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key) {
|
|
472
|
+
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
473
|
+
}
|
|
474
|
+
const filePath = writeProviderEnvState("telegram", nextParsed, deps);
|
|
475
|
+
process.stdout.write(`Saved Telegram bot entry "${current.key}" to ${filePath}\n`);
|
|
476
|
+
return filePath;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async function editTelegramBotGuided(ui, parsed, selected, current, flags, deps) {
|
|
480
|
+
const bindingAction = await promptKeepChangeClear(ui, "Server bot binding", {
|
|
481
|
+
allowClear: true,
|
|
482
|
+
defaultValue: current.serverBotID ? "keep" : "change",
|
|
483
|
+
});
|
|
484
|
+
if (bindingAction === "change") {
|
|
485
|
+
const serverBot = await chooseServerBot(
|
|
486
|
+
ui,
|
|
487
|
+
"telegram",
|
|
488
|
+
flags["base-url"] || deps.defaultSiteURL,
|
|
489
|
+
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
490
|
+
deps,
|
|
491
|
+
);
|
|
492
|
+
current.serverBotID = serverBot.botID;
|
|
493
|
+
if (!current.roleProfile && serverBot.role) {
|
|
494
|
+
current.roleProfile = serverBot.role;
|
|
495
|
+
}
|
|
496
|
+
} else if (bindingAction === "clear") {
|
|
497
|
+
current.serverBotID = "";
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const usernameAction = await promptKeepChangeClear(ui, "Telegram username", {
|
|
501
|
+
allowClear: true,
|
|
502
|
+
defaultValue: current.username ? "keep" : "change",
|
|
503
|
+
});
|
|
504
|
+
if (usernameAction === "change") {
|
|
505
|
+
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(
|
|
506
|
+
await promptRequiredLine(ui, "Telegram username (without @)", current.username),
|
|
507
|
+
"",
|
|
508
|
+
);
|
|
509
|
+
} else if (usernameAction === "clear") {
|
|
510
|
+
current.username = "";
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const tokenAction = await promptKeepChangeClear(ui, "Telegram token", {
|
|
514
|
+
allowClear: false,
|
|
515
|
+
defaultValue: "keep",
|
|
516
|
+
});
|
|
517
|
+
if (tokenAction === "change") {
|
|
518
|
+
current.token = await promptRequiredLine(ui, "Telegram bot token", current.token);
|
|
519
|
+
if (await promptYesNo(ui, "Verify updated token now?", true)) {
|
|
520
|
+
const verifyResult = await verifyTelegramTokenCandidate(
|
|
521
|
+
"telegram",
|
|
522
|
+
current.token,
|
|
523
|
+
String(parsed.TELEGRAM_API_BASE_URL || "").trim(),
|
|
524
|
+
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
525
|
+
deps,
|
|
526
|
+
);
|
|
527
|
+
process.stdout.write(`Verify: ${verifyResult.ok ? "OK" : "FAIL"}${verifyResult.detail ? ` - ${verifyResult.detail}` : ""}\n`);
|
|
528
|
+
const maybeUsername = extractVerifiedTelegramUsername(verifyResult.detail);
|
|
529
|
+
if (verifyResult.ok && maybeUsername && !current.username) {
|
|
530
|
+
current.username = maybeUsername;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const roleAction = await promptKeepChangeClear(ui, "Role profile", {
|
|
536
|
+
allowClear: true,
|
|
537
|
+
defaultValue: current.roleProfile ? "keep" : "change",
|
|
538
|
+
});
|
|
539
|
+
if (roleAction === "change") {
|
|
540
|
+
current.roleProfile = requireDependency(deps, "normalizeRunnerRoleProfileName")(
|
|
541
|
+
await promptTelegramRoleProfile(ui, deps, current.roleProfile),
|
|
542
|
+
);
|
|
543
|
+
} else if (roleAction === "clear") {
|
|
544
|
+
current.roleProfile = "";
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const clientAction = await promptKeepChangeClear(ui, "AI client", {
|
|
548
|
+
allowClear: true,
|
|
549
|
+
defaultValue: current.client ? "keep" : "change",
|
|
550
|
+
});
|
|
551
|
+
if (clientAction === "change") {
|
|
552
|
+
current.client = requireDependency(deps, "normalizeLocalAIClientName")(
|
|
553
|
+
await promptAIClient(ui, deps, current.client),
|
|
554
|
+
"",
|
|
555
|
+
);
|
|
556
|
+
} else if (clientAction === "clear") {
|
|
557
|
+
current.client = "";
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const modelAction = await promptKeepChangeClear(ui, "AI model", {
|
|
561
|
+
allowClear: true,
|
|
562
|
+
defaultValue: current.model ? "keep" : "change",
|
|
563
|
+
});
|
|
564
|
+
if (modelAction === "change") {
|
|
565
|
+
current.model = await promptLine(ui, "AI model", current.model);
|
|
566
|
+
} else if (modelAction === "clear") {
|
|
567
|
+
current.model = "";
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const permissionAction = await promptKeepChangeClear(ui, "AI permission mode", {
|
|
571
|
+
allowClear: true,
|
|
572
|
+
defaultValue: current.permissionMode ? "keep" : "change",
|
|
573
|
+
});
|
|
574
|
+
if (permissionAction === "change") {
|
|
575
|
+
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(
|
|
576
|
+
await promptPermissionMode(ui, current.permissionMode),
|
|
577
|
+
"",
|
|
578
|
+
);
|
|
579
|
+
} else if (permissionAction === "clear") {
|
|
580
|
+
current.permissionMode = "";
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const reasoningAction = await promptKeepChangeClear(ui, "AI reasoning effort", {
|
|
584
|
+
allowClear: true,
|
|
585
|
+
defaultValue: current.reasoningEffort ? "keep" : "change",
|
|
586
|
+
});
|
|
587
|
+
if (reasoningAction === "change") {
|
|
588
|
+
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(
|
|
589
|
+
await promptReasoningEffort(ui, current.reasoningEffort),
|
|
590
|
+
"",
|
|
591
|
+
);
|
|
592
|
+
} else if (reasoningAction === "clear") {
|
|
593
|
+
current.reasoningEffort = "";
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const botKeyAction = await promptKeepChangeClear(ui, "Local bot key", {
|
|
597
|
+
allowClear: false,
|
|
598
|
+
defaultValue: "keep",
|
|
599
|
+
});
|
|
600
|
+
if (botKeyAction === "change") {
|
|
601
|
+
const normalizeBotKey = requireDependency(deps, "normalizeTelegramBotEnvKey");
|
|
602
|
+
let nextKey = normalizeBotKey(await promptRequiredLine(ui, "Local bot key", current.key), current.key);
|
|
603
|
+
const existing = new Set(telegramEntriesForDisplay(parsed, deps).map((entry) => entry.key).filter((key) => key !== current.key));
|
|
604
|
+
while (existing.has(nextKey)) {
|
|
605
|
+
process.stdout.write(`Telegram bot key "${nextKey}" already exists.\n`);
|
|
606
|
+
nextKey = normalizeBotKey(await promptRequiredLine(ui, "Local bot key", `${nextKey}_2`), `${nextKey}_2`);
|
|
607
|
+
}
|
|
608
|
+
current.key = nextKey;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const defaultChoice = await promptChoice(
|
|
612
|
+
ui,
|
|
613
|
+
"Default Telegram bot setting",
|
|
614
|
+
[
|
|
615
|
+
{ value: "keep", label: "Keep current default setting", description: String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key ? "currently default" : "not default" },
|
|
616
|
+
{ value: "set", label: "Set this bot as default" },
|
|
617
|
+
{ value: "unset", label: "Do not make this bot default" },
|
|
618
|
+
],
|
|
619
|
+
{ defaultIndex: 0 },
|
|
620
|
+
);
|
|
621
|
+
if (defaultChoice?.value === "set") {
|
|
622
|
+
parsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
623
|
+
} else if (defaultChoice?.value === "unset" && String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key) {
|
|
624
|
+
parsed.TELEGRAM_DEFAULT_BOT_KEY = "";
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (!await promptYesNo(ui, `Save changes for "${current.key}" now?`, true)) {
|
|
628
|
+
process.stdout.write("Cancelled.\n");
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
632
|
+
}
|
|
633
|
+
|
|
402
634
|
async function selectProvider(ui, initialProvider, deps) {
|
|
403
635
|
const normalizeProvider = requireDependency(deps, "normalizeBotProvider");
|
|
404
636
|
const provider = String(initialProvider || "").trim();
|
|
@@ -708,7 +940,7 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
708
940
|
const nonInteractive = boolFromRaw(flags["non-interactive"] ?? flags.yes, false);
|
|
709
941
|
const serverBot = nonInteractive
|
|
710
942
|
? {
|
|
711
|
-
botID:
|
|
943
|
+
botID: getServerBotIDFlag(flags),
|
|
712
944
|
role: String(flags.role || "").trim(),
|
|
713
945
|
name: "",
|
|
714
946
|
}
|
|
@@ -783,27 +1015,27 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
783
1015
|
);
|
|
784
1016
|
const client = requireDependency(deps, "normalizeLocalAIClientName")(
|
|
785
1017
|
nonInteractive
|
|
786
|
-
?
|
|
787
|
-
: await promptAIClient(ui, deps, flags
|
|
1018
|
+
? getAIClientFlag(flags)
|
|
1019
|
+
: await promptAIClient(ui, deps, getAIClientFlag(flags)),
|
|
788
1020
|
"",
|
|
789
1021
|
);
|
|
790
|
-
const model = nonInteractive ?
|
|
1022
|
+
const model = nonInteractive ? getAIModelFlag(flags) : await promptLine(ui, "AI model", getAIModelFlag(flags));
|
|
791
1023
|
const permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(
|
|
792
1024
|
nonInteractive
|
|
793
|
-
?
|
|
794
|
-
: await promptPermissionMode(ui,
|
|
1025
|
+
? getAIPermissionModeFlag(flags)
|
|
1026
|
+
: await promptPermissionMode(ui, getAIPermissionModeFlag(flags)),
|
|
795
1027
|
"",
|
|
796
1028
|
);
|
|
797
1029
|
const reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(
|
|
798
1030
|
nonInteractive
|
|
799
|
-
?
|
|
800
|
-
: await promptReasoningEffort(ui,
|
|
1031
|
+
? getAIReasoningEffortFlag(flags)
|
|
1032
|
+
: await promptReasoningEffort(ui, getAIReasoningEffortFlag(flags)),
|
|
801
1033
|
"",
|
|
802
1034
|
);
|
|
803
1035
|
|
|
804
1036
|
const nextParsed = upsertTelegramEntry(parsed, {
|
|
805
1037
|
key: botKey,
|
|
806
|
-
serverBotID: String(flags
|
|
1038
|
+
serverBotID: String(getServerBotIDFlag(flags) || serverBot.botID || "").trim(),
|
|
807
1039
|
username,
|
|
808
1040
|
token,
|
|
809
1041
|
roleProfile,
|
|
@@ -888,8 +1120,8 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
888
1120
|
}
|
|
889
1121
|
let current = { ...selected };
|
|
890
1122
|
if (nonInteractive) {
|
|
891
|
-
if (flags
|
|
892
|
-
current.serverBotID =
|
|
1123
|
+
if (getServerBotIDFlag(flags)) {
|
|
1124
|
+
current.serverBotID = getServerBotIDFlag(flags);
|
|
893
1125
|
}
|
|
894
1126
|
if (Object.prototype.hasOwnProperty.call(flags, "username")) {
|
|
895
1127
|
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(flags.username || "");
|
|
@@ -900,25 +1132,35 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
900
1132
|
if (Object.prototype.hasOwnProperty.call(flags, "role-profile")) {
|
|
901
1133
|
current.roleProfile = requireDependency(deps, "normalizeRunnerRoleProfileName")(flags["role-profile"] || "");
|
|
902
1134
|
}
|
|
903
|
-
if (
|
|
904
|
-
current.client = requireDependency(deps, "normalizeLocalAIClientName")(flags
|
|
1135
|
+
if (hasOwnFlag(flags, "client") || hasOwnFlag(flags, "ai-client")) {
|
|
1136
|
+
current.client = requireDependency(deps, "normalizeLocalAIClientName")(getAIClientFlag(flags), "");
|
|
905
1137
|
}
|
|
906
|
-
if (
|
|
907
|
-
current.model =
|
|
1138
|
+
if (hasOwnFlag(flags, "model") || hasOwnFlag(flags, "ai-model")) {
|
|
1139
|
+
current.model = getAIModelFlag(flags);
|
|
908
1140
|
}
|
|
909
|
-
if (
|
|
910
|
-
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(flags
|
|
1141
|
+
if (hasOwnFlag(flags, "permission-mode") || hasOwnFlag(flags, "ai-permission-mode")) {
|
|
1142
|
+
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(getAIPermissionModeFlag(flags), "");
|
|
911
1143
|
}
|
|
912
|
-
if (
|
|
913
|
-
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(flags
|
|
1144
|
+
if (hasOwnFlag(flags, "reasoning-effort") || hasOwnFlag(flags, "ai-reasoning-effort")) {
|
|
1145
|
+
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(getAIReasoningEffortFlag(flags), "");
|
|
914
1146
|
}
|
|
915
1147
|
if (boolFromRaw(flags.default, false)) {
|
|
916
1148
|
parsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
917
1149
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1150
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
const editMode = await promptChoice(
|
|
1154
|
+
ui,
|
|
1155
|
+
`How do you want to edit Telegram bot "${current.key}"?`,
|
|
1156
|
+
[
|
|
1157
|
+
{ value: "guided", label: "Guided edit (Recommended)", description: "Step-by-step prompts with numbered choices" },
|
|
1158
|
+
{ value: "field_menu", label: "Field menu", description: "Choose one field at a time until save" },
|
|
1159
|
+
],
|
|
1160
|
+
{ defaultIndex: 0 },
|
|
1161
|
+
);
|
|
1162
|
+
if (editMode?.value === "guided") {
|
|
1163
|
+
await editTelegramBotGuided(ui, parsed, selected, current, flags, deps);
|
|
922
1164
|
return;
|
|
923
1165
|
}
|
|
924
1166
|
while (true) {
|
|
@@ -942,16 +1184,7 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
942
1184
|
);
|
|
943
1185
|
if (!choice) return;
|
|
944
1186
|
if (choice.value === "save") {
|
|
945
|
-
|
|
946
|
-
if (current.key !== selected.key) {
|
|
947
|
-
nextParsed = removeTelegramEntry(nextParsed, selected.key);
|
|
948
|
-
}
|
|
949
|
-
nextParsed = upsertTelegramEntry(nextParsed, current);
|
|
950
|
-
if (String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key) {
|
|
951
|
-
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
952
|
-
}
|
|
953
|
-
const filePath = writeProviderEnvState("telegram", nextParsed, deps);
|
|
954
|
-
process.stdout.write(`Saved Telegram bot entry "${current.key}" to ${filePath}\n`);
|
|
1187
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
955
1188
|
return;
|
|
956
1189
|
}
|
|
957
1190
|
if (choice.value === "server_bot_id") {
|
|
@@ -1410,14 +1643,14 @@ async function runBotMigrate(ui, flags, deps) {
|
|
|
1410
1643
|
}
|
|
1411
1644
|
const nextParsed = upsertTelegramEntry(parsed, {
|
|
1412
1645
|
key: botKey,
|
|
1413
|
-
serverBotID:
|
|
1646
|
+
serverBotID: getServerBotIDFlag(flags),
|
|
1414
1647
|
username: requireDependency(deps, "normalizeTelegramBotUsername")(flags["bot-name"] || flags.username || ""),
|
|
1415
1648
|
token: legacyToken,
|
|
1416
1649
|
roleProfile: requireDependency(deps, "normalizeRunnerRoleProfileName")(flags["role-profile"] || ""),
|
|
1417
|
-
client: requireDependency(deps, "normalizeLocalAIClientName")(flags
|
|
1418
|
-
model:
|
|
1419
|
-
permissionMode: requireDependency(deps, "normalizeLocalAIPermissionMode")(flags
|
|
1420
|
-
reasoningEffort: requireDependency(deps, "normalizeLocalAIReasoningEffort")(flags
|
|
1650
|
+
client: requireDependency(deps, "normalizeLocalAIClientName")(getAIClientFlag(flags), ""),
|
|
1651
|
+
model: getAIModelFlag(flags),
|
|
1652
|
+
permissionMode: requireDependency(deps, "normalizeLocalAIPermissionMode")(getAIPermissionModeFlag(flags), ""),
|
|
1653
|
+
reasoningEffort: requireDependency(deps, "normalizeLocalAIReasoningEffort")(getAIReasoningEffortFlag(flags), ""),
|
|
1421
1654
|
});
|
|
1422
1655
|
if (!hasNamedTelegramEntry(parsed, deps) || !String(nextParsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim()) {
|
|
1423
1656
|
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = botKey;
|
|
@@ -225,29 +225,36 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
225
225
|
cliPath,
|
|
226
226
|
args: [
|
|
227
227
|
"bot", "add",
|
|
228
|
-
"--provider", "telegram",
|
|
229
|
-
"--non-interactive", "true",
|
|
230
228
|
"--base-url", baseURL,
|
|
231
229
|
"--timeout-seconds", "5",
|
|
232
|
-
"--bot-key", "main_test",
|
|
233
|
-
"--bot-id", mock.bots[0].id,
|
|
234
|
-
"--token", "selftest-main-token",
|
|
235
|
-
"--role-profile", "monitor",
|
|
236
|
-
"--client", "codex",
|
|
237
|
-
"--permission-mode", "read_only",
|
|
238
|
-
"--reasoning-effort", "low",
|
|
239
|
-
"--default", "true",
|
|
240
|
-
"--verify", "true",
|
|
241
230
|
],
|
|
242
|
-
env
|
|
231
|
+
env: {
|
|
232
|
+
...env,
|
|
233
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
234
|
+
"1", // provider: telegram
|
|
235
|
+
"1", // server bot: first listed bot
|
|
236
|
+
"main_test",
|
|
237
|
+
"selftest-main-token",
|
|
238
|
+
"y", // verify now
|
|
239
|
+
"", // keep verified username
|
|
240
|
+
"3", // role profile: monitor
|
|
241
|
+
"2", // ai client: codex
|
|
242
|
+
"gpt-5-codex",
|
|
243
|
+
"2", // permission: read_only
|
|
244
|
+
"2", // reasoning: low
|
|
245
|
+
"y", // set as default
|
|
246
|
+
]),
|
|
247
|
+
},
|
|
243
248
|
});
|
|
244
249
|
const addState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
245
250
|
push(
|
|
246
|
-
"
|
|
251
|
+
"bot_add_guided_creates_named_telegram_entry",
|
|
247
252
|
String(addState.TELEGRAM_BOT_MAIN_TEST_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
253
|
+
&& String(addState.TELEGRAM_BOT_MAIN_TEST_USERNAME || "").trim().toLowerCase() === "monitorselftestbot"
|
|
248
254
|
&& String(addState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "") === "codex"
|
|
255
|
+
&& String(addState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "") === "gpt-5-codex"
|
|
249
256
|
&& String(addState.TELEGRAM_DEFAULT_BOT_KEY || "") === "main_test",
|
|
250
|
-
`default=${String(addState.TELEGRAM_DEFAULT_BOT_KEY || "")} client=${String(addState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")}`,
|
|
257
|
+
`default=${String(addState.TELEGRAM_DEFAULT_BOT_KEY || "")} client=${String(addState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")} model=${String(addState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "")}`,
|
|
251
258
|
);
|
|
252
259
|
|
|
253
260
|
const showResult = await runCLI({
|
|
@@ -268,6 +275,43 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
268
275
|
`key=${String(safeObject(showPayload.entry).key || "")} client=${String(safeObject(showPayload.entry).client || "")}`,
|
|
269
276
|
);
|
|
270
277
|
|
|
278
|
+
await runCLI({
|
|
279
|
+
cliPath,
|
|
280
|
+
args: ["bot", "edit"],
|
|
281
|
+
env: {
|
|
282
|
+
...env,
|
|
283
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
284
|
+
"1", // provider: telegram
|
|
285
|
+
"1", // bot entry: main_test
|
|
286
|
+
"1", // edit mode: guided
|
|
287
|
+
"1", // keep server bot binding
|
|
288
|
+
"1", // keep username
|
|
289
|
+
"1", // keep token
|
|
290
|
+
"1", // keep role profile
|
|
291
|
+
"2", // change AI client
|
|
292
|
+
"4", // gemini
|
|
293
|
+
"2", // change AI model
|
|
294
|
+
"guided-gemini-pro",
|
|
295
|
+
"2", // change permission mode
|
|
296
|
+
"3", // workspace_write
|
|
297
|
+
"2", // change reasoning effort
|
|
298
|
+
"3", // medium
|
|
299
|
+
"1", // keep bot key
|
|
300
|
+
"1", // keep default setting
|
|
301
|
+
"y", // save
|
|
302
|
+
]),
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
const guidedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
306
|
+
push(
|
|
307
|
+
"bot_edit_guided_prompts_update_ai_binding_fields",
|
|
308
|
+
String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "") === "gemini"
|
|
309
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "") === "guided-gemini-pro"
|
|
310
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
311
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_REASONING_EFFORT || "") === "medium",
|
|
312
|
+
`client=${String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")} model=${String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "")}`,
|
|
313
|
+
);
|
|
314
|
+
|
|
271
315
|
await runCLI({
|
|
272
316
|
cliPath,
|
|
273
317
|
args: [
|
|
@@ -359,6 +403,49 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
359
403
|
`entries=${String(ensureArray(telegramEntry.entries).length)}`,
|
|
360
404
|
);
|
|
361
405
|
|
|
406
|
+
await runCLI({
|
|
407
|
+
cliPath,
|
|
408
|
+
args: [
|
|
409
|
+
"bot", "add",
|
|
410
|
+
"--provider", "telegram",
|
|
411
|
+
"--non-interactive", "true",
|
|
412
|
+
"--base-url", baseURL,
|
|
413
|
+
"--timeout-seconds", "5",
|
|
414
|
+
"--bot-key", "explicit_test",
|
|
415
|
+
"--server-bot-id", mock.bots[0].id,
|
|
416
|
+
"--username", "MonitorSelftestBot",
|
|
417
|
+
"--token", "selftest-main-token",
|
|
418
|
+
"--role-profile", "monitor",
|
|
419
|
+
"--ai-client", "codex",
|
|
420
|
+
"--ai-model", "gpt-5-codex",
|
|
421
|
+
"--ai-permission-mode", "read_only",
|
|
422
|
+
"--ai-reasoning-effort", "low",
|
|
423
|
+
"--verify", "true",
|
|
424
|
+
],
|
|
425
|
+
env,
|
|
426
|
+
});
|
|
427
|
+
const aliasAddState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
428
|
+
push(
|
|
429
|
+
"bot_add_accepts_ai_prefixed_option_aliases",
|
|
430
|
+
String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
431
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_CLIENT || "") === "codex"
|
|
432
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_MODEL || "") === "gpt-5-codex"
|
|
433
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_PERMISSION_MODE || "") === "read_only"
|
|
434
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_REASONING_EFFORT || "") === "low",
|
|
435
|
+
`client=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_MODEL || "")}`,
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
await runCLI({
|
|
439
|
+
cliPath,
|
|
440
|
+
args: [
|
|
441
|
+
"bot", "remove",
|
|
442
|
+
"--provider", "telegram",
|
|
443
|
+
"--bot-key", "explicit_test",
|
|
444
|
+
"--non-interactive", "true",
|
|
445
|
+
],
|
|
446
|
+
env,
|
|
447
|
+
});
|
|
448
|
+
|
|
362
449
|
const migratedEnv = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
363
450
|
migratedEnv.TELEGRAM_BOT_TOKEN = "legacy-selftest-token";
|
|
364
451
|
fs.writeFileSync(
|