metheus-governance-mcp-cli 0.2.91 → 0.2.93

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 CHANGED
@@ -31,7 +31,7 @@ Install creates local provider settings templates here:
31
31
  These files are for local provider bot secrets, local transport options, and optional per-bot local AI binding.
32
32
 
33
33
  - Store locally:
34
- - `TELEGRAM_BOT_TOKEN` or named Telegram bot mappings such as `TELEGRAM_BOT_RYOAI_BOT_TOKEN`
34
+ - `TELEGRAM_BOT_TOKEN` or named Telegram bot mappings such as `TELEGRAM_BOT_RYOAI_TOKEN`
35
35
  - `SLACK_BOT_TOKEN`
36
36
  - `KAKAOTALK_BOT_TOKEN`
37
37
  - Server-side Metheus stores project chat destination metadata separately:
@@ -48,21 +48,21 @@ Example templates:
48
48
  TELEGRAM_API_BASE_URL=
49
49
  TELEGRAM_AUTO_CLEAR_WEBHOOK=true
50
50
  TELEGRAM_ALLOWED_UPDATES=message,edited_message
51
- TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot
51
+ TELEGRAM_DEFAULT_BOT_KEY=ryoai
52
52
 
53
53
  # Legacy fallback
54
54
  TELEGRAM_BOT_TOKEN=
55
55
 
56
56
  # Preferred named bot mapping
57
- TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID=
57
+ TELEGRAM_BOT_RYOAI_SERVER_BOT_ID=
58
58
  # Optional fallback only when server bot binding is unavailable
59
- # TELEGRAM_BOT_RYOAI_BOT_USERNAME=<bot_username>
60
- TELEGRAM_BOT_RYOAI_BOT_TOKEN=
61
- TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE=monitor
62
- TELEGRAM_BOT_RYOAI_BOT_AI_CLIENT=gpt
63
- TELEGRAM_BOT_RYOAI_BOT_AI_MODEL=gpt-5.4
64
- TELEGRAM_BOT_RYOAI_BOT_AI_PERMISSION_MODE=read_only
65
- TELEGRAM_BOT_RYOAI_BOT_AI_REASONING_EFFORT=low
59
+ # TELEGRAM_BOT_RYOAI_USERNAME=<bot_username>
60
+ TELEGRAM_BOT_RYOAI_TOKEN=
61
+ TELEGRAM_BOT_RYOAI_ROLE_PROFILE=monitor
62
+ TELEGRAM_BOT_RYOAI_AI_CLIENT=gpt
63
+ TELEGRAM_BOT_RYOAI_AI_MODEL=gpt-5.4
64
+ TELEGRAM_BOT_RYOAI_AI_PERMISSION_MODE=read_only
65
+ TELEGRAM_BOT_RYOAI_AI_REASONING_EFFORT=low
66
66
 
67
67
  # ~/.metheus/slack.env
68
68
  SLACK_BOT_TOKEN=
@@ -164,6 +164,8 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
164
164
  - `~/.metheus/kakaotalk.env`
165
165
  - `~/.metheus/bot-runner.json`
166
166
 
167
+ When `telegram.env` already exists, bootstrap/setup keeps your secrets but auto-normalizes the file to the latest named-entry layout so stale keys such as `TELEGRAM_BOT_<NAME>_BOT_*` are rewritten to `TELEGRAM_BOT_<NAME>_*`.
168
+
167
169
  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
170
 
169
171
  `~/.metheus/bot-runner.json` is the local automation profile for:
@@ -212,15 +214,15 @@ Direct commands:
212
214
 
213
215
  ```bash
214
216
  metheus-governance-mcp-cli bot list
215
- metheus-governance-mcp-cli bot show --provider telegram --bot-key ryoai_bot
217
+ metheus-governance-mcp-cli bot show --provider telegram --bot-key ryoai
216
218
  metheus-governance-mcp-cli bot add --provider telegram
217
219
  metheus-governance-mcp-cli bot edit
218
220
  metheus-governance-mcp-cli bot edit --provider telegram
219
221
  metheus-governance-mcp-cli bot remove --provider telegram
220
- metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai_bot
221
- metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai_bot
222
+ metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai
223
+ metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai
222
224
  metheus-governance-mcp-cli bot global --provider telegram
223
- metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai_bot
225
+ metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai
224
226
  ```
225
227
 
226
228
  Behavior:
@@ -269,11 +271,11 @@ Non-interactive examples:
269
271
  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
270
272
  metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --default true
271
273
  metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --ai-client gpt --ai-model "gpt-5.4" --ai-permission-mode read_only --ai-reasoning-effort low
272
- metheus-governance-mcp-cli bot edit --provider telegram --bot-key ryoai_bot --non-interactive true --ai-client claude --ai-model "Sonnet 4.6r" --ai-permission-mode danger_full_access --ai-reasoning-effort high
273
- metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai_bot --non-interactive true
274
- metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai_bot --server-bot-id <server_bot_uuid> --bot-name <telegram_username> --role-profile monitor --ai-client gpt --ai-permission-mode read_only --ai-reasoning-effort low --non-interactive true
275
- metheus-governance-mcp-cli bot remove --provider telegram --bot-key ryoai_bot --non-interactive true
276
- metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai_bot --json true
274
+ metheus-governance-mcp-cli bot edit --provider telegram --bot-key ryoai --non-interactive true --ai-client claude --ai-model "Sonnet 4.6r" --ai-permission-mode danger_full_access --ai-reasoning-effort high
275
+ metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai --non-interactive true
276
+ metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai --server-bot-id <server_bot_uuid> --bot-name <telegram_username> --role-profile monitor --ai-client gpt --ai-permission-mode read_only --ai-reasoning-effort low --non-interactive true
277
+ metheus-governance-mcp-cli bot remove --provider telegram --bot-key ryoai --non-interactive true
278
+ metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai --json true
277
279
  ```
278
280
 
279
281
  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.
package/cli.mjs CHANGED
@@ -749,32 +749,32 @@ function providerEnvTemplate(provider) {
749
749
  "# TELEGRAM_BOT_TOKEN=<bot token>",
750
750
  "#",
751
751
  "# Preferred v2 multi-bot mapping:",
752
- "# TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot",
753
- "# TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID=<server bot uuid>",
754
- "# TELEGRAM_BOT_RYOAI_BOT_USERNAME=<optional fallback username when server binding is unavailable>",
755
- "# TELEGRAM_BOT_RYOAI_BOT_TOKEN=<bot token>",
756
- "# TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE=monitor",
757
- "# TELEGRAM_BOT_RYOAI_BOT_AI_CLIENT=gpt",
758
- "# TELEGRAM_BOT_RYOAI_BOT_AI_MODEL=gpt-5.4",
759
- "# TELEGRAM_BOT_RYOAI_BOT_AI_PERMISSION_MODE=read_only",
760
- "# TELEGRAM_BOT_RYOAI_BOT_AI_REASONING_EFFORT=low",
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
761
  "",
762
762
  "TELEGRAM_API_BASE_URL=",
763
763
  "TELEGRAM_AUTO_CLEAR_WEBHOOK=true",
764
764
  "TELEGRAM_ALLOWED_UPDATES=message,edited_message",
765
- "TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot",
765
+ "TELEGRAM_DEFAULT_BOT_KEY=ryoai",
766
766
  "",
767
767
  "# Legacy fallback (still supported)",
768
768
  "TELEGRAM_BOT_TOKEN=",
769
769
  "",
770
770
  "# Preferred named bot entry",
771
- "TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID=",
772
- "TELEGRAM_BOT_RYOAI_BOT_TOKEN=",
773
- "TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE=",
774
- "TELEGRAM_BOT_RYOAI_BOT_AI_CLIENT=",
775
- "TELEGRAM_BOT_RYOAI_BOT_AI_MODEL=",
776
- "TELEGRAM_BOT_RYOAI_BOT_AI_PERMISSION_MODE=",
777
- "TELEGRAM_BOT_RYOAI_BOT_AI_REASONING_EFFORT=",
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
778
  "",
779
779
  ].join("\n");
780
780
  }
@@ -1053,7 +1053,12 @@ function ensureProviderEnvTemplate(provider) {
1053
1053
  const filePath = providerEnvFilePath(provider);
1054
1054
  try {
1055
1055
  if (fs.existsSync(filePath)) {
1056
- return { filePath, created: false, existed: true };
1056
+ return {
1057
+ filePath,
1058
+ created: false,
1059
+ existed: true,
1060
+ normalized: normalizeExistingProviderEnvFile(provider, filePath),
1061
+ };
1057
1062
  }
1058
1063
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
1059
1064
  fs.writeFileSync(filePath, providerEnvTemplate(provider), "utf8");
@@ -2636,11 +2641,21 @@ function parseSimpleEnvText(rawText) {
2636
2641
  return out;
2637
2642
  }
2638
2643
 
2644
+ function formatProviderEnvValue(rawValue) {
2645
+ const text = String(rawValue ?? "");
2646
+ if (!text) return "";
2647
+ if (/^[A-Za-z0-9_./:@,\-]+$/.test(text)) {
2648
+ return text;
2649
+ }
2650
+ return JSON.stringify(text);
2651
+ }
2652
+
2639
2653
  function normalizeTelegramBotEnvKey(rawValue, fallback = "") {
2640
2654
  const normalized = String(rawValue || "")
2641
2655
  .trim()
2642
2656
  .toLowerCase()
2643
2657
  .replace(/[^a-z0-9]+/g, "_")
2658
+ .replace(/_bot$/g, "")
2644
2659
  .replace(/^_+|_+$/g, "");
2645
2660
  return normalized || fallback;
2646
2661
  }
@@ -2704,6 +2719,124 @@ function collectTelegramEnvBotEntries(parsedEnv) {
2704
2719
  return Array.from(entries.values());
2705
2720
  }
2706
2721
 
2722
+ function isTelegramEntryEnvKey(rawKey) {
2723
+ 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
+ .test(String(rawKey || "").trim());
2725
+ }
2726
+
2727
+ function telegramEntryCommentNameForEnv(entry) {
2728
+ const current = safeObject(entry);
2729
+ const username = normalizeTelegramBotUsername(current.username || "");
2730
+ if (username) return username;
2731
+ const key = normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
2732
+ if (!key) return "telegram_bot";
2733
+ return key.endsWith("_bot") ? key : `${key}_bot`;
2734
+ }
2735
+
2736
+ function renderNormalizedTelegramEnv(parsedEnv) {
2737
+ 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
+ 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
+ const lines = [
2759
+ "# Metheus local Telegram bot settings",
2760
+ "# Keep this file on your machine only. Do not commit it.",
2761
+ "# Store Telegram bot secrets, AI bindings, and local transport options only.",
2762
+ "",
2763
+ `TELEGRAM_API_BASE_URL=${formatProviderEnvValue(parsed.TELEGRAM_API_BASE_URL || "")}`,
2764
+ `TELEGRAM_AUTO_CLEAR_WEBHOOK=${boolFromRaw(parsed.TELEGRAM_AUTO_CLEAR_WEBHOOK, true) ? "true" : "false"}`,
2765
+ `TELEGRAM_ALLOWED_UPDATES=${formatProviderEnvValue(String(parsed.TELEGRAM_ALLOWED_UPDATES || "").trim() || "message,edited_message")}`,
2766
+ `TELEGRAM_DEFAULT_BOT_KEY=${formatProviderEnvValue(defaultBotKey || "")}`,
2767
+ "",
2768
+ "# Legacy fallback",
2769
+ `TELEGRAM_BOT_TOKEN=${formatProviderEnvValue(parsed.TELEGRAM_BOT_TOKEN || "")}`,
2770
+ "",
2771
+ ];
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
+ const knownKeys = new Set([
2796
+ "TELEGRAM_API_BASE_URL",
2797
+ "TELEGRAM_AUTO_CLEAR_WEBHOOK",
2798
+ "TELEGRAM_ALLOWED_UPDATES",
2799
+ "TELEGRAM_DEFAULT_BOT_KEY",
2800
+ "TELEGRAM_BOT_TOKEN",
2801
+ ]);
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
+ const extras = Object.keys(parsed)
2814
+ .filter((key) => !knownKeys.has(key) && !isTelegramEntryEnvKey(key))
2815
+ .sort((left, right) => left.localeCompare(right));
2816
+ if (extras.length) {
2817
+ lines.push("# Additional preserved keys");
2818
+ extras.forEach((key) => {
2819
+ lines.push(`${key}=${formatProviderEnvValue(parsed[key])}`);
2820
+ });
2821
+ lines.push("");
2822
+ }
2823
+ return `${lines.join("\n").replace(/\n{3,}/g, "\n\n").trimEnd()}\n`;
2824
+ }
2825
+
2826
+ function normalizeExistingProviderEnvFile(provider, filePath) {
2827
+ if (normalizeBotProvider(provider) !== "telegram") return false;
2828
+ const raw = fs.readFileSync(filePath, "utf8");
2829
+ const rendered = renderNormalizedTelegramEnv(parseSimpleEnvText(raw));
2830
+ if (raw.replace(/\r\n/g, "\n") === rendered.replace(/\r\n/g, "\n")) {
2831
+ return false;
2832
+ }
2833
+ fs.writeFileSync(filePath, rendered, {
2834
+ encoding: "utf8",
2835
+ mode: 0o600,
2836
+ });
2837
+ return true;
2838
+ }
2839
+
2707
2840
  function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
2708
2841
  const parsed = safeObject(parsedEnv);
2709
2842
  const legacyToken = String(parsed.TELEGRAM_BOT_TOKEN || "").trim();
@@ -5078,8 +5211,8 @@ TELEGRAM_API_BASE_URL=http://127.0.0.1:8999/api
5078
5211
  TELEGRAM_AUTO_CLEAR_WEBHOOK=false
5079
5212
  TELEGRAM_ALLOWED_UPDATES=message,edited_message,channel_post
5080
5213
  TELEGRAM_DEFAULT_BOT_KEY=review
5081
- TELEGRAM_BOT_RYOAI_BOT_USERNAME=RyoAI_bot
5082
- TELEGRAM_BOT_RYOAI_BOT_TOKEN=ryoai-token
5214
+ TELEGRAM_BOT_RYOAI_USERNAME=RyoAI_bot
5215
+ TELEGRAM_BOT_RYOAI_TOKEN=ryoai-token
5083
5216
  TELEGRAM_BOT_REVIEW_SERVER_BOT_ID=bot-review
5084
5217
  TELEGRAM_BOT_REVIEW_USERNAME=ReviewBot
5085
5218
  TELEGRAM_BOT_REVIEW_TOKEN=review-token
@@ -5108,11 +5241,25 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
5108
5241
  "telegram_env_v2_bot_name_override_selects_matching_token",
5109
5242
  telegramEnvV2ByUsername.ok
5110
5243
  && telegramEnvV2ByUsername.token === "ryoai-token"
5111
- && telegramEnvV2ByUsername.botKey === "ryoai_bot"
5244
+ && telegramEnvV2ByUsername.botKey === "ryoai"
5112
5245
  && Array.isArray(telegramEnvV2ByUsername.allowedUpdates)
5113
5246
  && telegramEnvV2ByUsername.allowedUpdates.includes("channel_post"),
5114
5247
  `bot=${String(telegramEnvV2ByUsername.botKey || "(none)")} updates=${String((telegramEnvV2ByUsername.allowedUpdates || []).join(","))}`,
5115
5248
  );
5249
+ const telegramEnvNormalizedText = renderNormalizedTelegramEnv(parseSimpleEnvText(`
5250
+ TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot
5251
+ TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID=bot-ryoai
5252
+ TELEGRAM_BOT_RYOAI_BOT_TOKEN=ryoai-token
5253
+ `));
5254
+ push(
5255
+ "telegram_env_existing_file_auto_normalizes_named_keys",
5256
+ telegramEnvNormalizedText.includes("TELEGRAM_DEFAULT_BOT_KEY=ryoai")
5257
+ && telegramEnvNormalizedText.includes("TELEGRAM_BOT_RYOAI_SERVER_BOT_ID=bot-ryoai")
5258
+ && telegramEnvNormalizedText.includes("TELEGRAM_BOT_RYOAI_TOKEN=ryoai-token")
5259
+ && telegramEnvNormalizedText.includes("# Telegram bot entry: ryoai_bot")
5260
+ && !telegramEnvNormalizedText.includes("TELEGRAM_BOT_RYOAI_BOT_TOKEN"),
5261
+ telegramEnvNormalizedText,
5262
+ );
5116
5263
  const telegramSupport = getProviderSupport("telegram");
5117
5264
  push(
5118
5265
  "provider_support_telegram_full_runner",
@@ -67,7 +67,11 @@ function suggestDisplayedAIModel(deps, clientName, rawModelValue = "") {
67
67
  }
68
68
 
69
69
  function normalizeServerBotIdentityText(rawValue) {
70
- return String(rawValue || "").trim().replace(/^@+/, "").toLowerCase();
70
+ return String(rawValue || "")
71
+ .trim()
72
+ .replace(/^@+/, "")
73
+ .toLowerCase()
74
+ .replace(/_bot$/g, "");
71
75
  }
72
76
 
73
77
  function summarizeServerBotRoles(bots) {
@@ -437,6 +441,15 @@ function telegramEntryEnvKeys(botKey) {
437
441
  };
438
442
  }
439
443
 
444
+ function telegramEntryCommentName(entry) {
445
+ const current = safeObject(entry);
446
+ const username = String(current.username || "").trim();
447
+ if (username) return username;
448
+ const key = String(current.key || "").trim();
449
+ if (!key) return "telegram_bot";
450
+ return key.endsWith("_bot") ? key : `${key}_bot`;
451
+ }
452
+
440
453
  function persistTelegramUsername(entry) {
441
454
  const current = safeObject(entry);
442
455
  if (current.__preferServerIdentity) return "";
@@ -487,6 +500,11 @@ function telegramKnownKeys(parsedEnv, deps) {
487
500
  return keys;
488
501
  }
489
502
 
503
+ function isTelegramEntryEnvKey(rawKey) {
504
+ return /^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i
505
+ .test(String(rawKey || "").trim());
506
+ }
507
+
490
508
  function renderTelegramEnv(parsedEnv, deps) {
491
509
  const parsed = safeObject(parsedEnv);
492
510
  const collectEntries = requireDependency(deps, "collectTelegramEnvBotEntries");
@@ -531,7 +549,7 @@ function renderTelegramEnv(parsedEnv, deps) {
531
549
  entries.forEach((entry) => {
532
550
  const keys = telegramEntryEnvKeys(entry.key);
533
551
  const entryLines = [
534
- `# Telegram bot entry: ${entry.key}`,
552
+ `# Telegram bot entry: ${telegramEntryCommentName(entry)}`,
535
553
  `${keys.serverBotID}=${formatEnvValue(entry.serverBotID || "")}`,
536
554
  ];
537
555
  if (String(entry.username || "").trim()) {
@@ -551,7 +569,7 @@ function renderTelegramEnv(parsedEnv, deps) {
551
569
  }
552
570
  const knownKeys = telegramKnownKeys(parsed, deps);
553
571
  const extras = Object.keys(parsed)
554
- .filter((key) => !knownKeys.has(key))
572
+ .filter((key) => !knownKeys.has(key) && !isTelegramEntryEnvKey(key))
555
573
  .sort((left, right) => left.localeCompare(right));
556
574
  if (extras.length) {
557
575
  lines.push("# Additional preserved keys");
@@ -391,12 +391,12 @@ export async function runSelftestBotCommands(push, deps) {
391
391
  const groupedState = parseSimpleEnvText(fs.readFileSync(telegramEnvPath, "utf8"));
392
392
  push(
393
393
  "bot_add_guided_autoresolves_server_bot_group_without_role_prompt",
394
- String(groupedState.TELEGRAM_BOT_RYOAI_BOT_USERNAME || "").trim() === ""
395
- && String(groupedState.TELEGRAM_BOT_RYOAI_BOT_SERVER_BOT_ID || "") === ""
396
- && String(groupedState.TELEGRAM_BOT_RYOAI_BOT_ROLE_PROFILE || "") === ""
397
- && String(groupedState.TELEGRAM_BOT_RYOAI_BOT_AI_CLIENT || "") === ""
398
- && String(groupedState.TELEGRAM_BOT_RYOAI_BOT_AI_PERMISSION_MODE || "") === "",
399
- `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 || "")}`,
394
+ String(groupedState.TELEGRAM_BOT_RYOAI_USERNAME || "").trim() === ""
395
+ && String(groupedState.TELEGRAM_BOT_RYOAI_SERVER_BOT_ID || "") === ""
396
+ && String(groupedState.TELEGRAM_BOT_RYOAI_ROLE_PROFILE || "") === ""
397
+ && String(groupedState.TELEGRAM_BOT_RYOAI_AI_CLIENT || "") === ""
398
+ && String(groupedState.TELEGRAM_BOT_RYOAI_AI_PERMISSION_MODE || "") === "",
399
+ `username=${String(groupedState.TELEGRAM_BOT_RYOAI_USERNAME || "")} server_bot_id=${String(groupedState.TELEGRAM_BOT_RYOAI_SERVER_BOT_ID || "")} role=${String(groupedState.TELEGRAM_BOT_RYOAI_ROLE_PROFILE || "")}`,
400
400
  );
401
401
 
402
402
  const groupedEditResult = await runCLI({
@@ -410,7 +410,7 @@ export async function runSelftestBotCommands(push, deps) {
410
410
  ...env,
411
411
  METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
412
412
  "1", // provider: telegram
413
- "2", // bot entry: ryoai_bot
413
+ "2", // bot entry: ryoai
414
414
  "1", // keep token
415
415
  "2", // grouped role settings: edit one role
416
416
  "3", // select role to edit: worker
@@ -455,7 +455,7 @@ export async function runSelftestBotCommands(push, deps) {
455
455
  args: [
456
456
  "bot", "show",
457
457
  "--provider", "telegram",
458
- "--bot-key", "ryoai_bot",
458
+ "--bot-key", "ryoai",
459
459
  "--base-url", `http://127.0.0.1:${groupedMock.port}`,
460
460
  "--json", "true",
461
461
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.91",
3
+ "version": "0.2.93",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [