metheus-governance-mcp-cli 0.2.286 → 0.2.288

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.
Files changed (3) hide show
  1. package/README.md +9 -3
  2. package/cli.mjs +182 -70
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -379,7 +379,7 @@ Behavior:
379
379
  - `bot room-audit` now suggests executable runner routes for the managed server+local intersection. Room visibility is still reported, but a bot no longer has to appear in the admin list before route automation can prepare it.
380
380
  - `bot room-audit` defaults to `monitor` only unless you pass `--role` or `--roles`.
381
381
  - `bot room-audit --apply true` writes missing suggested routes into `~/.metheus/bot-runner.json` and disables overlapping enabled routes in the same project/provider/destination/bot scope that are outside the selected role set.
382
- - `runner project up` is the one-command path for Telegram project operations: it runs the same room audit, applies the selected role routes, and can immediately start polling for that project destination.
382
+ - `runner project up` is the one-command direct CLI path for Telegram project operations: it runs the same room audit, applies the selected role routes, and starts detached polling by default unless you explicitly pass `--start false`.
383
383
  - `runner project up` can be narrowed with `--bot-name`, `--bot-id`, `--role`, or `--roles <csv>` when you do not want every suggested role route for that room.
384
384
  - `bot remove` without flags starts a guided numbered flow: provider -> bot entry -> confirm removal.
385
385
  - Telegram stores one bot file per entry under `~/.metheus/telegram-bots/<ServerBotName>.env` with generic fields:
@@ -422,6 +422,8 @@ metheus-governance-mcp-cli bot verify --provider telegram --bot-name <server_bot
422
422
  metheus-governance-mcp-cli bot room-audit --provider telegram --project-id <project_uuid> --destination-label <room_label> --json true
423
423
  metheus-governance-mcp-cli bot room-audit --provider telegram --project-id <project_uuid> --destination-label <room_label> --apply true --json true
424
424
  metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label>
425
+ metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label> --start false
426
+ metheus-governance-mcp-cli runner start-detached --project-id <project_uuid> --provider telegram --destination-label <room_label>
425
427
  metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label> --bot-name <server_bot_name> --roles monitor,review --start false
426
428
  ```
427
429
 
@@ -540,7 +542,8 @@ Commands:
540
542
 
541
543
  ```bash
542
544
  metheus-governance-mcp-cli runner list
543
- metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label>
545
+ metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label> --start false
546
+ metheus-governance-mcp-cli runner start-detached --project-id <project_uuid> --provider telegram --destination-label <room_label>
544
547
  metheus-governance-mcp-cli runner route add
545
548
  metheus-governance-mcp-cli runner route edit --route-name telegram-monitor
546
549
  metheus-governance-mcp-cli runner route remove --route-name telegram-monitor
@@ -553,7 +556,7 @@ metheus-governance-mcp-cli runner start --route-name telegram-monitor --concurre
553
556
  Route management:
554
557
  - `runner route add` creates one executable route by selecting the project, provider, role, server bot, and project chat destination in order.
555
558
  - `runner route add` now auto-uses the suggested route name, `5000` ms poll interval, and `enabled=true` unless you pass explicit flags or edit the route later.
556
- - `runner project up` is the shortest practical route bootstrap path for Telegram: it audits one project destination, writes any missing suggested routes, then starts polling for that same destination unless you pass `--start false`.
559
+ - `runner project up` is the shortest practical route bootstrap path for Telegram: it audits one project destination, writes any missing suggested routes, and starts detached polling by default unless you explicitly pass `--start false`.
557
560
  - if room visibility probe fails but one or more enabled routes already exist for that project destination, `runner project up` now treats the probe failure as a warning and can still start those existing routes.
558
561
  - `runner project up --dry-run-delivery true` lets the started runner validate route execution without sending a real provider message.
559
562
  - In public Telegram bot conversations, the stored route role is treated as a hint only. Live room context, the current human request, and recent bot replies take priority over the stored route role hint when the local AI client decides how to answer.
@@ -567,7 +570,10 @@ Recommended operational path:
567
570
 
568
571
  ```bash
569
572
  metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label>
573
+ metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label> --start false
574
+ metheus-governance-mcp-cli runner start-detached --project-id <project_uuid> --provider telegram --destination-label <room_label>
570
575
  metheus-governance-mcp-cli runner project up --project-id <project_uuid> --provider telegram --destination-label <room_label> --bot-name <server_bot_name> --roles monitor,review --start false
576
+ metheus-governance-mcp-cli runner start-detached --project-id <project_uuid> --provider telegram --destination-label <room_label> --bot-name <server_bot_name> --role monitor
571
577
  ```
572
578
 
573
579
  If you want the older step-by-step path instead:
package/cli.mjs CHANGED
@@ -12258,11 +12258,11 @@ async function runRunnerProjectUp(flags) {
12258
12258
  if (!matchingRoutes.length) {
12259
12259
  throw new Error("runner project up did not find any enabled routes for the selected project destination");
12260
12260
  }
12261
- if (!boolFromRaw(flags.json, false)) {
12262
- process.stdout.write(
12263
- `${startDetachedRequested ? "Starting detached runner" : "Starting runner"} for project ${summaryPayload.project_id} destination ${summaryPayload.destination_label || summaryPayload.destination_id} using ${matchingRoutes.length} enabled route(s).\n`,
12264
- );
12265
- }
12261
+ if (!boolFromRaw(flags.json, false)) {
12262
+ process.stdout.write(
12263
+ `${startDetachedRequested ? "Starting detached runner" : "Starting foreground runner (stops when this session ends)"} for project ${summaryPayload.project_id} destination ${summaryPayload.destination_label || summaryPayload.destination_id} using ${matchingRoutes.length} enabled route(s).\n`,
12264
+ );
12265
+ }
12266
12266
  if (startDetachedRequested) {
12267
12267
  await runRunnerStartDetachedResolvedRoutes(matchingRoutes, startFlags, "runner project up");
12268
12268
  return;
@@ -12277,39 +12277,94 @@ async function runRunnerProjectUp(flags) {
12277
12277
  });
12278
12278
  }
12279
12279
 
12280
- function canStartRunnerDespiteProjectUpApplyFailure({ applyRequested, applyResult, matchingRoutes }) {
12281
- if (!applyRequested) return false;
12282
- const normalizedApplyResult = safeObject(applyResult);
12283
- if (normalizedApplyResult.ok !== false) return false;
12280
+ function canStartRunnerDespiteProjectUpApplyFailure({ applyRequested, applyResult, matchingRoutes }) {
12281
+ if (!applyRequested) return false;
12282
+ const normalizedApplyResult = safeObject(applyResult);
12283
+ if (normalizedApplyResult.ok !== false) return false;
12284
12284
  const errorText = String(normalizedApplyResult.error || "").trim();
12285
12285
  if (errorText !== "route apply skipped because the Telegram room visibility probe failed") {
12286
12286
  return false;
12287
12287
  }
12288
- return ensureArray(matchingRoutes).length > 0;
12289
- }
12290
-
12291
- async function buildRunnerProjectUpResult(flags = {}) {
12292
- const ui = createPrompter();
12293
- try {
12294
- if (shouldRenderPromptChrome(flags)) {
12295
- ui.setFlow("RUNNER PROJECT UP", "Audit one project destination, create missing runner routes, and optionally start polling");
12296
- }
12297
- const provider = String(flags.provider || "").trim()
12298
- ? normalizeBotProvider(flags.provider)
12299
- : "telegram";
12300
- if (provider !== "telegram") {
12301
- throw new Error("runner project up currently supports only --provider telegram");
12302
- }
12303
- const applyRequested = Object.prototype.hasOwnProperty.call(flags, "apply")
12304
- ? boolFromRaw(flags.apply, true)
12305
- : true;
12306
- const startDetachedRequested = Object.prototype.hasOwnProperty.call(flags, "start-detached")
12307
- ? boolFromRaw(flags["start-detached"], true)
12308
- : boolFromRaw(flags.detached, false);
12309
- const startRequested = Object.prototype.hasOwnProperty.call(flags, "start")
12310
- ? boolFromRaw(flags.start, true)
12311
- : true;
12312
- const shouldStartRunner = startRequested || startDetachedRequested;
12288
+ return ensureArray(matchingRoutes).length > 0;
12289
+ }
12290
+
12291
+ function resolveRunnerProjectUpExecutionPolicy(flags = {}) {
12292
+ const applyRequested = Object.prototype.hasOwnProperty.call(flags, "apply")
12293
+ ? boolFromRaw(flags.apply, true)
12294
+ : true;
12295
+ const explicitStartDetachedRequested = Object.prototype.hasOwnProperty.call(flags, "start-detached");
12296
+ const explicitDetachedAliasRequested = Object.prototype.hasOwnProperty.call(flags, "detached");
12297
+ const explicitStartRequested = Object.prototype.hasOwnProperty.call(flags, "start");
12298
+ const startRequested = Object.prototype.hasOwnProperty.call(flags, "start")
12299
+ ? boolFromRaw(flags.start, true)
12300
+ : false;
12301
+ const startDetachedRequested = explicitStartDetachedRequested
12302
+ ? boolFromRaw(flags["start-detached"], true)
12303
+ : (explicitDetachedAliasRequested
12304
+ ? boolFromRaw(flags.detached, false)
12305
+ : !explicitStartRequested);
12306
+ const shouldStartRunner = startRequested || startDetachedRequested;
12307
+ return {
12308
+ applyRequested,
12309
+ startDetachedRequested,
12310
+ startRequested,
12311
+ shouldStartRunner,
12312
+ foregroundStartRequested: startRequested && !startDetachedRequested,
12313
+ };
12314
+ }
12315
+
12316
+ function buildRunnerStartDetachedCommand(flags = {}) {
12317
+ return [CLI_NAME, "runner", "start-detached", ...serializeCLIFlags(flags, {
12318
+ omit: ["json", "start", "start-detached", "detached"],
12319
+ })].join(" ");
12320
+ }
12321
+
12322
+ function buildRunnerProjectUpNextSteps({
12323
+ applyRequested,
12324
+ shouldStartRunner,
12325
+ projectID,
12326
+ provider,
12327
+ destinationID,
12328
+ matchingRoutes,
12329
+ startFlags,
12330
+ }) {
12331
+ const nextSteps = [];
12332
+ const routeNames = ensureArray(matchingRoutes).map((route) => normalizeRunnerRoute(route).name).filter(Boolean);
12333
+ if (!applyRequested) {
12334
+ nextSteps.push(`${CLI_NAME} runner project up --project-id ${projectID} --provider ${provider} --destination-id ${destinationID} --apply true --start false`);
12335
+ }
12336
+ if (!shouldStartRunner) {
12337
+ if (routeNames.length > 0) {
12338
+ nextSteps.push(`${CLI_NAME} runner show --route-name ${routeNames[0]}`);
12339
+ nextSteps.push(buildRunnerStartDetachedCommand(startFlags));
12340
+ } else if (applyRequested) {
12341
+ nextSteps.push(`${CLI_NAME} runner project up --project-id ${projectID} --provider ${provider} --destination-id ${destinationID} --apply true --start false`);
12342
+ }
12343
+ return nextSteps;
12344
+ }
12345
+ nextSteps.push(`${CLI_NAME} runner show --route-name ${routeNames[0] || "<route_name>"}`);
12346
+ return nextSteps;
12347
+ }
12348
+
12349
+ async function buildRunnerProjectUpResult(flags = {}) {
12350
+ const ui = createPrompter();
12351
+ try {
12352
+ if (shouldRenderPromptChrome(flags)) {
12353
+ ui.setFlow("RUNNER PROJECT UP", "Audit one project destination, create missing runner routes, and start detached polling by default unless --start false is passed");
12354
+ }
12355
+ const provider = String(flags.provider || "").trim()
12356
+ ? normalizeBotProvider(flags.provider)
12357
+ : "telegram";
12358
+ if (provider !== "telegram") {
12359
+ throw new Error("runner project up currently supports only --provider telegram");
12360
+ }
12361
+ const {
12362
+ applyRequested,
12363
+ startDetachedRequested,
12364
+ startRequested,
12365
+ shouldStartRunner,
12366
+ foregroundStartRequested,
12367
+ } = resolveRunnerProjectUpExecutionPolicy(flags);
12313
12368
  const roleFilter = parseRunnerProjectUpRoles(flags);
12314
12369
  const botNameFilter = String(flags["bot-name"] || "").trim();
12315
12370
  const botIDFilter = String(flags["bot-id"] || "").trim();
@@ -12392,30 +12447,35 @@ async function buildRunnerProjectUpResult(flags = {}) {
12392
12447
  route_apply_requested: applyRequested,
12393
12448
  route_apply_changed: Boolean(applyResult.changed),
12394
12449
  route_config_file: String(applyResult.filePath || auditPayload.routeSuggestionConfigFilePath || "-").trim() || "-",
12395
- enabled_routes_for_selection: matchingRoutes.map((route) => normalizeRunnerRoute(route).name).filter(Boolean),
12396
- start_requested: shouldStartRunner,
12397
- start_detached_requested: startDetachedRequested,
12398
- next_steps: [],
12399
- applied_routes: ensureArray(applyResult.appliedRoutes).map((item) => safeObject(item)),
12400
- disabled_routes: ensureArray(applyResult.disabledRoutes).map((item) => safeObject(item)),
12401
- };
12402
- if (!applyRequested) {
12403
- summaryPayload.next_steps.push(`${CLI_NAME} runner project up --project-id ${summaryPayload.project_id} --provider ${provider} --destination-id ${summaryPayload.destination_id} --apply true --start false`);
12404
- } else if (!shouldStartRunner) {
12405
- summaryPayload.next_steps.push(`${CLI_NAME} runner project up --project-id ${summaryPayload.project_id} --provider ${provider} --destination-id ${summaryPayload.destination_id}`);
12406
- } else {
12407
- summaryPayload.next_steps.push(`${CLI_NAME} runner show --route-name ${summaryPayload.enabled_routes_for_selection[0] || "<route_name>"}`);
12408
- }
12409
- if (applyRequested && applyResult.ok === false && applyResult.error) {
12410
- if (applyFailureWarningOnly) {
12411
- summaryPayload.warning = String(applyResult.error || "").trim();
12412
- } else {
12413
- summaryPayload.error = String(applyResult.error || "").trim();
12414
- }
12415
- }
12416
- return {
12417
- summaryPayload,
12418
- applyRequested,
12450
+ enabled_routes_for_selection: matchingRoutes.map((route) => normalizeRunnerRoute(route).name).filter(Boolean),
12451
+ start_requested: shouldStartRunner,
12452
+ start_detached_requested: startDetachedRequested,
12453
+ next_steps: [],
12454
+ applied_routes: ensureArray(applyResult.appliedRoutes).map((item) => safeObject(item)),
12455
+ disabled_routes: ensureArray(applyResult.disabledRoutes).map((item) => safeObject(item)),
12456
+ };
12457
+ summaryPayload.next_steps.push(...buildRunnerProjectUpNextSteps({
12458
+ applyRequested,
12459
+ shouldStartRunner,
12460
+ projectID: summaryPayload.project_id,
12461
+ provider,
12462
+ destinationID: summaryPayload.destination_id,
12463
+ matchingRoutes,
12464
+ startFlags,
12465
+ }));
12466
+ if (applyRequested && applyResult.ok === false && applyResult.error) {
12467
+ if (applyFailureWarningOnly) {
12468
+ summaryPayload.warning = String(applyResult.error || "").trim();
12469
+ } else {
12470
+ summaryPayload.error = String(applyResult.error || "").trim();
12471
+ }
12472
+ }
12473
+ if (foregroundStartRequested && !summaryPayload.warning && !summaryPayload.error) {
12474
+ summaryPayload.warning = "foreground runner start was explicitly requested; the runner stops when this terminal session ends. Use runner start-detached for persistent polling.";
12475
+ }
12476
+ return {
12477
+ summaryPayload,
12478
+ applyRequested,
12419
12479
  applyResult,
12420
12480
  shouldStartRunner,
12421
12481
  startDetachedRequested,
@@ -16907,12 +16967,12 @@ function buildLocalToolSpecs() {
16907
16967
  "Delete one project context item permanently.",
16908
16968
  inputSchema: buildProjectContextGetInputSchema(),
16909
16969
  },
16910
- {
16911
- name: "runner.project_up",
16912
- description:
16913
- "Audit one project destination, create missing runner routes, and optionally start polling. Use this before runner.start_detached when the route is not ready yet.",
16914
- inputSchema: buildRunnerProjectUpInputSchema(),
16915
- },
16970
+ {
16971
+ name: "runner.project_up",
16972
+ description:
16973
+ "Audit one project destination, create missing runner routes, and optionally start polling only when explicitly requested. Use this before runner.start_detached when the route is not ready yet.",
16974
+ inputSchema: buildRunnerProjectUpInputSchema(),
16975
+ },
16916
16976
  {
16917
16977
  name: "runner.show",
16918
16978
  description:
@@ -19267,12 +19327,64 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
19267
19327
  push("detached_runner_linux_launcher_selects_supported_terminal", false, String(err?.message || err));
19268
19328
  }
19269
19329
 
19270
- try {
19271
- push(
19272
- "runner_project_up_probe_failure_allows_existing_route_start",
19273
- canStartRunnerDespiteProjectUpApplyFailure({
19274
- applyRequested: true,
19275
- applyResult: { ok: false, error: "route apply skipped because the Telegram room visibility probe failed" },
19330
+ try {
19331
+ const projectUpPolicy = resolveRunnerProjectUpExecutionPolicy({});
19332
+ push(
19333
+ "runner_project_up_default_policy_prefers_detached_start",
19334
+ projectUpPolicy.applyRequested === true
19335
+ && projectUpPolicy.startRequested === false
19336
+ && projectUpPolicy.startDetachedRequested === true
19337
+ && projectUpPolicy.shouldStartRunner === true,
19338
+ `apply=${projectUpPolicy.applyRequested} start=${projectUpPolicy.startRequested} detached=${projectUpPolicy.startDetachedRequested} shouldStart=${projectUpPolicy.shouldStartRunner}`,
19339
+ );
19340
+ } catch (err) {
19341
+ push("runner_project_up_default_policy_prefers_detached_start", false, String(err?.message || err));
19342
+ }
19343
+
19344
+ try {
19345
+ const projectUpPolicy = resolveRunnerProjectUpExecutionPolicy({ start: false });
19346
+ push(
19347
+ "runner_project_up_explicit_start_false_keeps_prepare_only",
19348
+ projectUpPolicy.applyRequested === true
19349
+ && projectUpPolicy.startRequested === false
19350
+ && projectUpPolicy.startDetachedRequested === false
19351
+ && projectUpPolicy.shouldStartRunner === false,
19352
+ `apply=${projectUpPolicy.applyRequested} start=${projectUpPolicy.startRequested} detached=${projectUpPolicy.startDetachedRequested} shouldStart=${projectUpPolicy.shouldStartRunner}`,
19353
+ );
19354
+ } catch (err) {
19355
+ push("runner_project_up_explicit_start_false_keeps_prepare_only", false, String(err?.message || err));
19356
+ }
19357
+
19358
+ try {
19359
+ const nextSteps = buildRunnerProjectUpNextSteps({
19360
+ applyRequested: true,
19361
+ shouldStartRunner: false,
19362
+ projectID: selftestProjectID,
19363
+ provider: "telegram",
19364
+ destinationID: "dest-1",
19365
+ matchingRoutes: [{ name: "telegram-monitor-selftest", enabled: true }],
19366
+ startFlags: {
19367
+ "project-id": selftestProjectID,
19368
+ provider: "telegram",
19369
+ "destination-id": "dest-1",
19370
+ },
19371
+ });
19372
+ push(
19373
+ "runner_project_up_next_steps_prefer_start_detached",
19374
+ nextSteps.includes(`${CLI_NAME} runner show --route-name telegram-monitor-selftest`)
19375
+ && nextSteps.includes(`${CLI_NAME} runner start-detached --project-id ${selftestProjectID} --provider telegram --destination-id dest-1`),
19376
+ nextSteps.join(" | "),
19377
+ );
19378
+ } catch (err) {
19379
+ push("runner_project_up_next_steps_prefer_start_detached", false, String(err?.message || err));
19380
+ }
19381
+
19382
+ try {
19383
+ push(
19384
+ "runner_project_up_probe_failure_allows_existing_route_start",
19385
+ canStartRunnerDespiteProjectUpApplyFailure({
19386
+ applyRequested: true,
19387
+ applyResult: { ok: false, error: "route apply skipped because the Telegram room visibility probe failed" },
19276
19388
  matchingRoutes: [{ name: "telegram-monitor-selftest" }],
19277
19389
  }) === true,
19278
19390
  "existing_routes=1 probe_failure=warning_only",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.286",
3
+ "version": "0.2.288",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [