metheus-governance-mcp-cli 0.2.102 → 0.2.104
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 +22 -14
- package/cli.mjs +211 -24
- package/lib/bot-commands.mjs +229 -61
- package/lib/selftest-bot-commands.mjs +15 -4
- package/lib/setup-registration.mjs +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,9 +31,9 @@ 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-wide settings in `~/.metheus/telegram-bots/
|
|
35
|
-
- `TELEGRAM_BOT_TOKEN` as a legacy Telegram fallback in `
|
|
36
|
-
- one Telegram bot file per entry in `~/.metheus/telegram-bots/<
|
|
34
|
+
- Telegram-wide settings in `~/.metheus/telegram-bots/global.env`
|
|
35
|
+
- `TELEGRAM_BOT_TOKEN` as a legacy Telegram fallback in `global.env`
|
|
36
|
+
- one Telegram bot file per entry in `~/.metheus/telegram-bots/<ServerBotName>.env`
|
|
37
37
|
- `SLACK_BOT_TOKEN`
|
|
38
38
|
- `KAKAOTALK_BOT_TOKEN`
|
|
39
39
|
- Server-side Metheus stores project chat destination metadata separately:
|
|
@@ -41,12 +41,13 @@ These files are for local provider bot secrets, local transport options, and opt
|
|
|
41
41
|
- `chat_id` / channel / room identifier
|
|
42
42
|
- label / active state
|
|
43
43
|
- Do not put project chat destination identifiers in local env files.
|
|
44
|
-
- Telegram-wide settings now live in `telegram-bots/
|
|
44
|
+
- Telegram-wide settings now live in `telegram-bots/global.env`; Telegram per-bot secrets and server metadata live in `telegram-bots/*.env`.
|
|
45
|
+
- Grouped server bots also persist `TELEGRAM_BOT_SERVER_ROLE_IDS`, so the local file keeps the exact role-to-server-bot-id mapping instead of pretending that one grouped bot has only one server UUID.
|
|
45
46
|
|
|
46
47
|
Example templates:
|
|
47
48
|
|
|
48
49
|
```env
|
|
49
|
-
# ~/.metheus/telegram-bots/
|
|
50
|
+
# ~/.metheus/telegram-bots/global.env
|
|
50
51
|
TELEGRAM_API_BASE_URL=
|
|
51
52
|
TELEGRAM_AUTO_CLEAR_WEBHOOK=true
|
|
52
53
|
TELEGRAM_ALLOWED_UPDATES=message,edited_message
|
|
@@ -57,10 +58,11 @@ TELEGRAM_BOT_TOKEN=
|
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
```env
|
|
60
|
-
# ~/.metheus/telegram-bots/
|
|
61
|
+
# ~/.metheus/telegram-bots/RyoAI_bot.env
|
|
61
62
|
TELEGRAM_BOT_SERVER_BOT_ID=<server_bot_uuid>
|
|
62
63
|
TELEGRAM_BOT_SERVER_NAME=RyoAI_bot
|
|
63
64
|
TELEGRAM_BOT_SERVER_ROLES=monitor,review,worker,approval
|
|
65
|
+
TELEGRAM_BOT_SERVER_ROLE_IDS=monitor:<uuid>,review:<uuid>,worker:<uuid>,approval:<uuid>
|
|
64
66
|
# Optional fallback only when server bot binding is unavailable
|
|
65
67
|
# TELEGRAM_BOT_USERNAME=ryoai_bot
|
|
66
68
|
TELEGRAM_BOT_TOKEN=
|
|
@@ -172,10 +174,12 @@ metheus-governance-mcp-cli setup --project-id <project_uuid> --ctxpack-key "<ctx
|
|
|
172
174
|
- `~/.metheus/kakaotalk.env`
|
|
173
175
|
- `~/.metheus/bot-runner.json`
|
|
174
176
|
|
|
177
|
+
Bootstrap or setup does not create one file per server bot automatically. Per-bot Telegram files are created later when you run `bot add`, `bot verify`, or `bot edit` against a real server bot identity.
|
|
178
|
+
|
|
175
179
|
When Telegram local config already exists, bootstrap/setup keeps your secrets but auto-normalizes the layout to the latest split structure:
|
|
176
180
|
|
|
177
|
-
- Telegram-wide settings stay in `~/.metheus/telegram-bots/
|
|
178
|
-
- per-bot secrets move to `~/.metheus/telegram-bots/<
|
|
181
|
+
- Telegram-wide settings stay in `~/.metheus/telegram-bots/global.env`
|
|
182
|
+
- per-bot secrets move to `~/.metheus/telegram-bots/<ServerBotName>.env`
|
|
179
183
|
- stale inline keys such as `TELEGRAM_BOT_<NAME>_BOT_*` are rewritten into generic per-bot keys
|
|
180
184
|
|
|
181
185
|
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.
|
|
@@ -185,7 +189,7 @@ Fill provider bot secrets and provider-local transport options locally. Project
|
|
|
185
189
|
- which provider/role bot profile to use
|
|
186
190
|
- which `project_id -> workspace_dir` mapping to apply locally
|
|
187
191
|
- which role profile maps to which local CLI/model/permission/reasoning policy
|
|
188
|
-
- which server bot maps to which local LLM execution profile via `telegram-bots/
|
|
192
|
+
- which server bot maps to which local LLM execution profile via `telegram-bots/global.env`, `telegram-bots/*.env`, or fallback `bot_bindings`
|
|
189
193
|
|
|
190
194
|
Built-in helper command for legacy fallback/testing:
|
|
191
195
|
|
|
@@ -261,10 +265,11 @@ Behavior:
|
|
|
261
265
|
- `bot set-default` without flags starts a guided numbered flow: provider -> bot entry -> confirm default change.
|
|
262
266
|
- `bot verify` without flags starts a guided numbered flow: provider -> bot entry -> output format.
|
|
263
267
|
- `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
|
|
264
|
-
- Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<
|
|
268
|
+
- Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<ServerBotName>.env` with generic fields:
|
|
265
269
|
- `TELEGRAM_BOT_SERVER_BOT_ID`
|
|
266
270
|
- `TELEGRAM_BOT_SERVER_NAME`
|
|
267
271
|
- `TELEGRAM_BOT_SERVER_ROLES`
|
|
272
|
+
- `TELEGRAM_BOT_SERVER_ROLE_IDS`
|
|
268
273
|
- `TELEGRAM_BOT_USERNAME` only as a fallback when server bot binding is unavailable
|
|
269
274
|
- `TELEGRAM_BOT_TOKEN`
|
|
270
275
|
- `TELEGRAM_BOT_ROLE_PROFILE`
|
|
@@ -275,7 +280,7 @@ Behavior:
|
|
|
275
280
|
- Slack and KakaoTalk currently use a single local token entry per provider in this command flow.
|
|
276
281
|
- `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.
|
|
277
282
|
- `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.
|
|
278
|
-
- In `bot show` and `bot verify`, `
|
|
283
|
+
- In `bot show` and `bot verify`, `saved_local_file` means the values already stored on disk under `~/.metheus/telegram-bots/*.env`, while `current_server_protocol` means the fresh `/api/v1/me/bots` response from the server right now.
|
|
279
284
|
- `bot global` edits Telegram-wide local settings such as API base URL, allowed updates, and default bot key.
|
|
280
285
|
- `bot set-default` updates `TELEGRAM_DEFAULT_BOT_KEY`.
|
|
281
286
|
- `bot migrate` moves legacy `TELEGRAM_BOT_TOKEN` into a named Telegram bot entry.
|
|
@@ -293,10 +298,12 @@ metheus-governance-mcp-cli bot remove --provider telegram --bot-name RyoAI_bot -
|
|
|
293
298
|
metheus-governance-mcp-cli bot verify --provider telegram --bot-name RyoAI_bot --json true
|
|
294
299
|
```
|
|
295
300
|
|
|
296
|
-
For direct Telegram adds, the CLI derives the local file name from the matched server bot name. You normally do not need `--bot-key` or `--username`. Treat `--bot-key` as an advanced compatibility selector only when you intentionally need
|
|
301
|
+
For direct Telegram adds, the CLI derives the local file name from the matched server bot name. You normally do not need `--bot-key` or `--username`. Treat `--bot-key` as an advanced compatibility selector only when you intentionally need to target an older local selector directly.
|
|
297
302
|
|
|
298
303
|
For direct Telegram edits, prefer `--bot-name` or `--bot-id` because server bot identity is the source of truth. Use `--bot-key` only when you intentionally need the advanced local selector. If one server bot name expands to multiple roles such as `approval / worker / review / monitor`, prefer the guided `bot edit` flow so you can keep the current grouped settings, edit one role only, or walk every role in sequence instead of forcing one entry-level AI override.
|
|
299
304
|
|
|
305
|
+
For runner commands, you can still use `--route-name` directly, but normal operator workflows can also use `--bot-name` or `--bot-id` when those identify one enabled route uniquely. Use `runner list` first if you are not sure which route belongs to which server bot.
|
|
306
|
+
|
|
300
307
|
Current support status:
|
|
301
308
|
|
|
302
309
|
- Telegram: full local bot entry management, token verification, bot-to-AI binding, inbound runner support
|
|
@@ -377,6 +384,7 @@ Execution model:
|
|
|
377
384
|
Commands:
|
|
378
385
|
|
|
379
386
|
```bash
|
|
387
|
+
metheus-governance-mcp-cli runner list
|
|
380
388
|
metheus-governance-mcp-cli runner once --route-name telegram-monitor
|
|
381
389
|
metheus-governance-mcp-cli runner start --route-name telegram-monitor
|
|
382
390
|
```
|
|
@@ -403,7 +411,7 @@ Recommended production path:
|
|
|
403
411
|
- keep `project_mappings.<project_id>.workspace_dir` aligned to that teammate's actual local project folder
|
|
404
412
|
- let `ctxpack pull` or project connection refresh the mapping automatically
|
|
405
413
|
- keep per-role execution policy under `role_profiles`
|
|
406
|
-
- keep Telegram-wide binding defaults in `~/.metheus/telegram-bots/
|
|
414
|
+
- keep Telegram-wide binding defaults in `~/.metheus/telegram-bots/global.env`
|
|
407
415
|
- use `bot_bindings` in `bot-runner.json` only as local fallback/override
|
|
408
416
|
- runner resolution order is: explicit `route.role_profile` -> provider env bot binding -> `bot_bindings` -> server bot role -> `route.role`
|
|
409
417
|
|
|
@@ -476,7 +484,7 @@ Notes:
|
|
|
476
484
|
- `local-bot-bridge` reads stdin JSON from the runner and can call Codex/Claude/Gemini for you
|
|
477
485
|
- `route.command` fallback is disabled by default; enable it only temporarily with `METHEUS_ALLOW_LEGACY_RUNNER_COMMAND=1`
|
|
478
486
|
- today this automation path is implemented for Telegram end-to-end
|
|
479
|
-
- prefer `TELEGRAM_API_BASE_URL=` inside `~/.metheus/telegram-bots/
|
|
487
|
+
- prefer `TELEGRAM_API_BASE_URL=` inside `~/.metheus/telegram-bots/global.env` for local Telegram API overrides; `METHEUS_TELEGRAM_API_BASE_URL` remains a process-level fallback mainly for mock/regression testing
|
|
480
488
|
- Slack can use direct local send, but automatic inbound runner flow is not completed yet
|
|
481
489
|
- KakaoTalk config can be stored now, but direct send/runner flow is not implemented yet
|
|
482
490
|
- `doctor` now reports provider support for both enabled runner routes and active project chat destinations
|
package/cli.mjs
CHANGED
|
@@ -154,8 +154,9 @@ const AUTH_STORE_RELATIVE_PATH = path.join(".metheus", "governance-mcp-auth.json
|
|
|
154
154
|
const BOT_RUNNER_CONFIG_RELATIVE_PATH = path.join(".metheus", "bot-runner.json");
|
|
155
155
|
const BOT_RUNNER_STATE_RELATIVE_PATH = path.join(".metheus", "bot-runner-state.json");
|
|
156
156
|
const BOT_RUNNER_CONFIG_VERSION = 2;
|
|
157
|
-
const
|
|
158
|
-
const
|
|
157
|
+
const TELEGRAM_ROOT_LEGACY_ENV_RELATIVE_PATH = path.join(".metheus", "telegram.env");
|
|
158
|
+
const TELEGRAM_LEGACY_GLOBAL_ENV_RELATIVE_PATH = path.join(".metheus", "telegram-bots", "_global.env");
|
|
159
|
+
const TELEGRAM_GLOBAL_ENV_RELATIVE_PATH = path.join(".metheus", "telegram-bots", "global.env");
|
|
159
160
|
const PROVIDER_ENV_CONFIG = {
|
|
160
161
|
telegram: {
|
|
161
162
|
relativePath: TELEGRAM_GLOBAL_ENV_RELATIVE_PATH,
|
|
@@ -241,20 +242,21 @@ function printUsage() {
|
|
|
241
242
|
` ${cmd} setup [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--workspace-fallback-dir <path>] [--name <server_name>]`,
|
|
242
243
|
` ${cmd} bot setup [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>]`,
|
|
243
244
|
` ${cmd} bot list [--provider <telegram|slack|kakaotalk>] [--json <true|false>]`,
|
|
244
|
-
` ${cmd} bot show [--provider <telegram|slack|kakaotalk>] [--bot-name <server_name>] [--bot-id <uuid>] [--
|
|
245
|
+
` ${cmd} bot show [--provider <telegram|slack|kakaotalk>] [--bot-name <server_name>] [--bot-id <uuid>] [--json <true|false>]`,
|
|
245
246
|
` ${cmd} bot add [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>]`,
|
|
246
247
|
` ${cmd} bot edit [--provider <telegram|slack|kakaotalk>] [--base-url <url>] [--timeout-seconds <n>]`,
|
|
247
248
|
` ${cmd} bot remove [--provider <telegram|slack|kakaotalk>]`,
|
|
248
|
-
` ${cmd} bot set-default --provider telegram [--bot-name <server_name>] [--bot-id <uuid>]
|
|
249
|
-
` ${cmd} bot migrate --provider telegram [--bot-name <server_name>] [--bot-id <uuid>]
|
|
250
|
-
` ${cmd} bot verify [--provider <telegram|slack|kakaotalk>] [--bot-name <server_name>] [--bot-id <uuid>] [--
|
|
249
|
+
` ${cmd} bot set-default --provider telegram [--bot-name <server_name>] [--bot-id <uuid>]`,
|
|
250
|
+
` ${cmd} bot migrate --provider telegram [--bot-name <server_name>] [--bot-id <uuid>]`,
|
|
251
|
+
` ${cmd} bot verify [--provider <telegram|slack|kakaotalk>] [--bot-name <server_name>] [--bot-id <uuid>] [--timeout-seconds <n>] [--json <true|false>]`,
|
|
251
252
|
` ${cmd} bot global --provider telegram [--api-base-url <url>] [--auto-clear-webhook <true|false>] [--allowed-updates <csv>] [--default-bot-key <key>]`,
|
|
252
253
|
` ${cmd} doctor [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--timeout-seconds <n>] [--strict <true|false>]`,
|
|
253
254
|
` ${cmd} proxy [--project-id <uuid>] [--ctxpack-key <key>] [--base-url <url>] [--workspace-dir <path|auto>] [--include-drafts <true|false>] [--auto-pull-on-conflict <true|false>] [--timeout-seconds <n>]`,
|
|
254
255
|
` ${cmd} selftest [--json <true|false>]`,
|
|
255
256
|
` ${cmd} local-bot-bridge [--client <codex|claude|gemini|sample>] [--cwd <path>] [--model <name>] [--permission-mode <read_only|workspace_write|danger_full_access>] [--reasoning-effort <low|medium|high>]`,
|
|
256
|
-
` ${cmd} runner
|
|
257
|
-
` ${cmd} runner
|
|
257
|
+
` ${cmd} runner list [--json <true|false>]`,
|
|
258
|
+
` ${cmd} runner once [--route-name <name> | --bot-name <server_name> | --bot-id <uuid>] [--project-id <uuid>] [--provider <telegram|slack|kakaotalk>] [--role <monitor|review|worker|approval>] [--role-profile <name>] [--mentions-only <true|false>] [--reply-to-bot-messages <true|false>] [--direct-messages <true|false>] [--ignore-edited-messages <true|false>] [--dry-run-delivery <true|false>] [--context-comments <n>] [--archive-replies <true|false>]`,
|
|
259
|
+
` ${cmd} runner start [--route-name <name> | --bot-name <server_name> | --bot-id <uuid>] [--project-id <uuid>] [--provider <telegram|slack|kakaotalk>] [--role <monitor|review|worker|approval>] [--role-profile <name>] [--mentions-only <true|false>] [--reply-to-bot-messages <true|false>] [--direct-messages <true|false>] [--ignore-edited-messages <true|false>] [--dry-run-delivery <true|false>] [--poll-interval-ms <n>] [--context-comments <n>] [--archive-replies <true|false>]`,
|
|
258
260
|
` ${cmd} ctxpack pull [--project-id <uuid>] [--base-url <url>] [--workspace-dir <path|auto>] [--paths <csv>] [--timeout-seconds <n>]`,
|
|
259
261
|
` ${cmd} auth status`,
|
|
260
262
|
` ${cmd} auth login [--base-url <url>] [--flow <auto|device|callback|manual>] [--keycloak-url <url>] [--realm <name>] [--client-id <id>] [--open-browser <true|false>] [--callback-port <n>] [--timeout-seconds <n>] [--manual <true|false>]`,
|
|
@@ -739,18 +741,57 @@ function providerEnvFilePath(provider) {
|
|
|
739
741
|
}
|
|
740
742
|
|
|
741
743
|
function telegramLegacyEnvFilePath() {
|
|
742
|
-
return resolveHomeFilePath(
|
|
744
|
+
return resolveHomeFilePath(TELEGRAM_ROOT_LEGACY_ENV_RELATIVE_PATH);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
function telegramLegacyGlobalEnvFilePath() {
|
|
748
|
+
return resolveHomeFilePath(TELEGRAM_LEGACY_GLOBAL_ENV_RELATIVE_PATH);
|
|
743
749
|
}
|
|
744
750
|
|
|
745
751
|
function telegramBotEntriesDirPath() {
|
|
746
752
|
return resolveHomeFilePath(".metheus/telegram-bots");
|
|
747
753
|
}
|
|
748
754
|
|
|
755
|
+
function normalizeComparablePath(rawPath) {
|
|
756
|
+
const resolved = path.resolve(String(rawPath || ""));
|
|
757
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
function sanitizeTelegramBotFileStem(rawValue, fallback = "telegram_bot") {
|
|
761
|
+
const text = String(rawValue || "")
|
|
762
|
+
.trim()
|
|
763
|
+
.replace(/[<>:"/\\|?*\x00-\x1f]/g, "_")
|
|
764
|
+
.replace(/\s+/g, "_")
|
|
765
|
+
.replace(/^_+|_+$/g, "");
|
|
766
|
+
return text || fallback;
|
|
767
|
+
}
|
|
768
|
+
|
|
749
769
|
function telegramBotEntryFilePath(botKey) {
|
|
750
770
|
const normalizedKey = normalizeTelegramBotEnvKey(botKey || "", "telegram_bot") || "telegram_bot";
|
|
751
771
|
return path.join(telegramBotEntriesDirPath(), `${normalizedKey}.env`);
|
|
752
772
|
}
|
|
753
773
|
|
|
774
|
+
function telegramBotEntryFilePathForEntry(entryRaw) {
|
|
775
|
+
const entry = safeObject(entryRaw);
|
|
776
|
+
const fallbackKey = normalizeTelegramBotEnvKey(entry.key || "", "telegram_bot") || "telegram_bot";
|
|
777
|
+
const preferredStem = sanitizeTelegramBotFileStem(
|
|
778
|
+
firstNonEmptyString([entry.serverBotName, entry.username, entry.key]),
|
|
779
|
+
fallbackKey,
|
|
780
|
+
);
|
|
781
|
+
return path.join(telegramBotEntriesDirPath(), `${preferredStem}.env`);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function findTelegramEntryPathVariant(targetPath) {
|
|
785
|
+
const dirPath = path.dirname(targetPath);
|
|
786
|
+
if (!fs.existsSync(dirPath)) return "";
|
|
787
|
+
const targetComparable = normalizeComparablePath(targetPath);
|
|
788
|
+
const match = fs.readdirSync(dirPath, { withFileTypes: true })
|
|
789
|
+
.filter((item) => item.isFile() && /\.env$/i.test(item.name))
|
|
790
|
+
.map((item) => path.join(dirPath, item.name))
|
|
791
|
+
.find((candidatePath) => normalizeComparablePath(candidatePath) === targetComparable);
|
|
792
|
+
return String(match || "").trim();
|
|
793
|
+
}
|
|
794
|
+
|
|
754
795
|
function providerEnvTemplate(provider) {
|
|
755
796
|
const config = providerEnvConfig(provider);
|
|
756
797
|
if (normalizeBotProvider(provider) === "telegram") {
|
|
@@ -758,7 +799,7 @@ function providerEnvTemplate(provider) {
|
|
|
758
799
|
"# Metheus local Telegram bot settings",
|
|
759
800
|
"# Keep this file on your machine only. Do not commit it.",
|
|
760
801
|
"# Store Telegram-wide settings here.",
|
|
761
|
-
"# This global file now lives in ~/.metheus/telegram-bots/
|
|
802
|
+
"# This global file now lives in ~/.metheus/telegram-bots/global.env.",
|
|
762
803
|
"# Per-bot secrets and AI settings live in ~/.metheus/telegram-bots/<server-bot-name>.env.",
|
|
763
804
|
"# Project chat destinations must be managed on the Metheus server.",
|
|
764
805
|
"",
|
|
@@ -2525,6 +2566,75 @@ async function runRunnerOnce(flags) {
|
|
|
2525
2566
|
}
|
|
2526
2567
|
}
|
|
2527
2568
|
|
|
2569
|
+
function buildRunnerRouteListRows() {
|
|
2570
|
+
const config = loadBotRunnerConfig({ persistIfNeeded: true });
|
|
2571
|
+
const telegramState = readTelegramEnvState();
|
|
2572
|
+
const telegramEntries = ensureArray(telegramState.entries);
|
|
2573
|
+
return ensureArray(config.routes).map((rawRoute, index) => {
|
|
2574
|
+
const route = normalizeRunnerRoute(rawRoute);
|
|
2575
|
+
const matchedTelegramEntry = route.provider === "telegram"
|
|
2576
|
+
? telegramEntries.find((entry) => {
|
|
2577
|
+
const current = safeObject(entry);
|
|
2578
|
+
return (
|
|
2579
|
+
(route.botID && current.serverBotID && current.serverBotID === route.botID)
|
|
2580
|
+
|| (route.botName && current.serverBotName && current.serverBotName === route.botName)
|
|
2581
|
+
);
|
|
2582
|
+
})
|
|
2583
|
+
: null;
|
|
2584
|
+
const resolvedBotName = firstNonEmptyString([
|
|
2585
|
+
route.botName,
|
|
2586
|
+
matchedTelegramEntry?.serverBotName,
|
|
2587
|
+
matchedTelegramEntry?.key,
|
|
2588
|
+
"-",
|
|
2589
|
+
]);
|
|
2590
|
+
return {
|
|
2591
|
+
index: index + 1,
|
|
2592
|
+
name: route.name || runnerRouteKey(route),
|
|
2593
|
+
enabled: route.enabled !== false,
|
|
2594
|
+
provider: route.provider || "-",
|
|
2595
|
+
projectID: route.projectID || "-",
|
|
2596
|
+
botName: resolvedBotName,
|
|
2597
|
+
botID: route.botID || "-",
|
|
2598
|
+
role: route.role || "-",
|
|
2599
|
+
roleProfile: route.roleProfile || "-",
|
|
2600
|
+
destinationLabel: route.destinationLabel || "-",
|
|
2601
|
+
pollIntervalMs: route.pollIntervalMs || 0,
|
|
2602
|
+
configFilePath: config.filePath,
|
|
2603
|
+
};
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
async function runRunnerList(flags) {
|
|
2608
|
+
const rows = buildRunnerRouteListRows();
|
|
2609
|
+
if (boolFromRaw(flags.json, false)) {
|
|
2610
|
+
process.stdout.write(`${JSON.stringify({ ok: true, routes: rows }, null, 2)}\n`);
|
|
2611
|
+
return;
|
|
2612
|
+
}
|
|
2613
|
+
process.stdout.write("Runner routes\n");
|
|
2614
|
+
if (!rows.length) {
|
|
2615
|
+
process.stdout.write(" none configured\n");
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
process.stdout.write(` file: ${rows[0].configFilePath}\n`);
|
|
2619
|
+
rows.forEach((row) => {
|
|
2620
|
+
process.stdout.write(
|
|
2621
|
+
[
|
|
2622
|
+
` - ${row.name}${row.enabled ? "" : " [disabled]"}`,
|
|
2623
|
+
` provider: ${row.provider}`,
|
|
2624
|
+
` project_id: ${row.projectID}`,
|
|
2625
|
+
` server_bot_name: ${row.botName}`,
|
|
2626
|
+
` bot_id: ${row.botID}`,
|
|
2627
|
+
` role: ${row.role}`,
|
|
2628
|
+
` role_profile: ${row.roleProfile}`,
|
|
2629
|
+
` destination_label: ${row.destinationLabel}`,
|
|
2630
|
+
` poll_interval_ms: ${row.pollIntervalMs}`,
|
|
2631
|
+
` run_once: ${CLI_NAME} runner once --route-name ${row.name}`,
|
|
2632
|
+
row.botName ? ` run_once_by_bot_name: ${CLI_NAME} runner once --bot-name "${row.botName}"` : "",
|
|
2633
|
+
].join("\n") + "\n",
|
|
2634
|
+
);
|
|
2635
|
+
});
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2528
2638
|
async function runRunnerStart(flags) {
|
|
2529
2639
|
const jsonMode = boolFromRaw(flags.json, false);
|
|
2530
2640
|
const routes = resolveRunnerRoutes(flags, "start");
|
|
@@ -2585,6 +2695,10 @@ async function runRunner(argv) {
|
|
|
2585
2695
|
const [subcommandRaw = "", ...rest] = argv;
|
|
2586
2696
|
const subcommand = String(subcommandRaw || "").trim().toLowerCase();
|
|
2587
2697
|
const flags = parseArgs(rest);
|
|
2698
|
+
if (subcommand === "list") {
|
|
2699
|
+
await runRunnerList(flags);
|
|
2700
|
+
return;
|
|
2701
|
+
}
|
|
2588
2702
|
if (subcommand === "once") {
|
|
2589
2703
|
await runRunnerOnce(flags);
|
|
2590
2704
|
return;
|
|
@@ -2593,7 +2707,7 @@ async function runRunner(argv) {
|
|
|
2593
2707
|
await runRunnerStart(flags);
|
|
2594
2708
|
return;
|
|
2595
2709
|
}
|
|
2596
|
-
throw new Error("runner requires a subcommand: once | start");
|
|
2710
|
+
throw new Error("runner requires a subcommand: list | once | start");
|
|
2597
2711
|
}
|
|
2598
2712
|
|
|
2599
2713
|
async function runLocalBotBridge(argv) {
|
|
@@ -2707,12 +2821,39 @@ function parseTelegramServerRoles(rawValue) {
|
|
|
2707
2821
|
return Array.from(new Set(preferredTelegramServerRoleSort(values)));
|
|
2708
2822
|
}
|
|
2709
2823
|
|
|
2824
|
+
function parseTelegramServerRoleIDs(rawValue) {
|
|
2825
|
+
const output = {};
|
|
2826
|
+
String(rawValue || "")
|
|
2827
|
+
.split(",")
|
|
2828
|
+
.map((value) => String(value || "").trim())
|
|
2829
|
+
.filter(Boolean)
|
|
2830
|
+
.forEach((pair) => {
|
|
2831
|
+
const separatorIndex = pair.indexOf(":");
|
|
2832
|
+
if (separatorIndex <= 0) return;
|
|
2833
|
+
const role = String(pair.slice(0, separatorIndex) || "").trim();
|
|
2834
|
+
const id = String(pair.slice(separatorIndex + 1) || "").trim();
|
|
2835
|
+
if (!role || !id) return;
|
|
2836
|
+
output[role] = id;
|
|
2837
|
+
});
|
|
2838
|
+
return preferredTelegramServerRoleSort(Object.keys(output)).reduce((acc, role) => {
|
|
2839
|
+
acc[role] = output[role];
|
|
2840
|
+
return acc;
|
|
2841
|
+
}, {});
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2844
|
+
function formatTelegramServerRoleIDs(roleIDs) {
|
|
2845
|
+
return preferredTelegramServerRoleSort(Object.keys(safeObject(roleIDs)))
|
|
2846
|
+
.map((role) => `${role}:${String(safeObject(roleIDs)[role] || "").trim()}`)
|
|
2847
|
+
.filter((item) => !item.endsWith(":"))
|
|
2848
|
+
.join(",");
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2710
2851
|
function collectTelegramEnvBotEntries(parsedEnv) {
|
|
2711
2852
|
const parsed = safeObject(parsedEnv);
|
|
2712
2853
|
const entries = new Map();
|
|
2713
2854
|
for (const [rawKey, rawValue] of Object.entries(parsed)) {
|
|
2714
2855
|
const match = String(rawKey || "").trim().match(
|
|
2715
|
-
/^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|SERVER_NAME|SERVER_ROLES|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i,
|
|
2856
|
+
/^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|SERVER_NAME|SERVER_ROLES|SERVER_ROLE_IDS|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i,
|
|
2716
2857
|
);
|
|
2717
2858
|
if (!match) continue;
|
|
2718
2859
|
const botKey = normalizeTelegramBotEnvKey(match[1], "");
|
|
@@ -2725,6 +2866,7 @@ function collectTelegramEnvBotEntries(parsedEnv) {
|
|
|
2725
2866
|
serverBotID: "",
|
|
2726
2867
|
serverBotName: "",
|
|
2727
2868
|
serverRoles: [],
|
|
2869
|
+
serverRoleIDs: {},
|
|
2728
2870
|
roleProfile: "",
|
|
2729
2871
|
client: "",
|
|
2730
2872
|
model: "",
|
|
@@ -2742,6 +2884,8 @@ function collectTelegramEnvBotEntries(parsedEnv) {
|
|
|
2742
2884
|
entry.serverBotName = textValue;
|
|
2743
2885
|
} else if (field === "SERVER_ROLES") {
|
|
2744
2886
|
entry.serverRoles = parseTelegramServerRoles(textValue);
|
|
2887
|
+
} else if (field === "SERVER_ROLE_IDS") {
|
|
2888
|
+
entry.serverRoleIDs = parseTelegramServerRoleIDs(textValue);
|
|
2745
2889
|
} else if (field === "ROLE_PROFILE") {
|
|
2746
2890
|
entry.roleProfile = normalizeRunnerRoleProfileName(textValue);
|
|
2747
2891
|
} else if (field === "AI_CLIENT") {
|
|
@@ -2788,6 +2932,7 @@ function parseTelegramBotEntryFile(filePath) {
|
|
|
2788
2932
|
serverBotID: String(parsed.TELEGRAM_BOT_SERVER_BOT_ID || "").trim(),
|
|
2789
2933
|
serverBotName: String(parsed.TELEGRAM_BOT_SERVER_NAME || "").trim(),
|
|
2790
2934
|
serverRoles: parseTelegramServerRoles(parsed.TELEGRAM_BOT_SERVER_ROLES || ""),
|
|
2935
|
+
serverRoleIDs: parseTelegramServerRoleIDs(parsed.TELEGRAM_BOT_SERVER_ROLE_IDS || ""),
|
|
2791
2936
|
token: String(parsed.TELEGRAM_BOT_TOKEN || "").trim(),
|
|
2792
2937
|
roleProfile: normalizeRunnerRoleProfileName(parsed.TELEGRAM_BOT_ROLE_PROFILE || ""),
|
|
2793
2938
|
client: normalizeLocalAIClientName(parsed.TELEGRAM_BOT_AI_CLIENT || "", ""),
|
|
@@ -2824,7 +2969,11 @@ function loadTelegramBotEntriesFromFiles() {
|
|
|
2824
2969
|
const dirPath = telegramBotEntriesDirPath();
|
|
2825
2970
|
if (!fs.existsSync(dirPath)) return [];
|
|
2826
2971
|
return fs.readdirSync(dirPath, { withFileTypes: true })
|
|
2827
|
-
.filter((item) => item.isFile() && /\.env$/i.test(item.name)
|
|
2972
|
+
.filter((item) => item.isFile() && /\.env$/i.test(item.name))
|
|
2973
|
+
.filter((item) => {
|
|
2974
|
+
const lowered = item.name.toLowerCase();
|
|
2975
|
+
return lowered !== "_global.env" && lowered !== "global.env";
|
|
2976
|
+
})
|
|
2828
2977
|
.map((item) => path.join(dirPath, item.name))
|
|
2829
2978
|
.sort((left, right) => left.localeCompare(right))
|
|
2830
2979
|
.map((filePath) => {
|
|
@@ -2851,6 +3000,7 @@ function buildMergedTelegramEnvParsed(globalParsed, entries) {
|
|
|
2851
3000
|
merged[`TELEGRAM_BOT_${upper}_SERVER_BOT_ID`] = String(entry.serverBotID || "").trim();
|
|
2852
3001
|
merged[`TELEGRAM_BOT_${upper}_SERVER_NAME`] = String(entry.serverBotName || "").trim();
|
|
2853
3002
|
merged[`TELEGRAM_BOT_${upper}_SERVER_ROLES`] = ensureArray(entry.serverRoles).join(",");
|
|
3003
|
+
merged[`TELEGRAM_BOT_${upper}_SERVER_ROLE_IDS`] = formatTelegramServerRoleIDs(entry.serverRoleIDs);
|
|
2854
3004
|
merged[`TELEGRAM_BOT_${upper}_USERNAME`] = normalizeTelegramBotUsername(entry.username || "");
|
|
2855
3005
|
merged[`TELEGRAM_BOT_${upper}_TOKEN`] = String(entry.token || "").trim();
|
|
2856
3006
|
merged[`TELEGRAM_BOT_${upper}_ROLE_PROFILE`] = String(entry.roleProfile || "").trim();
|
|
@@ -2865,9 +3015,12 @@ function buildMergedTelegramEnvParsed(globalParsed, entries) {
|
|
|
2865
3015
|
function readTelegramEnvState() {
|
|
2866
3016
|
const filePath = providerEnvFilePath("telegram");
|
|
2867
3017
|
const legacyFilePath = telegramLegacyEnvFilePath();
|
|
3018
|
+
const legacyGlobalFilePath = telegramLegacyGlobalEnvFilePath();
|
|
2868
3019
|
let sourceFilePath = filePath;
|
|
2869
3020
|
try {
|
|
2870
|
-
if (!fs.existsSync(filePath) && fs.existsSync(
|
|
3021
|
+
if (!fs.existsSync(filePath) && fs.existsSync(legacyGlobalFilePath)) {
|
|
3022
|
+
sourceFilePath = legacyGlobalFilePath;
|
|
3023
|
+
} else if (!fs.existsSync(filePath) && fs.existsSync(legacyFilePath)) {
|
|
2871
3024
|
sourceFilePath = legacyFilePath;
|
|
2872
3025
|
} else if (!fs.existsSync(filePath)) {
|
|
2873
3026
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
@@ -2877,6 +3030,7 @@ function readTelegramEnvState() {
|
|
|
2877
3030
|
return {
|
|
2878
3031
|
filePath,
|
|
2879
3032
|
legacyFilePath,
|
|
3033
|
+
legacyGlobalFilePath,
|
|
2880
3034
|
sourceFilePath,
|
|
2881
3035
|
entriesDirPath: telegramBotEntriesDirPath(),
|
|
2882
3036
|
parsed: {},
|
|
@@ -2903,6 +3057,7 @@ function readTelegramEnvState() {
|
|
|
2903
3057
|
return {
|
|
2904
3058
|
filePath,
|
|
2905
3059
|
legacyFilePath,
|
|
3060
|
+
legacyGlobalFilePath,
|
|
2906
3061
|
sourceFilePath,
|
|
2907
3062
|
entriesDirPath: telegramBotEntriesDirPath(),
|
|
2908
3063
|
parsed: buildMergedTelegramEnvParsed(globalParsed, entries),
|
|
@@ -2912,7 +3067,7 @@ function readTelegramEnvState() {
|
|
|
2912
3067
|
}
|
|
2913
3068
|
|
|
2914
3069
|
function isTelegramEntryEnvKey(rawKey) {
|
|
2915
|
-
return /^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|SERVER_NAME|SERVER_ROLES|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i
|
|
3070
|
+
return /^TELEGRAM_BOT_([A-Z0-9_]+)_(TOKEN|USERNAME|SERVER_BOT_ID|SERVER_NAME|SERVER_ROLES|SERVER_ROLE_IDS|ROLE_PROFILE|AI_CLIENT|AI_MODEL|AI_PERMISSION_MODE|AI_REASONING_EFFORT)$/i
|
|
2916
3071
|
.test(String(rawKey || "").trim());
|
|
2917
3072
|
}
|
|
2918
3073
|
|
|
@@ -2935,7 +3090,7 @@ function renderNormalizedTelegramEnv(parsedEnv) {
|
|
|
2935
3090
|
"# Metheus local Telegram bot settings",
|
|
2936
3091
|
"# Keep this file on your machine only. Do not commit it.",
|
|
2937
3092
|
"# Store Telegram-wide settings here.",
|
|
2938
|
-
"# This global file lives in ~/.metheus/telegram-bots/
|
|
3093
|
+
"# This global file lives in ~/.metheus/telegram-bots/global.env.",
|
|
2939
3094
|
"# Per-bot secrets and AI settings live in ~/.metheus/telegram-bots/<server-bot-name>.env.",
|
|
2940
3095
|
"",
|
|
2941
3096
|
`TELEGRAM_API_BASE_URL=${formatProviderEnvValue(parsed.TELEGRAM_API_BASE_URL || "")}`,
|
|
@@ -2971,6 +3126,7 @@ function renderTelegramBotEntryEnv(entryRaw) {
|
|
|
2971
3126
|
const entry = safeObject(entryRaw);
|
|
2972
3127
|
const botName = telegramEntryCommentNameForEnv(entry);
|
|
2973
3128
|
const serverRoles = parseTelegramServerRoles(entry.serverRoles || "");
|
|
3129
|
+
const serverRoleIDs = formatTelegramServerRoleIDs(entry.serverRoleIDs);
|
|
2974
3130
|
const lines = [
|
|
2975
3131
|
"# Metheus local Telegram bot entry",
|
|
2976
3132
|
`# Server bot: ${botName}`,
|
|
@@ -2978,6 +3134,7 @@ function renderTelegramBotEntryEnv(entryRaw) {
|
|
|
2978
3134
|
`TELEGRAM_BOT_SERVER_BOT_ID=${formatProviderEnvValue(entry.serverBotID || "")}`,
|
|
2979
3135
|
`TELEGRAM_BOT_SERVER_NAME=${formatProviderEnvValue(entry.serverBotName || "")}`,
|
|
2980
3136
|
`TELEGRAM_BOT_SERVER_ROLES=${formatProviderEnvValue(serverRoles.join(","))}`,
|
|
3137
|
+
`TELEGRAM_BOT_SERVER_ROLE_IDS=${formatProviderEnvValue(serverRoleIDs)}`,
|
|
2981
3138
|
];
|
|
2982
3139
|
if (!String(entry.serverBotID || "").trim() && !String(entry.serverBotName || "").trim() && String(entry.username || "").trim()) {
|
|
2983
3140
|
lines.push(
|
|
@@ -3006,6 +3163,7 @@ function writeTelegramEnvState(parsedEnv) {
|
|
|
3006
3163
|
|| entry.serverBotID
|
|
3007
3164
|
|| entry.serverBotName
|
|
3008
3165
|
|| ensureArray(entry.serverRoles).length
|
|
3166
|
+
|| Object.keys(safeObject(entry.serverRoleIDs)).length
|
|
3009
3167
|
|| entry.roleProfile
|
|
3010
3168
|
|| entry.client
|
|
3011
3169
|
|| entry.model
|
|
@@ -3021,6 +3179,7 @@ function writeTelegramEnvState(parsedEnv) {
|
|
|
3021
3179
|
});
|
|
3022
3180
|
const globalFilePath = providerEnvFilePath("telegram");
|
|
3023
3181
|
const legacyFilePath = telegramLegacyEnvFilePath();
|
|
3182
|
+
const legacyGlobalFilePath = telegramLegacyGlobalEnvFilePath();
|
|
3024
3183
|
fs.mkdirSync(path.dirname(globalFilePath), { recursive: true });
|
|
3025
3184
|
fs.writeFileSync(globalFilePath, renderNormalizedTelegramEnv(globalParsed), {
|
|
3026
3185
|
encoding: "utf8",
|
|
@@ -3030,24 +3189,46 @@ function writeTelegramEnvState(parsedEnv) {
|
|
|
3030
3189
|
fs.mkdirSync(entriesDirPath, { recursive: true });
|
|
3031
3190
|
const activeFiles = new Set();
|
|
3032
3191
|
entries.forEach((entry) => {
|
|
3033
|
-
const entryFilePath =
|
|
3034
|
-
|
|
3192
|
+
const entryFilePath = telegramBotEntryFilePathForEntry(entry);
|
|
3193
|
+
const previousEntryFilePath = String(entry.entryFilePath || "").trim();
|
|
3194
|
+
const discoveredEntryFilePath = previousEntryFilePath || findTelegramEntryPathVariant(entryFilePath);
|
|
3195
|
+
const sourceEntryFilePath = discoveredEntryFilePath || previousEntryFilePath;
|
|
3196
|
+
if (sourceEntryFilePath && sourceEntryFilePath !== entryFilePath && fs.existsSync(sourceEntryFilePath)) {
|
|
3197
|
+
const previousComparable = normalizeComparablePath(sourceEntryFilePath);
|
|
3198
|
+
const nextComparable = normalizeComparablePath(entryFilePath);
|
|
3199
|
+
if (previousComparable === nextComparable) {
|
|
3200
|
+
const tempRenamePath = path.join(
|
|
3201
|
+
path.dirname(entryFilePath),
|
|
3202
|
+
`.__rename__.${Date.now()}-${Math.random().toString(16).slice(2)}.env`,
|
|
3203
|
+
);
|
|
3204
|
+
fs.renameSync(sourceEntryFilePath, tempRenamePath);
|
|
3205
|
+
fs.renameSync(tempRenamePath, entryFilePath);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
activeFiles.add(normalizeComparablePath(entryFilePath));
|
|
3035
3209
|
fs.writeFileSync(entryFilePath, renderTelegramBotEntryEnv(entry), {
|
|
3036
3210
|
encoding: "utf8",
|
|
3037
3211
|
mode: 0o600,
|
|
3038
3212
|
});
|
|
3039
3213
|
});
|
|
3040
3214
|
fs.readdirSync(entriesDirPath, { withFileTypes: true })
|
|
3041
|
-
.filter((item) => item.isFile() && /\.env$/i.test(item.name)
|
|
3215
|
+
.filter((item) => item.isFile() && /\.env$/i.test(item.name))
|
|
3216
|
+
.filter((item) => {
|
|
3217
|
+
const lowered = item.name.toLowerCase();
|
|
3218
|
+
return lowered !== "_global.env" && lowered !== "global.env";
|
|
3219
|
+
})
|
|
3042
3220
|
.forEach((item) => {
|
|
3043
|
-
const filePath =
|
|
3221
|
+
const filePath = normalizeComparablePath(path.join(entriesDirPath, item.name));
|
|
3044
3222
|
if (!activeFiles.has(filePath)) {
|
|
3045
|
-
fs.rmSync(
|
|
3223
|
+
fs.rmSync(path.join(entriesDirPath, item.name), { force: true });
|
|
3046
3224
|
}
|
|
3047
3225
|
});
|
|
3048
3226
|
if (legacyFilePath !== globalFilePath && fs.existsSync(legacyFilePath)) {
|
|
3049
3227
|
fs.rmSync(legacyFilePath, { force: true });
|
|
3050
3228
|
}
|
|
3229
|
+
if (legacyGlobalFilePath !== globalFilePath && fs.existsSync(legacyGlobalFilePath)) {
|
|
3230
|
+
fs.rmSync(legacyGlobalFilePath, { force: true });
|
|
3231
|
+
}
|
|
3051
3232
|
return globalFilePath;
|
|
3052
3233
|
}
|
|
3053
3234
|
|
|
@@ -3067,6 +3248,7 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
3067
3248
|
|| entry.serverBotID
|
|
3068
3249
|
|| entry.serverBotName
|
|
3069
3250
|
|| ensureArray(entry.serverRoles).length
|
|
3251
|
+
|| Object.keys(safeObject(entry.serverRoleIDs)).length
|
|
3070
3252
|
));
|
|
3071
3253
|
const desiredBotID = firstNonEmptyString([
|
|
3072
3254
|
selectors.serverBotID,
|
|
@@ -3118,7 +3300,8 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
3118
3300
|
provider: "telegram",
|
|
3119
3301
|
providerLabel: config.label,
|
|
3120
3302
|
filePath,
|
|
3121
|
-
|
|
3303
|
+
entryFilePath: telegramBotEntryFilePathForEntry(selected),
|
|
3304
|
+
error: `TELEGRAM_BOT_TOKEN is missing in ${telegramBotEntryFilePathForEntry(selected) || filePath}`,
|
|
3122
3305
|
token: "",
|
|
3123
3306
|
};
|
|
3124
3307
|
}
|
|
@@ -3127,14 +3310,16 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
3127
3310
|
provider: "telegram",
|
|
3128
3311
|
providerLabel: config.label,
|
|
3129
3312
|
filePath,
|
|
3313
|
+
entryFilePath: telegramBotEntryFilePathForEntry(selected),
|
|
3130
3314
|
token: selected.token,
|
|
3131
3315
|
source: "telegram_env_v2",
|
|
3132
|
-
tokenKey:
|
|
3316
|
+
tokenKey: "TELEGRAM_BOT_TOKEN",
|
|
3133
3317
|
botKey: selected.key,
|
|
3134
3318
|
botUsername: selected.username,
|
|
3135
3319
|
serverBotID: selected.serverBotID,
|
|
3136
3320
|
serverBotName: selected.serverBotName,
|
|
3137
3321
|
serverRoles: ensureArray(selected.serverRoles),
|
|
3322
|
+
serverRoleIDs: safeObject(selected.serverRoleIDs),
|
|
3138
3323
|
roleProfile: selected.roleProfile,
|
|
3139
3324
|
client: selected.client,
|
|
3140
3325
|
model: selected.model,
|
|
@@ -3161,6 +3346,7 @@ function resolveTelegramEnvConfig(parsedEnv, filePath, config, selectors = {}) {
|
|
|
3161
3346
|
serverBotID: "",
|
|
3162
3347
|
serverBotName: "",
|
|
3163
3348
|
serverRoles: [],
|
|
3349
|
+
serverRoleIDs: {},
|
|
3164
3350
|
roleProfile: "",
|
|
3165
3351
|
client: "",
|
|
3166
3352
|
model: "",
|
|
@@ -3732,6 +3918,7 @@ function buildBotCommandDeps() {
|
|
|
3732
3918
|
providerEnvFilePath,
|
|
3733
3919
|
telegramBotEntriesDirPath,
|
|
3734
3920
|
telegramBotEntryFilePath,
|
|
3921
|
+
telegramBotEntryFilePathForEntry,
|
|
3735
3922
|
ensureProviderEnvTemplate,
|
|
3736
3923
|
parseCommandAndFlags,
|
|
3737
3924
|
parseSimpleEnvText,
|
|
@@ -5521,7 +5708,7 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
|
|
|
5521
5708
|
const normalizedState = readTelegramEnvState();
|
|
5522
5709
|
writeTelegramEnvState(normalizedState.parsed);
|
|
5523
5710
|
normalizedGlobalText = fs.readFileSync(providerEnvFilePath("telegram"), "utf8");
|
|
5524
|
-
normalizedBotText = fs.readFileSync(
|
|
5711
|
+
normalizedBotText = fs.readFileSync(telegramBotEntryFilePathForEntry({ serverBotName: "RyoAI_bot", key: "ryoai_bot" }), "utf8");
|
|
5525
5712
|
} finally {
|
|
5526
5713
|
if (previousUserProfile === undefined) delete process.env.USERPROFILE;
|
|
5527
5714
|
else process.env.USERPROFILE = previousUserProfile;
|