metheus-governance-mcp-cli 0.2.92 → 0.2.94
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 +34 -22
- package/cli.mjs +318 -29
- package/lib/bot-commands.mjs +30 -2
- package/lib/selftest-bot-commands.mjs +54 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ npm install -g metheus-governance-mcp-cli@latest
|
|
|
24
24
|
Install creates local provider settings templates here:
|
|
25
25
|
|
|
26
26
|
- `~/.metheus/telegram.env`
|
|
27
|
+
- `~/.metheus/telegram-bots/`
|
|
27
28
|
- `~/.metheus/slack.env`
|
|
28
29
|
- `~/.metheus/kakaotalk.env`
|
|
29
30
|
- `~/.metheus/bot-runner.json`
|
|
@@ -31,7 +32,8 @@ Install creates local provider settings templates here:
|
|
|
31
32
|
These files are for local provider bot secrets, local transport options, and optional per-bot local AI binding.
|
|
32
33
|
|
|
33
34
|
- Store locally:
|
|
34
|
-
- `TELEGRAM_BOT_TOKEN`
|
|
35
|
+
- `TELEGRAM_BOT_TOKEN` as a legacy Telegram fallback in `telegram.env`
|
|
36
|
+
- one Telegram bot file per entry in `~/.metheus/telegram-bots/<bot-key>.env`
|
|
35
37
|
- `SLACK_BOT_TOKEN`
|
|
36
38
|
- `KAKAOTALK_BOT_TOKEN`
|
|
37
39
|
- Server-side Metheus stores project chat destination metadata separately:
|
|
@@ -39,7 +41,7 @@ These files are for local provider bot secrets, local transport options, and opt
|
|
|
39
41
|
- `chat_id` / channel / room identifier
|
|
40
42
|
- label / active state
|
|
41
43
|
- Do not put project chat destination identifiers in local env files.
|
|
42
|
-
- Telegram
|
|
44
|
+
- Telegram-wide settings stay in `telegram.env`; Telegram per-bot secrets and AI fields live in `telegram-bots/*.env`.
|
|
43
45
|
|
|
44
46
|
Example templates:
|
|
45
47
|
|
|
@@ -52,18 +54,21 @@ TELEGRAM_DEFAULT_BOT_KEY=ryoai
|
|
|
52
54
|
|
|
53
55
|
# Legacy fallback
|
|
54
56
|
TELEGRAM_BOT_TOKEN=
|
|
57
|
+
```
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
```env
|
|
60
|
+
# ~/.metheus/telegram-bots/ryoai.env
|
|
61
|
+
TELEGRAM_BOT_NAME=ryoai_bot
|
|
62
|
+
TELEGRAM_BOT_SERVER_BOT_ID=
|
|
63
|
+
TELEGRAM_BOT_TOKEN=
|
|
64
|
+
TELEGRAM_BOT_ROLE_PROFILE=
|
|
65
|
+
TELEGRAM_BOT_AI_CLIENT=
|
|
66
|
+
TELEGRAM_BOT_AI_MODEL=
|
|
67
|
+
TELEGRAM_BOT_AI_PERMISSION_MODE=
|
|
68
|
+
TELEGRAM_BOT_AI_REASONING_EFFORT=
|
|
69
|
+
```
|
|
66
70
|
|
|
71
|
+
```env
|
|
67
72
|
# ~/.metheus/slack.env
|
|
68
73
|
SLACK_BOT_TOKEN=
|
|
69
74
|
|
|
@@ -160,10 +165,17 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
|
|
|
160
165
|
`setup` also ensures local provider templates exist:
|
|
161
166
|
|
|
162
167
|
- `~/.metheus/telegram.env`
|
|
168
|
+
- `~/.metheus/telegram-bots/`
|
|
163
169
|
- `~/.metheus/slack.env`
|
|
164
170
|
- `~/.metheus/kakaotalk.env`
|
|
165
171
|
- `~/.metheus/bot-runner.json`
|
|
166
172
|
|
|
173
|
+
When Telegram local config already exists, bootstrap/setup keeps your secrets but auto-normalizes the layout to the latest split structure:
|
|
174
|
+
|
|
175
|
+
- Telegram-wide settings stay in `~/.metheus/telegram.env`
|
|
176
|
+
- per-bot secrets move to `~/.metheus/telegram-bots/<bot-key>.env`
|
|
177
|
+
- stale inline keys such as `TELEGRAM_BOT_<NAME>_BOT_*` are rewritten into generic per-bot keys
|
|
178
|
+
|
|
167
179
|
Fill provider bot secrets and provider-local transport options locally. Project chat destination identifiers should be managed on the Metheus server as project chat destinations, not as local env values and not inside legacy Chat Hooks/webhooks.
|
|
168
180
|
|
|
169
181
|
`~/.metheus/bot-runner.json` is the local automation profile for:
|
|
@@ -228,7 +240,7 @@ Behavior:
|
|
|
228
240
|
- `bot setup` asks for `Telegram / Slack / KakaoTalk` first, then prompts with numbered actions.
|
|
229
241
|
- `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 AI model selection when the resolved defaults leave it blank -> optional default bot.
|
|
230
242
|
- 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
|
|
243
|
+
- For Telegram, the local bot file stem 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
244
|
- 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
245
|
- 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.
|
|
234
246
|
- `bot edit` without flags now uses the same sequential flow every time: provider -> bot entry -> username/token review -> grouped server-role review when needed -> AI field choices -> default choice -> save.
|
|
@@ -247,15 +259,15 @@ Behavior:
|
|
|
247
259
|
- `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
|
|
248
260
|
- `bot verify` without flags starts a guided numbered flow: provider -> bot entry -> output format.
|
|
249
261
|
- `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
|
|
250
|
-
- Telegram
|
|
251
|
-
- `
|
|
252
|
-
- `
|
|
253
|
-
- `
|
|
254
|
-
- `
|
|
255
|
-
- `
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
- `
|
|
262
|
+
- Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<bot-key>.env` with generic fields:
|
|
263
|
+
- `TELEGRAM_BOT_NAME`
|
|
264
|
+
- `TELEGRAM_BOT_SERVER_BOT_ID`
|
|
265
|
+
- `TELEGRAM_BOT_TOKEN`
|
|
266
|
+
- `TELEGRAM_BOT_ROLE_PROFILE`
|
|
267
|
+
- `TELEGRAM_BOT_AI_CLIENT`
|
|
268
|
+
- `TELEGRAM_BOT_AI_MODEL`
|
|
269
|
+
- `TELEGRAM_BOT_AI_PERMISSION_MODE`
|
|
270
|
+
- `TELEGRAM_BOT_AI_REASONING_EFFORT`
|
|
259
271
|
- Slack and KakaoTalk currently use a single local token entry per provider in this command flow.
|
|
260
272
|
- `bot verify` checks the configured local token, cross-checks the server bot binding, prints the effective runtime role profile summary that the runner will use, and shows which local runner routes currently point at this bot entry.
|
|
261
273
|
- `bot show` prints one local bot entry in detail, including grouped role summaries when one server bot name expands to multiple roles and any linked local runner routes.
|
package/cli.mjs
CHANGED
|
@@ -736,46 +736,33 @@ function providerEnvFilePath(provider) {
|
|
|
736
736
|
return resolveHomeFilePath(providerEnvConfig(provider).relativePath);
|
|
737
737
|
}
|
|
738
738
|
|
|
739
|
+
function telegramBotEntriesDirPath() {
|
|
740
|
+
return resolveHomeFilePath(".metheus/telegram-bots");
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function telegramBotEntryFilePath(botKey) {
|
|
744
|
+
const normalizedKey = normalizeTelegramBotEnvKey(botKey || "", "telegram_bot") || "telegram_bot";
|
|
745
|
+
return path.join(telegramBotEntriesDirPath(), `${normalizedKey}.env`);
|
|
746
|
+
}
|
|
747
|
+
|
|
739
748
|
function providerEnvTemplate(provider) {
|
|
740
749
|
const config = providerEnvConfig(provider);
|
|
741
750
|
if (normalizeBotProvider(provider) === "telegram") {
|
|
742
751
|
return [
|
|
743
752
|
"# Metheus local Telegram bot settings",
|
|
744
753
|
"# Keep this file on your machine only. Do not commit it.",
|
|
745
|
-
"# Store Telegram
|
|
754
|
+
"# Store only Telegram-wide settings here.",
|
|
755
|
+
"# Per-bot secrets and AI settings live in ~/.metheus/telegram-bots/<bot-key>.env.",
|
|
746
756
|
"# Project chat destinations must be managed on the Metheus server.",
|
|
747
|
-
"#",
|
|
748
|
-
"# Legacy single-bot fallback:",
|
|
749
|
-
"# TELEGRAM_BOT_TOKEN=<bot token>",
|
|
750
|
-
"#",
|
|
751
|
-
"# Preferred v2 multi-bot mapping:",
|
|
752
|
-
"# TELEGRAM_DEFAULT_BOT_KEY=ryoai",
|
|
753
|
-
"# TELEGRAM_BOT_RYOAI_SERVER_BOT_ID=<server bot uuid>",
|
|
754
|
-
"# TELEGRAM_BOT_RYOAI_USERNAME=<optional fallback username when server binding is unavailable>",
|
|
755
|
-
"# TELEGRAM_BOT_RYOAI_TOKEN=<bot token>",
|
|
756
|
-
"# TELEGRAM_BOT_RYOAI_ROLE_PROFILE=monitor",
|
|
757
|
-
"# TELEGRAM_BOT_RYOAI_AI_CLIENT=gpt",
|
|
758
|
-
"# TELEGRAM_BOT_RYOAI_AI_MODEL=gpt-5.4",
|
|
759
|
-
"# TELEGRAM_BOT_RYOAI_AI_PERMISSION_MODE=read_only",
|
|
760
|
-
"# TELEGRAM_BOT_RYOAI_AI_REASONING_EFFORT=low",
|
|
761
757
|
"",
|
|
762
758
|
"TELEGRAM_API_BASE_URL=",
|
|
763
759
|
"TELEGRAM_AUTO_CLEAR_WEBHOOK=true",
|
|
764
760
|
"TELEGRAM_ALLOWED_UPDATES=message,edited_message",
|
|
765
|
-
"TELEGRAM_DEFAULT_BOT_KEY=
|
|
761
|
+
"TELEGRAM_DEFAULT_BOT_KEY=",
|
|
766
762
|
"",
|
|
767
763
|
"# Legacy fallback (still supported)",
|
|
768
764
|
"TELEGRAM_BOT_TOKEN=",
|
|
769
765
|
"",
|
|
770
|
-
"# Preferred named bot entry",
|
|
771
|
-
"TELEGRAM_BOT_RYOAI_SERVER_BOT_ID=",
|
|
772
|
-
"TELEGRAM_BOT_RYOAI_TOKEN=",
|
|
773
|
-
"TELEGRAM_BOT_RYOAI_ROLE_PROFILE=",
|
|
774
|
-
"TELEGRAM_BOT_RYOAI_AI_CLIENT=",
|
|
775
|
-
"TELEGRAM_BOT_RYOAI_AI_MODEL=",
|
|
776
|
-
"TELEGRAM_BOT_RYOAI_AI_PERMISSION_MODE=",
|
|
777
|
-
"TELEGRAM_BOT_RYOAI_AI_REASONING_EFFORT=",
|
|
778
|
-
"",
|
|
779
766
|
].join("\n");
|
|
780
767
|
}
|
|
781
768
|
return [
|
|
@@ -1053,7 +1040,12 @@ function ensureProviderEnvTemplate(provider) {
|
|
|
1053
1040
|
const filePath = providerEnvFilePath(provider);
|
|
1054
1041
|
try {
|
|
1055
1042
|
if (fs.existsSync(filePath)) {
|
|
1056
|
-
return {
|
|
1043
|
+
return {
|
|
1044
|
+
filePath,
|
|
1045
|
+
created: false,
|
|
1046
|
+
existed: true,
|
|
1047
|
+
normalized: normalizeExistingProviderEnvFile(provider, filePath),
|
|
1048
|
+
};
|
|
1057
1049
|
}
|
|
1058
1050
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
1059
1051
|
fs.writeFileSync(filePath, providerEnvTemplate(provider), "utf8");
|
|
@@ -2636,6 +2628,15 @@ function parseSimpleEnvText(rawText) {
|
|
|
2636
2628
|
return out;
|
|
2637
2629
|
}
|
|
2638
2630
|
|
|
2631
|
+
function formatProviderEnvValue(rawValue) {
|
|
2632
|
+
const text = String(rawValue ?? "");
|
|
2633
|
+
if (!text) return "";
|
|
2634
|
+
if (/^[A-Za-z0-9_./:@,\-]+$/.test(text)) {
|
|
2635
|
+
return text;
|
|
2636
|
+
}
|
|
2637
|
+
return JSON.stringify(text);
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2639
2640
|
function normalizeTelegramBotEnvKey(rawValue, fallback = "") {
|
|
2640
2641
|
const normalized = String(rawValue || "")
|
|
2641
2642
|
.trim()
|
|
@@ -2705,6 +2706,240 @@ function collectTelegramEnvBotEntries(parsedEnv) {
|
|
|
2705
2706
|
return Array.from(entries.values());
|
|
2706
2707
|
}
|
|
2707
2708
|
|
|
2709
|
+
function telegramBotEntryDisplayNameForState(entry) {
|
|
2710
|
+
const current = safeObject(entry);
|
|
2711
|
+
const username = normalizeTelegramBotUsername(current.username || "");
|
|
2712
|
+
if (username) return username;
|
|
2713
|
+
const key = normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
|
|
2714
|
+
if (!key) return "telegram_bot";
|
|
2715
|
+
return key.endsWith("_bot") ? key : `${key}_bot`;
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
function parseTelegramBotEntryFile(filePath) {
|
|
2719
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
2720
|
+
const parsed = parseSimpleEnvText(raw);
|
|
2721
|
+
const keyFromFile = normalizeTelegramBotEnvKey(path.basename(filePath, path.extname(filePath)), "telegram_bot");
|
|
2722
|
+
return {
|
|
2723
|
+
key: keyFromFile,
|
|
2724
|
+
username: normalizeTelegramBotUsername(parsed.TELEGRAM_BOT_NAME || parsed.TELEGRAM_BOT_USERNAME || ""),
|
|
2725
|
+
serverBotID: String(parsed.TELEGRAM_BOT_SERVER_BOT_ID || "").trim(),
|
|
2726
|
+
token: String(parsed.TELEGRAM_BOT_TOKEN || "").trim(),
|
|
2727
|
+
roleProfile: normalizeRunnerRoleProfileName(parsed.TELEGRAM_BOT_ROLE_PROFILE || ""),
|
|
2728
|
+
client: normalizeLocalAIClientName(parsed.TELEGRAM_BOT_AI_CLIENT || "", ""),
|
|
2729
|
+
model: String(parsed.TELEGRAM_BOT_AI_MODEL || "").trim(),
|
|
2730
|
+
permissionMode: normalizeLocalAIPermissionMode(parsed.TELEGRAM_BOT_AI_PERMISSION_MODE || "", ""),
|
|
2731
|
+
reasoningEffort: normalizeLocalAIReasoningEffort(parsed.TELEGRAM_BOT_AI_REASONING_EFFORT || "", ""),
|
|
2732
|
+
entryFilePath: filePath,
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
function loadTelegramBotEntriesFromFiles() {
|
|
2737
|
+
const dirPath = telegramBotEntriesDirPath();
|
|
2738
|
+
if (!fs.existsSync(dirPath)) return [];
|
|
2739
|
+
return fs.readdirSync(dirPath, { withFileTypes: true })
|
|
2740
|
+
.filter((item) => item.isFile() && /\.env$/i.test(item.name))
|
|
2741
|
+
.map((item) => path.join(dirPath, item.name))
|
|
2742
|
+
.sort((left, right) => left.localeCompare(right))
|
|
2743
|
+
.map((filePath) => {
|
|
2744
|
+
try {
|
|
2745
|
+
return parseTelegramBotEntryFile(filePath);
|
|
2746
|
+
} catch {
|
|
2747
|
+
return null;
|
|
2748
|
+
}
|
|
2749
|
+
})
|
|
2750
|
+
.filter(Boolean);
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
function buildMergedTelegramEnvParsed(globalParsed, entries) {
|
|
2754
|
+
const merged = { ...safeObject(globalParsed) };
|
|
2755
|
+
Object.keys(merged).forEach((key) => {
|
|
2756
|
+
if (isTelegramEntryEnvKey(key)) {
|
|
2757
|
+
delete merged[key];
|
|
2758
|
+
}
|
|
2759
|
+
});
|
|
2760
|
+
ensureArray(entries).forEach((entryRaw) => {
|
|
2761
|
+
const entry = safeObject(entryRaw);
|
|
2762
|
+
const upper = String(entry.key || "").trim().toUpperCase();
|
|
2763
|
+
if (!upper) return;
|
|
2764
|
+
merged[`TELEGRAM_BOT_${upper}_SERVER_BOT_ID`] = String(entry.serverBotID || "").trim();
|
|
2765
|
+
merged[`TELEGRAM_BOT_${upper}_USERNAME`] = normalizeTelegramBotUsername(entry.username || "");
|
|
2766
|
+
merged[`TELEGRAM_BOT_${upper}_TOKEN`] = String(entry.token || "").trim();
|
|
2767
|
+
merged[`TELEGRAM_BOT_${upper}_ROLE_PROFILE`] = String(entry.roleProfile || "").trim();
|
|
2768
|
+
merged[`TELEGRAM_BOT_${upper}_AI_CLIENT`] = String(entry.client || "").trim();
|
|
2769
|
+
merged[`TELEGRAM_BOT_${upper}_AI_MODEL`] = String(entry.model || "").trim();
|
|
2770
|
+
merged[`TELEGRAM_BOT_${upper}_AI_PERMISSION_MODE`] = String(entry.permissionMode || "").trim();
|
|
2771
|
+
merged[`TELEGRAM_BOT_${upper}_AI_REASONING_EFFORT`] = String(entry.reasoningEffort || "").trim();
|
|
2772
|
+
});
|
|
2773
|
+
return merged;
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
function readTelegramEnvState() {
|
|
2777
|
+
const filePath = providerEnvFilePath("telegram");
|
|
2778
|
+
try {
|
|
2779
|
+
if (!fs.existsSync(filePath)) {
|
|
2780
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
2781
|
+
fs.writeFileSync(filePath, providerEnvTemplate("telegram"), "utf8");
|
|
2782
|
+
}
|
|
2783
|
+
} catch (err) {
|
|
2784
|
+
return {
|
|
2785
|
+
filePath,
|
|
2786
|
+
entriesDirPath: telegramBotEntriesDirPath(),
|
|
2787
|
+
parsed: {},
|
|
2788
|
+
globalParsed: {},
|
|
2789
|
+
entries: [],
|
|
2790
|
+
error: String(err?.message || err),
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
const raw = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
2794
|
+
const globalParsedRaw = parseSimpleEnvText(raw);
|
|
2795
|
+
const inlineEntries = collectTelegramEnvBotEntries(globalParsedRaw);
|
|
2796
|
+
const fileEntries = loadTelegramBotEntriesFromFiles();
|
|
2797
|
+
const mergedEntries = new Map();
|
|
2798
|
+
inlineEntries.forEach((entry) => mergedEntries.set(entry.key, { ...entry }));
|
|
2799
|
+
fileEntries.forEach((entry) => mergedEntries.set(entry.key, { ...entry }));
|
|
2800
|
+
const globalParsed = { ...globalParsedRaw };
|
|
2801
|
+
Object.keys(globalParsed).forEach((key) => {
|
|
2802
|
+
if (isTelegramEntryEnvKey(key)) {
|
|
2803
|
+
delete globalParsed[key];
|
|
2804
|
+
}
|
|
2805
|
+
});
|
|
2806
|
+
const entries = Array.from(mergedEntries.values());
|
|
2807
|
+
return {
|
|
2808
|
+
filePath,
|
|
2809
|
+
entriesDirPath: telegramBotEntriesDirPath(),
|
|
2810
|
+
parsed: buildMergedTelegramEnvParsed(globalParsed, entries),
|
|
2811
|
+
globalParsed,
|
|
2812
|
+
entries,
|
|
2813
|
+
};
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
function isTelegramEntryEnvKey(rawKey) {
|
|
2817
|
+
return /^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i
|
|
2818
|
+
.test(String(rawKey || "").trim());
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
function telegramEntryCommentNameForEnv(entry) {
|
|
2822
|
+
const current = safeObject(entry);
|
|
2823
|
+
const username = normalizeTelegramBotUsername(current.username || "");
|
|
2824
|
+
if (username) return username;
|
|
2825
|
+
const key = normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
|
|
2826
|
+
if (!key) return "telegram_bot";
|
|
2827
|
+
return key.endsWith("_bot") ? key : `${key}_bot`;
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
function renderNormalizedTelegramEnv(parsedEnv) {
|
|
2831
|
+
const parsed = safeObject(parsedEnv);
|
|
2832
|
+
const defaultBotKey = normalizeTelegramBotEnvKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", "");
|
|
2833
|
+
const lines = [
|
|
2834
|
+
"# Metheus local Telegram bot settings",
|
|
2835
|
+
"# Keep this file on your machine only. Do not commit it.",
|
|
2836
|
+
"# Store only Telegram-wide settings here.",
|
|
2837
|
+
"# Per-bot secrets and AI settings live in ~/.metheus/telegram-bots/<bot-key>.env.",
|
|
2838
|
+
"",
|
|
2839
|
+
`TELEGRAM_API_BASE_URL=${formatProviderEnvValue(parsed.TELEGRAM_API_BASE_URL || "")}`,
|
|
2840
|
+
`TELEGRAM_AUTO_CLEAR_WEBHOOK=${boolFromRaw(parsed.TELEGRAM_AUTO_CLEAR_WEBHOOK, true) ? "true" : "false"}`,
|
|
2841
|
+
`TELEGRAM_ALLOWED_UPDATES=${formatProviderEnvValue(String(parsed.TELEGRAM_ALLOWED_UPDATES || "").trim() || "message,edited_message")}`,
|
|
2842
|
+
`TELEGRAM_DEFAULT_BOT_KEY=${formatProviderEnvValue(defaultBotKey || "")}`,
|
|
2843
|
+
"",
|
|
2844
|
+
"# Legacy fallback",
|
|
2845
|
+
`TELEGRAM_BOT_TOKEN=${formatProviderEnvValue(parsed.TELEGRAM_BOT_TOKEN || "")}`,
|
|
2846
|
+
"",
|
|
2847
|
+
];
|
|
2848
|
+
const knownKeys = new Set([
|
|
2849
|
+
"TELEGRAM_API_BASE_URL",
|
|
2850
|
+
"TELEGRAM_AUTO_CLEAR_WEBHOOK",
|
|
2851
|
+
"TELEGRAM_ALLOWED_UPDATES",
|
|
2852
|
+
"TELEGRAM_DEFAULT_BOT_KEY",
|
|
2853
|
+
"TELEGRAM_BOT_TOKEN",
|
|
2854
|
+
]);
|
|
2855
|
+
const extras = Object.keys(parsed)
|
|
2856
|
+
.filter((key) => !knownKeys.has(key) && !isTelegramEntryEnvKey(key))
|
|
2857
|
+
.sort((left, right) => left.localeCompare(right));
|
|
2858
|
+
if (extras.length) {
|
|
2859
|
+
lines.push("# Additional preserved keys");
|
|
2860
|
+
extras.forEach((key) => {
|
|
2861
|
+
lines.push(`${key}=${formatProviderEnvValue(parsed[key])}`);
|
|
2862
|
+
});
|
|
2863
|
+
lines.push("");
|
|
2864
|
+
}
|
|
2865
|
+
return `${lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd()}\n`;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
function renderTelegramBotEntryEnv(entryRaw) {
|
|
2869
|
+
const entry = safeObject(entryRaw);
|
|
2870
|
+
const botName = telegramEntryCommentNameForEnv(entry);
|
|
2871
|
+
const lines = [
|
|
2872
|
+
"# Metheus local Telegram bot entry",
|
|
2873
|
+
`# Bot: ${botName}`,
|
|
2874
|
+
"",
|
|
2875
|
+
`TELEGRAM_BOT_NAME=${formatProviderEnvValue(botName)}`,
|
|
2876
|
+
`TELEGRAM_BOT_SERVER_BOT_ID=${formatProviderEnvValue(entry.serverBotID || "")}`,
|
|
2877
|
+
`TELEGRAM_BOT_TOKEN=${formatProviderEnvValue(entry.token || "")}`,
|
|
2878
|
+
`TELEGRAM_BOT_ROLE_PROFILE=${formatProviderEnvValue(entry.roleProfile || "")}`,
|
|
2879
|
+
`TELEGRAM_BOT_AI_CLIENT=${formatProviderEnvValue(entry.client || "")}`,
|
|
2880
|
+
`TELEGRAM_BOT_AI_MODEL=${formatProviderEnvValue(entry.model || "")}`,
|
|
2881
|
+
`TELEGRAM_BOT_AI_PERMISSION_MODE=${formatProviderEnvValue(entry.permissionMode || "")}`,
|
|
2882
|
+
`TELEGRAM_BOT_AI_REASONING_EFFORT=${formatProviderEnvValue(entry.reasoningEffort || "")}`,
|
|
2883
|
+
"",
|
|
2884
|
+
];
|
|
2885
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
function writeTelegramEnvState(parsedEnv) {
|
|
2889
|
+
const parsed = safeObject(parsedEnv);
|
|
2890
|
+
const entries = collectTelegramEnvBotEntries(parsed)
|
|
2891
|
+
.filter((entry) => (
|
|
2892
|
+
entry.token
|
|
2893
|
+
|| entry.username
|
|
2894
|
+
|| entry.serverBotID
|
|
2895
|
+
|| entry.roleProfile
|
|
2896
|
+
|| entry.client
|
|
2897
|
+
|| entry.model
|
|
2898
|
+
|| entry.permissionMode
|
|
2899
|
+
|| entry.reasoningEffort
|
|
2900
|
+
))
|
|
2901
|
+
.sort((left, right) => String(left.key || "").localeCompare(String(right.key || "")));
|
|
2902
|
+
const globalParsed = { ...parsed };
|
|
2903
|
+
Object.keys(globalParsed).forEach((key) => {
|
|
2904
|
+
if (isTelegramEntryEnvKey(key)) {
|
|
2905
|
+
delete globalParsed[key];
|
|
2906
|
+
}
|
|
2907
|
+
});
|
|
2908
|
+
const globalFilePath = providerEnvFilePath("telegram");
|
|
2909
|
+
fs.mkdirSync(path.dirname(globalFilePath), { recursive: true });
|
|
2910
|
+
fs.writeFileSync(globalFilePath, renderNormalizedTelegramEnv(globalParsed), {
|
|
2911
|
+
encoding: "utf8",
|
|
2912
|
+
mode: 0o600,
|
|
2913
|
+
});
|
|
2914
|
+
const entriesDirPath = telegramBotEntriesDirPath();
|
|
2915
|
+
fs.mkdirSync(entriesDirPath, { recursive: true });
|
|
2916
|
+
const activeFiles = new Set();
|
|
2917
|
+
entries.forEach((entry) => {
|
|
2918
|
+
const entryFilePath = telegramBotEntryFilePath(entry.key);
|
|
2919
|
+
activeFiles.add(path.resolve(entryFilePath));
|
|
2920
|
+
fs.writeFileSync(entryFilePath, renderTelegramBotEntryEnv(entry), {
|
|
2921
|
+
encoding: "utf8",
|
|
2922
|
+
mode: 0o600,
|
|
2923
|
+
});
|
|
2924
|
+
});
|
|
2925
|
+
fs.readdirSync(entriesDirPath, { withFileTypes: true })
|
|
2926
|
+
.filter((item) => item.isFile() && /\.env$/i.test(item.name))
|
|
2927
|
+
.forEach((item) => {
|
|
2928
|
+
const filePath = path.resolve(path.join(entriesDirPath, item.name));
|
|
2929
|
+
if (!activeFiles.has(filePath)) {
|
|
2930
|
+
fs.rmSync(filePath, { force: true });
|
|
2931
|
+
}
|
|
2932
|
+
});
|
|
2933
|
+
return globalFilePath;
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
function normalizeExistingProviderEnvFile(provider, filePath) {
|
|
2937
|
+
if (normalizeBotProvider(provider) !== "telegram") return false;
|
|
2938
|
+
const state = readTelegramEnvState();
|
|
2939
|
+
writeTelegramEnvState(state.parsed);
|
|
2940
|
+
return true;
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2708
2943
|
function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
2709
2944
|
const parsed = safeObject(parsedEnv);
|
|
2710
2945
|
const legacyToken = String(parsed.TELEGRAM_BOT_TOKEN || "").trim();
|
|
@@ -2835,6 +3070,20 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
2835
3070
|
function loadProviderEnvConfig(provider, selectors = {}) {
|
|
2836
3071
|
const normalizedProvider = normalizeBotProvider(provider);
|
|
2837
3072
|
const config = providerEnvConfig(normalizedProvider);
|
|
3073
|
+
if (normalizedProvider === "telegram") {
|
|
3074
|
+
const state = readTelegramEnvState();
|
|
3075
|
+
if (state.error) {
|
|
3076
|
+
return {
|
|
3077
|
+
ok: false,
|
|
3078
|
+
provider: normalizedProvider,
|
|
3079
|
+
providerLabel: config.label,
|
|
3080
|
+
filePath: state.filePath,
|
|
3081
|
+
error: state.error,
|
|
3082
|
+
token: "",
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
return resolveTelegramEnvConfig(state.parsed, state.filePath, config, selectors);
|
|
3086
|
+
}
|
|
2838
3087
|
const ensured = ensureProviderEnvTemplate(normalizedProvider);
|
|
2839
3088
|
const filePath = ensured.filePath;
|
|
2840
3089
|
if (ensured.error) {
|
|
@@ -2850,9 +3099,6 @@ function loadProviderEnvConfig(provider, selectors = {}) {
|
|
|
2850
3099
|
try {
|
|
2851
3100
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
2852
3101
|
const parsed = parseSimpleEnvText(raw);
|
|
2853
|
-
if (normalizedProvider === "telegram") {
|
|
2854
|
-
return resolveTelegramEnvConfig(parsed, filePath, config, selectors);
|
|
2855
|
-
}
|
|
2856
3102
|
const token = String(parsed[config.tokenKey] || "").trim();
|
|
2857
3103
|
if (!token) {
|
|
2858
3104
|
return {
|
|
@@ -3352,10 +3598,14 @@ function buildBotCommandDeps() {
|
|
|
3352
3598
|
providerEnvOrder: PROVIDER_ENV_ORDER,
|
|
3353
3599
|
providerEnvConfig,
|
|
3354
3600
|
providerEnvFilePath,
|
|
3601
|
+
telegramBotEntriesDirPath,
|
|
3602
|
+
telegramBotEntryFilePath,
|
|
3355
3603
|
ensureProviderEnvTemplate,
|
|
3356
3604
|
parseCommandAndFlags,
|
|
3357
3605
|
parseSimpleEnvText,
|
|
3358
3606
|
collectTelegramEnvBotEntries,
|
|
3607
|
+
readTelegramEnvState,
|
|
3608
|
+
writeTelegramEnvState,
|
|
3359
3609
|
normalizeBotProvider,
|
|
3360
3610
|
normalizeTelegramBotEnvKey,
|
|
3361
3611
|
normalizeTelegramBotUsername,
|
|
@@ -5114,6 +5364,45 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
5114
5364
|
&& telegramEnvV2ByUsername.allowedUpdates.includes("channel_post"),
|
|
5115
5365
|
`bot=${String(telegramEnvV2ByUsername.botKey || "(none)")} updates=${String((telegramEnvV2ByUsername.allowedUpdates || []).join(","))}`,
|
|
5116
5366
|
);
|
|
5367
|
+
const telegramEnvNormalizeTempHome = fs.mkdtempSync(path.join(os.tmpdir(), "metheus-telegram-env-normalize-"));
|
|
5368
|
+
const previousUserProfile = process.env.USERPROFILE;
|
|
5369
|
+
const previousHome = process.env.HOME;
|
|
5370
|
+
let normalizedGlobalText = "";
|
|
5371
|
+
let normalizedBotText = "";
|
|
5372
|
+
try {
|
|
5373
|
+
process.env.USERPROFILE = telegramEnvNormalizeTempHome;
|
|
5374
|
+
process.env.HOME = telegramEnvNormalizeTempHome;
|
|
5375
|
+
const normalizeTestEnvPath = providerEnvFilePath("telegram");
|
|
5376
|
+
fs.mkdirSync(path.dirname(normalizeTestEnvPath), { recursive: true });
|
|
5377
|
+
fs.writeFileSync(
|
|
5378
|
+
normalizeTestEnvPath,
|
|
5379
|
+
[
|
|
5380
|
+
"TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot",
|
|
5381
|
+
"TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID=bot-ryoai",
|
|
5382
|
+
"TELEGRAM_BOT_RYOAI_BOT_TOKEN=ryoai-token",
|
|
5383
|
+
"",
|
|
5384
|
+
].join("\n"),
|
|
5385
|
+
"utf8",
|
|
5386
|
+
);
|
|
5387
|
+
ensureProviderEnvTemplate("telegram");
|
|
5388
|
+
normalizedGlobalText = fs.readFileSync(normalizeTestEnvPath, "utf8");
|
|
5389
|
+
normalizedBotText = fs.readFileSync(telegramBotEntryFilePath("ryoai"), "utf8");
|
|
5390
|
+
} finally {
|
|
5391
|
+
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
5392
|
+
else process.env.USERPROFILE = previousUserProfile;
|
|
5393
|
+
if (previousHome === undefined) delete process.env.HOME;
|
|
5394
|
+
else process.env.HOME = previousHome;
|
|
5395
|
+
}
|
|
5396
|
+
push(
|
|
5397
|
+
"telegram_env_existing_file_auto_normalizes_named_keys",
|
|
5398
|
+
normalizedGlobalText.includes("TELEGRAM_DEFAULT_BOT_KEY=ryoai")
|
|
5399
|
+
&& !normalizedGlobalText.includes("TELEGRAM_BOT_RYOAI_BOT_TOKEN")
|
|
5400
|
+
&& !normalizedGlobalText.includes("TELEGRAM_BOT_RYOAI_TOKEN")
|
|
5401
|
+
&& normalizedBotText.includes("TELEGRAM_BOT_NAME=ryoai_bot")
|
|
5402
|
+
&& normalizedBotText.includes("TELEGRAM_BOT_SERVER_BOT_ID=bot-ryoai")
|
|
5403
|
+
&& normalizedBotText.includes("TELEGRAM_BOT_TOKEN=ryoai-token"),
|
|
5404
|
+
`${normalizedGlobalText}\n---\n${normalizedBotText}`,
|
|
5405
|
+
);
|
|
5117
5406
|
const telegramSupport = getProviderSupport("telegram");
|
|
5118
5407
|
push(
|
|
5119
5408
|
"provider_support_telegram_full_runner",
|
package/lib/bot-commands.mjs
CHANGED
|
@@ -411,6 +411,17 @@ async function promptKeepChangeClear(ui, title, { allowClear = true, defaultValu
|
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
function loadProviderEnvState(provider, deps) {
|
|
414
|
+
if (provider === "telegram" && typeof deps?.readTelegramEnvState === "function") {
|
|
415
|
+
const state = deps.readTelegramEnvState();
|
|
416
|
+
if (state?.error) {
|
|
417
|
+
throw new Error(String(state.error));
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
provider,
|
|
421
|
+
filePath: String(state.filePath || "").trim(),
|
|
422
|
+
parsed: safeObject(state.parsed),
|
|
423
|
+
};
|
|
424
|
+
}
|
|
414
425
|
const ensureTemplate = requireDependency(deps, "ensureProviderEnvTemplate");
|
|
415
426
|
const filePathResolver = requireDependency(deps, "providerEnvFilePath");
|
|
416
427
|
const parseEnv = requireDependency(deps, "parseSimpleEnvText");
|
|
@@ -441,6 +452,15 @@ function telegramEntryEnvKeys(botKey) {
|
|
|
441
452
|
};
|
|
442
453
|
}
|
|
443
454
|
|
|
455
|
+
function telegramEntryCommentName(entry) {
|
|
456
|
+
const current = safeObject(entry);
|
|
457
|
+
const username = String(current.username || "").trim();
|
|
458
|
+
if (username) return username;
|
|
459
|
+
const key = String(current.key || "").trim();
|
|
460
|
+
if (!key) return "telegram_bot";
|
|
461
|
+
return key.endsWith("_bot") ? key : `${key}_bot`;
|
|
462
|
+
}
|
|
463
|
+
|
|
444
464
|
function persistTelegramUsername(entry) {
|
|
445
465
|
const current = safeObject(entry);
|
|
446
466
|
if (current.__preferServerIdentity) return "";
|
|
@@ -491,6 +511,11 @@ function telegramKnownKeys(parsedEnv, deps) {
|
|
|
491
511
|
return keys;
|
|
492
512
|
}
|
|
493
513
|
|
|
514
|
+
function isTelegramEntryEnvKey(rawKey) {
|
|
515
|
+
return /^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i
|
|
516
|
+
.test(String(rawKey || "").trim());
|
|
517
|
+
}
|
|
518
|
+
|
|
494
519
|
function renderTelegramEnv(parsedEnv, deps) {
|
|
495
520
|
const parsed = safeObject(parsedEnv);
|
|
496
521
|
const collectEntries = requireDependency(deps, "collectTelegramEnvBotEntries");
|
|
@@ -535,7 +560,7 @@ function renderTelegramEnv(parsedEnv, deps) {
|
|
|
535
560
|
entries.forEach((entry) => {
|
|
536
561
|
const keys = telegramEntryEnvKeys(entry.key);
|
|
537
562
|
const entryLines = [
|
|
538
|
-
`# Telegram bot entry: ${entry
|
|
563
|
+
`# Telegram bot entry: ${telegramEntryCommentName(entry)}`,
|
|
539
564
|
`${keys.serverBotID}=${formatEnvValue(entry.serverBotID || "")}`,
|
|
540
565
|
];
|
|
541
566
|
if (String(entry.username || "").trim()) {
|
|
@@ -555,7 +580,7 @@ function renderTelegramEnv(parsedEnv, deps) {
|
|
|
555
580
|
}
|
|
556
581
|
const knownKeys = telegramKnownKeys(parsed, deps);
|
|
557
582
|
const extras = Object.keys(parsed)
|
|
558
|
-
.filter((key) => !knownKeys.has(key))
|
|
583
|
+
.filter((key) => !knownKeys.has(key) && !isTelegramEntryEnvKey(key))
|
|
559
584
|
.sort((left, right) => left.localeCompare(right));
|
|
560
585
|
if (extras.length) {
|
|
561
586
|
lines.push("# Additional preserved keys");
|
|
@@ -591,6 +616,9 @@ function renderTokenOnlyProviderEnv(provider, parsedEnv, deps) {
|
|
|
591
616
|
}
|
|
592
617
|
|
|
593
618
|
function writeProviderEnvState(provider, parsedEnv, deps) {
|
|
619
|
+
if (provider === "telegram" && typeof deps?.writeTelegramEnvState === "function") {
|
|
620
|
+
return deps.writeTelegramEnvState(parsedEnv);
|
|
621
|
+
}
|
|
594
622
|
const filePath = String(requireDependency(deps, "providerEnvFilePath")(provider) || "").trim();
|
|
595
623
|
const rendered = provider === "telegram"
|
|
596
624
|
? renderTelegramEnv(parsedEnv, deps)
|
|
@@ -289,6 +289,15 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
289
289
|
const baseURL = `http://127.0.0.1:${mock.port}`;
|
|
290
290
|
const telegramApiBaseURL = `${baseURL}/telegram`;
|
|
291
291
|
const telegramEnvPath = path.join(tempHome, ".metheus", "telegram.env");
|
|
292
|
+
const telegramBotEntriesDir = path.join(tempHome, ".metheus", "telegram-bots");
|
|
293
|
+
const readTelegramGlobals = () => parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
|
|
294
|
+
const readTelegramBotEntry = (botKey) => {
|
|
295
|
+
const filePath = path.join(telegramBotEntriesDir, `${String(botKey || "").trim()}.env`);
|
|
296
|
+
if (!fs.existsSync(filePath)) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
return parseSimpleEnvText(fs.readFileSync(filePath, "utf8"));
|
|
300
|
+
};
|
|
292
301
|
|
|
293
302
|
const setupResult = await runCLI({
|
|
294
303
|
cliPath,
|
|
@@ -314,7 +323,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
314
323
|
],
|
|
315
324
|
env,
|
|
316
325
|
});
|
|
317
|
-
const telegramGlobals =
|
|
326
|
+
const telegramGlobals = readTelegramGlobals();
|
|
318
327
|
push(
|
|
319
328
|
"bot_global_updates_telegram_settings",
|
|
320
329
|
String(telegramGlobals.TELEGRAM_API_BASE_URL || "") === telegramApiBaseURL
|
|
@@ -339,17 +348,18 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
339
348
|
]),
|
|
340
349
|
},
|
|
341
350
|
});
|
|
342
|
-
const addState =
|
|
351
|
+
const addState = readTelegramBotEntry("monitorselftestbot");
|
|
352
|
+
const addGlobals = readTelegramGlobals();
|
|
343
353
|
push(
|
|
344
354
|
"bot_add_guided_creates_named_telegram_entry",
|
|
345
|
-
String(addState.
|
|
346
|
-
&& String(addState.
|
|
347
|
-
&& String(addState.
|
|
348
|
-
&& String(addState.
|
|
349
|
-
&& String(addState.
|
|
350
|
-
&& String(addState.
|
|
351
|
-
&& String(
|
|
352
|
-
`default=${String(
|
|
355
|
+
String(addState.TELEGRAM_BOT_NAME || "").toLowerCase().includes("monitorselftestbot")
|
|
356
|
+
&& String(addState.TELEGRAM_BOT_TOKEN || "") === "selftest-main-token"
|
|
357
|
+
&& String(addState.TELEGRAM_BOT_ROLE_PROFILE || "") === "monitor"
|
|
358
|
+
&& String(addState.TELEGRAM_BOT_AI_CLIENT || "") === "codex"
|
|
359
|
+
&& String(addState.TELEGRAM_BOT_AI_PERMISSION_MODE || "") === "read_only"
|
|
360
|
+
&& String(addState.TELEGRAM_BOT_AI_REASONING_EFFORT || "") === "low"
|
|
361
|
+
&& String(addGlobals.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
362
|
+
`default=${String(addGlobals.TELEGRAM_DEFAULT_BOT_KEY || "")} token=${String(addState.TELEGRAM_BOT_TOKEN || "")} role=${String(addState.TELEGRAM_BOT_ROLE_PROFILE || "")} client=${String(addState.TELEGRAM_BOT_AI_CLIENT || "")}`,
|
|
353
363
|
);
|
|
354
364
|
|
|
355
365
|
const groupedMock = await createMockServer({
|
|
@@ -388,15 +398,15 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
388
398
|
]),
|
|
389
399
|
},
|
|
390
400
|
});
|
|
391
|
-
const groupedState =
|
|
401
|
+
const groupedState = readTelegramBotEntry("ryoai");
|
|
392
402
|
push(
|
|
393
403
|
"bot_add_guided_autoresolves_server_bot_group_without_role_prompt",
|
|
394
|
-
String(groupedState.
|
|
395
|
-
&& String(groupedState.
|
|
396
|
-
&& String(groupedState.
|
|
397
|
-
&& String(groupedState.
|
|
398
|
-
&& String(groupedState.
|
|
399
|
-
`
|
|
404
|
+
String(groupedState.TELEGRAM_BOT_NAME || "").toLowerCase() === "ryoai_bot"
|
|
405
|
+
&& String(groupedState.TELEGRAM_BOT_SERVER_BOT_ID || "") === ""
|
|
406
|
+
&& String(groupedState.TELEGRAM_BOT_ROLE_PROFILE || "") === ""
|
|
407
|
+
&& String(groupedState.TELEGRAM_BOT_AI_CLIENT || "") === ""
|
|
408
|
+
&& String(groupedState.TELEGRAM_BOT_AI_PERMISSION_MODE || "") === "",
|
|
409
|
+
`name=${String(groupedState.TELEGRAM_BOT_NAME || "")} server_bot_id=${String(groupedState.TELEGRAM_BOT_SERVER_BOT_ID || "")} role=${String(groupedState.TELEGRAM_BOT_ROLE_PROFILE || "")}`,
|
|
400
410
|
);
|
|
401
411
|
|
|
402
412
|
const groupedEditResult = await runCLI({
|
|
@@ -571,14 +581,14 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
571
581
|
!String(guidedEditResult.stdout || "").includes("Telegram username (without @)"),
|
|
572
582
|
String(guidedEditResult.stdout || "").split(/\r?\n/).filter((line) => line.includes("Telegram username")).join(" | ") || "username prompt skipped",
|
|
573
583
|
);
|
|
574
|
-
const guidedState =
|
|
584
|
+
const guidedState = readTelegramBotEntry("monitorselftestbot");
|
|
575
585
|
push(
|
|
576
586
|
"bot_edit_guided_prompts_update_ai_binding_fields",
|
|
577
|
-
String(guidedState.
|
|
578
|
-
&& String(guidedState.
|
|
579
|
-
&& String(guidedState.
|
|
580
|
-
&& String(guidedState.
|
|
581
|
-
`client=${String(guidedState.
|
|
587
|
+
String(guidedState.TELEGRAM_BOT_AI_CLIENT || "") === "gemini"
|
|
588
|
+
&& String(guidedState.TELEGRAM_BOT_AI_MODEL || "") === "gemini-3.1-pro"
|
|
589
|
+
&& String(guidedState.TELEGRAM_BOT_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
590
|
+
&& String(guidedState.TELEGRAM_BOT_AI_REASONING_EFFORT || "") === "medium",
|
|
591
|
+
`client=${String(guidedState.TELEGRAM_BOT_AI_CLIENT || "")} model=${String(guidedState.TELEGRAM_BOT_AI_MODEL || "")}`,
|
|
582
592
|
);
|
|
583
593
|
|
|
584
594
|
await runCLI({
|
|
@@ -596,15 +606,15 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
596
606
|
],
|
|
597
607
|
env,
|
|
598
608
|
});
|
|
599
|
-
const editedState =
|
|
609
|
+
const editedState = readTelegramBotEntry("monitorselftestbot");
|
|
600
610
|
push(
|
|
601
611
|
"bot_edit_updates_ai_binding_fields",
|
|
602
|
-
String(editedState.
|
|
603
|
-
&& String(editedState.
|
|
604
|
-
&& String(editedState.
|
|
605
|
-
&& String(editedState.
|
|
606
|
-
&& String(editedState.
|
|
607
|
-
`client=${String(editedState.
|
|
612
|
+
String(editedState.TELEGRAM_BOT_TOKEN || "") === "selftest-edited-token"
|
|
613
|
+
&& String(editedState.TELEGRAM_BOT_AI_CLIENT || "") === "claude"
|
|
614
|
+
&& String(editedState.TELEGRAM_BOT_AI_MODEL || "") === "Sonnet 4.6r"
|
|
615
|
+
&& String(editedState.TELEGRAM_BOT_AI_PERMISSION_MODE || "") === "workspace_write"
|
|
616
|
+
&& String(editedState.TELEGRAM_BOT_AI_REASONING_EFFORT || "") === "medium",
|
|
617
|
+
`client=${String(editedState.TELEGRAM_BOT_AI_CLIENT || "")} model=${String(editedState.TELEGRAM_BOT_AI_MODEL || "")}`,
|
|
608
618
|
);
|
|
609
619
|
|
|
610
620
|
await runCLI({
|
|
@@ -619,7 +629,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
619
629
|
]),
|
|
620
630
|
},
|
|
621
631
|
});
|
|
622
|
-
const guidedDefaultState =
|
|
632
|
+
const guidedDefaultState = readTelegramGlobals();
|
|
623
633
|
push(
|
|
624
634
|
"bot_set_default_guided_selects_entry",
|
|
625
635
|
String(guidedDefaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
@@ -662,7 +672,7 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
662
672
|
],
|
|
663
673
|
env,
|
|
664
674
|
});
|
|
665
|
-
const defaultState =
|
|
675
|
+
const defaultState = readTelegramGlobals();
|
|
666
676
|
push(
|
|
667
677
|
"bot_set_default_updates_default_bot_key",
|
|
668
678
|
String(defaultState.TELEGRAM_DEFAULT_BOT_KEY || "") === "monitorselftestbot",
|
|
@@ -744,16 +754,15 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
744
754
|
],
|
|
745
755
|
env,
|
|
746
756
|
});
|
|
747
|
-
const aliasAddState =
|
|
757
|
+
const aliasAddState = readTelegramBotEntry("monitorselftestbot");
|
|
748
758
|
push(
|
|
749
759
|
"bot_add_accepts_ai_prefixed_option_aliases",
|
|
750
|
-
String(aliasAddState.
|
|
751
|
-
&& String(aliasAddState.
|
|
752
|
-
&& String(aliasAddState.
|
|
753
|
-
&& String(aliasAddState.
|
|
754
|
-
&& String(aliasAddState.
|
|
755
|
-
|
|
756
|
-
`client=${String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_MONITORSELFTESTBOT_AI_MODEL || "")}`,
|
|
760
|
+
String(aliasAddState.TELEGRAM_BOT_SERVER_BOT_ID || "") === mock.bots[0].id
|
|
761
|
+
&& String(aliasAddState.TELEGRAM_BOT_AI_CLIENT || "") === "codex"
|
|
762
|
+
&& String(aliasAddState.TELEGRAM_BOT_AI_MODEL || "") === "gpt-5.4"
|
|
763
|
+
&& String(aliasAddState.TELEGRAM_BOT_AI_PERMISSION_MODE || "") === "read_only"
|
|
764
|
+
&& String(aliasAddState.TELEGRAM_BOT_AI_REASONING_EFFORT || "") === "low",
|
|
765
|
+
`client=${String(aliasAddState.TELEGRAM_BOT_AI_CLIENT || "")} model=${String(aliasAddState.TELEGRAM_BOT_AI_MODEL || "")}`,
|
|
757
766
|
);
|
|
758
767
|
|
|
759
768
|
const guidedRemoveBeforeList = await runCLI({
|
|
@@ -823,12 +832,13 @@ export async function runSelftestBotCommands(push, deps) {
|
|
|
823
832
|
],
|
|
824
833
|
env,
|
|
825
834
|
});
|
|
826
|
-
const migratedState =
|
|
835
|
+
const migratedState = readTelegramBotEntry("legacy_main");
|
|
836
|
+
const migratedGlobals = readTelegramGlobals();
|
|
827
837
|
push(
|
|
828
838
|
"bot_migrate_converts_legacy_token_to_named_entry",
|
|
829
|
-
String(migratedState.
|
|
830
|
-
&& String(
|
|
831
|
-
`legacy_named=${String(migratedState.
|
|
839
|
+
String(migratedState.TELEGRAM_BOT_TOKEN || "") === "legacy-selftest-token"
|
|
840
|
+
&& String(migratedGlobals.TELEGRAM_BOT_TOKEN || "") === "",
|
|
841
|
+
`legacy_named=${String(migratedState.TELEGRAM_BOT_TOKEN || "")} fallback=${String(migratedGlobals.TELEGRAM_BOT_TOKEN || "")}`,
|
|
832
842
|
);
|
|
833
843
|
} catch (err) {
|
|
834
844
|
push("bot_commands_smoke", false, String(err?.message || err));
|