metheus-governance-mcp-cli 0.2.77 → 0.2.79
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/lib/bot-commands.mjs +118 -52
- package/lib/selftest-bot-commands.mjs +12 -4
- package/package.json +1 -1
package/lib/bot-commands.mjs
CHANGED
|
@@ -711,22 +711,32 @@ async function editTelegramBotGuided(ui, parsed, selected, current, flags, deps)
|
|
|
711
711
|
let serverRoleAutoResolved = "";
|
|
712
712
|
let groupedServerRoles = [];
|
|
713
713
|
let groupedServerName = "";
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
714
|
+
let serverManagedIdentity = Boolean(current.serverBotID || current.__preferServerIdentity);
|
|
715
|
+
if (!serverManagedIdentity) {
|
|
716
|
+
const initialServerBot = await autoResolveTelegramServerBot(current, flags, deps);
|
|
717
|
+
if (String(initialServerBot.botID || "").trim() || initialServerBot.matchMode === "group") {
|
|
718
|
+
serverManagedIdentity = true;
|
|
719
|
+
}
|
|
717
720
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
defaultValue: current.username ? "keep" : "change",
|
|
722
|
-
});
|
|
723
|
-
if (usernameAction === "change") {
|
|
724
|
-
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(
|
|
725
|
-
await promptRequiredLine(ui, "Telegram username (without @)", current.username),
|
|
726
|
-
"",
|
|
727
|
-
);
|
|
728
|
-
} else if (usernameAction === "clear") {
|
|
721
|
+
let usernameAction = "keep";
|
|
722
|
+
if (serverManagedIdentity) {
|
|
723
|
+
current.__preferServerIdentity = true;
|
|
729
724
|
current.username = "";
|
|
725
|
+
serverRoleAutoResolved = String(current.roleProfile || "").trim() || "__server_binding__";
|
|
726
|
+
process.stdout.write("Telegram username is managed from server bot info and cannot be edited here.\n");
|
|
727
|
+
} else {
|
|
728
|
+
usernameAction = await promptKeepChangeClear(ui, "Telegram username", {
|
|
729
|
+
allowClear: true,
|
|
730
|
+
defaultValue: current.username ? "keep" : "change",
|
|
731
|
+
});
|
|
732
|
+
if (usernameAction === "change") {
|
|
733
|
+
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(
|
|
734
|
+
await promptRequiredLine(ui, "Telegram username (without @)", current.username),
|
|
735
|
+
"",
|
|
736
|
+
);
|
|
737
|
+
} else if (usernameAction === "clear") {
|
|
738
|
+
current.username = "";
|
|
739
|
+
}
|
|
730
740
|
}
|
|
731
741
|
|
|
732
742
|
const tokenAction = await promptKeepChangeClear(ui, "Telegram token", {
|
|
@@ -1113,19 +1123,16 @@ function printBotShow(provider, state, entry, deps, extras = {}) {
|
|
|
1113
1123
|
process.stdout.write(` token: ${token ? maskSecret(token) : "(not configured)"}\n`);
|
|
1114
1124
|
}
|
|
1115
1125
|
|
|
1116
|
-
async function chooseTelegramEntry(ui, parsedEnv, deps, title = "Select Telegram bot entry") {
|
|
1126
|
+
async function chooseTelegramEntry(ui, parsedEnv, deps, title = "Select Telegram bot entry", flags = {}) {
|
|
1117
1127
|
const entries = telegramEntriesForDisplay(parsedEnv, deps);
|
|
1118
1128
|
if (!entries.length) {
|
|
1119
1129
|
throw new Error("no Telegram bot entries are configured");
|
|
1120
1130
|
}
|
|
1131
|
+
const displayRows = await buildTelegramEntrySelectionRows(entries, flags, deps);
|
|
1121
1132
|
const selected = await promptChoice(
|
|
1122
1133
|
ui,
|
|
1123
1134
|
title,
|
|
1124
|
-
|
|
1125
|
-
value: entry.key,
|
|
1126
|
-
label: `${telegramEntryDisplayName(entry)}${entry.isDefault ? " [default]" : ""}`,
|
|
1127
|
-
description: telegramEntryDisplayDescription(entry),
|
|
1128
|
-
})),
|
|
1135
|
+
displayRows,
|
|
1129
1136
|
{ defaultIndex: 0 },
|
|
1130
1137
|
);
|
|
1131
1138
|
return entries.find((entry) => entry.key === selected.value) || entries[0];
|
|
@@ -1154,7 +1161,7 @@ async function resolveTelegramEntryForShow(ui, parsedEnv, flags, deps) {
|
|
|
1154
1161
|
if (nonInteractive) {
|
|
1155
1162
|
throw new Error("Telegram bot selector is required when multiple entries exist; pass --bot-key, --bot-id, or --bot-name");
|
|
1156
1163
|
}
|
|
1157
|
-
return chooseTelegramEntry(ui, parsedEnv, deps, "Select Telegram bot entry");
|
|
1164
|
+
return chooseTelegramEntry(ui, parsedEnv, deps, "Select Telegram bot entry", flags);
|
|
1158
1165
|
}
|
|
1159
1166
|
|
|
1160
1167
|
async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps, options = {}) {
|
|
@@ -1715,34 +1722,11 @@ async function maybePromptGroupedServerRoleProfiles(ui, serverBot, deps) {
|
|
|
1715
1722
|
return true;
|
|
1716
1723
|
}
|
|
1717
1724
|
|
|
1718
|
-
|
|
1725
|
+
function resolveTelegramServerBindingDetailsFromBots(envConfig, bots, deps) {
|
|
1719
1726
|
const current = safeObject(envConfig);
|
|
1720
1727
|
if (!String(current.serverBotID || "").trim() && !String(current.botUsername || "").trim() && !String(current.botKey || "").trim()) {
|
|
1721
1728
|
return null;
|
|
1722
1729
|
}
|
|
1723
|
-
const lookup = await requireDependency(deps, "listServerBots")({
|
|
1724
|
-
provider: "telegram",
|
|
1725
|
-
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
1726
|
-
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1727
|
-
});
|
|
1728
|
-
if (!lookup?.ok) {
|
|
1729
|
-
return {
|
|
1730
|
-
ok: false,
|
|
1731
|
-
mode: "lookup_error",
|
|
1732
|
-
matchedBy: "",
|
|
1733
|
-
name: "",
|
|
1734
|
-
role: "",
|
|
1735
|
-
roles: [],
|
|
1736
|
-
effectiveRoleProfile: null,
|
|
1737
|
-
effectiveRoleProfiles: {},
|
|
1738
|
-
detail: `server bot lookup unavailable: ${lookup?.error || "unknown error"}`,
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
const bots = ensureArray(lookup.bots).map((bot) => ({
|
|
1742
|
-
id: String(bot?.id || "").trim(),
|
|
1743
|
-
role: String(bot?.role || bot?.bot_role || "").trim(),
|
|
1744
|
-
name: String(bot?.name || "").trim(),
|
|
1745
|
-
})).filter((bot) => bot.id);
|
|
1746
1730
|
const resolveGroupedPayload = (matches, matchedBy) => {
|
|
1747
1731
|
const roles = preferredRoleSort(summarizeServerBotRoles(matches));
|
|
1748
1732
|
return {
|
|
@@ -1827,6 +1811,88 @@ async function resolveTelegramServerBindingDetails(envConfig, flags, deps) {
|
|
|
1827
1811
|
};
|
|
1828
1812
|
}
|
|
1829
1813
|
|
|
1814
|
+
async function resolveTelegramServerBindingDetails(envConfig, flags, deps) {
|
|
1815
|
+
const lookup = await requireDependency(deps, "listServerBots")({
|
|
1816
|
+
provider: "telegram",
|
|
1817
|
+
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
1818
|
+
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1819
|
+
});
|
|
1820
|
+
if (!lookup?.ok) {
|
|
1821
|
+
return {
|
|
1822
|
+
ok: false,
|
|
1823
|
+
mode: "lookup_error",
|
|
1824
|
+
matchedBy: "",
|
|
1825
|
+
name: "",
|
|
1826
|
+
role: "",
|
|
1827
|
+
roles: [],
|
|
1828
|
+
effectiveRoleProfile: null,
|
|
1829
|
+
effectiveRoleProfiles: {},
|
|
1830
|
+
detail: `server bot lookup unavailable: ${lookup?.error || "unknown error"}`,
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
const bots = ensureArray(lookup.bots).map((bot) => ({
|
|
1834
|
+
id: String(bot?.id || "").trim(),
|
|
1835
|
+
role: String(bot?.role || bot?.bot_role || "").trim(),
|
|
1836
|
+
name: String(bot?.name || "").trim(),
|
|
1837
|
+
})).filter((bot) => bot.id);
|
|
1838
|
+
return resolveTelegramServerBindingDetailsFromBots(envConfig, bots, deps);
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
async function buildTelegramEntrySelectionRows(entries, flags, deps) {
|
|
1842
|
+
const listServerBots = requireDependency(deps, "listServerBots");
|
|
1843
|
+
let bots = [];
|
|
1844
|
+
try {
|
|
1845
|
+
const lookup = await listServerBots({
|
|
1846
|
+
provider: "telegram",
|
|
1847
|
+
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
1848
|
+
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1849
|
+
});
|
|
1850
|
+
bots = ensureArray(lookup?.bots).map((bot) => ({
|
|
1851
|
+
id: String(bot?.id || "").trim(),
|
|
1852
|
+
role: String(bot?.role || bot?.bot_role || "").trim(),
|
|
1853
|
+
name: String(bot?.name || "").trim(),
|
|
1854
|
+
})).filter((bot) => bot.id);
|
|
1855
|
+
} catch {
|
|
1856
|
+
bots = [];
|
|
1857
|
+
}
|
|
1858
|
+
return ensureArray(entries).map((entry) => {
|
|
1859
|
+
const current = safeObject(entry);
|
|
1860
|
+
const binding = bots.length
|
|
1861
|
+
? resolveTelegramServerBindingDetailsFromBots(
|
|
1862
|
+
{
|
|
1863
|
+
serverBotID: current.serverBotID,
|
|
1864
|
+
botUsername: current.username,
|
|
1865
|
+
botKey: current.key,
|
|
1866
|
+
roleProfile: current.roleProfile,
|
|
1867
|
+
},
|
|
1868
|
+
bots,
|
|
1869
|
+
deps,
|
|
1870
|
+
)
|
|
1871
|
+
: null;
|
|
1872
|
+
const serverName = String(binding?.name || "").trim();
|
|
1873
|
+
const singleRole = String(binding?.role || "").trim();
|
|
1874
|
+
const groupedRoles = ensureArray(binding?.roles).filter(Boolean);
|
|
1875
|
+
let label = telegramEntryDisplayName(entry);
|
|
1876
|
+
if (serverName && singleRole) {
|
|
1877
|
+
label = `${serverName} [${singleRole}]`;
|
|
1878
|
+
} else if (serverName && groupedRoles.length) {
|
|
1879
|
+
label = `${serverName} [${groupedRoles.join(", ")}]`;
|
|
1880
|
+
} else if (serverName) {
|
|
1881
|
+
label = serverName;
|
|
1882
|
+
}
|
|
1883
|
+
const descriptionParts = [
|
|
1884
|
+
current.key ? `local:${current.key}` : "",
|
|
1885
|
+
current.serverBotID ? `server:${current.serverBotID}` : "",
|
|
1886
|
+
current.client ? `AI:${current.client}` : "",
|
|
1887
|
+
].filter(Boolean);
|
|
1888
|
+
return {
|
|
1889
|
+
value: current.key,
|
|
1890
|
+
label: `${label}${current.isDefault ? " [default]" : ""}`,
|
|
1891
|
+
description: descriptionParts.join(" "),
|
|
1892
|
+
};
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1830
1896
|
function buildTemporaryTelegramEnvConfig({ token, apiBaseURL }) {
|
|
1831
1897
|
return {
|
|
1832
1898
|
ok: true,
|
|
@@ -2115,7 +2181,7 @@ async function editTelegramGlobalSettings(ui, flags, deps) {
|
|
|
2115
2181
|
process.stdout.write("No Telegram bot entries exist yet.\n");
|
|
2116
2182
|
return;
|
|
2117
2183
|
}
|
|
2118
|
-
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select default Telegram bot");
|
|
2184
|
+
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select default Telegram bot", flags);
|
|
2119
2185
|
parsed.TELEGRAM_DEFAULT_BOT_KEY = selected.key;
|
|
2120
2186
|
}
|
|
2121
2187
|
const filePath = writeProviderEnvState("telegram", parsed, deps);
|
|
@@ -2128,7 +2194,7 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
2128
2194
|
const nonInteractive = boolFromRaw(flags["non-interactive"] ?? flags.yes, false);
|
|
2129
2195
|
const selected = nonInteractive
|
|
2130
2196
|
? findTelegramEntryByFlags(parsed, flags, deps)
|
|
2131
|
-
: await chooseTelegramEntry(ui, parsed, deps);
|
|
2197
|
+
: await chooseTelegramEntry(ui, parsed, deps, "Select Telegram bot entry", flags);
|
|
2132
2198
|
if (!selected) {
|
|
2133
2199
|
throw new Error("Telegram bot selector is required for non-interactive edit");
|
|
2134
2200
|
}
|
|
@@ -2168,10 +2234,10 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
2168
2234
|
await editTelegramBotGuided(ui, parsed, selected, current, flags, deps);
|
|
2169
2235
|
}
|
|
2170
2236
|
|
|
2171
|
-
async function removeTelegramBot(ui, deps) {
|
|
2237
|
+
async function removeTelegramBot(ui, flags, deps) {
|
|
2172
2238
|
const state = loadProviderEnvState("telegram", deps);
|
|
2173
2239
|
const parsed = { ...state.parsed };
|
|
2174
|
-
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select Telegram bot entry to remove");
|
|
2240
|
+
const selected = await chooseTelegramEntry(ui, parsed, deps, "Select Telegram bot entry to remove", flags);
|
|
2175
2241
|
if (!selected) return;
|
|
2176
2242
|
if (!await promptConfirmChoice(ui, `Remove Telegram bot "${selected.key}"?`, {
|
|
2177
2243
|
confirmLabel: "Remove bot",
|
|
@@ -2206,7 +2272,7 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
2206
2272
|
botName: requestedBotName,
|
|
2207
2273
|
};
|
|
2208
2274
|
} else {
|
|
2209
|
-
const selected = await chooseTelegramEntry(ui, state.parsed, deps, "Select Telegram bot entry to verify");
|
|
2275
|
+
const selected = await chooseTelegramEntry(ui, state.parsed, deps, "Select Telegram bot entry to verify", flags);
|
|
2210
2276
|
selectors = {
|
|
2211
2277
|
botKey: selected.key,
|
|
2212
2278
|
botID: selected.serverBotID,
|
|
@@ -2546,7 +2612,7 @@ async function runBotRemove(ui, flags, deps) {
|
|
|
2546
2612
|
process.stdout.write(`Removed Telegram bot "${selected.key}" from ${filePath}\n`);
|
|
2547
2613
|
return;
|
|
2548
2614
|
}
|
|
2549
|
-
await removeTelegramBot(ui, deps);
|
|
2615
|
+
await removeTelegramBot(ui, flags, deps);
|
|
2550
2616
|
return;
|
|
2551
2617
|
}
|
|
2552
2618
|
await removeTokenOnlyProvider(ui, provider, flags, deps);
|
|
@@ -2573,7 +2639,7 @@ async function runBotSetDefault(ui, flags, deps) {
|
|
|
2573
2639
|
const nonInteractive = boolFromRaw(flags["non-interactive"] ?? flags.yes, false);
|
|
2574
2640
|
const selected = nonInteractive
|
|
2575
2641
|
? findTelegramEntryByFlags(parsed, flags, deps)
|
|
2576
|
-
: await chooseTelegramEntry(ui, parsed, deps, "Select default Telegram bot");
|
|
2642
|
+
: await chooseTelegramEntry(ui, parsed, deps, "Select default Telegram bot", flags);
|
|
2577
2643
|
if (!selected) {
|
|
2578
2644
|
throw new Error("Telegram bot selector is required for set-default");
|
|
2579
2645
|
}
|
|
@@ -347,7 +347,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
347
347
|
`username=${String(groupedState.TELEGRAM_BOT_RYOAI_BOT_USERNAME || "")} server_bot_id=${String(groupedState.TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID || "")} role=${String(groupedState.TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE || "")}`,
|
|
348
348
|
);
|
|
349
349
|
|
|
350
|
-
await runCLI({
|
|
350
|
+
const groupedEditResult = await runCLI({
|
|
351
351
|
cliPath,
|
|
352
352
|
args: [
|
|
353
353
|
"bot", "edit",
|
|
@@ -359,7 +359,6 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
359
359
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
360
360
|
"1", // provider: telegram
|
|
361
361
|
"2", // bot entry: ryoai_bot
|
|
362
|
-
"1", // keep username
|
|
363
362
|
"1", // keep token
|
|
364
363
|
"2", // grouped role settings: edit one role
|
|
365
364
|
"3", // select role to edit: worker
|
|
@@ -381,6 +380,11 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
381
380
|
]),
|
|
382
381
|
},
|
|
383
382
|
});
|
|
383
|
+
push(
|
|
384
|
+
"bot_edit_grouped_server_roles_skips_local_username_prompt",
|
|
385
|
+
!String(groupedEditResult.stdout || "").includes("Telegram username (without @)"),
|
|
386
|
+
String(groupedEditResult.stdout || "").split(/\r?\n/).filter((line) => line.includes("Telegram username")).join(" | ") || "username prompt skipped",
|
|
387
|
+
);
|
|
384
388
|
const groupedRunnerConfigPath = path.join(tempHome, ".metheus", "bot-runner.json");
|
|
385
389
|
const groupedRunnerConfig = readJSON(fs.readFileSync(groupedRunnerConfigPath, "utf8"));
|
|
386
390
|
push(
|
|
@@ -487,7 +491,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
487
491
|
`routes=${JSON.stringify(safeObject(showWithRoutesPayload.routeLinks))}`,
|
|
488
492
|
);
|
|
489
493
|
|
|
490
|
-
await runCLI({
|
|
494
|
+
const guidedEditResult = await runCLI({
|
|
491
495
|
cliPath,
|
|
492
496
|
args: ["bot", "edit"],
|
|
493
497
|
env: {
|
|
@@ -495,7 +499,6 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
495
499
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
496
500
|
"1", // provider: telegram
|
|
497
501
|
"1", // bot entry: @monitorselftestbot
|
|
498
|
-
"1", // keep username
|
|
499
502
|
"1", // keep token
|
|
500
503
|
"2", // change AI client
|
|
501
504
|
"4", // gemini
|
|
@@ -510,6 +513,11 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
510
513
|
]),
|
|
511
514
|
},
|
|
512
515
|
});
|
|
516
|
+
push(
|
|
517
|
+
"bot_edit_single_server_binding_skips_local_username_prompt",
|
|
518
|
+
!String(guidedEditResult.stdout || "").includes("Telegram username (without @)"),
|
|
519
|
+
String(guidedEditResult.stdout || "").split(/\r?\n/).filter((line) => line.includes("Telegram username")).join(" | ") || "username prompt skipped",
|
|
520
|
+
);
|
|
513
521
|
const guidedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
514
522
|
push(
|
|
515
523
|
"bot_edit_guided_prompts_update_ai_binding_fields",
|