metheus-governance-mcp-cli 0.2.166 → 0.2.168

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 +21 -0
  2. package/cli.mjs +66 -4
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -441,6 +441,7 @@ Route management:
441
441
  - `runner route add` creates one executable route by selecting the project, provider, role, server bot, and project chat destination in order.
442
442
  - `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.
443
443
  - `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`.
444
+ - 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.
444
445
  - `runner project up --dry-run-delivery true` lets the started runner validate route execution without sending a real provider message.
445
446
  - 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.
446
447
  - `runner route edit` updates one stored route. Use it when the destination, role, or server bot for an existing route changes.
@@ -519,6 +520,9 @@ Workspace/source-of-truth model:
519
520
  - use local tool `runner.start_detached` to launch an existing runner route in a separate local terminal
520
521
  - use local tool `runner.status` to inspect detached runner processes launched by this CLI
521
522
  - use local tool `runner.stop` to stop detached runner processes launched by this CLI
523
+ - detached runner lifecycle belongs to the local Governance MCP tools, not to the current Codex/Claude/Gemini chat turn
524
+ - client AI should resolve workspace + route and then request `runner.start_detached`; it should not try to keep the polling runner attached to its own session
525
+ - the operational goal is: AI session may exit, but detached runner must continue polling independently on the local machine
522
526
  - `runner.start_detached` opens a separate terminal window on Windows, Terminal.app on macOS, and a supported Linux terminal emulator (`x-terminal-emulator`, `gnome-terminal`, `konsole`, `mate-terminal`, `tilix`, `alacritty`, or `xterm`)
523
527
  - on Linux, install one of those terminal emulators first; detached runner launch will fail fast if none are available
524
528
  - `bot-runner.json` stores executable route config and role profiles; it is not the project workspace registry
@@ -591,6 +595,23 @@ Mapping behavior:
591
595
  - `project.workspace.bind` updates the workspace registry directly; it does not need `bot-runner.json` side effects to succeed
592
596
  - use `runner.project_up` after workspace binding to prepare executable routes for one project destination
593
597
  - use `runner.show` to inspect the selected route before launching it
598
+ - use `runner.start_detached` to hand runner lifecycle over to the local machine after route preparation; do not rely on the current client AI process to keep polling alive
599
+
600
+ Recommended local runner bootstrap:
601
+
602
+ ```text
603
+ 1. project.workspace
604
+ 2. project.workspace.bind # only when the registry binding is missing or wrong
605
+ 3. runner.project_up
606
+ 4. runner.show
607
+ 5. runner.start_detached
608
+ 6. runner.status / runner.stop
609
+ ```
610
+
611
+ Operational principle:
612
+ - the local Governance MCP tools own runner startup and lifecycle
613
+ - the client AI only decides when to start/inspect/stop the runner
614
+ - the detached runner must keep running even if the current AI tool session exits
594
615
 
595
616
  Runner command contract:
596
617
  - stdin: JSON payload containing project, destination, trigger message, and recent context comments
package/cli.mjs CHANGED
@@ -4720,7 +4720,16 @@ function resolveRunnerProjectUpRoutes({
4720
4720
 
4721
4721
  async function runRunnerProjectUp(flags) {
4722
4722
  const result = await buildRunnerProjectUpResult(flags);
4723
- const { summaryPayload, applyRequested, applyResult, shouldStartRunner, matchingRoutes, startDetachedRequested, startFlags } = result;
4723
+ const {
4724
+ summaryPayload,
4725
+ applyRequested,
4726
+ applyResult,
4727
+ shouldStartRunner,
4728
+ matchingRoutes,
4729
+ startDetachedRequested,
4730
+ startFlags,
4731
+ applyFailureBlocksStart,
4732
+ } = result;
4724
4733
  if (boolFromRaw(flags.json, false)) {
4725
4734
  process.stdout.write(`${JSON.stringify(summaryPayload, null, 2)}\n`);
4726
4735
  } else {
@@ -4746,11 +4755,12 @@ async function runRunnerProjectUp(flags) {
4746
4755
  `enabled_routes_for_selection: ${summaryPayload.enabled_routes_for_selection.join(", ") || "-"}`,
4747
4756
  `start_requested: ${summaryPayload.start_requested ? "true" : "false"}`,
4748
4757
  `start_detached_requested: ${summaryPayload.start_detached_requested ? "true" : "false"}`,
4758
+ ...(summaryPayload.warning ? [`warning: ${summaryPayload.warning}`] : []),
4749
4759
  `next_steps: ${summaryPayload.next_steps.join(" | ") || "-"}`,
4750
4760
  ].join("\n") + "\n",
4751
4761
  );
4752
4762
  }
4753
- if (applyRequested && applyResult.ok === false) {
4763
+ if (applyFailureBlocksStart) {
4754
4764
  process.exitCode = 1;
4755
4765
  if (shouldStartRunner) {
4756
4766
  throw new Error(String(applyResult.error || "runner project up could not apply runner routes").trim());
@@ -4775,6 +4785,17 @@ async function runRunnerProjectUp(flags) {
4775
4785
  await runRunnerStartResolvedRoutes(matchingRoutes, startFlags);
4776
4786
  }
4777
4787
 
4788
+ function canStartRunnerDespiteProjectUpApplyFailure({ applyRequested, applyResult, matchingRoutes }) {
4789
+ if (!applyRequested) return false;
4790
+ const normalizedApplyResult = safeObject(applyResult);
4791
+ if (normalizedApplyResult.ok !== false) return false;
4792
+ const errorText = String(normalizedApplyResult.error || "").trim();
4793
+ if (errorText !== "route apply skipped because the Telegram room visibility probe failed") {
4794
+ return false;
4795
+ }
4796
+ return ensureArray(matchingRoutes).length > 0;
4797
+ }
4798
+
4778
4799
  async function buildRunnerProjectUpResult(flags = {}) {
4779
4800
  const ui = createPrompter();
4780
4801
  try {
@@ -4855,8 +4876,13 @@ async function buildRunnerProjectUpResult(flags = {}) {
4855
4876
  ...(botNameFilter ? { "bot-name": botNameFilter } : {}),
4856
4877
  ...(botIDFilter ? { "bot-id": botIDFilter } : {}),
4857
4878
  };
4879
+ const applyFailureWarningOnly = canStartRunnerDespiteProjectUpApplyFailure({
4880
+ applyRequested,
4881
+ applyResult,
4882
+ matchingRoutes,
4883
+ });
4858
4884
  const summaryPayload = {
4859
- ok: !applyRequested || applyResult.ok !== false,
4885
+ ok: !applyRequested || applyResult.ok !== false || applyFailureWarningOnly,
4860
4886
  provider,
4861
4887
  project_id: String(auditPayload.projectID || "").trim(),
4862
4888
  destination_label: String(destination.destinationLabel || "").trim(),
@@ -4889,7 +4915,11 @@ async function buildRunnerProjectUpResult(flags = {}) {
4889
4915
  summaryPayload.next_steps.push(`${CLI_NAME} runner show --route-name ${summaryPayload.enabled_routes_for_selection[0] || "<route_name>"}`);
4890
4916
  }
4891
4917
  if (applyRequested && applyResult.ok === false && applyResult.error) {
4892
- summaryPayload.error = String(applyResult.error || "").trim();
4918
+ if (applyFailureWarningOnly) {
4919
+ summaryPayload.warning = String(applyResult.error || "").trim();
4920
+ } else {
4921
+ summaryPayload.error = String(applyResult.error || "").trim();
4922
+ }
4893
4923
  }
4894
4924
  return {
4895
4925
  summaryPayload,
@@ -4899,6 +4929,7 @@ async function buildRunnerProjectUpResult(flags = {}) {
4899
4929
  startDetachedRequested,
4900
4930
  matchingRoutes,
4901
4931
  startFlags,
4932
+ applyFailureBlocksStart: applyRequested && applyResult.ok === false && !applyFailureWarningOnly,
4902
4933
  };
4903
4934
  } finally {
4904
4935
  ui.close();
@@ -8609,6 +8640,9 @@ function appendProjectHintToInitialize(responseObj, args, options = {}) {
8609
8640
  `- Use \`${projectWorkspaceBindTool}\` only when you need to explicitly write/update the local project-workspaces.json registry binding.`,
8610
8641
  `- Use \`${runnerProjectUpTool}\` to audit a project destination and create/select runner routes before starting polling. Then use \`${runnerShowTool}\` to inspect the resolved route if needed.`,
8611
8642
  `- To run automated polling independently of the current AI session, call \`${runnerStartDetachedTool}\` after the workspace binding and route are ready. Use \`${runnerStatusTool}\` to inspect detached runner processes and \`${runnerStopTool}\` to stop them later.`,
8643
+ "- Treat detached runner lifecycle as owned by the local Governance MCP tools, not by the current AI session.",
8644
+ `- Do not keep a long-running runner attached to the current client AI turn. Use \`${runnerStartDetachedTool}\` so the runner survives after the AI session exits.`,
8645
+ "- The AI should resolve the project workspace, prepare the route, and request detached start; the runner process itself must continue independently in a separate local terminal/process.",
8612
8646
  `- After resolving the local workspace, call \`${projectSummaryTool}\` for project overview/agenda/server metadata.`,
8613
8647
  `- If user enters a Project ID in text (e.g., "Project ID <uuid>"), pass that exact UUID as \`project_id\` argument when calling \`${projectSummaryTool}\`.`,
8614
8648
  `- \`${projectDescribeTool}\` and \`${projectGetTool}\` are aliases of \`${projectSummaryTool}\`.`,
@@ -9812,6 +9846,34 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
9812
9846
  push("detached_runner_linux_launcher_selects_supported_terminal", false, String(err?.message || err));
9813
9847
  }
9814
9848
 
9849
+ try {
9850
+ push(
9851
+ "runner_project_up_probe_failure_allows_existing_route_start",
9852
+ canStartRunnerDespiteProjectUpApplyFailure({
9853
+ applyRequested: true,
9854
+ applyResult: { ok: false, error: "route apply skipped because the Telegram room visibility probe failed" },
9855
+ matchingRoutes: [{ name: "telegram-monitor-selftest" }],
9856
+ }) === true,
9857
+ "existing_routes=1 probe_failure=warning_only",
9858
+ );
9859
+ } catch (err) {
9860
+ push("runner_project_up_probe_failure_allows_existing_route_start", false, String(err?.message || err));
9861
+ }
9862
+
9863
+ try {
9864
+ push(
9865
+ "runner_project_up_probe_failure_blocks_without_existing_route",
9866
+ canStartRunnerDespiteProjectUpApplyFailure({
9867
+ applyRequested: true,
9868
+ applyResult: { ok: false, error: "route apply skipped because the Telegram room visibility probe failed" },
9869
+ matchingRoutes: [],
9870
+ }) === false,
9871
+ "existing_routes=0 probe_failure=blocked",
9872
+ );
9873
+ } catch (err) {
9874
+ push("runner_project_up_probe_failure_blocks_without_existing_route", false, String(err?.message || err));
9875
+ }
9876
+
9815
9877
  try {
9816
9878
  const projectUpResponse = await handleLocalProjectToolDispatchImpl(
9817
9879
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.166",
3
+ "version": "0.2.168",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [