metheus-governance-mcp-cli 0.2.64 → 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 +9 -3
- package/lib/bot-commands.mjs +328 -45
- package/lib/selftest-bot-commands.mjs +217 -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,11 @@ 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.
|
|
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.
|
|
227
233
|
- Telegram supports named local bot entries with:
|
|
228
234
|
- `SERVER_BOT_ID`
|
|
229
235
|
- `USERNAME`
|
|
@@ -244,10 +250,10 @@ Non-interactive examples:
|
|
|
244
250
|
|
|
245
251
|
```bash
|
|
246
252
|
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-
|
|
253
|
+
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
|
|
254
|
+
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
255
|
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
|
|
256
|
+
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
257
|
metheus-governance-mcp-cli bot remove --provider telegram --bot-key main --non-interactive true
|
|
252
258
|
metheus-governance-mcp-cli bot verify --provider telegram --bot-key main --json true
|
|
253
259
|
```
|
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) => {
|
|
@@ -132,6 +182,26 @@ async function promptYesNo(ui, promptText, defaultValue = true) {
|
|
|
132
182
|
}
|
|
133
183
|
}
|
|
134
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
|
+
|
|
135
205
|
function formatChoiceLabel(option) {
|
|
136
206
|
return `${String(option.label || option.value || "").trim()}${option.description ? ` - ${option.description}` : ""}`;
|
|
137
207
|
}
|
|
@@ -163,6 +233,19 @@ async function promptChoice(ui, title, options, { defaultIndex = 0, allowCancel
|
|
|
163
233
|
}
|
|
164
234
|
}
|
|
165
235
|
|
|
236
|
+
async function promptKeepChangeClear(ui, title, { allowClear = true, defaultValue = "keep" } = {}) {
|
|
237
|
+
const options = [
|
|
238
|
+
{ value: "keep", label: "Keep current value" },
|
|
239
|
+
{ value: "change", label: "Change value" },
|
|
240
|
+
];
|
|
241
|
+
if (allowClear) {
|
|
242
|
+
options.push({ value: "clear", label: "Clear value" });
|
|
243
|
+
}
|
|
244
|
+
const defaultIndex = Math.max(0, options.findIndex((option) => option.value === defaultValue));
|
|
245
|
+
const selected = await promptChoice(ui, title, options, { defaultIndex });
|
|
246
|
+
return selected?.value || "keep";
|
|
247
|
+
}
|
|
248
|
+
|
|
166
249
|
function loadProviderEnvState(provider, deps) {
|
|
167
250
|
const ensureTemplate = requireDependency(deps, "ensureProviderEnvTemplate");
|
|
168
251
|
const filePathResolver = requireDependency(deps, "providerEnvFilePath");
|
|
@@ -399,6 +482,175 @@ function findTelegramEntryByFlags(parsedEnv, flags, deps) {
|
|
|
399
482
|
return null;
|
|
400
483
|
}
|
|
401
484
|
|
|
485
|
+
function saveTelegramBotEdit(parsed, selected, current, deps) {
|
|
486
|
+
let nextParsed = parsed;
|
|
487
|
+
if (current.key !== selected.key) {
|
|
488
|
+
nextParsed = removeTelegramEntry(nextParsed, selected.key);
|
|
489
|
+
}
|
|
490
|
+
nextParsed = upsertTelegramEntry(nextParsed, current);
|
|
491
|
+
if (String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key) {
|
|
492
|
+
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
493
|
+
}
|
|
494
|
+
const filePath = writeProviderEnvState("telegram", nextParsed, deps);
|
|
495
|
+
process.stdout.write(`Saved Telegram bot entry "${current.key}" to ${filePath}\n`);
|
|
496
|
+
return filePath;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
async function editTelegramBotGuided(ui, parsed, selected, current, flags, deps) {
|
|
500
|
+
const bindingAction = await promptKeepChangeClear(ui, "Server bot binding", {
|
|
501
|
+
allowClear: true,
|
|
502
|
+
defaultValue: current.serverBotID ? "keep" : "change",
|
|
503
|
+
});
|
|
504
|
+
if (bindingAction === "change") {
|
|
505
|
+
const serverBot = await chooseServerBot(
|
|
506
|
+
ui,
|
|
507
|
+
"telegram",
|
|
508
|
+
flags["base-url"] || deps.defaultSiteURL,
|
|
509
|
+
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
510
|
+
deps,
|
|
511
|
+
);
|
|
512
|
+
current.serverBotID = serverBot.botID;
|
|
513
|
+
if (!current.roleProfile && serverBot.role) {
|
|
514
|
+
current.roleProfile = serverBot.role;
|
|
515
|
+
}
|
|
516
|
+
} else if (bindingAction === "clear") {
|
|
517
|
+
current.serverBotID = "";
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const usernameAction = await promptKeepChangeClear(ui, "Telegram username", {
|
|
521
|
+
allowClear: true,
|
|
522
|
+
defaultValue: current.username ? "keep" : "change",
|
|
523
|
+
});
|
|
524
|
+
if (usernameAction === "change") {
|
|
525
|
+
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(
|
|
526
|
+
await promptRequiredLine(ui, "Telegram username (without @)", current.username),
|
|
527
|
+
"",
|
|
528
|
+
);
|
|
529
|
+
} else if (usernameAction === "clear") {
|
|
530
|
+
current.username = "";
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const tokenAction = await promptKeepChangeClear(ui, "Telegram token", {
|
|
534
|
+
allowClear: false,
|
|
535
|
+
defaultValue: "keep",
|
|
536
|
+
});
|
|
537
|
+
if (tokenAction === "change") {
|
|
538
|
+
current.token = await promptRequiredLine(ui, "Telegram bot token", current.token);
|
|
539
|
+
if (await promptYesNo(ui, "Verify updated token now?", true)) {
|
|
540
|
+
const verifyResult = await verifyTelegramTokenCandidate(
|
|
541
|
+
"telegram",
|
|
542
|
+
current.token,
|
|
543
|
+
String(parsed.TELEGRAM_API_BASE_URL || "").trim(),
|
|
544
|
+
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
545
|
+
deps,
|
|
546
|
+
);
|
|
547
|
+
process.stdout.write(`Verify: ${verifyResult.ok ? "OK" : "FAIL"}${verifyResult.detail ? ` - ${verifyResult.detail}` : ""}\n`);
|
|
548
|
+
const maybeUsername = extractVerifiedTelegramUsername(verifyResult.detail);
|
|
549
|
+
if (verifyResult.ok && maybeUsername && !current.username) {
|
|
550
|
+
current.username = maybeUsername;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const roleAction = await promptKeepChangeClear(ui, "Role profile", {
|
|
556
|
+
allowClear: true,
|
|
557
|
+
defaultValue: current.roleProfile ? "keep" : "change",
|
|
558
|
+
});
|
|
559
|
+
if (roleAction === "change") {
|
|
560
|
+
current.roleProfile = requireDependency(deps, "normalizeRunnerRoleProfileName")(
|
|
561
|
+
await promptTelegramRoleProfile(ui, deps, current.roleProfile),
|
|
562
|
+
);
|
|
563
|
+
} else if (roleAction === "clear") {
|
|
564
|
+
current.roleProfile = "";
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const clientAction = await promptKeepChangeClear(ui, "AI client", {
|
|
568
|
+
allowClear: true,
|
|
569
|
+
defaultValue: current.client ? "keep" : "change",
|
|
570
|
+
});
|
|
571
|
+
if (clientAction === "change") {
|
|
572
|
+
current.client = requireDependency(deps, "normalizeLocalAIClientName")(
|
|
573
|
+
await promptAIClient(ui, deps, current.client),
|
|
574
|
+
"",
|
|
575
|
+
);
|
|
576
|
+
} else if (clientAction === "clear") {
|
|
577
|
+
current.client = "";
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const modelAction = await promptKeepChangeClear(ui, "AI model", {
|
|
581
|
+
allowClear: true,
|
|
582
|
+
defaultValue: current.model ? "keep" : "change",
|
|
583
|
+
});
|
|
584
|
+
if (modelAction === "change") {
|
|
585
|
+
current.model = await promptLine(ui, "AI model", current.model);
|
|
586
|
+
} else if (modelAction === "clear") {
|
|
587
|
+
current.model = "";
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const permissionAction = await promptKeepChangeClear(ui, "AI permission mode", {
|
|
591
|
+
allowClear: true,
|
|
592
|
+
defaultValue: current.permissionMode ? "keep" : "change",
|
|
593
|
+
});
|
|
594
|
+
if (permissionAction === "change") {
|
|
595
|
+
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(
|
|
596
|
+
await promptPermissionMode(ui, current.permissionMode),
|
|
597
|
+
"",
|
|
598
|
+
);
|
|
599
|
+
} else if (permissionAction === "clear") {
|
|
600
|
+
current.permissionMode = "";
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
const reasoningAction = await promptKeepChangeClear(ui, "AI reasoning effort", {
|
|
604
|
+
allowClear: true,
|
|
605
|
+
defaultValue: current.reasoningEffort ? "keep" : "change",
|
|
606
|
+
});
|
|
607
|
+
if (reasoningAction === "change") {
|
|
608
|
+
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(
|
|
609
|
+
await promptReasoningEffort(ui, current.reasoningEffort),
|
|
610
|
+
"",
|
|
611
|
+
);
|
|
612
|
+
} else if (reasoningAction === "clear") {
|
|
613
|
+
current.reasoningEffort = "";
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const botKeyAction = await promptKeepChangeClear(ui, "Local bot key", {
|
|
617
|
+
allowClear: false,
|
|
618
|
+
defaultValue: "keep",
|
|
619
|
+
});
|
|
620
|
+
if (botKeyAction === "change") {
|
|
621
|
+
const normalizeBotKey = requireDependency(deps, "normalizeTelegramBotEnvKey");
|
|
622
|
+
let nextKey = normalizeBotKey(await promptRequiredLine(ui, "Local bot key", current.key), current.key);
|
|
623
|
+
const existing = new Set(telegramEntriesForDisplay(parsed, deps).map((entry) => entry.key).filter((key) => key !== current.key));
|
|
624
|
+
while (existing.has(nextKey)) {
|
|
625
|
+
process.stdout.write(`Telegram bot key "${nextKey}" already exists.\n`);
|
|
626
|
+
nextKey = normalizeBotKey(await promptRequiredLine(ui, "Local bot key", `${nextKey}_2`), `${nextKey}_2`);
|
|
627
|
+
}
|
|
628
|
+
current.key = nextKey;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const defaultChoice = await promptChoice(
|
|
632
|
+
ui,
|
|
633
|
+
"Default Telegram bot setting",
|
|
634
|
+
[
|
|
635
|
+
{ value: "keep", label: "Keep current default setting", description: String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key ? "currently default" : "not default" },
|
|
636
|
+
{ value: "set", label: "Set this bot as default" },
|
|
637
|
+
{ value: "unset", label: "Do not make this bot default" },
|
|
638
|
+
],
|
|
639
|
+
{ defaultIndex: 0 },
|
|
640
|
+
);
|
|
641
|
+
if (defaultChoice?.value === "set") {
|
|
642
|
+
parsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
643
|
+
} else if (defaultChoice?.value === "unset" && String(parsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim() === selected.key) {
|
|
644
|
+
parsed.TELEGRAM_DEFAULT_BOT_KEY = "";
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (!await promptYesNo(ui, `Save changes for "${current.key}" now?`, true)) {
|
|
648
|
+
process.stdout.write("Cancelled.\n");
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
652
|
+
}
|
|
653
|
+
|
|
402
654
|
async function selectProvider(ui, initialProvider, deps) {
|
|
403
655
|
const normalizeProvider = requireDependency(deps, "normalizeBotProvider");
|
|
404
656
|
const provider = String(initialProvider || "").trim();
|
|
@@ -708,7 +960,7 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
708
960
|
const nonInteractive = boolFromRaw(flags["non-interactive"] ?? flags.yes, false);
|
|
709
961
|
const serverBot = nonInteractive
|
|
710
962
|
? {
|
|
711
|
-
botID:
|
|
963
|
+
botID: getServerBotIDFlag(flags),
|
|
712
964
|
role: String(flags.role || "").trim(),
|
|
713
965
|
name: "",
|
|
714
966
|
}
|
|
@@ -783,27 +1035,27 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
783
1035
|
);
|
|
784
1036
|
const client = requireDependency(deps, "normalizeLocalAIClientName")(
|
|
785
1037
|
nonInteractive
|
|
786
|
-
?
|
|
787
|
-
: await promptAIClient(ui, deps, flags
|
|
1038
|
+
? getAIClientFlag(flags)
|
|
1039
|
+
: await promptAIClient(ui, deps, getAIClientFlag(flags)),
|
|
788
1040
|
"",
|
|
789
1041
|
);
|
|
790
|
-
const model = nonInteractive ?
|
|
1042
|
+
const model = nonInteractive ? getAIModelFlag(flags) : await promptLine(ui, "AI model", getAIModelFlag(flags));
|
|
791
1043
|
const permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(
|
|
792
1044
|
nonInteractive
|
|
793
|
-
?
|
|
794
|
-
: await promptPermissionMode(ui,
|
|
1045
|
+
? getAIPermissionModeFlag(flags)
|
|
1046
|
+
: await promptPermissionMode(ui, getAIPermissionModeFlag(flags)),
|
|
795
1047
|
"",
|
|
796
1048
|
);
|
|
797
1049
|
const reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(
|
|
798
1050
|
nonInteractive
|
|
799
|
-
?
|
|
800
|
-
: await promptReasoningEffort(ui,
|
|
1051
|
+
? getAIReasoningEffortFlag(flags)
|
|
1052
|
+
: await promptReasoningEffort(ui, getAIReasoningEffortFlag(flags)),
|
|
801
1053
|
"",
|
|
802
1054
|
);
|
|
803
1055
|
|
|
804
1056
|
const nextParsed = upsertTelegramEntry(parsed, {
|
|
805
1057
|
key: botKey,
|
|
806
|
-
serverBotID: String(flags
|
|
1058
|
+
serverBotID: String(getServerBotIDFlag(flags) || serverBot.botID || "").trim(),
|
|
807
1059
|
username,
|
|
808
1060
|
token,
|
|
809
1061
|
roleProfile,
|
|
@@ -888,8 +1140,8 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
888
1140
|
}
|
|
889
1141
|
let current = { ...selected };
|
|
890
1142
|
if (nonInteractive) {
|
|
891
|
-
if (flags
|
|
892
|
-
current.serverBotID =
|
|
1143
|
+
if (getServerBotIDFlag(flags)) {
|
|
1144
|
+
current.serverBotID = getServerBotIDFlag(flags);
|
|
893
1145
|
}
|
|
894
1146
|
if (Object.prototype.hasOwnProperty.call(flags, "username")) {
|
|
895
1147
|
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(flags.username || "");
|
|
@@ -900,25 +1152,35 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
900
1152
|
if (Object.prototype.hasOwnProperty.call(flags, "role-profile")) {
|
|
901
1153
|
current.roleProfile = requireDependency(deps, "normalizeRunnerRoleProfileName")(flags["role-profile"] || "");
|
|
902
1154
|
}
|
|
903
|
-
if (
|
|
904
|
-
current.client = requireDependency(deps, "normalizeLocalAIClientName")(flags
|
|
1155
|
+
if (hasOwnFlag(flags, "client") || hasOwnFlag(flags, "ai-client")) {
|
|
1156
|
+
current.client = requireDependency(deps, "normalizeLocalAIClientName")(getAIClientFlag(flags), "");
|
|
905
1157
|
}
|
|
906
|
-
if (
|
|
907
|
-
current.model =
|
|
1158
|
+
if (hasOwnFlag(flags, "model") || hasOwnFlag(flags, "ai-model")) {
|
|
1159
|
+
current.model = getAIModelFlag(flags);
|
|
908
1160
|
}
|
|
909
|
-
if (
|
|
910
|
-
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(flags
|
|
1161
|
+
if (hasOwnFlag(flags, "permission-mode") || hasOwnFlag(flags, "ai-permission-mode")) {
|
|
1162
|
+
current.permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(getAIPermissionModeFlag(flags), "");
|
|
911
1163
|
}
|
|
912
|
-
if (
|
|
913
|
-
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(flags
|
|
1164
|
+
if (hasOwnFlag(flags, "reasoning-effort") || hasOwnFlag(flags, "ai-reasoning-effort")) {
|
|
1165
|
+
current.reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(getAIReasoningEffortFlag(flags), "");
|
|
914
1166
|
}
|
|
915
1167
|
if (boolFromRaw(flags.default, false)) {
|
|
916
1168
|
parsed.TELEGRAM_DEFAULT_BOT_KEY = current.key;
|
|
917
1169
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1170
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
1171
|
+
return;
|
|
1172
|
+
}
|
|
1173
|
+
const editMode = await promptChoice(
|
|
1174
|
+
ui,
|
|
1175
|
+
`How do you want to edit Telegram bot "${current.key}"?`,
|
|
1176
|
+
[
|
|
1177
|
+
{ value: "guided", label: "Guided edit (Recommended)", description: "Step-by-step prompts with numbered choices" },
|
|
1178
|
+
{ value: "field_menu", label: "Field menu", description: "Choose one field at a time until save" },
|
|
1179
|
+
],
|
|
1180
|
+
{ defaultIndex: 0 },
|
|
1181
|
+
);
|
|
1182
|
+
if (editMode?.value === "guided") {
|
|
1183
|
+
await editTelegramBotGuided(ui, parsed, selected, current, flags, deps);
|
|
922
1184
|
return;
|
|
923
1185
|
}
|
|
924
1186
|
while (true) {
|
|
@@ -942,16 +1204,7 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
942
1204
|
);
|
|
943
1205
|
if (!choice) return;
|
|
944
1206
|
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`);
|
|
1207
|
+
saveTelegramBotEdit(parsed, selected, current, deps);
|
|
955
1208
|
return;
|
|
956
1209
|
}
|
|
957
1210
|
if (choice.value === "server_bot_id") {
|
|
@@ -1029,7 +1282,13 @@ async function removeTelegramBot(ui, deps) {
|
|
|
1029
1282
|
const parsed = { ...state.parsed };
|
|
1030
1283
|
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select Telegram bot entry to remove");
|
|
1031
1284
|
if (!selected) return;
|
|
1032
|
-
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
|
+
})) {
|
|
1033
1292
|
process.stdout.write("Cancelled.\n");
|
|
1034
1293
|
return;
|
|
1035
1294
|
}
|
|
@@ -1105,7 +1364,23 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1105
1364
|
}
|
|
1106
1365
|
}
|
|
1107
1366
|
}
|
|
1108
|
-
|
|
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) {
|
|
1109
1384
|
process.stdout.write(
|
|
1110
1385
|
`${JSON.stringify({
|
|
1111
1386
|
ok: overallOK,
|
|
@@ -1361,9 +1636,7 @@ async function runBotVerify(ui, flags, deps) {
|
|
|
1361
1636
|
}
|
|
1362
1637
|
|
|
1363
1638
|
async function runBotSetDefault(ui, flags, deps) {
|
|
1364
|
-
const provider =
|
|
1365
|
-
? requireDependency(deps, "normalizeBotProvider")(flags.provider)
|
|
1366
|
-
: "telegram";
|
|
1639
|
+
const provider = await selectProvider(ui, flags.provider, deps);
|
|
1367
1640
|
if (provider !== "telegram") {
|
|
1368
1641
|
throw new Error("bot set-default currently supports only --provider telegram");
|
|
1369
1642
|
}
|
|
@@ -1376,6 +1649,16 @@ async function runBotSetDefault(ui, flags, deps) {
|
|
|
1376
1649
|
if (!selected) {
|
|
1377
1650
|
throw new Error("Telegram bot selector is required for set-default");
|
|
1378
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
|
+
}
|
|
1379
1662
|
parsed.TELEGRAM_DEFAULT_BOT_KEY = selected.key;
|
|
1380
1663
|
const filePath = writeProviderEnvState("telegram", parsed, deps);
|
|
1381
1664
|
process.stdout.write(`Set TELEGRAM_DEFAULT_BOT_KEY=${selected.key} in ${filePath}\n`);
|
|
@@ -1410,14 +1693,14 @@ async function runBotMigrate(ui, flags, deps) {
|
|
|
1410
1693
|
}
|
|
1411
1694
|
const nextParsed = upsertTelegramEntry(parsed, {
|
|
1412
1695
|
key: botKey,
|
|
1413
|
-
serverBotID:
|
|
1696
|
+
serverBotID: getServerBotIDFlag(flags),
|
|
1414
1697
|
username: requireDependency(deps, "normalizeTelegramBotUsername")(flags["bot-name"] || flags.username || ""),
|
|
1415
1698
|
token: legacyToken,
|
|
1416
1699
|
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
|
|
1700
|
+
client: requireDependency(deps, "normalizeLocalAIClientName")(getAIClientFlag(flags), ""),
|
|
1701
|
+
model: getAIModelFlag(flags),
|
|
1702
|
+
permissionMode: requireDependency(deps, "normalizeLocalAIPermissionMode")(getAIPermissionModeFlag(flags), ""),
|
|
1703
|
+
reasoningEffort: requireDependency(deps, "normalizeLocalAIReasoningEffort")(getAIReasoningEffortFlag(flags), ""),
|
|
1421
1704
|
});
|
|
1422
1705
|
if (!hasNamedTelegramEntry(parsed, deps) || !String(nextParsed.TELEGRAM_DEFAULT_BOT_KEY || "").trim()) {
|
|
1423
1706
|
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = botKey;
|
|
@@ -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
|
{
|
|
@@ -225,29 +264,36 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
225
264
|
cliPath,
|
|
226
265
|
args: [
|
|
227
266
|
"bot", "add",
|
|
228
|
-
"--provider", "telegram",
|
|
229
|
-
"--non-interactive", "true",
|
|
230
267
|
"--base-url", baseURL,
|
|
231
268
|
"--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
269
|
],
|
|
242
|
-
env
|
|
270
|
+
env: {
|
|
271
|
+
...env,
|
|
272
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
273
|
+
"1", // provider: telegram
|
|
274
|
+
"1", // server bot: first listed bot
|
|
275
|
+
"main_test",
|
|
276
|
+
"selftest-main-token",
|
|
277
|
+
"y", // verify now
|
|
278
|
+
"", // keep verified username
|
|
279
|
+
"3", // role profile: monitor
|
|
280
|
+
"2", // ai client: codex
|
|
281
|
+
"gpt-5-codex",
|
|
282
|
+
"2", // permission: read_only
|
|
283
|
+
"2", // reasoning: low
|
|
284
|
+
"y", // set as default
|
|
285
|
+
]),
|
|
286
|
+
},
|
|
243
287
|
});
|
|
244
288
|
const addState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
245
289
|
push(
|
|
246
|
-
"
|
|
290
|
+
"bot_add_guided_creates_named_telegram_entry",
|
|
247
291
|
String(addState.TELEGRAM_BOT_MAIN_TEST_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
292
|
+
&& String(addState.TELEGRAM_BOT_MAIN_TEST_USERNAME || "").trim().toLowerCase() === "monitorselftestbot"
|
|
248
293
|
&& String(addState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "") === "codex"
|
|
294
|
+
&& String(addState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "") === "gpt-5-codex"
|
|
249
295
|
&& 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 || "")}`,
|
|
296
|
+
`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
297
|
);
|
|
252
298
|
|
|
253
299
|
const showResult = await runCLI({
|
|
@@ -268,6 +314,43 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
268
314
|
`key=${String(safeObject(showPayload.entry).key || "")} client=${String(safeObject(showPayload.entry).client || "")}`,
|
|
269
315
|
);
|
|
270
316
|
|
|
317
|
+
await runCLI({
|
|
318
|
+
cliPath,
|
|
319
|
+
args: ["bot", "edit"],
|
|
320
|
+
env: {
|
|
321
|
+
...env,
|
|
322
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
323
|
+
"1", // provider: telegram
|
|
324
|
+
"1", // bot entry: main_test
|
|
325
|
+
"1", // edit mode: guided
|
|
326
|
+
"1", // keep server bot binding
|
|
327
|
+
"1", // keep username
|
|
328
|
+
"1", // keep token
|
|
329
|
+
"1", // keep role profile
|
|
330
|
+
"2", // change AI client
|
|
331
|
+
"4", // gemini
|
|
332
|
+
"2", // change AI model
|
|
333
|
+
"guided-gemini-pro",
|
|
334
|
+
"2", // change permission mode
|
|
335
|
+
"3", // workspace_write
|
|
336
|
+
"2", // change reasoning effort
|
|
337
|
+
"3", // medium
|
|
338
|
+
"1", // keep bot key
|
|
339
|
+
"1", // keep default setting
|
|
340
|
+
"y", // save
|
|
341
|
+
]),
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
const guidedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
345
|
+
push(
|
|
346
|
+
"bot_edit_guided_prompts_update_ai_binding_fields",
|
|
347
|
+
String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "") === "gemini"
|
|
348
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "") === "guided-gemini-pro"
|
|
349
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
350
|
+
&& String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_REASONING_EFFORT || "") === "medium",
|
|
351
|
+
`client=${String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")} model=${String(guidedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "")}`,
|
|
352
|
+
);
|
|
353
|
+
|
|
271
354
|
await runCLI({
|
|
272
355
|
cliPath,
|
|
273
356
|
args: [
|
|
@@ -294,6 +377,50 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
294
377
|
`client=${String(editedState.TELEGRAM_BOT_MAIN_TEST_AI_CLIENT || "")} model=${String(editedState.TELEGRAM_BOT_MAIN_TEST_AI_MODEL || "")}`,
|
|
295
378
|
);
|
|
296
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
|
+
|
|
297
424
|
await runCLI({
|
|
298
425
|
cliPath,
|
|
299
426
|
args: [
|
|
@@ -359,6 +486,82 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
359
486
|
`entries=${String(ensureArray(telegramEntry.entries).length)}`,
|
|
360
487
|
);
|
|
361
488
|
|
|
489
|
+
await runCLI({
|
|
490
|
+
cliPath,
|
|
491
|
+
args: [
|
|
492
|
+
"bot", "add",
|
|
493
|
+
"--provider", "telegram",
|
|
494
|
+
"--non-interactive", "true",
|
|
495
|
+
"--base-url", baseURL,
|
|
496
|
+
"--timeout-seconds", "5",
|
|
497
|
+
"--bot-key", "explicit_test",
|
|
498
|
+
"--server-bot-id", mock.bots[0].id,
|
|
499
|
+
"--username", "MonitorSelftestBot",
|
|
500
|
+
"--token", "selftest-main-token",
|
|
501
|
+
"--role-profile", "monitor",
|
|
502
|
+
"--ai-client", "codex",
|
|
503
|
+
"--ai-model", "gpt-5-codex",
|
|
504
|
+
"--ai-permission-mode", "read_only",
|
|
505
|
+
"--ai-reasoning-effort", "low",
|
|
506
|
+
"--verify", "true",
|
|
507
|
+
],
|
|
508
|
+
env,
|
|
509
|
+
});
|
|
510
|
+
const aliasAddState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
511
|
+
push(
|
|
512
|
+
"bot_add_accepts_ai_prefixed_option_aliases",
|
|
513
|
+
String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
514
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_CLIENT || "") === "codex"
|
|
515
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_MODEL || "") === "gpt-5-codex"
|
|
516
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_PERMISSION_MODE || "") === "read_only"
|
|
517
|
+
&& String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_REASONING_EFFORT || "") === "low",
|
|
518
|
+
`client=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_EXPLICIT_TEST_AI_MODEL || "")}`,
|
|
519
|
+
);
|
|
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
|
+
|
|
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({
|
|
548
|
+
cliPath,
|
|
549
|
+
args: [
|
|
550
|
+
"bot", "list",
|
|
551
|
+
"--provider", "telegram",
|
|
552
|
+
"--json", "true",
|
|
553
|
+
],
|
|
554
|
+
env,
|
|
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
|
+
);
|
|
564
|
+
|
|
362
565
|
const migratedEnv = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
363
566
|
migratedEnv.TELEGRAM_BOT_TOKEN = "legacy-selftest-token";
|
|
364
567
|
fs.writeFileSync(
|