metheus-governance-mcp-cli 0.2.69 → 0.2.70
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 +12 -6
- package/cli.mjs +28 -10
- package/lib/bot-commands.mjs +408 -78
- package/lib/selftest-bot-commands.mjs +120 -57
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,7 +55,8 @@ TELEGRAM_BOT_TOKEN=
|
|
|
55
55
|
|
|
56
56
|
# Preferred named bot mapping
|
|
57
57
|
TELEGRAM_BOT_MAIN_SERVER_BOT_ID=
|
|
58
|
-
|
|
58
|
+
# Optional fallback only when server bot binding is unavailable
|
|
59
|
+
# TELEGRAM_BOT_MAIN_USERNAME=<bot_username>
|
|
59
60
|
TELEGRAM_BOT_MAIN_TOKEN=
|
|
60
61
|
TELEGRAM_BOT_MAIN_ROLE_PROFILE=monitor
|
|
61
62
|
TELEGRAM_BOT_MAIN_AI_CLIENT=codex
|
|
@@ -225,9 +226,11 @@ metheus-governance-mcp-cli bot verify --provider telegram --bot-key main
|
|
|
225
226
|
Behavior:
|
|
226
227
|
|
|
227
228
|
- `bot setup` asks for `Telegram / Slack / KakaoTalk` first, then prompts with numbered actions.
|
|
228
|
-
- `bot add` without flags
|
|
229
|
-
-
|
|
230
|
-
-
|
|
229
|
+
- `bot add` without flags now uses the shortest practical guided flow: provider -> token -> verify -> optional save-anyway only when verify fails -> optional username fallback only when verify cannot discover it -> optional default bot.
|
|
230
|
+
- In the normal Telegram path, `bot add` does not ask for a local bot key, a server bot UUID, or an approval / worker / review / monitor choice.
|
|
231
|
+
- For Telegram, the local env key is auto-generated from the matched server bot name or verified username, so you do not have to invent a separate local nickname first.
|
|
232
|
+
- For Telegram, the CLI tries to match the verified bot identity against the server `me/bots` list first. If the server exposes one logical bot name with multiple roles such as `approval`, `worker`, `review`, and `monitor`, the CLI does not ask you to choose one UUID. It binds by server bot name and keeps the local role/AI fields empty so runtime can use the server bot role for each route.
|
|
233
|
+
- When the Telegram username matches exactly one server bot role, the CLI still auto-fills the local `role_profile` and blank AI defaults from your local `bot-runner.json` `role_profiles` mapping.
|
|
231
234
|
- `bot edit` without flags starts a guided numbered flow: provider -> bot entry -> guided edit -> step-by-step field choices.
|
|
232
235
|
- In guided `bot edit`, changing the bound Telegram responsibility can also auto-fill blank local AI fields from the selected server role and skip redundant role/AI prompts.
|
|
233
236
|
- `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
|
|
@@ -235,7 +238,7 @@ Behavior:
|
|
|
235
238
|
- `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
|
|
236
239
|
- Telegram supports named local bot entries with:
|
|
237
240
|
- `SERVER_BOT_ID`
|
|
238
|
-
- `USERNAME`
|
|
241
|
+
- `USERNAME` (optional fallback only when server binding is unavailable)
|
|
239
242
|
- `TOKEN`
|
|
240
243
|
- `ROLE_PROFILE`
|
|
241
244
|
- `AI_CLIENT`
|
|
@@ -253,7 +256,8 @@ Non-interactive examples:
|
|
|
253
256
|
|
|
254
257
|
```bash
|
|
255
258
|
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
|
|
256
|
-
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --
|
|
259
|
+
metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --default true
|
|
260
|
+
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
|
|
257
261
|
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
|
|
258
262
|
metheus-governance-mcp-cli bot set-default --provider telegram --bot-key main --non-interactive true
|
|
259
263
|
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
|
|
@@ -261,6 +265,8 @@ metheus-governance-mcp-cli bot remove --provider telegram --bot-key main --non-i
|
|
|
261
265
|
metheus-governance-mcp-cli bot verify --provider telegram --bot-key main --json true
|
|
262
266
|
```
|
|
263
267
|
|
|
268
|
+
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.
|
|
269
|
+
|
|
264
270
|
Current support status:
|
|
265
271
|
|
|
266
272
|
- Telegram: full local bot entry management, token verification, bot-to-AI binding, inbound runner support
|
package/cli.mjs
CHANGED
|
@@ -748,7 +748,7 @@ function providerEnvTemplate(provider) {
|
|
|
748
748
|
"# Preferred v2 multi-bot mapping:",
|
|
749
749
|
"# TELEGRAM_DEFAULT_BOT_KEY=main",
|
|
750
750
|
"# TELEGRAM_BOT_MAIN_SERVER_BOT_ID=<server bot uuid>",
|
|
751
|
-
"# TELEGRAM_BOT_MAIN_USERNAME=<
|
|
751
|
+
"# TELEGRAM_BOT_MAIN_USERNAME=<optional fallback username when server binding is unavailable>",
|
|
752
752
|
"# TELEGRAM_BOT_MAIN_TOKEN=<bot token>",
|
|
753
753
|
"# TELEGRAM_BOT_MAIN_ROLE_PROFILE=monitor",
|
|
754
754
|
"# TELEGRAM_BOT_MAIN_AI_CLIENT=codex",
|
|
@@ -766,7 +766,6 @@ function providerEnvTemplate(provider) {
|
|
|
766
766
|
"",
|
|
767
767
|
"# Preferred named bot entry",
|
|
768
768
|
"TELEGRAM_BOT_MAIN_SERVER_BOT_ID=",
|
|
769
|
-
"TELEGRAM_BOT_MAIN_USERNAME=",
|
|
770
769
|
"TELEGRAM_BOT_MAIN_TOKEN=",
|
|
771
770
|
"TELEGRAM_BOT_MAIN_ROLE_PROFILE=",
|
|
772
771
|
"TELEGRAM_BOT_MAIN_AI_CLIENT=",
|
|
@@ -2730,7 +2729,9 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
2730
2729
|
selected = entries.find((entry) => entry.serverBotID === desiredBotID) || null;
|
|
2731
2730
|
}
|
|
2732
2731
|
if (!selected && desiredUsername) {
|
|
2733
|
-
selected = entries.find(
|
|
2732
|
+
selected = entries.find(
|
|
2733
|
+
(entry) => entry.username === desiredUsername || normalizeTelegramBotUsername(entry.key) === desiredUsername,
|
|
2734
|
+
) || null;
|
|
2734
2735
|
}
|
|
2735
2736
|
if (!selected && desiredBotKey) {
|
|
2736
2737
|
selected = entries.find((entry) => entry.key === desiredBotKey) || null;
|
|
@@ -3697,8 +3698,9 @@ async function runDoctor(flags) {
|
|
|
3697
3698
|
}
|
|
3698
3699
|
const detailParts = [];
|
|
3699
3700
|
if (envConfig.botKey) detailParts.push(`bot=${envConfig.botKey}`);
|
|
3700
|
-
|
|
3701
|
-
|
|
3701
|
+
if (envConfig.botUsername) detailParts.push(`@${envConfig.botUsername}`);
|
|
3702
|
+
if (envConfig.serverBotID) detailParts.push(`server_bot_id=${envConfig.serverBotID}`);
|
|
3703
|
+
else if (envConfig.botKey) detailParts.push(`server_name=${envConfig.botKey}`);
|
|
3702
3704
|
if (envConfig.client) detailParts.push(`ai=${envConfig.client}`);
|
|
3703
3705
|
addDoctorCheck(
|
|
3704
3706
|
rows,
|
|
@@ -3715,12 +3717,28 @@ async function runDoctor(flags) {
|
|
|
3715
3717
|
);
|
|
3716
3718
|
}
|
|
3717
3719
|
if (route.botID && !envConfig.serverBotID) {
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
`runner route ${routeLabel} server_bot_id`,
|
|
3722
|
-
`route bot_id ${route.botID} is set, but local env entry does not carry SERVER_BOT_ID`,
|
|
3720
|
+
const serverMatch = ensureArray(serverBots).find((bot) => String(bot.id || "").trim() === String(route.botID || "").trim());
|
|
3721
|
+
const routeBotName = normalizeTelegramBotUsername(
|
|
3722
|
+
firstNonEmptyString([route.botName, route.bot_name, serverMatch?.name]),
|
|
3723
3723
|
);
|
|
3724
|
+
const envBotName = normalizeTelegramBotUsername(envConfig.botUsername || envConfig.botKey);
|
|
3725
|
+
if (routeBotName && envBotName && routeBotName === envBotName) {
|
|
3726
|
+
addDoctorCheck(
|
|
3727
|
+
rows,
|
|
3728
|
+
"ok",
|
|
3729
|
+
`runner route ${routeLabel} server bot`,
|
|
3730
|
+
envConfig.botUsername
|
|
3731
|
+
? `resolved by bot username @${envConfig.botUsername}`
|
|
3732
|
+
: `resolved by server bot name ${envConfig.botKey}`,
|
|
3733
|
+
);
|
|
3734
|
+
} else {
|
|
3735
|
+
addDoctorCheck(
|
|
3736
|
+
rows,
|
|
3737
|
+
strictMode ? "fail" : "warn",
|
|
3738
|
+
`runner route ${routeLabel} server_bot_id`,
|
|
3739
|
+
`route bot_id ${route.botID} is set, but local env entry does not carry SERVER_BOT_ID`,
|
|
3740
|
+
);
|
|
3741
|
+
}
|
|
3724
3742
|
}
|
|
3725
3743
|
if (serverBots && route.botID) {
|
|
3726
3744
|
const match = ensureArray(serverBots).find((bot) => String(bot.id || "").trim() === String(route.botID || "").trim());
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -43,6 +43,35 @@ function firstNonEmptyString(values) {
|
|
|
43
43
|
return "";
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function uniqueNormalizedValues(values, deps, fallback = "") {
|
|
47
|
+
const normalizeBotKey = requireDependency(deps, "normalizeTelegramBotEnvKey");
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
const ordered = [];
|
|
50
|
+
ensureArray(values).forEach((value) => {
|
|
51
|
+
const normalized = normalizeBotKey(value || "", "");
|
|
52
|
+
if (!normalized || seen.has(normalized)) return;
|
|
53
|
+
seen.add(normalized);
|
|
54
|
+
ordered.push(normalized);
|
|
55
|
+
});
|
|
56
|
+
if (ordered.length) return ordered;
|
|
57
|
+
const fallbackKey = normalizeBotKey(fallback || "", "");
|
|
58
|
+
return fallbackKey ? [fallbackKey] : [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function normalizeServerBotIdentityText(rawValue) {
|
|
62
|
+
return String(rawValue || "").trim().replace(/^@+/, "").toLowerCase();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function summarizeServerBotRoles(bots) {
|
|
66
|
+
return Array.from(
|
|
67
|
+
new Set(
|
|
68
|
+
ensureArray(bots)
|
|
69
|
+
.map((bot) => String(bot?.role || "").trim())
|
|
70
|
+
.filter(Boolean),
|
|
71
|
+
),
|
|
72
|
+
).sort((left, right) => left.localeCompare(right));
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
function hasOwnFlag(flags, key) {
|
|
47
76
|
return Object.prototype.hasOwnProperty.call(safeObject(flags), key);
|
|
48
77
|
}
|
|
@@ -105,7 +134,7 @@ function printBotUsage(deps) {
|
|
|
105
134
|
` ${cliName} bot setup`,
|
|
106
135
|
` ${cliName} bot list [--provider <telegram|slack|kakaotalk>] [--json <true|false>]`,
|
|
107
136
|
` ${cliName} bot show [--provider <telegram|slack|kakaotalk>] [--bot-key <key>] [--bot-id <uuid>] [--bot-name <name>] [--json <true|false>]`,
|
|
108
|
-
` ${cliName} bot add [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>] [--non-interactive <true|false>] [--
|
|
137
|
+
` ${cliName} bot add [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>] [--non-interactive <true|false>] [--server-bot-id <uuid>] [--token <token>] [--default <true|false>] [--verify <true|false>] [--ai-client <name>] [--ai-model <name>] [--ai-permission-mode <mode>] [--ai-reasoning-effort <level>] [--bot-key <advanced_key>] [--username <fallback_name>] [--role-profile <name>]`,
|
|
109
138
|
` ${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>]`,
|
|
110
139
|
` ${cliName} bot remove [--provider <telegram|slack|kakaotalk>] [--non-interactive <true|false>] [--bot-key <key>]`,
|
|
111
140
|
` ${cliName} bot set-default --provider telegram [--bot-key <key>] [--non-interactive <true|false>]`,
|
|
@@ -113,6 +142,14 @@ function printBotUsage(deps) {
|
|
|
113
142
|
` ${cliName} bot verify [--provider <telegram|slack|kakaotalk>] [--bot-key <key>] [--timeout-seconds <n>] [--json <true|false>]`,
|
|
114
143
|
` ${cliName} bot global --provider telegram [--non-interactive <true|false>] [--api-base-url <url>] [--auto-clear-webhook <true|false>] [--allowed-updates <csv>] [--default-bot-key <key>]`,
|
|
115
144
|
"",
|
|
145
|
+
`Behavior:`,
|
|
146
|
+
` - bot setup asks for provider first, then shows a numbered action menu.`,
|
|
147
|
+
` - bot add without flags uses the shortest practical guided flow: provider -> token -> verify -> optional username fallback -> optional default bot.`,
|
|
148
|
+
` - in the normal Telegram path, bot add does not ask for a local bot key or a server role/profile choice.`,
|
|
149
|
+
` - server bot name/UUID is the source of truth; local key is auto-derived unless you intentionally override it with --bot-key.`,
|
|
150
|
+
` - bot edit without flags asks for provider, existing entry, then a numbered edit flow.`,
|
|
151
|
+
` - bot set-default / bot verify / bot remove also support guided numbered selection when run without flags.`,
|
|
152
|
+
"",
|
|
116
153
|
].join("\n"),
|
|
117
154
|
);
|
|
118
155
|
}
|
|
@@ -277,6 +314,13 @@ function telegramEntryEnvKeys(botKey) {
|
|
|
277
314
|
};
|
|
278
315
|
}
|
|
279
316
|
|
|
317
|
+
function persistTelegramUsername(entry) {
|
|
318
|
+
const current = safeObject(entry);
|
|
319
|
+
if (current.__preferServerIdentity) return "";
|
|
320
|
+
if (String(current.serverBotID || "").trim()) return "";
|
|
321
|
+
return normalizeServerBotIdentityText(current.username || "");
|
|
322
|
+
}
|
|
323
|
+
|
|
280
324
|
function removeTelegramEntry(parsedEnv, botKey) {
|
|
281
325
|
const parsed = { ...safeObject(parsedEnv) };
|
|
282
326
|
const keys = telegramEntryEnvKeys(botKey);
|
|
@@ -295,7 +339,7 @@ function upsertTelegramEntry(parsedEnv, entry) {
|
|
|
295
339
|
const keys = telegramEntryEnvKeys(entry.key);
|
|
296
340
|
const next = { ...parsed };
|
|
297
341
|
next[keys.serverBotID] = String(entry.serverBotID || "").trim();
|
|
298
|
-
next[keys.username] =
|
|
342
|
+
next[keys.username] = persistTelegramUsername(entry);
|
|
299
343
|
next[keys.token] = String(entry.token || "").trim();
|
|
300
344
|
next[keys.roleProfile] = String(entry.roleProfile || "").trim();
|
|
301
345
|
next[keys.client] = String(entry.client || "").trim();
|
|
@@ -363,10 +407,14 @@ function renderTelegramEnv(parsedEnv, deps) {
|
|
|
363
407
|
} else {
|
|
364
408
|
entries.forEach((entry) => {
|
|
365
409
|
const keys = telegramEntryEnvKeys(entry.key);
|
|
366
|
-
|
|
410
|
+
const entryLines = [
|
|
367
411
|
`# Telegram bot entry: ${entry.key}`,
|
|
368
412
|
`${keys.serverBotID}=${formatEnvValue(entry.serverBotID || "")}`,
|
|
369
|
-
|
|
413
|
+
];
|
|
414
|
+
if (String(entry.username || "").trim()) {
|
|
415
|
+
entryLines.push(`${keys.username}=${formatEnvValue(entry.username || "")}`);
|
|
416
|
+
}
|
|
417
|
+
entryLines.push(
|
|
370
418
|
`${keys.token}=${formatEnvValue(entry.token || "")}`,
|
|
371
419
|
`${keys.roleProfile}=${formatEnvValue(entry.roleProfile || "")}`,
|
|
372
420
|
`${keys.client}=${formatEnvValue(entry.client || "")}`,
|
|
@@ -375,6 +423,7 @@ function renderTelegramEnv(parsedEnv, deps) {
|
|
|
375
423
|
`${keys.reasoningEffort}=${formatEnvValue(entry.reasoningEffort || "")}`,
|
|
376
424
|
"",
|
|
377
425
|
);
|
|
426
|
+
lines.push(...entryLines);
|
|
378
427
|
});
|
|
379
428
|
}
|
|
380
429
|
const knownKeys = telegramKnownKeys(parsed, deps);
|
|
@@ -453,6 +502,23 @@ function telegramEntriesForDisplay(parsedEnv, deps) {
|
|
|
453
502
|
.sort((left, right) => String(left.key || "").localeCompare(String(right.key || "")));
|
|
454
503
|
}
|
|
455
504
|
|
|
505
|
+
function telegramEntryDisplayName(entry) {
|
|
506
|
+
const current = safeObject(entry);
|
|
507
|
+
const username = String(current.username || "").trim();
|
|
508
|
+
if (username) return `@${username}`;
|
|
509
|
+
return String(current.key || "").trim() || "(unnamed)";
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function telegramEntryDisplayDescription(entry) {
|
|
513
|
+
const current = safeObject(entry);
|
|
514
|
+
const detail = [
|
|
515
|
+
current.key ? `key:${current.key}` : "",
|
|
516
|
+
current.serverBotID ? `server:${current.serverBotID}` : "",
|
|
517
|
+
current.client ? `AI:${current.client}` : "",
|
|
518
|
+
].filter(Boolean);
|
|
519
|
+
return detail.join(" ");
|
|
520
|
+
}
|
|
521
|
+
|
|
456
522
|
function findTelegramEntryByFlags(parsedEnv, flags, deps) {
|
|
457
523
|
const entries = telegramEntriesForDisplay(parsedEnv, deps);
|
|
458
524
|
const requestedKey = String(flags["bot-key"] || "").trim();
|
|
@@ -473,9 +539,11 @@ function findTelegramEntryByFlags(parsedEnv, flags, deps) {
|
|
|
473
539
|
return match;
|
|
474
540
|
}
|
|
475
541
|
if (requestedName) {
|
|
476
|
-
const match = entries.find(
|
|
542
|
+
const match = entries.find(
|
|
543
|
+
(entry) => entry.username === requestedName || normalizeServerBotIdentityText(entry.key) === requestedName,
|
|
544
|
+
);
|
|
477
545
|
if (!match) {
|
|
478
|
-
throw new Error(`Telegram bot entry with
|
|
546
|
+
throw new Error(`Telegram bot entry with server bot name "${requestedName}" was not found`);
|
|
479
547
|
}
|
|
480
548
|
return match;
|
|
481
549
|
}
|
|
@@ -496,8 +564,44 @@ function saveTelegramBotEdit(parsed, selected, current, deps) {
|
|
|
496
564
|
return filePath;
|
|
497
565
|
}
|
|
498
566
|
|
|
567
|
+
function buildDerivedTelegramBotKey(parsedEnv, deps, preferredValues, { excludeKeys = [] } = {}) {
|
|
568
|
+
const normalizeBotKey = requireDependency(deps, "normalizeTelegramBotEnvKey");
|
|
569
|
+
const existingKeys = new Set(
|
|
570
|
+
telegramEntriesForDisplay(parsedEnv, deps)
|
|
571
|
+
.map((entry) => entry.key)
|
|
572
|
+
.filter((key) => !ensureArray(excludeKeys).includes(key)),
|
|
573
|
+
);
|
|
574
|
+
const candidates = uniqueNormalizedValues(
|
|
575
|
+
[
|
|
576
|
+
...ensureArray(preferredValues),
|
|
577
|
+
"main",
|
|
578
|
+
],
|
|
579
|
+
deps,
|
|
580
|
+
"main",
|
|
581
|
+
);
|
|
582
|
+
const baseKey = candidates[0] || normalizeBotKey("main", "main") || "main";
|
|
583
|
+
for (const candidate of candidates) {
|
|
584
|
+
if (!existingKeys.has(candidate)) {
|
|
585
|
+
return candidate;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
let suffix = 2;
|
|
589
|
+
while (existingKeys.has(`${baseKey}_${suffix}`)) {
|
|
590
|
+
suffix += 1;
|
|
591
|
+
}
|
|
592
|
+
return `${baseKey}_${suffix}`;
|
|
593
|
+
}
|
|
594
|
+
|
|
499
595
|
async function editTelegramBotGuided(ui, parsed, selected, current, flags, deps) {
|
|
500
596
|
let serverRoleAutoResolved = "";
|
|
597
|
+
const aiFlagOverrides = hasOwnFlag(flags, "client")
|
|
598
|
+
|| hasOwnFlag(flags, "ai-client")
|
|
599
|
+
|| hasOwnFlag(flags, "model")
|
|
600
|
+
|| hasOwnFlag(flags, "ai-model")
|
|
601
|
+
|| hasOwnFlag(flags, "permission-mode")
|
|
602
|
+
|| hasOwnFlag(flags, "ai-permission-mode")
|
|
603
|
+
|| hasOwnFlag(flags, "reasoning-effort")
|
|
604
|
+
|| hasOwnFlag(flags, "ai-reasoning-effort");
|
|
501
605
|
const bindingAction = await promptKeepChangeClear(ui, "Server bot binding", {
|
|
502
606
|
allowClear: true,
|
|
503
607
|
defaultValue: current.serverBotID ? "keep" : "change",
|
|
@@ -509,15 +613,39 @@ async function editTelegramBotGuided(ui, parsed, selected, current, flags, deps)
|
|
|
509
613
|
flags["base-url"] || deps.defaultSiteURL,
|
|
510
614
|
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
511
615
|
deps,
|
|
616
|
+
{
|
|
617
|
+
preferredUsername: current.username,
|
|
618
|
+
preferredName: current.username,
|
|
619
|
+
},
|
|
512
620
|
);
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
current.
|
|
621
|
+
if (serverBot.matchMode === "group") {
|
|
622
|
+
current.serverBotID = "";
|
|
623
|
+
current.__preferServerIdentity = true;
|
|
624
|
+
if (!String(flags["role-profile"] || "").trim()) {
|
|
625
|
+
current.roleProfile = "";
|
|
626
|
+
}
|
|
627
|
+
if (!aiFlagOverrides) {
|
|
628
|
+
current.client = "";
|
|
629
|
+
current.model = "";
|
|
630
|
+
current.permissionMode = "";
|
|
631
|
+
current.reasoningEffort = "";
|
|
632
|
+
}
|
|
633
|
+
serverRoleAutoResolved = "__server_role_group__";
|
|
634
|
+
process.stdout.write(
|
|
635
|
+
`Matched server Telegram bot "${serverBot.name || current.username || current.key}" with roles: ${ensureArray(serverBot.roles).join(", ")}. Runtime will use the server role, so local role/AI fields can stay empty.\n`,
|
|
636
|
+
);
|
|
637
|
+
} else {
|
|
638
|
+
current.serverBotID = serverBot.botID;
|
|
639
|
+
current.__preferServerIdentity = true;
|
|
640
|
+
if (!current.roleProfile && serverBot.role) {
|
|
641
|
+
current.roleProfile = serverBot.role;
|
|
642
|
+
}
|
|
643
|
+
serverRoleAutoResolved = String(serverBot.role || current.roleProfile || "").trim();
|
|
644
|
+
applyRoleProfileDefaults(current, resolveRoleProfileDefaults(current.roleProfile || serverBot.role, deps));
|
|
516
645
|
}
|
|
517
|
-
serverRoleAutoResolved = String(serverBot.role || current.roleProfile || "").trim();
|
|
518
|
-
applyRoleProfileDefaults(current, resolveRoleProfileDefaults(current.roleProfile || serverBot.role, deps));
|
|
519
646
|
} else if (bindingAction === "clear") {
|
|
520
647
|
current.serverBotID = "";
|
|
648
|
+
current.__preferServerIdentity = false;
|
|
521
649
|
}
|
|
522
650
|
|
|
523
651
|
const usernameAction = await promptKeepChangeClear(ui, "Telegram username", {
|
|
@@ -754,7 +882,8 @@ function printBotList(provider, state, deps) {
|
|
|
754
882
|
entries.forEach((entry) => {
|
|
755
883
|
process.stdout.write(
|
|
756
884
|
[
|
|
757
|
-
` - ${entry
|
|
885
|
+
` - ${telegramEntryDisplayName(entry)}${entry.isDefault ? " [default]" : ""}`,
|
|
886
|
+
` key: ${entry.key || "-"}`,
|
|
758
887
|
` server_bot_id: ${entry.serverBotID || "-"}`,
|
|
759
888
|
` username: ${entry.username ? `@${entry.username}` : "-"}`,
|
|
760
889
|
` token: ${entry.token ? maskSecret(entry.token) : "-"}`,
|
|
@@ -778,6 +907,7 @@ function printBotShow(provider, state, entry, deps, extras = {}) {
|
|
|
778
907
|
const selectedEntry = entry || {};
|
|
779
908
|
process.stdout.write(`${providerLabel(provider, deps)} bot\n`);
|
|
780
909
|
process.stdout.write(` file: ${state.filePath}\n`);
|
|
910
|
+
process.stdout.write(` name: ${telegramEntryDisplayName(selectedEntry)}\n`);
|
|
781
911
|
process.stdout.write(` key: ${selectedEntry.key || "-"}\n`);
|
|
782
912
|
process.stdout.write(` default: ${selectedEntry.isDefault ? "yes" : "no"}\n`);
|
|
783
913
|
process.stdout.write(` server_bot_id: ${selectedEntry.serverBotID || "-"}\n`);
|
|
@@ -810,8 +940,8 @@ async function chooseTelegramEntry(ui, parsedEnv, deps, title = "Select Telegram
|
|
|
810
940
|
title,
|
|
811
941
|
entries.map((entry) => ({
|
|
812
942
|
value: entry.key,
|
|
813
|
-
label: `${entry
|
|
814
|
-
description:
|
|
943
|
+
label: `${telegramEntryDisplayName(entry)}${entry.isDefault ? " [default]" : ""}`,
|
|
944
|
+
description: telegramEntryDisplayDescription(entry),
|
|
815
945
|
})),
|
|
816
946
|
{ defaultIndex: 0 },
|
|
817
947
|
);
|
|
@@ -844,7 +974,7 @@ async function resolveTelegramEntryForShow(ui, parsedEnv, flags, deps) {
|
|
|
844
974
|
return chooseTelegramEntry(ui, parsedEnv, deps, "Select Telegram bot entry");
|
|
845
975
|
}
|
|
846
976
|
|
|
847
|
-
async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
977
|
+
async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps, options = {}) {
|
|
848
978
|
const lookup = requireDependency(deps, "listServerBots");
|
|
849
979
|
const result = await lookup({ provider, baseURL, timeoutSeconds });
|
|
850
980
|
const bots = ensureArray(result?.bots).map((bot) => ({
|
|
@@ -857,11 +987,40 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
857
987
|
process.stdout.write(`Server bot profiles unavailable: ${result.error}\n`);
|
|
858
988
|
}
|
|
859
989
|
const manualID = await promptLine(ui, "Server bot UUID (blank to leave empty)", "");
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
990
|
+
return {
|
|
991
|
+
botID: manualID,
|
|
992
|
+
role: "",
|
|
993
|
+
name: "",
|
|
994
|
+
roles: [],
|
|
995
|
+
matchMode: manualID ? "manual" : "blank",
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
const preferredIdentity = normalizeServerBotIdentityText(
|
|
999
|
+
firstNonEmptyString([options.preferredUsername, options.preferredName]),
|
|
1000
|
+
);
|
|
1001
|
+
if (preferredIdentity) {
|
|
1002
|
+
const matchedByName = bots.filter(
|
|
1003
|
+
(bot) => normalizeServerBotIdentityText(bot.name) === preferredIdentity,
|
|
1004
|
+
);
|
|
1005
|
+
if (matchedByName.length === 1) {
|
|
1006
|
+
const match = matchedByName[0] || {};
|
|
1007
|
+
return {
|
|
1008
|
+
botID: String(match.id || "").trim(),
|
|
1009
|
+
role: String(match.role || "").trim(),
|
|
1010
|
+
name: String(match.name || "").trim(),
|
|
1011
|
+
roles: summarizeServerBotRoles([match]),
|
|
1012
|
+
matchMode: "exact",
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
if (matchedByName.length > 1) {
|
|
1016
|
+
return {
|
|
1017
|
+
botID: "",
|
|
1018
|
+
role: "",
|
|
1019
|
+
name: String(matchedByName[0]?.name || "").trim(),
|
|
1020
|
+
roles: summarizeServerBotRoles(matchedByName),
|
|
1021
|
+
matchMode: "group",
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
865
1024
|
}
|
|
866
1025
|
if (bots.length === 1) {
|
|
867
1026
|
const match = bots[0] || {};
|
|
@@ -869,8 +1028,30 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
869
1028
|
botID: String(match.id || "").trim(),
|
|
870
1029
|
role: String(match.role || "").trim(),
|
|
871
1030
|
name: String(match.name || "").trim(),
|
|
1031
|
+
roles: summarizeServerBotRoles([match]),
|
|
1032
|
+
matchMode: "exact",
|
|
872
1033
|
};
|
|
873
1034
|
}
|
|
1035
|
+
const groupedByName = new Map();
|
|
1036
|
+
bots.forEach((bot) => {
|
|
1037
|
+
const nameKey = normalizeServerBotIdentityText(bot.name) || bot.id;
|
|
1038
|
+
if (!groupedByName.has(nameKey)) {
|
|
1039
|
+
groupedByName.set(nameKey, []);
|
|
1040
|
+
}
|
|
1041
|
+
groupedByName.get(nameKey).push(bot);
|
|
1042
|
+
});
|
|
1043
|
+
if (groupedByName.size === 1) {
|
|
1044
|
+
const groupedBots = ensureArray(groupedByName.values().next().value);
|
|
1045
|
+
if (groupedBots.length > 1) {
|
|
1046
|
+
return {
|
|
1047
|
+
botID: "",
|
|
1048
|
+
role: "",
|
|
1049
|
+
name: String(groupedBots[0]?.name || "").trim(),
|
|
1050
|
+
roles: summarizeServerBotRoles(groupedBots),
|
|
1051
|
+
matchMode: "group",
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
874
1055
|
const preferredRoleOrder = ["monitor", "review", "worker", "approval"];
|
|
875
1056
|
const roleGroups = new Map();
|
|
876
1057
|
bots.forEach((bot) => {
|
|
@@ -921,7 +1102,7 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
921
1102
|
{ defaultIndex: 0 },
|
|
922
1103
|
);
|
|
923
1104
|
if (!roleChoice || roleChoice.value === "__blank__") {
|
|
924
|
-
return { botID: "", role: "", name: "" };
|
|
1105
|
+
return { botID: "", role: "", name: "", roles: [], matchMode: "blank" };
|
|
925
1106
|
}
|
|
926
1107
|
if (roleChoice.value === "__manual__") {
|
|
927
1108
|
const manualID = await promptLine(ui, "Server bot UUID", "");
|
|
@@ -929,6 +1110,8 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
929
1110
|
botID: manualID,
|
|
930
1111
|
role: "",
|
|
931
1112
|
name: "",
|
|
1113
|
+
roles: [],
|
|
1114
|
+
matchMode: manualID ? "manual" : "blank",
|
|
932
1115
|
};
|
|
933
1116
|
}
|
|
934
1117
|
if (String(roleChoice.value || "").startsWith("role:")) {
|
|
@@ -938,6 +1121,8 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
938
1121
|
botID: String(match.id || "").trim(),
|
|
939
1122
|
role: String(match.role || "").trim(),
|
|
940
1123
|
name: String(match.name || "").trim(),
|
|
1124
|
+
roles: summarizeServerBotRoles([match]),
|
|
1125
|
+
matchMode: "exact",
|
|
941
1126
|
};
|
|
942
1127
|
}
|
|
943
1128
|
const selectedRole = String(roleChoice.value || "").slice(6);
|
|
@@ -965,7 +1150,7 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
965
1150
|
{ defaultIndex: 0 },
|
|
966
1151
|
);
|
|
967
1152
|
if (!choice || choice.value === "__blank__") {
|
|
968
|
-
return { botID: "", role: "", name: "" };
|
|
1153
|
+
return { botID: "", role: "", name: "", roles: [], matchMode: "blank" };
|
|
969
1154
|
}
|
|
970
1155
|
if (choice.value === "__manual__") {
|
|
971
1156
|
const manualID = await promptLine(ui, "Server bot UUID", "");
|
|
@@ -973,6 +1158,8 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
973
1158
|
botID: manualID,
|
|
974
1159
|
role: selectedRole,
|
|
975
1160
|
name: "",
|
|
1161
|
+
roles: selectedRole ? [selectedRole] : [],
|
|
1162
|
+
matchMode: manualID ? "manual" : "blank",
|
|
976
1163
|
};
|
|
977
1164
|
}
|
|
978
1165
|
const match = matches.find((bot) => bot.id === choice.value) || {};
|
|
@@ -980,6 +1167,72 @@ async function chooseServerBot(ui, provider, baseURL, timeoutSeconds, deps) {
|
|
|
980
1167
|
botID: String(match.id || "").trim(),
|
|
981
1168
|
role: String(match.role || "").trim(),
|
|
982
1169
|
name: String(match.name || "").trim(),
|
|
1170
|
+
roles: summarizeServerBotRoles([match]),
|
|
1171
|
+
matchMode: "exact",
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
async function resolveServerBotForNonInteractive(provider, flags, deps, options = {}) {
|
|
1176
|
+
const requestedBotID = String(getServerBotIDFlag(flags) || "").trim();
|
|
1177
|
+
const requestedName = normalizeServerBotIdentityText(
|
|
1178
|
+
firstNonEmptyString([
|
|
1179
|
+
flags["bot-name"],
|
|
1180
|
+
flags.username,
|
|
1181
|
+
options.preferredUsername,
|
|
1182
|
+
options.preferredName,
|
|
1183
|
+
]),
|
|
1184
|
+
);
|
|
1185
|
+
if (!requestedBotID && !requestedName) {
|
|
1186
|
+
return { botID: "", role: "", name: "", roles: [], matchMode: "blank" };
|
|
1187
|
+
}
|
|
1188
|
+
const lookup = await requireDependency(deps, "listServerBots")({
|
|
1189
|
+
provider,
|
|
1190
|
+
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
1191
|
+
timeoutSeconds: intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1192
|
+
});
|
|
1193
|
+
const bots = ensureArray(lookup?.bots).map((bot) => ({
|
|
1194
|
+
id: String(bot?.id || "").trim(),
|
|
1195
|
+
role: String(bot?.role || bot?.bot_role || "").trim(),
|
|
1196
|
+
name: String(bot?.name || "").trim(),
|
|
1197
|
+
})).filter((bot) => bot.id);
|
|
1198
|
+
if (!lookup?.ok) {
|
|
1199
|
+
throw new Error(lookup?.error || "server bot lookup unavailable");
|
|
1200
|
+
}
|
|
1201
|
+
if (requestedBotID) {
|
|
1202
|
+
const match = bots.find((bot) => bot.id === requestedBotID);
|
|
1203
|
+
if (!match) {
|
|
1204
|
+
throw new Error(`server bot ${requestedBotID} not found`);
|
|
1205
|
+
}
|
|
1206
|
+
return {
|
|
1207
|
+
botID: match.id,
|
|
1208
|
+
role: match.role,
|
|
1209
|
+
name: match.name,
|
|
1210
|
+
roles: summarizeServerBotRoles([match]),
|
|
1211
|
+
matchMode: "exact",
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
const matchedByName = bots.filter(
|
|
1215
|
+
(bot) => normalizeServerBotIdentityText(bot.name) === requestedName,
|
|
1216
|
+
);
|
|
1217
|
+
if (!matchedByName.length) {
|
|
1218
|
+
throw new Error(`no server bot matched ${requestedName}`);
|
|
1219
|
+
}
|
|
1220
|
+
if (matchedByName.length === 1) {
|
|
1221
|
+
const match = matchedByName[0] || {};
|
|
1222
|
+
return {
|
|
1223
|
+
botID: String(match.id || "").trim(),
|
|
1224
|
+
role: String(match.role || "").trim(),
|
|
1225
|
+
name: String(match.name || "").trim(),
|
|
1226
|
+
roles: summarizeServerBotRoles([match]),
|
|
1227
|
+
matchMode: "exact",
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
return {
|
|
1231
|
+
botID: "",
|
|
1232
|
+
role: "",
|
|
1233
|
+
name: String(matchedByName[0]?.name || "").trim(),
|
|
1234
|
+
roles: summarizeServerBotRoles(matchedByName),
|
|
1235
|
+
matchMode: "group",
|
|
983
1236
|
};
|
|
984
1237
|
}
|
|
985
1238
|
|
|
@@ -1090,35 +1343,9 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
1090
1343
|
const state = loadProviderEnvState("telegram", deps);
|
|
1091
1344
|
const parsed = { ...state.parsed };
|
|
1092
1345
|
const nonInteractive = boolFromRaw(flags["non-interactive"] ?? flags.yes, false);
|
|
1093
|
-
const serverBot = nonInteractive
|
|
1094
|
-
? {
|
|
1095
|
-
botID: getServerBotIDFlag(flags),
|
|
1096
|
-
role: String(flags.role || "").trim(),
|
|
1097
|
-
name: "",
|
|
1098
|
-
}
|
|
1099
|
-
: await chooseServerBot(
|
|
1100
|
-
ui,
|
|
1101
|
-
"telegram",
|
|
1102
|
-
flags["base-url"] || deps.defaultSiteURL,
|
|
1103
|
-
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1104
|
-
deps,
|
|
1105
|
-
);
|
|
1106
1346
|
const normalizeBotKey = requireDependency(deps, "normalizeTelegramBotEnvKey");
|
|
1107
1347
|
const existingKeys = new Set(telegramEntriesForDisplay(parsed, deps).map((entry) => entry.key));
|
|
1108
|
-
const defaultKeyHint = normalizeBotKey(flags["bot-key"] ||
|
|
1109
|
-
let botKey = normalizeBotKey(
|
|
1110
|
-
nonInteractive
|
|
1111
|
-
? String(flags["bot-key"] || defaultKeyHint).trim()
|
|
1112
|
-
: await promptRequiredLine(ui, "Local Telegram bot key", defaultKeyHint),
|
|
1113
|
-
defaultKeyHint,
|
|
1114
|
-
);
|
|
1115
|
-
if (nonInteractive && existingKeys.has(botKey)) {
|
|
1116
|
-
throw new Error(`Telegram bot key "${botKey}" already exists`);
|
|
1117
|
-
}
|
|
1118
|
-
while (!nonInteractive && existingKeys.has(botKey)) {
|
|
1119
|
-
process.stdout.write(`Telegram bot key "${botKey}" already exists.\n`);
|
|
1120
|
-
botKey = normalizeBotKey(await promptRequiredLine(ui, "Local Telegram bot key", `${botKey}_2`), `${botKey}_2`);
|
|
1121
|
-
}
|
|
1348
|
+
const defaultKeyHint = normalizeBotKey(flags["bot-key"] || "main", "main");
|
|
1122
1349
|
|
|
1123
1350
|
const token = nonInteractive
|
|
1124
1351
|
? String(flags.token || "").trim()
|
|
@@ -1159,12 +1386,69 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
1159
1386
|
? String(flags.username || usernameDefault).trim()
|
|
1160
1387
|
: (usernameDefault || await promptLine(ui, "Telegram username (without @)", usernameDefault)),
|
|
1161
1388
|
);
|
|
1389
|
+
const serverBot = nonInteractive
|
|
1390
|
+
? await resolveServerBotForNonInteractive("telegram", flags, deps, {
|
|
1391
|
+
preferredUsername: username,
|
|
1392
|
+
preferredName: username,
|
|
1393
|
+
})
|
|
1394
|
+
: await chooseServerBot(
|
|
1395
|
+
ui,
|
|
1396
|
+
"telegram",
|
|
1397
|
+
flags["base-url"] || deps.defaultSiteURL,
|
|
1398
|
+
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1399
|
+
deps,
|
|
1400
|
+
{
|
|
1401
|
+
preferredUsername: username,
|
|
1402
|
+
preferredName: username,
|
|
1403
|
+
},
|
|
1404
|
+
);
|
|
1405
|
+
let botKey = normalizeBotKey(
|
|
1406
|
+
nonInteractive
|
|
1407
|
+
? String(
|
|
1408
|
+
flags["bot-key"]
|
|
1409
|
+
|| buildDerivedTelegramBotKey(
|
|
1410
|
+
parsed,
|
|
1411
|
+
deps,
|
|
1412
|
+
[
|
|
1413
|
+
serverBot.name,
|
|
1414
|
+
username,
|
|
1415
|
+
flags["bot-name"],
|
|
1416
|
+
flags.username,
|
|
1417
|
+
defaultKeyHint,
|
|
1418
|
+
],
|
|
1419
|
+
),
|
|
1420
|
+
).trim()
|
|
1421
|
+
: buildDerivedTelegramBotKey(
|
|
1422
|
+
parsed,
|
|
1423
|
+
deps,
|
|
1424
|
+
[
|
|
1425
|
+
flags["bot-key"],
|
|
1426
|
+
serverBot.name,
|
|
1427
|
+
username,
|
|
1428
|
+
flags["bot-name"],
|
|
1429
|
+
flags.username,
|
|
1430
|
+
defaultKeyHint,
|
|
1431
|
+
],
|
|
1432
|
+
),
|
|
1433
|
+
defaultKeyHint,
|
|
1434
|
+
);
|
|
1435
|
+
if (nonInteractive && existingKeys.has(botKey)) {
|
|
1436
|
+
throw new Error(`Telegram bot key "${botKey}" already exists`);
|
|
1437
|
+
}
|
|
1438
|
+
const serverGroupMatched = !nonInteractive && serverBot.matchMode === "group";
|
|
1439
|
+
if (serverGroupMatched) {
|
|
1440
|
+
process.stdout.write(
|
|
1441
|
+
`Matched server Telegram bot "${serverBot.name || username || botKey}" with roles: ${ensureArray(serverBot.roles).join(", ")}. Runtime will use the server role, so local role/AI fields can stay empty.\n`,
|
|
1442
|
+
);
|
|
1443
|
+
}
|
|
1162
1444
|
const defaultRoleProfile = firstNonEmptyString([flags["role-profile"], serverBot.role, ""]);
|
|
1163
1445
|
const roleProfileAutoResolved = !nonInteractive && !String(flags["role-profile"] || "").trim() && Boolean(defaultRoleProfile);
|
|
1164
1446
|
const roleProfile = requireDependency(deps, "normalizeRunnerRoleProfileName")(
|
|
1165
1447
|
nonInteractive
|
|
1166
1448
|
? String(flags["role-profile"] || defaultRoleProfile).trim()
|
|
1167
|
-
: (
|
|
1449
|
+
: (serverGroupMatched && !String(flags["role-profile"] || "").trim()
|
|
1450
|
+
? ""
|
|
1451
|
+
: (roleProfileAutoResolved ? defaultRoleProfile : await promptTelegramRoleProfile(ui, deps, defaultRoleProfile))),
|
|
1168
1452
|
);
|
|
1169
1453
|
const roleProfileDefaults = resolveRoleProfileDefaults(roleProfile, deps);
|
|
1170
1454
|
const aiFlagOverrides = hasOwnFlag(flags, "client")
|
|
@@ -1176,33 +1460,45 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
1176
1460
|
|| hasOwnFlag(flags, "reasoning-effort")
|
|
1177
1461
|
|| hasOwnFlag(flags, "ai-reasoning-effort");
|
|
1178
1462
|
const autoApplyRoleDefaults = !nonInteractive && roleProfileAutoResolved && !aiFlagOverrides;
|
|
1463
|
+
const autoUseServerRoleRouting = !nonInteractive
|
|
1464
|
+
&& serverGroupMatched
|
|
1465
|
+
&& !String(flags["role-profile"] || "").trim()
|
|
1466
|
+
&& !aiFlagOverrides;
|
|
1179
1467
|
const client = requireDependency(deps, "normalizeLocalAIClientName")(
|
|
1180
1468
|
nonInteractive
|
|
1181
1469
|
? firstNonEmptyString([getAIClientFlag(flags), roleProfileDefaults.client])
|
|
1182
|
-
: (
|
|
1183
|
-
?
|
|
1184
|
-
:
|
|
1470
|
+
: (autoUseServerRoleRouting
|
|
1471
|
+
? getAIClientFlag(flags)
|
|
1472
|
+
: (autoApplyRoleDefaults
|
|
1473
|
+
? firstNonEmptyString([getAIClientFlag(flags), roleProfileDefaults.client])
|
|
1474
|
+
: await promptAIClient(ui, deps, firstNonEmptyString([getAIClientFlag(flags), roleProfileDefaults.client])))),
|
|
1185
1475
|
"",
|
|
1186
1476
|
);
|
|
1187
1477
|
const model = nonInteractive
|
|
1188
1478
|
? firstNonEmptyString([getAIModelFlag(flags), roleProfileDefaults.model])
|
|
1189
|
-
: (
|
|
1190
|
-
?
|
|
1191
|
-
:
|
|
1479
|
+
: (autoUseServerRoleRouting
|
|
1480
|
+
? getAIModelFlag(flags)
|
|
1481
|
+
: (autoApplyRoleDefaults
|
|
1482
|
+
? firstNonEmptyString([getAIModelFlag(flags), roleProfileDefaults.model])
|
|
1483
|
+
: await promptLine(ui, "AI model", firstNonEmptyString([getAIModelFlag(flags), roleProfileDefaults.model]))));
|
|
1192
1484
|
const permissionMode = requireDependency(deps, "normalizeLocalAIPermissionMode")(
|
|
1193
1485
|
nonInteractive
|
|
1194
1486
|
? firstNonEmptyString([getAIPermissionModeFlag(flags), roleProfileDefaults.permissionMode])
|
|
1195
|
-
: (
|
|
1196
|
-
?
|
|
1197
|
-
:
|
|
1487
|
+
: (autoUseServerRoleRouting
|
|
1488
|
+
? getAIPermissionModeFlag(flags)
|
|
1489
|
+
: (autoApplyRoleDefaults
|
|
1490
|
+
? firstNonEmptyString([getAIPermissionModeFlag(flags), roleProfileDefaults.permissionMode])
|
|
1491
|
+
: await promptPermissionMode(ui, firstNonEmptyString([getAIPermissionModeFlag(flags), roleProfileDefaults.permissionMode])))),
|
|
1198
1492
|
"",
|
|
1199
1493
|
);
|
|
1200
1494
|
const reasoningEffort = requireDependency(deps, "normalizeLocalAIReasoningEffort")(
|
|
1201
1495
|
nonInteractive
|
|
1202
1496
|
? firstNonEmptyString([getAIReasoningEffortFlag(flags), roleProfileDefaults.reasoningEffort])
|
|
1203
|
-
: (
|
|
1204
|
-
?
|
|
1205
|
-
:
|
|
1497
|
+
: (autoUseServerRoleRouting
|
|
1498
|
+
? getAIReasoningEffortFlag(flags)
|
|
1499
|
+
: (autoApplyRoleDefaults
|
|
1500
|
+
? firstNonEmptyString([getAIReasoningEffortFlag(flags), roleProfileDefaults.reasoningEffort])
|
|
1501
|
+
: await promptReasoningEffort(ui, firstNonEmptyString([getAIReasoningEffortFlag(flags), roleProfileDefaults.reasoningEffort])))),
|
|
1206
1502
|
"",
|
|
1207
1503
|
);
|
|
1208
1504
|
|
|
@@ -1210,6 +1506,7 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
1210
1506
|
key: botKey,
|
|
1211
1507
|
serverBotID: String(getServerBotIDFlag(flags) || serverBot.botID || "").trim(),
|
|
1212
1508
|
username,
|
|
1509
|
+
__preferServerIdentity: serverBot.matchMode === "group" || Boolean(String(getServerBotIDFlag(flags) || serverBot.botID || "").trim()),
|
|
1213
1510
|
token,
|
|
1214
1511
|
roleProfile,
|
|
1215
1512
|
client,
|
|
@@ -1218,9 +1515,11 @@ async function addTelegramBot(ui, flags, deps) {
|
|
|
1218
1515
|
reasoningEffort,
|
|
1219
1516
|
});
|
|
1220
1517
|
|
|
1221
|
-
const
|
|
1518
|
+
const currentDefaultKey = normalizeBotKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", "");
|
|
1519
|
+
const hasCurrentDefault = telegramEntriesForDisplay(parsed, deps).some((entry) => entry.key === currentDefaultKey);
|
|
1222
1520
|
if (
|
|
1223
1521
|
boolFromRaw(flags.default, false)
|
|
1522
|
+
|| (nonInteractive && !hasCurrentDefault)
|
|
1224
1523
|
|| (!nonInteractive && !hasCurrentDefault && await promptYesNo(ui, "Set this bot as TELEGRAM_DEFAULT_BOT_KEY?", true))
|
|
1225
1524
|
) {
|
|
1226
1525
|
nextParsed.TELEGRAM_DEFAULT_BOT_KEY = botKey;
|
|
@@ -1296,6 +1595,7 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
1296
1595
|
if (nonInteractive) {
|
|
1297
1596
|
if (getServerBotIDFlag(flags)) {
|
|
1298
1597
|
current.serverBotID = getServerBotIDFlag(flags);
|
|
1598
|
+
current.__preferServerIdentity = true;
|
|
1299
1599
|
}
|
|
1300
1600
|
if (Object.prototype.hasOwnProperty.call(flags, "username")) {
|
|
1301
1601
|
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(flags.username || "");
|
|
@@ -1368,10 +1668,21 @@ async function editTelegramBot(ui, flags, deps) {
|
|
|
1368
1668
|
flags["base-url"] || deps.defaultSiteURL,
|
|
1369
1669
|
intFromRaw(flags["timeout-seconds"], 15) || 15,
|
|
1370
1670
|
deps,
|
|
1671
|
+
{
|
|
1672
|
+
preferredUsername: current.username,
|
|
1673
|
+
preferredName: current.username,
|
|
1674
|
+
},
|
|
1371
1675
|
);
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1676
|
+
if (serverBot.matchMode === "group") {
|
|
1677
|
+
current.serverBotID = "";
|
|
1678
|
+
process.stdout.write(
|
|
1679
|
+
`Matched server Telegram bot "${serverBot.name || current.username || current.key}" with roles: ${ensureArray(serverBot.roles).join(", ")}. Keep role/AI fields empty if you want runtime role-based resolution.\n`,
|
|
1680
|
+
);
|
|
1681
|
+
} else {
|
|
1682
|
+
current.serverBotID = serverBot.botID;
|
|
1683
|
+
if (!current.roleProfile && serverBot.role) {
|
|
1684
|
+
current.roleProfile = serverBot.role;
|
|
1685
|
+
}
|
|
1375
1686
|
}
|
|
1376
1687
|
} else if (choice.value === "username") {
|
|
1377
1688
|
current.username = requireDependency(deps, "normalizeTelegramBotUsername")(
|
|
@@ -1490,7 +1801,7 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1490
1801
|
);
|
|
1491
1802
|
let serverBinding = null;
|
|
1492
1803
|
let overallOK = Boolean(result.ok);
|
|
1493
|
-
if (provider === "telegram" && String(envConfig.serverBotID || "").trim()) {
|
|
1804
|
+
if (provider === "telegram" && (String(envConfig.serverBotID || "").trim() || String(envConfig.botUsername || "").trim() || String(envConfig.botKey || "").trim())) {
|
|
1494
1805
|
const lookup = await requireDependency(deps, "listServerBots")({
|
|
1495
1806
|
provider,
|
|
1496
1807
|
baseURL: flags["base-url"] || deps.defaultSiteURL,
|
|
@@ -1503,18 +1814,37 @@ async function verifyProviderEntry(ui, provider, flags, deps) {
|
|
|
1503
1814
|
};
|
|
1504
1815
|
overallOK = false;
|
|
1505
1816
|
} else {
|
|
1506
|
-
const
|
|
1507
|
-
if (
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1817
|
+
const normalizedServerIdentity = normalizeServerBotIdentityText(envConfig.botUsername || envConfig.botKey);
|
|
1818
|
+
if (String(envConfig.serverBotID || "").trim()) {
|
|
1819
|
+
const match = ensureArray(lookup.bots).find((bot) => String(bot.id || "").trim() === String(envConfig.serverBotID || "").trim());
|
|
1820
|
+
if (!match) {
|
|
1821
|
+
serverBinding = {
|
|
1822
|
+
ok: false,
|
|
1823
|
+
detail: `server bot ${envConfig.serverBotID} not found`,
|
|
1824
|
+
};
|
|
1825
|
+
overallOK = false;
|
|
1826
|
+
} else {
|
|
1827
|
+
serverBinding = {
|
|
1828
|
+
ok: true,
|
|
1829
|
+
detail: `${String(match.name || "").trim() || "(unnamed)"} [${String(match.role || "").trim() || "-"}]`,
|
|
1830
|
+
};
|
|
1831
|
+
}
|
|
1513
1832
|
} else {
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1833
|
+
const matches = ensureArray(lookup.bots).filter(
|
|
1834
|
+
(bot) => normalizeServerBotIdentityText(bot?.name) === normalizedServerIdentity,
|
|
1835
|
+
);
|
|
1836
|
+
if (!matches.length) {
|
|
1837
|
+
serverBinding = {
|
|
1838
|
+
ok: false,
|
|
1839
|
+
detail: `no server bot matched ${envConfig.botUsername ? `@${envConfig.botUsername}` : envConfig.botKey}`,
|
|
1840
|
+
};
|
|
1841
|
+
overallOK = false;
|
|
1842
|
+
} else {
|
|
1843
|
+
serverBinding = {
|
|
1844
|
+
ok: true,
|
|
1845
|
+
detail: `${String(matches[0]?.name || "").trim() || "(unnamed)"} roles: ${summarizeServerBotRoles(matches).join(", ") || "-"}`,
|
|
1846
|
+
};
|
|
1847
|
+
}
|
|
1518
1848
|
}
|
|
1519
1849
|
}
|
|
1520
1850
|
}
|
|
@@ -84,20 +84,26 @@ function readTrailingJSON(rawText) {
|
|
|
84
84
|
return readJSON(text.slice(start));
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
function createMockServer() {
|
|
88
|
-
const serverBots =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
function createMockServer(options = {}) {
|
|
88
|
+
const serverBots = ensureArray(options.serverBots).length
|
|
89
|
+
? ensureArray(options.serverBots)
|
|
90
|
+
: [
|
|
91
|
+
{
|
|
92
|
+
id: "11111111-2222-3333-4444-555555555555",
|
|
93
|
+
name: "MonitorSelftestBot",
|
|
94
|
+
provider: "telegram",
|
|
95
|
+
bot_role: "monitor",
|
|
96
|
+
is_active: true,
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
const telegramUsersByToken = new Map(
|
|
100
|
+
ensureArray(options.telegramUsersByToken).length
|
|
101
|
+
? ensureArray(options.telegramUsersByToken)
|
|
102
|
+
: [
|
|
103
|
+
["selftest-main-token", "MonitorSelftestBot"],
|
|
104
|
+
["selftest-edited-token", "MonitorSelftestBot"],
|
|
105
|
+
],
|
|
106
|
+
);
|
|
101
107
|
|
|
102
108
|
const server = http.createServer((req, res) => {
|
|
103
109
|
const url = new URL(req.url || "/", "http://127.0.0.1");
|
|
@@ -271,7 +277,6 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
271
277
|
...env,
|
|
272
278
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
273
279
|
"1", // provider: telegram
|
|
274
|
-
"main_test",
|
|
275
280
|
"selftest-main-token",
|
|
276
281
|
"y", // verify now
|
|
277
282
|
]),
|
|
@@ -280,22 +285,82 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
280
285
|
const addState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
281
286
|
push(
|
|
282
287
|
"bot_add_guided_creates_named_telegram_entry",
|
|
283
|
-
String(addState.
|
|
284
|
-
&& String(addState.
|
|
285
|
-
&& String(addState.
|
|
286
|
-
&& String(addState.
|
|
287
|
-
&& String(addState.
|
|
288
|
-
&& String(addState.
|
|
289
|
-
&& String(addState.TELEGRAM_DEFAULT_BOT_KEY || "") === "
|
|
290
|
-
`default=${String(addState.TELEGRAM_DEFAULT_BOT_KEY || "")} role=${String(addState.
|
|
288
|
+
String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
289
|
+
&& String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_USERNAME || "").trim() === ""
|
|
290
|
+
&& String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_ROLE_PROFILE || "") === "monitor"
|
|
291
|
+
&& String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "") === "codex"
|
|
292
|
+
&& String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_PERMISSION_MODE || "") === "read_only"
|
|
293
|
+
&& String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_REASONING_EFFORT || "") === "low"
|
|
294
|
+
&& String(addState.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
295
|
+
`default=${String(addState.TELEGRAM_DEFAULT_BOT_KEY || "")} role=${String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_ROLE_PROFILE || "")} client=${String(addState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "")}`,
|
|
291
296
|
);
|
|
292
297
|
|
|
298
|
+
const groupedMock = await createMockServer({
|
|
299
|
+
serverBots: [
|
|
300
|
+
{ id: "977ef999-c40b-4cf6-a142-ade246f1b9cf", name: "RyoAI_bot", provider: "telegram", bot_role: "approval", is_active: true },
|
|
301
|
+
{ id: "d74b57de-a635-4bac-a20f-f8ada188cf97", name: "RyoAI_bot", provider: "telegram", bot_role: "worker", is_active: true },
|
|
302
|
+
{ id: "bbae9450-4236-487c-9a05-61dc4a626215", name: "RyoAI_bot", provider: "telegram", bot_role: "review", is_active: true },
|
|
303
|
+
{ id: "353896c5-3b6b-422f-9eeb-5dc9354f77b3", name: "RyoAI_bot", provider: "telegram", bot_role: "monitor", is_active: true },
|
|
304
|
+
],
|
|
305
|
+
telegramUsersByToken: [["selftest-group-token", "RyoAI_bot"]],
|
|
306
|
+
}).listen();
|
|
307
|
+
try {
|
|
308
|
+
await runCLI({
|
|
309
|
+
cliPath,
|
|
310
|
+
args: [
|
|
311
|
+
"bot", "global",
|
|
312
|
+
"--provider", "telegram",
|
|
313
|
+
"--non-interactive", "true",
|
|
314
|
+
"--api-base-url", `http://127.0.0.1:${groupedMock.port}/telegram`,
|
|
315
|
+
],
|
|
316
|
+
env,
|
|
317
|
+
});
|
|
318
|
+
await runCLI({
|
|
319
|
+
cliPath,
|
|
320
|
+
args: [
|
|
321
|
+
"bot", "add",
|
|
322
|
+
"--base-url", `http://127.0.0.1:${groupedMock.port}`,
|
|
323
|
+
"--timeout-seconds", "5",
|
|
324
|
+
],
|
|
325
|
+
env: {
|
|
326
|
+
...env,
|
|
327
|
+
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
328
|
+
"1",
|
|
329
|
+
"selftest-group-token",
|
|
330
|
+
"y",
|
|
331
|
+
]),
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
const groupedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
335
|
+
push(
|
|
336
|
+
"bot_add_guided_autoresolves_server_bot_group_without_role_prompt",
|
|
337
|
+
String(groupedState.TELEGRAM_BOT_RYOAI_BOT_USERNAME || "").trim() === ""
|
|
338
|
+
&& String(groupedState.TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID || "") === ""
|
|
339
|
+
&& String(groupedState.TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE || "") === ""
|
|
340
|
+
&& String(groupedState.TELEGRAM_BOT_RYOAI_BOT_AI_CLIENT || "") === ""
|
|
341
|
+
&& String(groupedState.TELEGRAM_BOT_RYOAI_BOT_AI_PERMISSION_MODE || "") === "",
|
|
342
|
+
`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 || "")}`,
|
|
343
|
+
);
|
|
344
|
+
} finally {
|
|
345
|
+
await groupedMock.close();
|
|
346
|
+
await runCLI({
|
|
347
|
+
cliPath,
|
|
348
|
+
args: [
|
|
349
|
+
"bot", "global",
|
|
350
|
+
"--provider", "telegram",
|
|
351
|
+
"--non-interactive", "true",
|
|
352
|
+
"--api-base-url", telegramApiBaseURL,
|
|
353
|
+
],
|
|
354
|
+
env,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
293
358
|
const showResult = await runCLI({
|
|
294
359
|
cliPath,
|
|
295
360
|
args: [
|
|
296
361
|
"bot", "show",
|
|
297
362
|
"--provider", "telegram",
|
|
298
|
-
"--bot-key", "
|
|
363
|
+
"--bot-key", "monitorselftestbot",
|
|
299
364
|
"--json", "true",
|
|
300
365
|
],
|
|
301
366
|
env,
|
|
@@ -303,7 +368,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
303
368
|
const showPayload = readJSON(showResult.stdout);
|
|
304
369
|
push(
|
|
305
370
|
"bot_show_returns_selected_telegram_entry",
|
|
306
|
-
safeObject(showPayload.entry).key === "
|
|
371
|
+
safeObject(showPayload.entry).key === "monitorselftestbot"
|
|
307
372
|
&& safeObject(showPayload.entry).client === "codex",
|
|
308
373
|
`key=${String(safeObject(showPayload.entry).key || "")} client=${String(safeObject(showPayload.entry).client || "")}`,
|
|
309
374
|
);
|
|
@@ -315,7 +380,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
315
380
|
...env,
|
|
316
381
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
317
382
|
"1", // provider: telegram
|
|
318
|
-
"1", // bot entry:
|
|
383
|
+
"1", // bot entry: @monitorselftestbot
|
|
319
384
|
"1", // edit mode: guided
|
|
320
385
|
"1", // keep server bot binding
|
|
321
386
|
"1", // keep username
|
|
@@ -338,11 +403,11 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
338
403
|
const guidedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
339
404
|
push(
|
|
340
405
|
"bot_edit_guided_prompts_update_ai_binding_fields",
|
|
341
|
-
String(guidedState.
|
|
342
|
-
&& String(guidedState.
|
|
343
|
-
&& String(guidedState.
|
|
344
|
-
&& String(guidedState.
|
|
345
|
-
`client=${String(guidedState.
|
|
406
|
+
String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "") === "gemini"
|
|
407
|
+
&& String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "") === "guided-gemini-pro"
|
|
408
|
+
&& String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
409
|
+
&& String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_REASONING_EFFORT || "") === "medium",
|
|
410
|
+
`client=${String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "")} model=${String(guidedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "")}`,
|
|
346
411
|
);
|
|
347
412
|
|
|
348
413
|
await runCLI({
|
|
@@ -350,7 +415,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
350
415
|
args: [
|
|
351
416
|
"bot", "edit",
|
|
352
417
|
"--provider", "telegram",
|
|
353
|
-
"--bot-key", "
|
|
418
|
+
"--bot-key", "monitorselftestbot",
|
|
354
419
|
"--non-interactive", "true",
|
|
355
420
|
"--token", "selftest-edited-token",
|
|
356
421
|
"--client", "claude",
|
|
@@ -363,12 +428,12 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
363
428
|
const editedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
364
429
|
push(
|
|
365
430
|
"bot_edit_updates_ai_binding_fields",
|
|
366
|
-
String(editedState.
|
|
367
|
-
&& String(editedState.
|
|
368
|
-
&& String(editedState.
|
|
369
|
-
&& String(editedState.
|
|
370
|
-
&& String(editedState.
|
|
371
|
-
`client=${String(editedState.
|
|
431
|
+
String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_TOKEN || "") === "selftest-edited-token"
|
|
432
|
+
&& String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "") === "claude"
|
|
433
|
+
&& String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "") === "claude-3.7-sonnet"
|
|
434
|
+
&& String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
435
|
+
&& String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_REASONING_EFFORT || "") === "medium",
|
|
436
|
+
`client=${String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "")} model=${String(editedState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "")}`,
|
|
372
437
|
);
|
|
373
438
|
|
|
374
439
|
await runCLI({
|
|
@@ -378,7 +443,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
378
443
|
...env,
|
|
379
444
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
380
445
|
"1", // provider: telegram
|
|
381
|
-
"1", // bot entry:
|
|
446
|
+
"1", // bot entry: @monitorselftestbot
|
|
382
447
|
"1", // confirm set default
|
|
383
448
|
]),
|
|
384
449
|
},
|
|
@@ -386,7 +451,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
386
451
|
const guidedDefaultState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
387
452
|
push(
|
|
388
453
|
"bot_set_default_guided_selects_entry",
|
|
389
|
-
String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "
|
|
454
|
+
String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
390
455
|
`default=${String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "")}`,
|
|
391
456
|
);
|
|
392
457
|
|
|
@@ -401,7 +466,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
401
466
|
...env,
|
|
402
467
|
METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
|
|
403
468
|
"1", // provider: telegram
|
|
404
|
-
"1", // bot entry:
|
|
469
|
+
"1", // bot entry: @monitorselftestbot
|
|
405
470
|
"2", // output format: json
|
|
406
471
|
]),
|
|
407
472
|
},
|
|
@@ -420,7 +485,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
420
485
|
args: [
|
|
421
486
|
"bot", "set-default",
|
|
422
487
|
"--provider", "telegram",
|
|
423
|
-
"--bot-key", "
|
|
488
|
+
"--bot-key", "monitorselftestbot",
|
|
424
489
|
"--non-interactive", "true",
|
|
425
490
|
],
|
|
426
491
|
env,
|
|
@@ -428,7 +493,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
428
493
|
const defaultState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
429
494
|
push(
|
|
430
495
|
"bot_set_default_updates_default_bot_key",
|
|
431
|
-
String(defaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "
|
|
496
|
+
String(defaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
432
497
|
`default=${String(defaultState.TELEGRAM_DEFAULT_BOT_KEY || "")}`,
|
|
433
498
|
);
|
|
434
499
|
|
|
@@ -437,7 +502,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
437
502
|
args: [
|
|
438
503
|
"bot", "verify",
|
|
439
504
|
"--provider", "telegram",
|
|
440
|
-
"--bot-key", "
|
|
505
|
+
"--bot-key", "monitorselftestbot",
|
|
441
506
|
"--base-url", baseURL,
|
|
442
507
|
"--timeout-seconds", "5",
|
|
443
508
|
"--json", "true",
|
|
@@ -458,7 +523,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
458
523
|
args: [
|
|
459
524
|
"bot", "remove",
|
|
460
525
|
"--provider", "telegram",
|
|
461
|
-
"--bot-key", "
|
|
526
|
+
"--bot-key", "monitorselftestbot",
|
|
462
527
|
"--non-interactive", "true",
|
|
463
528
|
],
|
|
464
529
|
env,
|
|
@@ -476,7 +541,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
476
541
|
const telegramEntry = safeObject(listPayload[0]);
|
|
477
542
|
push(
|
|
478
543
|
"bot_remove_deletes_named_telegram_entry",
|
|
479
|
-
ensureArray(telegramEntry.entries).
|
|
544
|
+
!ensureArray(telegramEntry.entries).some((entry) => String(safeObject(entry).key || "") === "monitorselftestbot"),
|
|
480
545
|
`entries=${String(ensureArray(telegramEntry.entries).length)}`,
|
|
481
546
|
);
|
|
482
547
|
|
|
@@ -488,11 +553,8 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
488
553
|
"--non-interactive", "true",
|
|
489
554
|
"--base-url", baseURL,
|
|
490
555
|
"--timeout-seconds", "5",
|
|
491
|
-
"--bot-key", "explicit_test",
|
|
492
556
|
"--server-bot-id", mock.bots[0].id,
|
|
493
|
-
"--username", "MonitorSelftestBot",
|
|
494
557
|
"--token", "selftest-main-token",
|
|
495
|
-
"--role-profile", "monitor",
|
|
496
558
|
"--ai-client", "codex",
|
|
497
559
|
"--ai-model", "gpt-5-codex",
|
|
498
560
|
"--ai-permission-mode", "read_only",
|
|
@@ -504,12 +566,13 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
504
566
|
const aliasAddState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
505
567
|
push(
|
|
506
568
|
"bot_add_accepts_ai_prefixed_option_aliases",
|
|
507
|
-
String(aliasAddState.
|
|
508
|
-
&& String(aliasAddState.
|
|
509
|
-
&& String(aliasAddState.
|
|
510
|
-
&& String(aliasAddState.
|
|
511
|
-
&& String(aliasAddState.
|
|
512
|
-
|
|
569
|
+
String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
570
|
+
&& String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_USERNAME || "") === ""
|
|
571
|
+
&& String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "") === "codex"
|
|
572
|
+
&& String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "") === "gpt-5-codex"
|
|
573
|
+
&& String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_PERMISSION_MODE || "") === "read_only"
|
|
574
|
+
&& String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_REASONING_EFFORT || "") === "low",
|
|
575
|
+
`client=${String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "")}`,
|
|
513
576
|
);
|
|
514
577
|
|
|
515
578
|
const guidedRemoveBeforeList = await runCLI({
|
|
@@ -524,7 +587,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
524
587
|
const guidedRemoveBeforePayload = ensureArray(readJSON(guidedRemoveBeforeList.stdout));
|
|
525
588
|
const guidedRemoveBeforeEntry = safeObject(guidedRemoveBeforePayload[0]);
|
|
526
589
|
const guidedRemoveEntries = ensureArray(guidedRemoveBeforeEntry.entries);
|
|
527
|
-
const explicitEntryIndex = guidedRemoveEntries.findIndex((entry) => String(safeObject(entry).key || "") === "
|
|
590
|
+
const explicitEntryIndex = guidedRemoveEntries.findIndex((entry) => String(safeObject(entry).key || "") === "monitorselftestbot");
|
|
528
591
|
|
|
529
592
|
await runCLI({
|
|
530
593
|
cliPath,
|
|
@@ -552,7 +615,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
552
615
|
push(
|
|
553
616
|
"bot_remove_guided_deletes_selected_entry",
|
|
554
617
|
explicitEntryIndex >= 0
|
|
555
|
-
&& ensureArray(guidedRemoveEntry.entries).
|
|
618
|
+
&& !ensureArray(guidedRemoveEntry.entries).some((entry) => String(safeObject(entry).key || "") === "explicit_test"),
|
|
556
619
|
`entries=${String(ensureArray(guidedRemoveEntry.entries).length)} selected=${String(explicitEntryIndex + 1)}`,
|
|
557
620
|
);
|
|
558
621
|
|