metheus-governance-mcp-cli 0.2.215 → 0.2.217

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
@@ -2797,7 +2797,7 @@ function shouldBypassRunnerStartupLoopForContractFollowup({
2797
2797
  return false;
2798
2798
  }
2799
2799
  const executionContractType = String(parsed.executionContractType || "").trim().toLowerCase();
2800
- if (executionContractType !== "delegation") {
2800
+ if (!executionContractType) {
2801
2801
  return false;
2802
2802
  }
2803
2803
  const senderBotSelector = normalizeTelegramMentionUsername(
@@ -3663,28 +3663,13 @@ function runnerRequestRequiresActionableContract(requestRaw) {
3663
3663
  const replyExpectation = String(request.conversation_reply_expectation || "").trim().toLowerCase();
3664
3664
  const executionContractType = String(request.execution_contract_type || "").trim().toLowerCase();
3665
3665
  const intentMode = String(request.conversation_intent_mode || "").trim().toLowerCase();
3666
- const intentType = String(
3667
- request.conversation_intent_type
3668
- || request.intent_type
3669
- || request.normalized_intent
3670
- || "",
3671
- ).trim().toLowerCase();
3672
- const hasExecutionIntent = [
3673
- "general_execution",
3674
- "ctxpack_mutation",
3675
- "workitem_mutation",
3676
- ].includes(intentType);
3677
3666
  if (request.execution_contract_actionable === true) {
3678
3667
  return true;
3679
3668
  }
3680
3669
  if (["delegation", "direct_result", "summary_request", "final_summary"].includes(executionContractType)) {
3681
3670
  return true;
3682
3671
  }
3683
- if (
3684
- intentMode === "single_bot"
3685
- && replyExpectation === "actionable"
3686
- && hasExecutionIntent
3687
- ) {
3672
+ if (intentMode === "single_bot" && replyExpectation === "actionable") {
3688
3673
  return true;
3689
3674
  }
3690
3675
  return false;
@@ -1773,7 +1773,7 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
1773
1773
 
1774
1774
  const lines = [
1775
1775
  "You are a Metheus local bot runner.",
1776
- `Task: ${taskName || "reply_to_project_chat_message"}`,
1776
+ `Task Metadata (non-authoritative): ${taskName || "reply_with_agent_context:generic"}`,
1777
1777
  `Provider: ${provider}`,
1778
1778
  `Role: ${role}`,
1779
1779
  `Role Profile: ${roleProfile || "-"}`,
@@ -1791,6 +1791,7 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
1791
1791
  "",
1792
1792
  "Agent contract/context blob (primary control and state input):",
1793
1793
  agentContext ? JSON.stringify(agentContext, null, 2) : "-",
1794
+ "Use the agent contract/context blob as the authoritative control input. Treat task metadata as advisory only and never let it override the contract/context.",
1794
1795
  "",
1795
1796
  "Current user request:",
1796
1797
  String(trigger.body || "").trim() || "-",
@@ -1285,19 +1285,6 @@ export async function resolveHumanIntentContext({
1285
1285
  runnerHumanIntentPromises.set(cacheKey, promise);
1286
1286
  }
1287
1287
  let humanIntent = await runnerHumanIntentPromises.get(cacheKey);
1288
- if (!isCompleteHumanIntentContract(humanIntent)) {
1289
- humanIntent = await analyzeHumanConversationIntentWithContractResolver({
1290
- text: parsed.body,
1291
- managedMentions,
1292
- peerMap,
1293
- deps,
1294
- executionPlan,
1295
- contractGuardrail: {
1296
- require_complete_contract: true,
1297
- reason: "Return a complete human intent contract for this managed-bot conversation.",
1298
- },
1299
- });
1300
- }
1301
1288
  if (!isCompleteHumanIntentContract(humanIntent)) {
1302
1289
  return {
1303
1290
  currentBotSelector,
@@ -1325,43 +1312,60 @@ function buildDirectHumanResponseContract({
1325
1312
  }) {
1326
1313
  const humanIntent = safeObject(humanIntentContext?.humanIntent);
1327
1314
  const conversation = safeObject(conversationContext);
1328
- const intentMode = String(conversation.intentMode || humanIntent.intentMode || "").trim();
1329
- const allowBotToBot = conversation.allowBotToBot === true || humanIntent.allowBotToBot === true;
1330
- const allowedResponderSelectors = uniqueOrdered(
1331
- ensureArray(conversation.allowedResponderSelectors || humanIntent.allowedResponderSelectors)
1315
+ const preferConversationContract = Boolean(
1316
+ String(conversation.intentMode || "").trim()
1317
+ || ensureArray(conversation.initialResponderSelectors).length
1318
+ || ensureArray(conversation.allowedResponderSelectors).length
1319
+ || String(conversation.leadBotUsername || "").trim()
1320
+ || String(conversation.summaryBotUsername || "").trim()
1321
+ || String(conversation.replyExpectation || "").trim(),
1322
+ );
1323
+ const source = preferConversationContract ? conversation : humanIntent;
1324
+ const secondary = preferConversationContract ? humanIntent : conversation;
1325
+ const normalizedAllowedResponderSelectors = uniqueOrdered(
1326
+ ensureArray(source.allowedResponderSelectors)
1332
1327
  .map((item) => normalizeMentionSelector(item))
1333
1328
  .filter(Boolean),
1334
1329
  );
1335
- const initialResponderSelectors = uniqueOrdered(
1336
- ensureArray(conversation.initialResponderSelectors || humanIntent.initialResponderSelectors)
1330
+ const normalizedInitialResponderSelectors = uniqueOrdered(
1331
+ ensureArray(source.initialResponderSelectors)
1337
1332
  .map((item) => normalizeMentionSelector(item))
1338
1333
  .filter(Boolean),
1339
1334
  );
1340
- const leadBotSelector = normalizeMentionSelector(conversation.leadBotUsername || humanIntent.leadBotSelector);
1341
- const summaryBotSelector = normalizeMentionSelector(conversation.summaryBotUsername || humanIntent.summaryBotSelector);
1335
+ const intentMode = String(source.intentMode || secondary.intentMode || "").trim();
1336
+ const allowBotToBot = source.allowBotToBot === true
1337
+ || (source.allowBotToBot !== false && secondary.allowBotToBot === true);
1338
+ const leadBotSelector = normalizeMentionSelector(
1339
+ source.leadBotUsername || source.leadBotSelector || secondary.leadBotUsername || secondary.leadBotSelector,
1340
+ );
1341
+ const summaryBotSelector = normalizeMentionSelector(
1342
+ source.summaryBotUsername || source.summaryBotSelector || secondary.summaryBotUsername || secondary.summaryBotSelector,
1343
+ );
1342
1344
  const replyExpectation = normalizeReplyExpectation(
1343
- conversation.replyExpectation || humanIntent.replyExpectation,
1345
+ source.replyExpectation || secondary.replyExpectation,
1344
1346
  "",
1345
1347
  );
1346
1348
  const intentType = normalizeHumanIntentType(
1347
- conversation.intentType || humanIntent.intentType,
1349
+ source.intentType || secondary.intentType,
1348
1350
  "",
1349
1351
  );
1350
1352
  const allowedContractTypes = uniqueOrdered(
1351
- ensureArray(conversation.allowedContractTypes || humanIntent.allowedContractTypes)
1353
+ ensureArray(source.allowedContractTypes || secondary.allowedContractTypes)
1352
1354
  .map((item) => String(item || "").trim().toLowerCase())
1353
1355
  .filter(Boolean),
1354
1356
  );
1355
- const requiresActionableContract = conversation.requiresActionableContract === true
1356
- || conversation.require_actionable_contract === true
1357
- || humanIntent.requiresActionableContract === true
1358
- || humanIntent.require_actionable_contract === true
1359
- || replyExpectation === "actionable";
1357
+ const requiresActionableContract = source.requiresActionableContract === true
1358
+ || source.require_actionable_contract === true
1359
+ || (
1360
+ source.requiresActionableContract !== false
1361
+ && source.require_actionable_contract !== false
1362
+ && (secondary.requiresActionableContract === true || secondary.require_actionable_contract === true)
1363
+ );
1360
1364
  return {
1361
1365
  intentMode,
1362
1366
  allowBotToBot,
1363
- allowedResponderSelectors,
1364
- initialResponderSelectors,
1367
+ allowedResponderSelectors: normalizedAllowedResponderSelectors,
1368
+ initialResponderSelectors: normalizedInitialResponderSelectors,
1365
1369
  leadBotSelector,
1366
1370
  summaryBotSelector,
1367
1371
  replyExpectation,
@@ -1379,17 +1383,23 @@ function mergeDirectHumanResponseContract({
1379
1383
  }) {
1380
1384
  const base = safeObject(baseContract);
1381
1385
  const response = safeObject(responseContract);
1382
- const execution = safeObject(executionContract);
1383
- const assignmentTargets = uniqueOrdered(
1384
- ensureArray(execution.assignments)
1385
- .map((item) => normalizeMentionSelector(safeObject(item).targetBot || safeObject(item).target_bot))
1386
- .filter(Boolean),
1387
- );
1388
- const nextResponders = uniqueOrdered(
1389
- ensureArray(execution.nextResponders || execution.next_responders || execution.responders)
1390
- .map((item) => normalizeMentionSelector(item))
1391
- .filter(Boolean),
1392
- );
1386
+ void executionContract;
1387
+ void currentBotSelector;
1388
+ const hasExplicitArray = (obj, keys) => keys.some((key) => Object.prototype.hasOwnProperty.call(obj, key));
1389
+ const explicitAllowedResponderSelectors = hasExplicitArray(response, ["human_allowed_responders", "allowed_responders"])
1390
+ ? uniqueOrdered(
1391
+ ensureArray(response.human_allowed_responders || response.allowed_responders)
1392
+ .map((item) => normalizeMentionSelector(item))
1393
+ .filter(Boolean),
1394
+ )
1395
+ : null;
1396
+ const explicitInitialResponderSelectors = hasExplicitArray(response, ["human_initial_responders", "initial_responders"])
1397
+ ? uniqueOrdered(
1398
+ ensureArray(response.human_initial_responders || response.initial_responders)
1399
+ .map((item) => normalizeMentionSelector(item))
1400
+ .filter(Boolean),
1401
+ )
1402
+ : null;
1393
1403
  const intentMode = String(
1394
1404
  response.human_intent_mode
1395
1405
  || response.intent_mode
@@ -1413,21 +1423,18 @@ function mergeDirectHumanResponseContract({
1413
1423
  : response.allow_bot_to_bot === true || response.allowBotToBot === true
1414
1424
  ? true
1415
1425
  : base.allowBotToBot === true;
1416
- const allowedResponderSelectors = uniqueOrdered([
1417
- ...ensureArray(base.allowedResponderSelectors),
1418
- ...ensureArray(response.human_allowed_responders || response.allowed_responders)
1419
- .map((item) => normalizeMentionSelector(item))
1420
- .filter(Boolean),
1421
- ...assignmentTargets,
1422
- ...nextResponders,
1423
- normalizeMentionSelector(execution.summaryBot || execution.summary_bot),
1424
- ].filter(Boolean));
1425
- const initialResponderSelectors = uniqueOrdered([
1426
- ...ensureArray(base.initialResponderSelectors),
1427
- ...ensureArray(response.human_initial_responders || response.initial_responders)
1428
- .map((item) => normalizeMentionSelector(item))
1429
- .filter(Boolean),
1430
- ].filter(Boolean));
1426
+ const allowedResponderSelectors = explicitAllowedResponderSelectors
1427
+ ?? uniqueOrdered(
1428
+ ensureArray(base.allowedResponderSelectors)
1429
+ .map((item) => normalizeMentionSelector(item))
1430
+ .filter(Boolean),
1431
+ );
1432
+ const initialResponderSelectors = explicitInitialResponderSelectors
1433
+ ?? uniqueOrdered(
1434
+ ensureArray(base.initialResponderSelectors)
1435
+ .map((item) => normalizeMentionSelector(item))
1436
+ .filter(Boolean),
1437
+ );
1431
1438
  const leadBotSelector = normalizeMentionSelector(
1432
1439
  response.human_lead_bot
1433
1440
  || response.lead_bot
@@ -1437,8 +1444,6 @@ function mergeDirectHumanResponseContract({
1437
1444
  const summaryBotSelector = normalizeMentionSelector(
1438
1445
  response.human_summary_bot
1439
1446
  || response.summary_bot
1440
- || execution.summaryBot
1441
- || execution.summary_bot
1442
1447
  || base.summaryBotSelector
1443
1448
  || "",
1444
1449
  );
@@ -1447,7 +1452,7 @@ function mergeDirectHumanResponseContract({
1447
1452
  ? false
1448
1453
  : explicitRequiresActionableContract === true
1449
1454
  ? true
1450
- : base.requiresActionableContract === true || replyExpectation === "actionable";
1455
+ : base.requiresActionableContract === true;
1451
1456
  const explicitAllowedContractTypes = uniqueOrdered(
1452
1457
  ensureArray(response.allowed_contract_types)
1453
1458
  .map((item) => String(item || "").trim().toLowerCase())
@@ -2588,6 +2593,11 @@ async function maybeExecuteDynamicRolePlan({
2588
2593
  || safeObject(safeObject(humanIntentContext).humanIntent).intentMode,
2589
2594
  );
2590
2595
  const actionableConversationRequiresContract = safeObject(directHumanResponseContract).requiresActionableContract === true;
2596
+ const actionableReplyExpectation = normalizeReplyExpectation(
2597
+ safeObject(directHumanResponseContract).replyExpectation
2598
+ || safeObject(safeObject(humanIntentContext).humanIntent).replyExpectation,
2599
+ "",
2600
+ ) === "actionable";
2591
2601
  const plannerContextComments = ensureArray(contextWindow).length
2592
2602
  ? ensureArray(contextWindow)
2593
2603
  : buildRunnerContextWindow(
@@ -2606,14 +2616,10 @@ async function maybeExecuteDynamicRolePlan({
2606
2616
  ) {
2607
2617
  return null;
2608
2618
  }
2609
- const executionIntentRequested = [
2610
- "general_execution",
2611
- "ctxpack_mutation",
2612
- "workitem_mutation",
2613
- ].includes(humanIntentType);
2614
2619
  const shouldPlanExecution = assignmentTasks.length > 0 || (
2615
2620
  triggerDecision.requiresDirectReply === true
2616
- && executionIntentRequested
2621
+ && humanIntentMode === "single_bot"
2622
+ && actionableReplyExpectation
2617
2623
  );
2618
2624
  if (!shouldPlanExecution) {
2619
2625
  return null;
@@ -95,15 +95,8 @@ function buildRunnerTaskName(humanIntentType, humanIntentContract = null) {
95
95
  const normalizedIntentType = String(humanIntentType || "").trim().toLowerCase();
96
96
  const contract = safeObject(humanIntentContract);
97
97
  const executionContractType = String(contract.executionContractType || contract.execution_contract_type || "").trim().toLowerCase();
98
- if (normalizedIntentType === "status_query") return "answer_project_status_query";
99
- if (normalizedIntentType === "workspace_query") return "answer_project_workspace_query";
100
- if (normalizedIntentType === "bot_role_query") return "answer_project_bot_role_query";
101
- if (normalizedIntentType === "artifact_location_query") return "answer_project_artifact_location_query";
102
- if (normalizedIntentType === "small_talk") return "reply_to_project_chat_greeting";
103
- if (executionContractType) {
104
- return "reply_to_project_actionable_message";
105
- }
106
- return "reply_to_project_chat_message";
98
+ const legacyHint = executionContractType || normalizedIntentType || "generic";
99
+ return `reply_with_agent_context:${legacyHint}`;
107
100
  }
108
101
 
109
102
  export function evaluateTelegramRunnerTrigger(record, route, bot) {
@@ -184,8 +177,14 @@ export function buildRunnerInputPayload({
184
177
  const executionContractType = String(
185
178
  directHumanIntent.executionContractType || directHumanIntent.execution_contract_type || "",
186
179
  ).trim().toLowerCase();
180
+ const taskMetadata = buildRunnerTaskName(directHumanIntent.intentType, directHumanIntent);
187
181
  return {
188
- task: buildRunnerTaskName(directHumanIntent.intentType, directHumanIntent),
182
+ task: taskMetadata,
183
+ task_metadata: {
184
+ legacy_task_hint: taskMetadata,
185
+ intent_type: String(directHumanIntent.intentType || "").trim(),
186
+ execution_contract_type: executionContractType,
187
+ },
189
188
  project_id: String(route?.projectID || "").trim(),
190
189
  provider: String(route?.provider || "").trim(),
191
190
  role: String(bot?.role || route?.role || "").trim(),
@@ -4565,20 +4565,20 @@ export async function runSelftestRunnerScenarios(push, deps) {
4565
4565
  },
4566
4566
  });
4567
4567
  push(
4568
- "direct_human_public_delegate_reply_is_upgraded_to_actionable_contract",
4568
+ "direct_human_public_delegate_reply_records_missing_contract_without_fabrication",
4569
4569
  processed.kind === "replied"
4570
4570
  && aiCalls === 1
4571
4571
  && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4572
4572
  && String(deliveredConversation[0]?.leadBotUsername || "") === "ryoai_bot"
4573
4573
  && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4574
4574
  && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4575
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation"
4576
- && String(processed.result?.response_contract_validation_status || "") === "valid"
4575
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4576
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract"
4577
4577
  && ensureArray(processed.result?.response_contract_validation_targets).includes("ryoai3_bot"),
4578
4578
  `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")} targets=${JSON.stringify(processed.result?.response_contract_validation_targets || [])}`,
4579
4579
  );
4580
4580
  } catch (err) {
4581
- push("direct_human_public_delegate_reply_is_upgraded_to_actionable_contract", false, String(err?.message || err));
4581
+ push("direct_human_public_delegate_reply_records_missing_contract_without_fabrication", false, String(err?.message || err));
4582
4582
  }
4583
4583
 
4584
4584
  try {
@@ -4718,20 +4718,20 @@ export async function runSelftestRunnerScenarios(push, deps) {
4718
4718
  },
4719
4719
  });
4720
4720
  push(
4721
- "direct_human_public_delegate_repairs_lead_bot_selector_for_archive_contract",
4721
+ "direct_human_public_delegate_preserves_lead_context_while_recording_missing_contract",
4722
4722
  processed.kind === "replied"
4723
4723
  && aiCalls === 1
4724
4724
  && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4725
4725
  && String(deliveredConversation[0]?.leadBotUsername || "") === "ryoai_bot"
4726
4726
  && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4727
4727
  && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4728
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation"
4729
- && String(processed.result?.response_contract_validation_status || "") === "valid",
4728
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4729
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract",
4730
4730
  `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} lead=${String(deliveredConversation[0]?.leadBotUsername || "(none)")} mode=${String(deliveredConversation[0]?.mode || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")}`,
4731
4731
  );
4732
- } catch (err) {
4733
- push("direct_human_public_delegate_repairs_lead_bot_selector_for_archive_contract", false, String(err?.message || err));
4734
- }
4732
+ } catch (err) {
4733
+ push("direct_human_public_delegate_preserves_lead_context_while_recording_missing_contract", false, String(err?.message || err));
4734
+ }
4735
4735
 
4736
4736
  try {
4737
4737
  let aiCalls = 0;
@@ -4865,19 +4865,19 @@ export async function runSelftestRunnerScenarios(push, deps) {
4865
4865
  },
4866
4866
  });
4867
4867
  push(
4868
- "direct_human_public_delegate_fallback_uses_response_allowed_responders",
4868
+ "direct_human_public_delegate_records_allowed_responders_without_fabricated_contract",
4869
4869
  processed.kind === "replied"
4870
4870
  && aiCalls === 1
4871
4871
  && String(deliveredConversation[0]?.mode || "") === "public_multi_bot"
4872
4872
  && Array.isArray(deliveredConversation[0]?.allowedResponderSelectors)
4873
4873
  && deliveredConversation[0].allowedResponderSelectors.includes("ryoai3_bot")
4874
- && String(deliveredConversation[0]?.executionContract?.type || "") === "delegation"
4875
- && String(processed.result?.response_contract_validation_status || "") === "valid",
4874
+ && !String(deliveredConversation[0]?.executionContract?.type || "").trim()
4875
+ && String(processed.result?.response_contract_validation_status || "") === "missing_required_contract",
4876
4876
  `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} mode=${String(deliveredConversation[0]?.mode || "(none)")} allowed=${JSON.stringify(deliveredConversation[0]?.allowedResponderSelectors || [])} contract=${String(deliveredConversation[0]?.executionContract?.type || "(none)")} validation=${String(processed.result?.response_contract_validation_status || "(none)")}`,
4877
4877
  );
4878
- } catch (err) {
4879
- push("direct_human_public_delegate_fallback_uses_response_allowed_responders", false, String(err?.message || err));
4880
- }
4878
+ } catch (err) {
4879
+ push("direct_human_public_delegate_records_allowed_responders_without_fabricated_contract", false, String(err?.message || err));
4880
+ }
4881
4881
 
4882
4882
  try {
4883
4883
  let aiCalls = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.215",
3
+ "version": "0.2.217",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [