metheus-governance-mcp-cli 0.2.93 → 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 +33 -23
- package/cli.mjs +244 -101
- package/lib/bot-commands.mjs +14 -0
- 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,11 +165,16 @@ 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
|
|
|
167
|
-
When
|
|
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
|
|
168
178
|
|
|
169
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.
|
|
170
180
|
|
|
@@ -230,7 +240,7 @@ Behavior:
|
|
|
230
240
|
- `bot setup` asks for `Telegram / Slack / KakaoTalk` first, then prompts with numbered actions.
|
|
231
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.
|
|
232
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.
|
|
233
|
-
- 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.
|
|
234
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.
|
|
235
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.
|
|
236
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.
|
|
@@ -249,15 +259,15 @@ Behavior:
|
|
|
249
259
|
- `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
|
|
250
260
|
- `bot verify` without flags starts a guided numbered flow: provider -> bot entry -> output format.
|
|
251
261
|
- `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
|
|
252
|
-
- Telegram
|
|
253
|
-
- `
|
|
254
|
-
- `
|
|
255
|
-
- `
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
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`
|
|
261
271
|
- Slack and KakaoTalk currently use a single local token entry per provider in this command flow.
|
|
262
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.
|
|
263
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 [
|
|
@@ -2719,6 +2706,113 @@ function collectTelegramEnvBotEntries(parsedEnv) {
|
|
|
2719
2706
|
return Array.from(entries.values());
|
|
2720
2707
|
}
|
|
2721
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
|
+
|
|
2722
2816
|
function isTelegramEntryEnvKey(rawKey) {
|
|
2723
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
|
|
2724
2818
|
.test(String(rawKey || "").trim());
|
|
@@ -2735,30 +2829,12 @@ function telegramEntryCommentNameForEnv(entry) {
|
|
|
2735
2829
|
|
|
2736
2830
|
function renderNormalizedTelegramEnv(parsedEnv) {
|
|
2737
2831
|
const parsed = safeObject(parsedEnv);
|
|
2738
|
-
const entries = collectTelegramEnvBotEntries(parsed)
|
|
2739
|
-
.filter((entry) => (
|
|
2740
|
-
entry.token
|
|
2741
|
-
|| entry.username
|
|
2742
|
-
|| entry.serverBotID
|
|
2743
|
-
|| entry.roleProfile
|
|
2744
|
-
|| entry.client
|
|
2745
|
-
|| entry.model
|
|
2746
|
-
|| entry.permissionMode
|
|
2747
|
-
|| entry.reasoningEffort
|
|
2748
|
-
))
|
|
2749
|
-
.sort((left, right) => String(left.key || "").localeCompare(String(right.key || "")));
|
|
2750
2832
|
const defaultBotKey = normalizeTelegramBotEnvKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", "");
|
|
2751
|
-
if (defaultBotKey) {
|
|
2752
|
-
entries.sort((left, right) => {
|
|
2753
|
-
if (left.key === defaultBotKey) return -1;
|
|
2754
|
-
if (right.key === defaultBotKey) return 1;
|
|
2755
|
-
return String(left.key || "").localeCompare(String(right.key || ""));
|
|
2756
|
-
});
|
|
2757
|
-
}
|
|
2758
2833
|
const lines = [
|
|
2759
2834
|
"# Metheus local Telegram bot settings",
|
|
2760
2835
|
"# Keep this file on your machine only. Do not commit it.",
|
|
2761
|
-
"# Store Telegram
|
|
2836
|
+
"# Store only Telegram-wide settings here.",
|
|
2837
|
+
"# Per-bot secrets and AI settings live in ~/.metheus/telegram-bots/<bot-key>.env.",
|
|
2762
2838
|
"",
|
|
2763
2839
|
`TELEGRAM_API_BASE_URL=${formatProviderEnvValue(parsed.TELEGRAM_API_BASE_URL || "")}`,
|
|
2764
2840
|
`TELEGRAM_AUTO_CLEAR_WEBHOOK=${boolFromRaw(parsed.TELEGRAM_AUTO_CLEAR_WEBHOOK, true) ? "true" : "false"}`,
|
|
@@ -2769,29 +2845,6 @@ function renderNormalizedTelegramEnv(parsedEnv) {
|
|
|
2769
2845
|
`TELEGRAM_BOT_TOKEN=${formatProviderEnvValue(parsed.TELEGRAM_BOT_TOKEN || "")}`,
|
|
2770
2846
|
"",
|
|
2771
2847
|
];
|
|
2772
|
-
if (!entries.length) {
|
|
2773
|
-
lines.push("# No named Telegram bot entries configured yet", "");
|
|
2774
|
-
} else {
|
|
2775
|
-
entries.forEach((entry) => {
|
|
2776
|
-
const upper = String(entry.key || "").trim().toUpperCase();
|
|
2777
|
-
lines.push(
|
|
2778
|
-
`# Telegram bot entry: ${telegramEntryCommentNameForEnv(entry)}`,
|
|
2779
|
-
`TELEGRAM_BOT_${upper}_SERVER_BOT_ID=${formatProviderEnvValue(entry.serverBotID || "")}`,
|
|
2780
|
-
);
|
|
2781
|
-
if (String(entry.username || "").trim()) {
|
|
2782
|
-
lines.push(`TELEGRAM_BOT_${upper}_USERNAME=${formatProviderEnvValue(entry.username || "")}`);
|
|
2783
|
-
}
|
|
2784
|
-
lines.push(
|
|
2785
|
-
`TELEGRAM_BOT_${upper}_TOKEN=${formatProviderEnvValue(entry.token || "")}`,
|
|
2786
|
-
`TELEGRAM_BOT_${upper}_ROLE_PROFILE=${formatProviderEnvValue(entry.roleProfile || "")}`,
|
|
2787
|
-
`TELEGRAM_BOT_${upper}_AI_CLIENT=${formatProviderEnvValue(entry.client || "")}`,
|
|
2788
|
-
`TELEGRAM_BOT_${upper}_AI_MODEL=${formatProviderEnvValue(entry.model || "")}`,
|
|
2789
|
-
`TELEGRAM_BOT_${upper}_AI_PERMISSION_MODE=${formatProviderEnvValue(entry.permissionMode || "")}`,
|
|
2790
|
-
`TELEGRAM_BOT_${upper}_AI_REASONING_EFFORT=${formatProviderEnvValue(entry.reasoningEffort || "")}`,
|
|
2791
|
-
"",
|
|
2792
|
-
);
|
|
2793
|
-
});
|
|
2794
|
-
}
|
|
2795
2848
|
const knownKeys = new Set([
|
|
2796
2849
|
"TELEGRAM_API_BASE_URL",
|
|
2797
2850
|
"TELEGRAM_AUTO_CLEAR_WEBHOOK",
|
|
@@ -2799,17 +2852,6 @@ function renderNormalizedTelegramEnv(parsedEnv) {
|
|
|
2799
2852
|
"TELEGRAM_DEFAULT_BOT_KEY",
|
|
2800
2853
|
"TELEGRAM_BOT_TOKEN",
|
|
2801
2854
|
]);
|
|
2802
|
-
entries.forEach((entry) => {
|
|
2803
|
-
const upper = String(entry.key || "").trim().toUpperCase();
|
|
2804
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_SERVER_BOT_ID`);
|
|
2805
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_USERNAME`);
|
|
2806
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_TOKEN`);
|
|
2807
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_ROLE_PROFILE`);
|
|
2808
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_AI_CLIENT`);
|
|
2809
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_AI_MODEL`);
|
|
2810
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_AI_PERMISSION_MODE`);
|
|
2811
|
-
knownKeys.add(`TELEGRAM_BOT_${upper}_AI_REASONING_EFFORT`);
|
|
2812
|
-
});
|
|
2813
2855
|
const extras = Object.keys(parsed)
|
|
2814
2856
|
.filter((key) => !knownKeys.has(key) && !isTelegramEntryEnvKey(key))
|
|
2815
2857
|
.sort((left, right) => left.localeCompare(right));
|
|
@@ -2823,17 +2865,78 @@ function renderNormalizedTelegramEnv(parsedEnv) {
|
|
|
2823
2865
|
return `${lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd()}\n`;
|
|
2824
2866
|
}
|
|
2825
2867
|
|
|
2826
|
-
function
|
|
2827
|
-
|
|
2828
|
-
const
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
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), {
|
|
2834
2911
|
encoding: "utf8",
|
|
2835
2912
|
mode: 0o600,
|
|
2836
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);
|
|
2837
2940
|
return true;
|
|
2838
2941
|
}
|
|
2839
2942
|
|
|
@@ -2967,6 +3070,20 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
2967
3070
|
function loadProviderEnvConfig(provider, selectors = {}) {
|
|
2968
3071
|
const normalizedProvider = normalizeBotProvider(provider);
|
|
2969
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
|
+
}
|
|
2970
3087
|
const ensured = ensureProviderEnvTemplate(normalizedProvider);
|
|
2971
3088
|
const filePath = ensured.filePath;
|
|
2972
3089
|
if (ensured.error) {
|
|
@@ -2982,9 +3099,6 @@ function loadProviderEnvConfig(provider, selectors = {}) {
|
|
|
2982
3099
|
try {
|
|
2983
3100
|
const raw = fs.readFileSync(filePath, "utf8");
|
|
2984
3101
|
const parsed = parseSimpleEnvText(raw);
|
|
2985
|
-
if (normalizedProvider === "telegram") {
|
|
2986
|
-
return resolveTelegramEnvConfig(parsed, filePath, config, selectors);
|
|
2987
|
-
}
|
|
2988
3102
|
const token = String(parsed[config.tokenKey] || "").trim();
|
|
2989
3103
|
if (!token) {
|
|
2990
3104
|
return {
|
|
@@ -3484,10 +3598,14 @@ function buildBotCommandDeps() {
|
|
|
3484
3598
|
providerEnvOrder: PROVIDER_ENV_ORDER,
|
|
3485
3599
|
providerEnvConfig,
|
|
3486
3600
|
providerEnvFilePath,
|
|
3601
|
+
telegramBotEntriesDirPath,
|
|
3602
|
+
telegramBotEntryFilePath,
|
|
3487
3603
|
ensureProviderEnvTemplate,
|
|
3488
3604
|
parseCommandAndFlags,
|
|
3489
3605
|
parseSimpleEnvText,
|
|
3490
3606
|
collectTelegramEnvBotEntries,
|
|
3607
|
+
readTelegramEnvState,
|
|
3608
|
+
writeTelegramEnvState,
|
|
3491
3609
|
normalizeBotProvider,
|
|
3492
3610
|
normalizeTelegramBotEnvKey,
|
|
3493
3611
|
normalizeTelegramBotUsername,
|
|
@@ -5246,19 +5364,44 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
5246
5364
|
&& telegramEnvV2ByUsername.allowedUpdates.includes("channel_post"),
|
|
5247
5365
|
`bot=${String(telegramEnvV2ByUsername.botKey || "(none)")} updates=${String((telegramEnvV2ByUsername.allowedUpdates || []).join(","))}`,
|
|
5248
5366
|
);
|
|
5249
|
-
const
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
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
|
+
}
|
|
5254
5396
|
push(
|
|
5255
5397
|
"telegram_env_existing_file_auto_normalizes_named_keys",
|
|
5256
|
-
|
|
5257
|
-
&&
|
|
5258
|
-
&&
|
|
5259
|
-
&&
|
|
5260
|
-
&&
|
|
5261
|
-
|
|
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}`,
|
|
5262
5405
|
);
|
|
5263
5406
|
const telegramSupport = getProviderSupport("telegram");
|
|
5264
5407
|
push(
|
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");
|
|
@@ -605,6 +616,9 @@ function renderTokenOnlyProviderEnv(provider, parsedEnv, deps) {
|
|
|
605
616
|
}
|
|
606
617
|
|
|
607
618
|
function writeProviderEnvState(provider, parsedEnv, deps) {
|
|
619
|
+
if (provider === "telegram" && typeof deps?.writeTelegramEnvState === "function") {
|
|
620
|
+
return deps.writeTelegramEnvState(parsedEnv);
|
|
621
|
+
}
|
|
608
622
|
const filePath = String(requireDependency(deps, "providerEnvFilePath")(provider) || "").trim();
|
|
609
623
|
const rendered = provider === "telegram"
|
|
610
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));
|