metheus-governance-mcp-cli 0.2.211 → 0.2.212

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/cli.mjs CHANGED
@@ -2764,6 +2764,62 @@ function sessionAllowsConversationResponder(sessionRaw, responderSelectorRaw = "
2764
2764
  return allowedResponders.includes(responderSelector);
2765
2765
  }
2766
2766
 
2767
+ function shouldBypassRunnerStartupLoopForContractFollowup({
2768
+ selectedRecord,
2769
+ bot,
2770
+ conversationSessionFacts = null,
2771
+ }) {
2772
+ const parsed = safeObject(selectedRecord?.parsedArchive);
2773
+ if (String(parsed.kind || "").trim().toLowerCase() !== "bot_reply") {
2774
+ return false;
2775
+ }
2776
+ const currentBotSelector = normalizeTelegramMentionUsername(bot?.username || bot?.name);
2777
+ if (!currentBotSelector) {
2778
+ return false;
2779
+ }
2780
+ const conversationID = String(parsed.conversationID || "").trim();
2781
+ if (!conversationID) {
2782
+ return false;
2783
+ }
2784
+ const executionContractType = String(parsed.executionContractType || "").trim().toLowerCase();
2785
+ if (executionContractType !== "delegation") {
2786
+ return false;
2787
+ }
2788
+ const senderBotSelector = normalizeTelegramMentionUsername(
2789
+ parsed.botUsername
2790
+ || parsed.botName
2791
+ || parsed.username
2792
+ || parsed.sender,
2793
+ );
2794
+ if (!senderBotSelector || senderBotSelector === currentBotSelector) {
2795
+ return false;
2796
+ }
2797
+ const assignmentTargets = ensureArray(parsed.executionContractAssignments)
2798
+ .map((item) => normalizeTelegramMentionUsername(safeObject(item).targetBot || safeObject(item).target_bot))
2799
+ .filter(Boolean);
2800
+ const nextResponders = ensureArray(parsed.executionContractNextResponders)
2801
+ .map((item) => normalizeTelegramMentionUsername(item))
2802
+ .filter(Boolean);
2803
+ const conversationTargetBot = normalizeTelegramMentionUsername(parsed.conversationTargetBotUsername);
2804
+ const currentBotIsExpectedResponder = assignmentTargets.includes(currentBotSelector)
2805
+ || nextResponders.includes(currentBotSelector)
2806
+ || conversationTargetBot === currentBotSelector;
2807
+ if (!currentBotIsExpectedResponder) {
2808
+ return false;
2809
+ }
2810
+ const sessionFacts = safeObject(conversationSessionFacts);
2811
+ const sessionExpectedResponders = ensureArray(sessionFacts.next_expected_responders)
2812
+ .map((item) => normalizeTelegramMentionUsername(item))
2813
+ .filter(Boolean);
2814
+ if (sessionExpectedResponders.length > 0 && !sessionExpectedResponders.includes(currentBotSelector)) {
2815
+ return false;
2816
+ }
2817
+ if (sessionFacts.any_closed === true && sessionFacts.any_open !== true) {
2818
+ return false;
2819
+ }
2820
+ return true;
2821
+ }
2822
+
2767
2823
  function findRunnerRequestsForMessageID(state, normalizedRoute, selectors = {}) {
2768
2824
  const chatID = String(selectors.chatID || "").trim();
2769
2825
  const messageID = intFromRawAllowZero(selectors.messageID, 0);
@@ -7707,6 +7763,13 @@ async function maybeHandleRunnerStartupLoopCandidate({
7707
7763
  }
7708
7764
  const conversationID = String(parsed.conversationID || "").trim();
7709
7765
  const conversationSessionFacts = collectBotRunnerConversationSessionFacts(normalizedRoute, conversationID);
7766
+ if (shouldBypassRunnerStartupLoopForContractFollowup({
7767
+ selectedRecord,
7768
+ bot,
7769
+ conversationSessionFacts,
7770
+ })) {
7771
+ return null;
7772
+ }
7710
7773
  const adjudication = await resolveRunnerStartupLoopAdjudication({
7711
7774
  selectedRecord,
7712
7775
  pendingOrdered,
@@ -15488,6 +15551,7 @@ TELEGRAM_BOT_REVIEW_TOKEN=review-token
15488
15551
  selectRunnerPendingWork,
15489
15552
  processRunnerSelectedRecord,
15490
15553
  resolveRunnerStartupLoopAdjudication,
15554
+ shouldBypassRunnerStartupLoopForContractFollowup,
15491
15555
  claimRunnerRequestForHumanComment,
15492
15556
  markRunnerRequestLifecycle,
15493
15557
  resolveRunnerContinuationRequestForBotReply,
@@ -118,16 +118,17 @@ export async function runSelftestRunnerScenarios(push, deps) {
118
118
  const safeObject = requireDependency(deps, "safeObject");
119
119
  const normalizeRunnerTriggerPolicy = requireDependency(deps, "normalizeRunnerTriggerPolicy");
120
120
  const evaluateTelegramRunnerTrigger = requireDependency(deps, "evaluateTelegramRunnerTrigger");
121
- const resolveRunnerResponderAdjudication = requireDependency(deps, "resolveRunnerResponderAdjudication");
122
- const selectPendingArchiveComments = requireDependency(deps, "selectPendingArchiveComments");
123
- const selectRunnerPendingWork = requireDependency(deps, "selectRunnerPendingWork");
124
- const processRunnerSelectedRecord = requireDependency(deps, "processRunnerSelectedRecord");
125
- const resolveRunnerStartupLoopAdjudication = requireDependency(deps, "resolveRunnerStartupLoopAdjudication");
126
- const runRunnerAIExecution = requireDependency(deps, "runRunnerAIExecution");
127
- const formatBotReplyArchiveComment = requireDependency(deps, "formatBotReplyArchiveComment");
128
- const findArchivedBotReplyRecord = requireDependency(deps, "findArchivedBotReplyRecord");
129
- const parseArchivedChatComment = requireDependency(deps, "parseArchivedChatComment");
130
- const validateWorkspaceArtifacts = requireDependency(deps, "validateWorkspaceArtifacts");
121
+ const resolveRunnerResponderAdjudication = requireDependency(deps, "resolveRunnerResponderAdjudication");
122
+ const selectPendingArchiveComments = requireDependency(deps, "selectPendingArchiveComments");
123
+ const selectRunnerPendingWork = requireDependency(deps, "selectRunnerPendingWork");
124
+ const processRunnerSelectedRecord = requireDependency(deps, "processRunnerSelectedRecord");
125
+ const resolveRunnerStartupLoopAdjudication = requireDependency(deps, "resolveRunnerStartupLoopAdjudication");
126
+ const shouldBypassRunnerStartupLoopForContractFollowup = requireDependency(deps, "shouldBypassRunnerStartupLoopForContractFollowup");
127
+ const runRunnerAIExecution = requireDependency(deps, "runRunnerAIExecution");
128
+ const formatBotReplyArchiveComment = requireDependency(deps, "formatBotReplyArchiveComment");
129
+ const findArchivedBotReplyRecord = requireDependency(deps, "findArchivedBotReplyRecord");
130
+ const parseArchivedChatComment = requireDependency(deps, "parseArchivedChatComment");
131
+ const validateWorkspaceArtifacts = requireDependency(deps, "validateWorkspaceArtifacts");
131
132
  const buildLocalBotPrompt = requireDependency(deps, "buildLocalBotPrompt");
132
133
 
133
134
  try {
@@ -367,13 +368,53 @@ export async function runSelftestRunnerScenarios(push, deps) {
367
368
  && adjudication?.startup_facts?.repeated_same_delegation_without_new_human === true,
368
369
  `decision=${String(adjudication?.decision || "")} action=${String(adjudication?.action || "")} imported=${String(adjudication?.startup_facts?.imported_on_current_poll)} repeated_delegation=${String(adjudication?.startup_facts?.repeated_same_delegation_without_new_human)}`,
369
370
  );
370
- } catch (err) {
371
- push(
372
- "runner_loop_adjudication_detects_repeated_same_delegation_without_new_human_input",
373
- false,
374
- String(err?.message || err),
375
- );
376
- }
371
+ } catch (err) {
372
+ push(
373
+ "runner_loop_adjudication_detects_repeated_same_delegation_without_new_human_input",
374
+ false,
375
+ String(err?.message || err),
376
+ );
377
+ }
378
+
379
+ try {
380
+ const shouldBypass = shouldBypassRunnerStartupLoopForContractFollowup({
381
+ selectedRecord: {
382
+ id: "bot-reply-4",
383
+ parsedArchive: {
384
+ kind: "bot_reply",
385
+ messageID: 52,
386
+ senderIsBot: true,
387
+ botUsername: "@bot-a",
388
+ conversationID: "conv-4",
389
+ executionContractType: "delegation",
390
+ executionContractAssignments: [
391
+ { targetBot: "@bot-b", task: "say hello" },
392
+ ],
393
+ executionContractNextResponders: ["@bot-b"],
394
+ conversationTargetBotUsername: "@bot-b",
395
+ },
396
+ },
397
+ bot: {
398
+ username: "@bot-b",
399
+ },
400
+ conversationSessionFacts: {
401
+ any_open: true,
402
+ any_closed: false,
403
+ next_expected_responders: ["bot-b"],
404
+ },
405
+ });
406
+ push(
407
+ "runner_startup_loop_bypasses_expected_delegation_followup_for_target_bot",
408
+ shouldBypass === true,
409
+ `should_bypass=${String(shouldBypass)}`,
410
+ );
411
+ } catch (err) {
412
+ push(
413
+ "runner_startup_loop_bypasses_expected_delegation_followup_for_target_bot",
414
+ false,
415
+ String(err?.message || err),
416
+ );
417
+ }
377
418
 
378
419
  try {
379
420
  const pendingSelection = selectPendingArchiveComments(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.211",
3
+ "version": "0.2.212",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [