metheus-governance-mcp-cli 0.2.72 → 0.2.73
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 +5 -3
- package/lib/bot-commands.mjs +256 -71
- package/lib/selftest-bot-commands.mjs +33 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -247,8 +247,8 @@ Behavior:
|
|
|
247
247
|
- `AI_PERMISSION_MODE`
|
|
248
248
|
- `AI_REASONING_EFFORT`
|
|
249
249
|
- Slack and KakaoTalk currently use a single local token entry per provider in this command flow.
|
|
250
|
-
- `bot verify` checks the configured local token and prints the
|
|
251
|
-
- `bot show` prints one local bot entry in detail.
|
|
250
|
+
- `bot verify` checks the configured local token, cross-checks the server bot binding, and prints the effective runtime role profile summary that the runner will use.
|
|
251
|
+
- `bot show` prints one local bot entry in detail, including grouped role summaries when one server bot name expands to multiple roles.
|
|
252
252
|
- `bot global` edits Telegram-wide local settings such as API base URL, allowed updates, and default bot key.
|
|
253
253
|
- `bot set-default` updates `TELEGRAM_DEFAULT_BOT_KEY`.
|
|
254
254
|
- `bot migrate` moves legacy `TELEGRAM_BOT_TOKEN` into a named Telegram bot entry.
|
|
@@ -259,7 +259,7 @@ Non-interactive examples:
|
|
|
259
259
|
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
|
|
260
260
|
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --default true
|
|
261
261
|
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --ai-client codex --ai-model gpt-5-codex --ai-permission-mode read_only --ai-reasoning-effort low
|
|
262
|
-
metheus-governance-mcp-cli bot edit --provider telegram --bot-key
|
|
262
|
+
metheus-governance-mcp-cli bot edit --provider telegram --bot-key ryoai_bot --non-interactive true --ai-client claude --ai-model claude-sonnet-4 --ai-permission-mode danger_full_access --ai-reasoning-effort high
|
|
263
263
|
metheus-governance-mcp-cli bot set-default --provider telegram --bot-key main --non-interactive true
|
|
264
264
|
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
|
|
265
265
|
metheus-governance-mcp-cli bot remove --provider telegram --bot-key main --non-interactive true
|
|
@@ -268,6 +268,8 @@ metheus-governance-mcp-cli bot verify --provider telegram --bot-key main --json
|
|
|
268
268
|
|
|
269
269
|
For direct Telegram adds, the CLI can derive the local entry key from the matched server bot name. You no longer need `--bot-key` or `--username` in the normal server-bound path. Treat `--bot-key` as an advanced override only when you intentionally want a different local suffix.
|
|
270
270
|
|
|
271
|
+
For direct Telegram edits, `--bot-key` still identifies which saved local entry to update. If one server bot name expands to multiple roles such as `approval / worker / review / monitor`, prefer the guided `bot edit` flow so you can keep the current grouped settings, edit one role only, or walk every role in sequence instead of forcing one entry-level AI override.
|
|
272
|
+
|
|
271
273
|
Current support status:
|
|
272
274
|
|
|
273
275
|
- Telegram: full local bot entry management, token verification, bot-to-AI binding, inbound runner support
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -809,6 +809,16 @@ function renderBotListPayload(provider, state, deps) {
|
|
|
809
809
|
};
|
|
810
810
|
}
|
|
811
811
|
|
|
812
|
+
function formatRoleProfileOutputLine(profile) {
|
|
813
|
+
const current = safeObject(profile);
|
|
814
|
+
return [
|
|
815
|
+
current.client ? `client=${current.client}` : "client=(blank)",
|
|
816
|
+
current.model ? `model=${current.model}` : "model=(blank)",
|
|
817
|
+
current.permissionMode ? `permission=${current.permissionMode}` : "permission=(blank)",
|
|
818
|
+
current.reasoningEffort ? `reasoning=${current.reasoningEffort}` : "reasoning=(blank)",
|
|
819
|
+
].join(" | ");
|
|
820
|
+
}
|
|
821
|
+
|
|
812
822
|
function buildBotShowPayload(provider, state, entry, deps, extras = {}) {
|
|
813
823
|
if (provider === "telegram") {
|
|
814
824
|
const selectedEntry = entry || null;
|
|
@@ -829,6 +839,7 @@ function buildBotShowPayload(provider, state, entry, deps, extras = {}) {
|
|
|
829
839
|
permissionMode: selectedEntry.permissionMode,
|
|
830
840
|
reasoningEffort: selectedEntry.reasoningEffort,
|
|
831
841
|
} : null,
|
|
842
|
+
serverBinding: safeObject(extras.serverBinding),
|
|
832
843
|
...safeObject(extras),
|
|
833
844
|
};
|
|
834
845
|
}
|
|
@@ -883,6 +894,7 @@ function printBotList(provider, state, deps) {
|
|
|
883
894
|
function printBotShow(provider, state, entry, deps, extras = {}) {
|
|
884
895
|
if (provider === "telegram") {
|
|
885
896
|
const selectedEntry = entry || {};
|
|
897
|
+
const serverBinding = safeObject(extras.serverBinding);
|
|
886
898
|
process.stdout.write(`${providerLabel(provider, deps)} bot\n`);
|
|
887
899
|
process.stdout.write(` file: ${state.filePath}\n`);
|
|
888
900
|
process.stdout.write(` name: ${telegramEntryDisplayName(selectedEntry)}\n`);
|
|
@@ -896,8 +908,21 @@ function printBotShow(provider, state, entry, deps, extras = {}) {
|
|
|
896
908
|
process.stdout.write(` ai_model: ${selectedEntry.model || "-"}\n`);
|
|
897
909
|
process.stdout.write(` permission_mode: ${selectedEntry.permissionMode || "-"}\n`);
|
|
898
910
|
process.stdout.write(` reasoning_effort: ${selectedEntry.reasoningEffort || "-"}\n`);
|
|
899
|
-
if (
|
|
900
|
-
process.stdout.write(` server_binding: ${
|
|
911
|
+
if (Object.keys(serverBinding).length) {
|
|
912
|
+
process.stdout.write(` server_binding: ${serverBinding.ok ? "OK" : "FAIL"}${serverBinding.detail ? ` (${serverBinding.detail})` : ""}\n`);
|
|
913
|
+
process.stdout.write(` server_binding_mode: ${serverBinding.mode || "-"}\n`);
|
|
914
|
+
process.stdout.write(` server_bot_name: ${serverBinding.name || "-"}\n`);
|
|
915
|
+
process.stdout.write(` server_bot_id: ${serverBinding.serverBotID || selectedEntry.serverBotID || "-" }\n`);
|
|
916
|
+
if (serverBinding.mode === "group") {
|
|
917
|
+
process.stdout.write(` server_roles: ${ensureArray(serverBinding.roles).join(", ") || "-"}\n`);
|
|
918
|
+
const groupedProfiles = safeObject(serverBinding.effectiveRoleProfiles);
|
|
919
|
+
Object.keys(groupedProfiles).forEach((role) => {
|
|
920
|
+
process.stdout.write(` runtime_role_profile[${role}]: ${formatRoleProfileOutputLine(groupedProfiles[role])}\n`);
|
|
921
|
+
});
|
|
922
|
+
} else if (serverBinding.effectiveRoleProfile) {
|
|
923
|
+
process.stdout.write(` server_role: ${serverBinding.role || "-"}\n`);
|
|
924
|
+
process.stdout.write(` runtime_role_profile: ${formatRoleProfileOutputLine(serverBinding.effectiveRoleProfile)}\n`);
|
|
925
|
+
}
|
|
901
926
|
}
|
|
902
927
|
return;
|
|
903
928
|
}
|
|
@@ -1348,6 +1373,31 @@ function formatRoleProfileSummary(profile) {
|
|
|
1348
1373
|
].join(" | ");
|
|
1349
1374
|
}
|
|
1350
1375
|
|
|
1376
|
+
function serializeRoleProfile(profile) {
|
|
1377
|
+
const current = safeObject(profile);
|
|
1378
|
+
return {
|
|
1379
|
+
role: String(current.role || "").trim(),
|
|
1380
|
+
client: String(current.client || "").trim(),
|
|
1381
|
+
model: String(current.model || "").trim(),
|
|
1382
|
+
permissionMode: String(current.permissionMode || "").trim(),
|
|
1383
|
+
reasoningEffort: String(current.reasoningEffort || "").trim(),
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
function buildRoleProfileOutput(roleName, deps) {
|
|
1388
|
+
return serializeRoleProfile(currentRoleProfileState(roleName, deps));
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
function buildGroupedRoleProfileOutput(roles, deps) {
|
|
1392
|
+
const output = {};
|
|
1393
|
+
preferredRoleSort(roles).forEach((role) => {
|
|
1394
|
+
const normalizedRole = String(role || "").trim();
|
|
1395
|
+
if (!normalizedRole) return;
|
|
1396
|
+
output[normalizedRole] = buildRoleProfileOutput(normalizedRole, deps);
|
|
1397
|
+
});
|
|
1398
|
+
return output;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1351
1401
|
function persistRoleProfileState(profile, deps) {
|
|
1352
1402
|
const current = safeObject(profile);
|
|
1353
1403
|
const role = requireDependency(deps, "normalizeRunnerRoleProfileName")(current.role || "");
|
|
@@ -1416,9 +1466,13 @@ async function maybePromptGroupedServerRoleProfiles(ui, serverBot, deps) {
|
|
|
1416
1466
|
if (roles.length <= 1) {
|
|
1417
1467
|
return false;
|
|
1418
1468
|
}
|
|
1469
|
+
process.stdout.write(`Current grouped role execution profiles for "${String(serverBot?.name || "").trim() || "telegram"}":\n`);
|
|
1470
|
+
roles.forEach((role) => {
|
|
1471
|
+
process.stdout.write(` - ${role}: ${formatRoleProfileSummary(currentRoleProfileState(role, deps))}\n`);
|
|
1472
|
+
});
|
|
1419
1473
|
const editChoice = await promptChoice(
|
|
1420
1474
|
ui,
|
|
1421
|
-
|
|
1475
|
+
"Grouped role settings",
|
|
1422
1476
|
[
|
|
1423
1477
|
{
|
|
1424
1478
|
value: "keep",
|
|
@@ -1426,22 +1480,173 @@ async function maybePromptGroupedServerRoleProfiles(ui, serverBot, deps) {
|
|
|
1426
1480
|
description: "use the existing role_profiles defaults as-is",
|
|
1427
1481
|
},
|
|
1428
1482
|
{
|
|
1429
|
-
value: "
|
|
1430
|
-
label: "
|
|
1431
|
-
description: "
|
|
1483
|
+
value: "one",
|
|
1484
|
+
label: "Edit one role",
|
|
1485
|
+
description: "change only the role that needs an update",
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
value: "all",
|
|
1489
|
+
label: "Edit all roles",
|
|
1490
|
+
description: "review each role in sequence",
|
|
1432
1491
|
},
|
|
1433
1492
|
],
|
|
1434
1493
|
{ defaultIndex: 0 },
|
|
1435
1494
|
);
|
|
1436
|
-
if (editChoice?.value
|
|
1495
|
+
if (editChoice?.value === "keep") {
|
|
1437
1496
|
return false;
|
|
1438
1497
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1498
|
+
if (editChoice?.value === "all") {
|
|
1499
|
+
for (const role of roles) {
|
|
1500
|
+
await promptRoleExecutionProfile(ui, role, deps);
|
|
1501
|
+
}
|
|
1502
|
+
return true;
|
|
1503
|
+
}
|
|
1504
|
+
const remaining = new Set(roles);
|
|
1505
|
+
while (remaining.size) {
|
|
1506
|
+
const roleChoice = await promptChoice(
|
|
1507
|
+
ui,
|
|
1508
|
+
"Select role to edit",
|
|
1509
|
+
[
|
|
1510
|
+
...Array.from(remaining).map((role) => ({
|
|
1511
|
+
value: role,
|
|
1512
|
+
label: role,
|
|
1513
|
+
description: formatRoleProfileSummary(currentRoleProfileState(role, deps)),
|
|
1514
|
+
})),
|
|
1515
|
+
{
|
|
1516
|
+
value: "__done__",
|
|
1517
|
+
label: "Done",
|
|
1518
|
+
description: "finish grouped role editing",
|
|
1519
|
+
},
|
|
1520
|
+
],
|
|
1521
|
+
{ defaultIndex: 0 },
|
|
1522
|
+
);
|
|
1523
|
+
if (!roleChoice || roleChoice.value === "__done__") {
|
|
1524
|
+
break;
|
|
1525
|
+
}
|
|
1526
|
+
await promptRoleExecutionProfile(ui, roleChoice.value, deps);
|
|
1527
|
+
remaining.delete(roleChoice.value);
|
|
1528
|
+
if (!remaining.size) {
|
|
1529
|
+
break;
|
|
1530
|
+
}
|
|
1531
|
+
if (!await promptYesNo(ui, "Edit another role?", false)) {
|
|
1532
|
+
break;
|
|
1533
|
+
}
|
|
1441
1534
|
}
|
|
1442
1535
|
return true;
|
|
1443
1536
|
}
|
|
1444
1537
|
|
|
1538
|
+
async function resolveTelegramServerBindingDetails(envConfig, flags, deps) {
|
|
1539
|
+
const current = safeObject(envConfig);
|
|
1540
|
+
if (!String(current.serverBotID || "").trim() && !String(current.botUsername || "").trim() && !String(current.botKey || "").trim()) {
|
|
1541
|
+
return null;
|
|
1542
|
+
}
|
|
1543
|
+
const lookup = await requireDependency(deps, "listServerBots")({
|
|
1544
|
+
provider: "telegram",
|
|
1545
|
+
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
1546
|
+
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1547
|
+
});
|
|
1548
|
+
if (!lookup?.ok) {
|
|
1549
|
+
return {
|
|
1550
|
+
ok: false,
|
|
1551
|
+
mode: "lookup_error",
|
|
1552
|
+
matchedBy: "",
|
|
1553
|
+
name: "",
|
|
1554
|
+
role: "",
|
|
1555
|
+
roles: [],
|
|
1556
|
+
effectiveRoleProfile: null,
|
|
1557
|
+
effectiveRoleProfiles: {},
|
|
1558
|
+
detail: `server bot lookup unavailable: ${lookup?.error || "unknown error"}`,
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
const bots = ensureArray(lookup.bots).map((bot) => ({
|
|
1562
|
+
id: String(bot?.id || "").trim(),
|
|
1563
|
+
role: String(bot?.role || bot?.bot_role || "").trim(),
|
|
1564
|
+
name: String(bot?.name || "").trim(),
|
|
1565
|
+
})).filter((bot) => bot.id);
|
|
1566
|
+
const resolveGroupedPayload = (matches, matchedBy) => {
|
|
1567
|
+
const roles = preferredRoleSort(summarizeServerBotRoles(matches));
|
|
1568
|
+
return {
|
|
1569
|
+
ok: true,
|
|
1570
|
+
mode: "group",
|
|
1571
|
+
matchedBy,
|
|
1572
|
+
name: String(matches[0]?.name || "").trim(),
|
|
1573
|
+
role: "",
|
|
1574
|
+
roles,
|
|
1575
|
+
serverBotID: String(current.serverBotID || "").trim(),
|
|
1576
|
+
effectiveRoleProfile: null,
|
|
1577
|
+
effectiveRoleProfiles: buildGroupedRoleProfileOutput(roles, deps),
|
|
1578
|
+
detail: `${String(matches[0]?.name || "").trim() || "(unnamed)"} roles: ${roles.join(", ") || "-"}`,
|
|
1579
|
+
};
|
|
1580
|
+
};
|
|
1581
|
+
if (String(current.serverBotID || "").trim()) {
|
|
1582
|
+
const match = bots.find((bot) => bot.id === String(current.serverBotID || "").trim());
|
|
1583
|
+
if (!match) {
|
|
1584
|
+
return {
|
|
1585
|
+
ok: false,
|
|
1586
|
+
mode: "missing",
|
|
1587
|
+
matchedBy: "server_bot_id",
|
|
1588
|
+
name: "",
|
|
1589
|
+
role: "",
|
|
1590
|
+
roles: [],
|
|
1591
|
+
serverBotID: String(current.serverBotID || "").trim(),
|
|
1592
|
+
effectiveRoleProfile: null,
|
|
1593
|
+
effectiveRoleProfiles: {},
|
|
1594
|
+
detail: `server bot ${current.serverBotID} not found`,
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
const sameNameMatches = bots.filter((bot) => normalizeServerBotIdentityText(bot.name) === normalizeServerBotIdentityText(match.name));
|
|
1598
|
+
if (sameNameMatches.length > 1) {
|
|
1599
|
+
return resolveGroupedPayload(sameNameMatches, "server_bot_id");
|
|
1600
|
+
}
|
|
1601
|
+
const effectiveRoleProfile = buildRoleProfileOutput(match.role || current.roleProfile || "", deps);
|
|
1602
|
+
return {
|
|
1603
|
+
ok: true,
|
|
1604
|
+
mode: "single",
|
|
1605
|
+
matchedBy: "server_bot_id",
|
|
1606
|
+
name: match.name,
|
|
1607
|
+
role: match.role,
|
|
1608
|
+
roles: summarizeServerBotRoles([match]),
|
|
1609
|
+
serverBotID: match.id,
|
|
1610
|
+
effectiveRoleProfile,
|
|
1611
|
+
effectiveRoleProfiles: {},
|
|
1612
|
+
detail: `${String(match.name || "").trim() || "(unnamed)"} [${String(match.role || "").trim() || "-"}]`,
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
const normalizedServerIdentity = normalizeServerBotIdentityText(current.botUsername || current.botKey);
|
|
1616
|
+
const matches = bots.filter((bot) => normalizeServerBotIdentityText(bot.name) === normalizedServerIdentity);
|
|
1617
|
+
if (!matches.length) {
|
|
1618
|
+
return {
|
|
1619
|
+
ok: false,
|
|
1620
|
+
mode: "missing",
|
|
1621
|
+
matchedBy: "server_bot_name",
|
|
1622
|
+
name: "",
|
|
1623
|
+
role: "",
|
|
1624
|
+
roles: [],
|
|
1625
|
+
serverBotID: "",
|
|
1626
|
+
effectiveRoleProfile: null,
|
|
1627
|
+
effectiveRoleProfiles: {},
|
|
1628
|
+
detail: `no server bot matched ${current.botUsername ? `@${current.botUsername}` : current.botKey}`,
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
if (matches.length > 1) {
|
|
1632
|
+
return resolveGroupedPayload(matches, "server_bot_name");
|
|
1633
|
+
}
|
|
1634
|
+
const match = matches[0] || {};
|
|
1635
|
+
const effectiveRoleProfile = buildRoleProfileOutput(match.role || current.roleProfile || "", deps);
|
|
1636
|
+
return {
|
|
1637
|
+
ok: true,
|
|
1638
|
+
mode: "single",
|
|
1639
|
+
matchedBy: "server_bot_name",
|
|
1640
|
+
name: String(match.name || "").trim(),
|
|
1641
|
+
role: String(match.role || "").trim(),
|
|
1642
|
+
roles: summarizeServerBotRoles([match]),
|
|
1643
|
+
serverBotID: String(match.id || "").trim(),
|
|
1644
|
+
effectiveRoleProfile,
|
|
1645
|
+
effectiveRoleProfiles: {},
|
|
1646
|
+
detail: `${String(match.name || "").trim() || "(unnamed)"} [${String(match.role || "").trim() || "-"}]`,
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1445
1650
|
function buildTemporaryTelegramEnvConfig({ token, apiBaseURL }) {
|
|
1446
1651
|
return {
|
|
1447
1652
|
ok: true,
|
|
@@ -1840,53 +2045,12 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1840
2045
|
envConfig,
|
|
1841
2046
|
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1842
2047
|
);
|
|
1843
|
-
let serverBinding = null;
|
|
1844
2048
|
let overallOK = Boolean(result.ok);
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1850
|
-
});
|
|
1851
|
-
if (!lookup?.ok) {
|
|
1852
|
-
serverBinding = {
|
|
1853
|
-
ok: false,
|
|
1854
|
-
detail: `server bot lookup unavailable: ${lookup?.error || "unknown error"}`,
|
|
1855
|
-
};
|
|
2049
|
+
let serverBinding = null;
|
|
2050
|
+
if (provider === "telegram") {
|
|
2051
|
+
serverBinding = await resolveTelegramServerBindingDetails(envConfig, flags, deps);
|
|
2052
|
+
if (serverBinding && !serverBinding.ok) {
|
|
1856
2053
|
overallOK = false;
|
|
1857
|
-
} else {
|
|
1858
|
-
const normalizedServerIdentity = normalizeServerBotIdentityText(envConfig.botUsername || envConfig.botKey);
|
|
1859
|
-
if (String(envConfig.serverBotID || "").trim()) {
|
|
1860
|
-
const match = ensureArray(lookup.bots).find((bot) => String(bot.id || "").trim() === String(envConfig.serverBotID || "").trim());
|
|
1861
|
-
if (!match) {
|
|
1862
|
-
serverBinding = {
|
|
1863
|
-
ok: false,
|
|
1864
|
-
detail: `server bot ${envConfig.serverBotID} not found`,
|
|
1865
|
-
};
|
|
1866
|
-
overallOK = false;
|
|
1867
|
-
} else {
|
|
1868
|
-
serverBinding = {
|
|
1869
|
-
ok: true,
|
|
1870
|
-
detail: `${String(match.name || "").trim() || "(unnamed)"} [${String(match.role || "").trim() || "-"}]`,
|
|
1871
|
-
};
|
|
1872
|
-
}
|
|
1873
|
-
} else {
|
|
1874
|
-
const matches = ensureArray(lookup.bots).filter(
|
|
1875
|
-
(bot) => normalizeServerBotIdentityText(bot?.name) === normalizedServerIdentity,
|
|
1876
|
-
);
|
|
1877
|
-
if (!matches.length) {
|
|
1878
|
-
serverBinding = {
|
|
1879
|
-
ok: false,
|
|
1880
|
-
detail: `no server bot matched ${envConfig.botUsername ? `@${envConfig.botUsername}` : envConfig.botKey}`,
|
|
1881
|
-
};
|
|
1882
|
-
overallOK = false;
|
|
1883
|
-
} else {
|
|
1884
|
-
serverBinding = {
|
|
1885
|
-
ok: true,
|
|
1886
|
-
detail: `${String(matches[0]?.name || "").trim() || "(unnamed)"} roles: ${summarizeServerBotRoles(matches).join(", ") || "-"}`,
|
|
1887
|
-
};
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
2054
|
}
|
|
1891
2055
|
}
|
|
1892
2056
|
const interactiveJsonChoice = (
|
|
@@ -1923,21 +2087,33 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1923
2087
|
}, null, 2)}\n`,
|
|
1924
2088
|
);
|
|
1925
2089
|
} else {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2090
|
+
const lines = [
|
|
2091
|
+
`${providerLabel(provider, deps)} verify: ${overallOK ? "OK" : "FAIL"}`,
|
|
2092
|
+
`file: ${envConfig.filePath}`,
|
|
2093
|
+
provider === "telegram" ? `bot_key: ${envConfig.botKey || "-"}` : "",
|
|
2094
|
+
provider === "telegram" ? `server_bot_id: ${envConfig.serverBotID || "-"}` : "",
|
|
2095
|
+
provider === "telegram" ? `role_profile: ${envConfig.roleProfile || "-"}` : "",
|
|
2096
|
+
provider === "telegram" ? `ai_client: ${envConfig.client || "-"}` : "",
|
|
2097
|
+
provider === "telegram" ? `ai_model: ${envConfig.model || "-"}` : "",
|
|
2098
|
+
provider === "telegram" ? `permission_mode: ${envConfig.permissionMode || "-"}` : "",
|
|
2099
|
+
provider === "telegram" ? `reasoning_effort: ${envConfig.reasoningEffort || "-"}` : "",
|
|
2100
|
+
`detail: ${result.detail || "-"}`,
|
|
2101
|
+
serverBinding ? `server_binding: ${serverBinding.ok ? "OK" : "FAIL"}${serverBinding.detail ? ` (${serverBinding.detail})` : ""}` : "",
|
|
2102
|
+
].filter(Boolean);
|
|
2103
|
+
if (provider === "telegram" && serverBinding) {
|
|
2104
|
+
lines.push(`server_binding_mode: ${serverBinding.mode || "-"}`);
|
|
2105
|
+
lines.push(`server_bot_name: ${serverBinding.name || "-"}`);
|
|
2106
|
+
lines.push(`server_roles: ${ensureArray(serverBinding.roles).join(", ") || "-"}`);
|
|
2107
|
+
if (serverBinding.mode === "group") {
|
|
2108
|
+
const groupedProfiles = safeObject(serverBinding.effectiveRoleProfiles);
|
|
2109
|
+
Object.keys(groupedProfiles).forEach((role) => {
|
|
2110
|
+
lines.push(`runtime_role_profile[${role}]: ${formatRoleProfileOutputLine(groupedProfiles[role])}`);
|
|
2111
|
+
});
|
|
2112
|
+
} else if (serverBinding.effectiveRoleProfile) {
|
|
2113
|
+
lines.push(`runtime_role_profile: ${formatRoleProfileOutputLine(serverBinding.effectiveRoleProfile)}`);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
1941
2117
|
}
|
|
1942
2118
|
if (!overallOK) {
|
|
1943
2119
|
process.exitCode = 1;
|
|
@@ -2096,12 +2272,21 @@ async function runBotShow(ui, flags, deps, explicitProvider = "") {
|
|
|
2096
2272
|
const state = loadProviderEnvState(provider, deps);
|
|
2097
2273
|
if (provider === "telegram") {
|
|
2098
2274
|
const entry = await resolveTelegramEntryForShow(ui, state.parsed, flags, deps);
|
|
2099
|
-
const
|
|
2275
|
+
const serverBinding = await resolveTelegramServerBindingDetails(
|
|
2276
|
+
requireDependency(deps, "loadProviderEnvConfig")(provider, {
|
|
2277
|
+
botKey: entry.key,
|
|
2278
|
+
botID: entry.serverBotID,
|
|
2279
|
+
botName: entry.username || entry.key,
|
|
2280
|
+
}),
|
|
2281
|
+
flags,
|
|
2282
|
+
deps,
|
|
2283
|
+
);
|
|
2284
|
+
const payload = buildBotShowPayload(provider, state, entry, deps, { serverBinding });
|
|
2100
2285
|
if (boolFromRaw(flags.json, false)) {
|
|
2101
2286
|
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
2102
2287
|
return;
|
|
2103
2288
|
}
|
|
2104
|
-
printBotShow(provider, state, entry, deps);
|
|
2289
|
+
printBotShow(provider, state, entry, deps, { serverBinding });
|
|
2105
2290
|
return;
|
|
2106
2291
|
}
|
|
2107
2292
|
const payload = buildBotShowPayload(provider, state, null, deps);
|
|
@@ -356,19 +356,21 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
356
356
|
"2", // bot entry: ryoai_bot
|
|
357
357
|
"1", // keep username
|
|
358
358
|
"1", // keep token
|
|
359
|
-
"2", //
|
|
360
|
-
"
|
|
361
|
-
"1", // review: keep current role profile settings
|
|
359
|
+
"2", // grouped role settings: edit one role
|
|
360
|
+
"3", // select role to edit: worker
|
|
362
361
|
"2", // worker: edit settings
|
|
363
362
|
"3", // worker AI client: claude
|
|
364
363
|
"worker-sonnet-4",
|
|
365
364
|
"4", // worker permission: danger_full_access
|
|
366
365
|
"4", // worker reasoning: high
|
|
366
|
+
"y", // edit another role
|
|
367
|
+
"3", // select role to edit: approval
|
|
367
368
|
"2", // approval: edit settings
|
|
368
369
|
"4", // approval AI client: gemini
|
|
369
370
|
"approval-pro-2",
|
|
370
371
|
"4", // approval permission: danger_full_access
|
|
371
372
|
"4", // approval reasoning: high
|
|
373
|
+
"n", // stop editing roles
|
|
372
374
|
"1", // keep current default setting
|
|
373
375
|
"y", // save
|
|
374
376
|
]),
|
|
@@ -386,6 +388,26 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
386
388
|
&& String(safeObject(safeObject(groupedRunnerConfig.role_profiles || {}).approval).model || "") === "approval-pro-2",
|
|
387
389
|
`worker=${JSON.stringify(safeObject(safeObject(groupedRunnerConfig.role_profiles || {}).worker))} approval=${JSON.stringify(safeObject(safeObject(groupedRunnerConfig.role_profiles || {}).approval))}`,
|
|
388
390
|
);
|
|
391
|
+
|
|
392
|
+
const groupedShowResult = await runCLI({
|
|
393
|
+
cliPath,
|
|
394
|
+
args: [
|
|
395
|
+
"bot", "show",
|
|
396
|
+
"--provider", "telegram",
|
|
397
|
+
"--bot-key", "ryoai_bot",
|
|
398
|
+
"--base-url", `http://127.0.0.1:${groupedMock.port}`,
|
|
399
|
+
"--json", "true",
|
|
400
|
+
],
|
|
401
|
+
env,
|
|
402
|
+
});
|
|
403
|
+
const groupedShowPayload = readJSON(groupedShowResult.stdout);
|
|
404
|
+
push(
|
|
405
|
+
"bot_show_reports_grouped_server_roles",
|
|
406
|
+
safeObject(groupedShowPayload.serverBinding).mode === "group"
|
|
407
|
+
&& safeObject(safeObject(groupedShowPayload.serverBinding).effectiveRoleProfiles).worker?.client === "claude"
|
|
408
|
+
&& safeObject(safeObject(groupedShowPayload.serverBinding).effectiveRoleProfiles).approval?.client === "gemini",
|
|
409
|
+
`mode=${String(safeObject(groupedShowPayload.serverBinding).mode || "")} worker=${String(safeObject(safeObject(groupedShowPayload.serverBinding).effectiveRoleProfiles).worker?.client || "")} approval=${String(safeObject(safeObject(groupedShowPayload.serverBinding).effectiveRoleProfiles).approval?.client || "")}`,
|
|
410
|
+
);
|
|
389
411
|
} finally {
|
|
390
412
|
await groupedMock.close();
|
|
391
413
|
await runCLI({
|
|
@@ -406,6 +428,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
406
428
|
"bot", "show",
|
|
407
429
|
"--provider", "telegram",
|
|
408
430
|
"--bot-key", "monitorselftestbot",
|
|
431
|
+
"--base-url", baseURL,
|
|
409
432
|
"--json", "true",
|
|
410
433
|
],
|
|
411
434
|
env,
|
|
@@ -414,8 +437,9 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
414
437
|
push(
|
|
415
438
|
"bot_show_returns_selected_telegram_entry",
|
|
416
439
|
safeObject(showPayload.entry).key === "monitorselftestbot"
|
|
417
|
-
&& safeObject(showPayload.entry).client === "codex"
|
|
418
|
-
|
|
440
|
+
&& safeObject(showPayload.entry).client === "codex"
|
|
441
|
+
&& safeObject(showPayload.serverBinding).mode === "single",
|
|
442
|
+
`key=${String(safeObject(showPayload.entry).key || "")} client=${String(safeObject(showPayload.entry).client || "")} mode=${String(safeObject(showPayload.serverBinding).mode || "")}`,
|
|
419
443
|
);
|
|
420
444
|
|
|
421
445
|
await runCLI({
|
|
@@ -436,7 +460,6 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
436
460
|
"3", // workspace_write
|
|
437
461
|
"2", // change reasoning effort
|
|
438
462
|
"3", // medium
|
|
439
|
-
"1", // keep bot key
|
|
440
463
|
"1", // keep default setting
|
|
441
464
|
"y", // save
|
|
442
465
|
]),
|
|
@@ -518,8 +541,9 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
518
541
|
"bot_verify_guided_can_emit_json",
|
|
519
542
|
guidedVerifyPayload.ok === true
|
|
520
543
|
&& safeObject(guidedVerifyPayload.serverBinding).ok === true
|
|
544
|
+
&& safeObject(guidedVerifyPayload.serverBinding).mode === "single"
|
|
521
545
|
&& String(guidedVerifyPayload.client || "") === "claude",
|
|
522
|
-
`verify=${String(guidedVerifyPayload.ok)} server=${String(safeObject(guidedVerifyPayload.serverBinding).detail || "")}`,
|
|
546
|
+
`verify=${String(guidedVerifyPayload.ok)} mode=${String(safeObject(guidedVerifyPayload.serverBinding).mode || "")} server=${String(safeObject(guidedVerifyPayload.serverBinding).detail || "")}`,
|
|
523
547
|
);
|
|
524
548
|
|
|
525
549
|
await runCLI({
|
|
@@ -556,8 +580,9 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
556
580
|
"bot_verify_cross_checks_server_bot_binding",
|
|
557
581
|
verifyPayload.ok === true
|
|
558
582
|
&& safeObject(verifyPayload.serverBinding).ok === true
|
|
583
|
+
&& safeObject(verifyPayload.serverBinding).mode === "single"
|
|
559
584
|
&& String(verifyPayload.client || "") === "claude",
|
|
560
|
-
`verify=${String(verifyPayload.ok)} server=${String(safeObject(verifyPayload.serverBinding).detail || "")}`,
|
|
585
|
+
`verify=${String(verifyPayload.ok)} mode=${String(safeObject(verifyPayload.serverBinding).mode || "")} server=${String(safeObject(verifyPayload.serverBinding).detail || "")}`,
|
|
561
586
|
);
|
|
562
587
|
|
|
563
588
|
await runCLI({
|