metheus-governance-mcp-cli 0.2.98 → 0.2.99

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
@@ -33,7 +33,7 @@ These files are for local provider bot secrets, local transport options, and opt
33
33
  - Store locally:
34
34
  - Telegram-wide settings in `~/.metheus/telegram-bots/_global.env`
35
35
  - `TELEGRAM_BOT_TOKEN` as a legacy Telegram fallback in `_global.env`
36
- - one Telegram bot file per entry in `~/.metheus/telegram-bots/<bot-key>.env`
36
+ - one Telegram bot file per entry in `~/.metheus/telegram-bots/<server-bot-name>.env`
37
37
  - `SLACK_BOT_TOKEN`
38
38
  - `KAKAOTALK_BOT_TOKEN`
39
39
  - Server-side Metheus stores project chat destination metadata separately:
@@ -50,14 +50,14 @@ Example templates:
50
50
  TELEGRAM_API_BASE_URL=
51
51
  TELEGRAM_AUTO_CLEAR_WEBHOOK=true
52
52
  TELEGRAM_ALLOWED_UPDATES=message,edited_message
53
- TELEGRAM_DEFAULT_BOT_KEY=ryoai
53
+ TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot
54
54
 
55
55
  # Legacy fallback
56
56
  TELEGRAM_BOT_TOKEN=
57
57
  ```
58
58
 
59
59
  ```env
60
- # ~/.metheus/telegram-bots/ryoai.env
60
+ # ~/.metheus/telegram-bots/ryoai_bot.env
61
61
  TELEGRAM_BOT_NAME=ryoai_bot
62
62
  TELEGRAM_BOT_SERVER_BOT_ID=
63
63
  TELEGRAM_BOT_TOKEN=
@@ -172,7 +172,7 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
172
172
  When Telegram local config already exists, bootstrap/setup keeps your secrets but auto-normalizes the layout to the latest split structure:
173
173
 
174
174
  - Telegram-wide settings stay in `~/.metheus/telegram-bots/_global.env`
175
- - per-bot secrets move to `~/.metheus/telegram-bots/<bot-key>.env`
175
+ - per-bot secrets move to `~/.metheus/telegram-bots/<server-bot-name>.env`
176
176
  - stale inline keys such as `TELEGRAM_BOT_<NAME>_BOT_*` are rewritten into generic per-bot keys
177
177
 
178
178
  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.
@@ -223,15 +223,15 @@ Direct commands:
223
223
 
224
224
  ```bash
225
225
  metheus-governance-mcp-cli bot list
226
- metheus-governance-mcp-cli bot show --provider telegram --bot-key ryoai
226
+ metheus-governance-mcp-cli bot show --provider telegram --bot-key ryoai_bot
227
227
  metheus-governance-mcp-cli bot add --provider telegram
228
228
  metheus-governance-mcp-cli bot edit
229
229
  metheus-governance-mcp-cli bot edit --provider telegram
230
230
  metheus-governance-mcp-cli bot remove --provider telegram
231
- metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai
232
- metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai
231
+ metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai_bot
232
+ metheus-governance-mcp-cli bot migrate --provider telegram --bot-key ryoai_bot
233
233
  metheus-governance-mcp-cli bot global --provider telegram
234
- metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai
234
+ metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai_bot
235
235
  ```
236
236
 
237
237
  Behavior:
@@ -258,7 +258,7 @@ Behavior:
258
258
  - `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
259
259
  - `bot verify` without flags starts a guided numbered flow: provider -> bot entry -> output format.
260
260
  - `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
261
- - Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<bot-key>.env` with generic fields:
261
+ - Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<server-bot-name>.env` with generic fields:
262
262
  - `TELEGRAM_BOT_NAME`
263
263
  - `TELEGRAM_BOT_SERVER_BOT_ID`
264
264
  - `TELEGRAM_BOT_TOKEN`
@@ -280,11 +280,11 @@ Non-interactive examples:
280
280
  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
281
281
  metheus-governance-mcp-cli bot add --provider telegram --non-interactive true --server-bot-id <server_bot_uuid> --token <telegram_bot_token> --default true
282
282
  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
283
- 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
284
- metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai --non-interactive true
285
- 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
286
- metheus-governance-mcp-cli bot remove --provider telegram --bot-key ryoai --non-interactive true
287
- metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai --json true
283
+ 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
284
+ metheus-governance-mcp-cli bot set-default --provider telegram --bot-key ryoai_bot --non-interactive true
285
+ 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
286
+ metheus-governance-mcp-cli bot remove --provider telegram --bot-key ryoai_bot --non-interactive true
287
+ metheus-governance-mcp-cli bot verify --provider telegram --bot-key ryoai_bot --json true
288
288
  ```
289
289
 
290
290
  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
@@ -2666,7 +2666,6 @@ function normalizeTelegramBotEnvKey(rawValue, fallback = "") {
2666
2666
  .trim()
2667
2667
  .toLowerCase()
2668
2668
  .replace(/[^a-z0-9]+/g, "_")
2669
- .replace(/_bot$/g, "")
2670
2669
  .replace(/^_+|_+$/g, "");
2671
2670
  return normalized || fallback;
2672
2671
  }
@@ -2727,24 +2726,30 @@ function collectTelegramEnvBotEntries(parsedEnv) {
2727
2726
  }
2728
2727
  entries.set(botKey, entry);
2729
2728
  }
2730
- return Array.from(entries.values());
2729
+ return Array.from(entries.values()).map((entryRaw) => {
2730
+ const entry = { ...safeObject(entryRaw) };
2731
+ const preferredKey = normalizeTelegramBotEnvKey(entry.username || "", "");
2732
+ if (preferredKey) {
2733
+ entry.key = preferredKey;
2734
+ }
2735
+ return entry;
2736
+ });
2731
2737
  }
2732
2738
 
2733
2739
  function telegramBotEntryDisplayNameForState(entry) {
2734
2740
  const current = safeObject(entry);
2735
2741
  const username = normalizeTelegramBotUsername(current.username || "");
2736
2742
  if (username) return username;
2737
- const key = normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
2738
- if (!key) return "telegram_bot";
2739
- return key.endsWith("_bot") ? key : `${key}_bot`;
2743
+ return normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
2740
2744
  }
2741
2745
 
2742
2746
  function parseTelegramBotEntryFile(filePath) {
2743
2747
  const raw = fs.readFileSync(filePath, "utf8");
2744
2748
  const parsed = parseSimpleEnvText(raw);
2745
2749
  const keyFromFile = normalizeTelegramBotEnvKey(path.basename(filePath, path.extname(filePath)), "telegram_bot");
2750
+ const keyFromName = normalizeTelegramBotEnvKey(parsed.TELEGRAM_BOT_NAME || parsed.TELEGRAM_BOT_USERNAME || "", "");
2746
2751
  return {
2747
- key: keyFromFile,
2752
+ key: keyFromName || keyFromFile,
2748
2753
  username: normalizeTelegramBotUsername(parsed.TELEGRAM_BOT_NAME || parsed.TELEGRAM_BOT_USERNAME || ""),
2749
2754
  serverBotID: String(parsed.TELEGRAM_BOT_SERVER_BOT_ID || "").trim(),
2750
2755
  token: String(parsed.TELEGRAM_BOT_TOKEN || "").trim(),
@@ -2757,6 +2762,28 @@ function parseTelegramBotEntryFile(filePath) {
2757
2762
  };
2758
2763
  }
2759
2764
 
2765
+ function remapTelegramDefaultBotKey(defaultKeyRaw, entries) {
2766
+ const defaultKey = normalizeTelegramBotEnvKey(defaultKeyRaw || "", "");
2767
+ if (!defaultKey) return "";
2768
+ const rows = ensureArray(entries).map((entry) => safeObject(entry));
2769
+ if (rows.some((entry) => String(entry.key || "").trim() === defaultKey)) {
2770
+ return defaultKey;
2771
+ }
2772
+ const directBotMatch = rows.find((entry) => String(entry.key || "").trim() === `${defaultKey}_bot`);
2773
+ if (directBotMatch) {
2774
+ return String(directBotMatch.key || "").trim();
2775
+ }
2776
+ const compactBotMatch = rows.find((entry) => String(entry.key || "").trim() === `${defaultKey}bot`);
2777
+ if (compactBotMatch) {
2778
+ return String(compactBotMatch.key || "").trim();
2779
+ }
2780
+ const byUsername = rows.find((entry) => normalizeTelegramBotUsername(entry.username || "") === defaultKey);
2781
+ if (byUsername) {
2782
+ return String(byUsername.key || "").trim();
2783
+ }
2784
+ return defaultKey;
2785
+ }
2786
+
2760
2787
  function loadTelegramBotEntriesFromFiles() {
2761
2788
  const dirPath = telegramBotEntriesDirPath();
2762
2789
  if (!fs.existsSync(dirPath)) return [];
@@ -2834,6 +2861,7 @@ function readTelegramEnvState() {
2834
2861
  }
2835
2862
  });
2836
2863
  const entries = Array.from(mergedEntries.values());
2864
+ globalParsed.TELEGRAM_DEFAULT_BOT_KEY = remapTelegramDefaultBotKey(globalParsed.TELEGRAM_DEFAULT_BOT_KEY || "", entries);
2837
2865
  return {
2838
2866
  filePath,
2839
2867
  legacyFilePath,
@@ -2854,14 +2882,15 @@ function telegramEntryCommentNameForEnv(entry) {
2854
2882
  const current = safeObject(entry);
2855
2883
  const username = normalizeTelegramBotUsername(current.username || "");
2856
2884
  if (username) return username;
2857
- const key = normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
2858
- if (!key) return "telegram_bot";
2859
- return key.endsWith("_bot") ? key : `${key}_bot`;
2885
+ return normalizeTelegramBotEnvKey(current.key || "", "telegram_bot");
2860
2886
  }
2861
2887
 
2862
2888
  function renderNormalizedTelegramEnv(parsedEnv) {
2863
2889
  const parsed = safeObject(parsedEnv);
2864
- const defaultBotKey = normalizeTelegramBotEnvKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", "");
2890
+ const defaultBotKey = remapTelegramDefaultBotKey(
2891
+ parsed.TELEGRAM_DEFAULT_BOT_KEY || "",
2892
+ collectTelegramEnvBotEntries(parsed),
2893
+ );
2865
2894
  const lines = [
2866
2895
  "# Metheus local Telegram bot settings",
2867
2896
  "# Keep this file on your machine only. Do not commit it.",
@@ -3001,7 +3030,7 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
3001
3030
  selectors.route?.telegramBotKey,
3002
3031
  selectors.route?.telegram_bot_key,
3003
3032
  ]), "");
3004
- const defaultBotKey = normalizeTelegramBotEnvKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", "");
3033
+ const defaultBotKey = remapTelegramDefaultBotKey(parsed.TELEGRAM_DEFAULT_BOT_KEY || "", entries);
3005
3034
  let selected = null;
3006
3035
  if (desiredBotID) {
3007
3036
  selected = entries.find((entry) => entry.serverBotID === desiredBotID) || null;
@@ -5384,7 +5413,7 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
5384
5413
  "telegram_env_v2_default_bot_key_selects_named_token",
5385
5414
  telegramEnvV2Default.ok
5386
5415
  && telegramEnvV2Default.token === "review-token"
5387
- && telegramEnvV2Default.botKey === "review"
5416
+ && telegramEnvV2Default.botKey === "reviewbot"
5388
5417
  && telegramEnvV2Default.autoClearWebhook === false,
5389
5418
  `bot=${String(telegramEnvV2Default.botKey || "(none)")} token=${String(telegramEnvV2Default.token || "(missing)")}`,
5390
5419
  );
@@ -5398,7 +5427,7 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
5398
5427
  "telegram_env_v2_bot_name_override_selects_matching_token",
5399
5428
  telegramEnvV2ByUsername.ok
5400
5429
  && telegramEnvV2ByUsername.token === "ryoai-token"
5401
- && telegramEnvV2ByUsername.botKey === "ryoai"
5430
+ && telegramEnvV2ByUsername.botKey === "ryoai_bot"
5402
5431
  && Array.isArray(telegramEnvV2ByUsername.allowedUpdates)
5403
5432
  && telegramEnvV2ByUsername.allowedUpdates.includes("channel_post"),
5404
5433
  `bot=${String(telegramEnvV2ByUsername.botKey || "(none)")} updates=${String((telegramEnvV2ByUsername.allowedUpdates || []).join(","))}`,
@@ -5423,9 +5452,10 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
5423
5452
  ].join("\n"),
5424
5453
  "utf8",
5425
5454
  );
5426
- ensureProviderEnvTemplate("telegram");
5455
+ const normalizedState = readTelegramEnvState();
5456
+ writeTelegramEnvState(normalizedState.parsed);
5427
5457
  normalizedGlobalText = fs.readFileSync(providerEnvFilePath("telegram"), "utf8");
5428
- normalizedBotText = fs.readFileSync(telegramBotEntryFilePath("ryoai"), "utf8");
5458
+ normalizedBotText = fs.readFileSync(telegramBotEntryFilePath("ryoai_bot"), "utf8");
5429
5459
  } finally {
5430
5460
  if (previousUserProfile === undefined) delete process.env.USERPROFILE;
5431
5461
  else process.env.USERPROFILE = previousUserProfile;
@@ -5434,7 +5464,7 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
5434
5464
  }
5435
5465
  push(
5436
5466
  "telegram_env_existing_file_auto_normalizes_named_keys",
5437
- normalizedGlobalText.includes("TELEGRAM_DEFAULT_BOT_KEY=ryoai")
5467
+ normalizedGlobalText.includes("TELEGRAM_DEFAULT_BOT_KEY=ryoai_bot")
5438
5468
  && !normalizedGlobalText.includes("TELEGRAM_BOT_RYOAI_BOT_TOKEN")
5439
5469
  && !normalizedGlobalText.includes("TELEGRAM_BOT_RYOAI_TOKEN")
5440
5470
  && normalizedBotText.includes("TELEGRAM_BOT_NAME=ryoai_bot")
@@ -398,7 +398,7 @@ export async function runSelftestBotCommands(push, deps) {
398
398
  ]),
399
399
  },
400
400
  });
401
- const groupedState = readTelegramBotEntry("ryoai");
401
+ const groupedState = readTelegramBotEntry("ryoai_bot");
402
402
  push(
403
403
  "bot_add_guided_autoresolves_server_bot_group_without_role_prompt",
404
404
  String(groupedState.TELEGRAM_BOT_NAME || "").toLowerCase() === "ryoai_bot"
@@ -420,7 +420,7 @@ export async function runSelftestBotCommands(push, deps) {
420
420
  ...env,
421
421
  METHEUS_SCRIPTED_PROMPT_ANSWERS: JSON.stringify([
422
422
  "1", // provider: telegram
423
- "2", // bot entry: ryoai
423
+ "2", // bot entry: ryoai_bot
424
424
  "1", // keep token
425
425
  "2", // grouped role settings: edit one role
426
426
  "3", // select role to edit: worker
@@ -465,7 +465,7 @@ export async function runSelftestBotCommands(push, deps) {
465
465
  args: [
466
466
  "bot", "show",
467
467
  "--provider", "telegram",
468
- "--bot-key", "ryoai",
468
+ "--bot-key", "ryoai_bot",
469
469
  "--base-url", `http://127.0.0.1:${groupedMock.port}`,
470
470
  "--json", "true",
471
471
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.98",
3
+ "version": "0.2.99",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [