metheus-governance-mcp-cli 0.2.268 → 0.2.270

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.
@@ -212,6 +212,67 @@ function readOutputFile(filePath) {
212
212
  return fs.readFileSync(filePath, "utf8");
213
213
  }
214
214
 
215
+ export function looksLikeCodexCliSessionTranscript(rawText = "") {
216
+ const text = String(rawText || "").trim();
217
+ if (!text) {
218
+ return false;
219
+ }
220
+ return /OpenAI Codex v|session id:|^workdir:|^model:|^provider:|^approval:|^sandbox:|^reasoning effort:|^--------|^user$|^codex$|mcp:.*\b(starting|ready)\b/i.test(text);
221
+ }
222
+
223
+ function summarizeCodexCliFailure({
224
+ status = 0,
225
+ stdoutText = "",
226
+ stderrText = "",
227
+ spawnError = null,
228
+ }) {
229
+ const genericMessage = status
230
+ ? `Codex CLI exited before returning a final reply (status ${status})`
231
+ : "Codex CLI exited before returning a final reply";
232
+ if (spawnError) {
233
+ const spawnMessage = String(spawnError?.message || spawnError || "").trim();
234
+ return spawnMessage
235
+ ? `${genericMessage}: ${spawnMessage}`
236
+ : genericMessage;
237
+ }
238
+ const candidateLines = `${String(stderrText || "")}\n${String(stdoutText || "")}`
239
+ .split(/\r?\n/)
240
+ .map((line) => String(line || "").trim())
241
+ .filter(Boolean)
242
+ .filter((line) => !looksLikeCodexCliSessionTranscript(line))
243
+ .filter((line) => /(error|failed|timeout|timed out|denied|missing|unavailable|not found|capacity)/i.test(line))
244
+ .slice(0, 2);
245
+ return candidateLines.length
246
+ ? `${genericMessage}: ${candidateLines.join(" | ")}`
247
+ : genericMessage;
248
+ }
249
+
250
+ export function resolveCodexRawTextProcessResult({
251
+ outputText = "",
252
+ stdoutText = "",
253
+ stderrText = "",
254
+ status = 0,
255
+ spawnError = null,
256
+ }) {
257
+ const normalizedOutputText = String(outputText || "").trim();
258
+ if (normalizedOutputText && !looksLikeCodexCliSessionTranscript(normalizedOutputText)) {
259
+ return normalizedOutputText;
260
+ }
261
+ const normalizedStdoutText = String(stdoutText || "").trim();
262
+ if (normalizedStdoutText && !looksLikeCodexCliSessionTranscript(normalizedStdoutText)) {
263
+ return normalizedStdoutText;
264
+ }
265
+ if (spawnError || status !== 0) {
266
+ throw new Error(summarizeCodexCliFailure({
267
+ status,
268
+ stdoutText: normalizedStdoutText,
269
+ stderrText,
270
+ spawnError,
271
+ }));
272
+ }
273
+ throw new Error("Codex CLI did not return a usable final reply");
274
+ }
275
+
215
276
  function tryParseEmbeddedJsonObject(text) {
216
277
  const raw = String(text || "").trim();
217
278
  if (!raw) return null;
@@ -686,13 +747,13 @@ function runCodexRawText({ promptText, workspaceDir, model, permissionMode, reas
686
747
  maxBuffer: 8 * 1024 * 1024,
687
748
  },
688
749
  );
689
- if (result.error) {
690
- throw new Error(String(result.error?.message || result.error));
691
- }
692
- if (result.status !== 0) {
693
- throw new Error(String(result.stderr || result.stdout || `codex exited with status ${result.status}`));
694
- }
695
- return readOutputFile(outputPath) || String(result.stdout || "");
750
+ return resolveCodexRawTextProcessResult({
751
+ outputText: readOutputFile(outputPath),
752
+ stdoutText: String(result.stdout || ""),
753
+ stderrText: String(result.stderr || ""),
754
+ status: Number.isInteger(result.status) ? result.status : 0,
755
+ spawnError: result.error || null,
756
+ });
696
757
  } finally {
697
758
  if (fs.existsSync(outputPath)) {
698
759
  fs.rmSync(outputPath, { force: true });
@@ -1876,6 +1937,9 @@ export function buildLocalBotPrompt(payload, { terse = true } = {}) {
1876
1937
  `- Trigger hint reason: ${String(responseContract.candidate_reason || "-").trim() || "-"}`,
1877
1938
  `- Mentioned bot usernames: ${ensureArray(responseContract.candidate_bot_usernames).length ? ensureArray(responseContract.candidate_bot_usernames).map((item) => `@${String(item || "").trim().replace(/^@+/, "")}`).join(", ") : "-"}`,
1878
1939
  `- Reply target bot username: ${String(responseContract.reply_to_bot_username || "").trim() ? `@${String(responseContract.reply_to_bot_username || "").trim().replace(/^@+/, "")}` : "-"}`,
1940
+ String(responseContract.reply_to_bot_username || "").trim()
1941
+ ? `- If you answer directly to that target bot, start the visible reply with @${String(responseContract.reply_to_bot_username || "").trim().replace(/^@+/, "")}.`
1942
+ : "",
1879
1943
  "",
1880
1944
  "Project background (context only):",
1881
1945
  `- Project ID: ${projectID || "-"}`,
@@ -17,6 +17,40 @@ function intFromRawAllowZero(raw, fallback = 0) {
17
17
  return Number.isFinite(parsed) ? parsed : fallback;
18
18
  }
19
19
 
20
+ function escapeRegexText(value) {
21
+ return String(value || "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22
+ }
23
+
24
+ function detectDirectedManagedReplyTarget({
25
+ text,
26
+ currentBotSelector = "",
27
+ managedMentions = [],
28
+ }) {
29
+ const normalizedText = String(text || "").trim();
30
+ const currentSelector = String(currentBotSelector || "").trim().toLowerCase();
31
+ if (!normalizedText || !currentSelector) {
32
+ return "";
33
+ }
34
+ const instructionPattern = /(?:\b(?:say|tell|greet|reply|answer|introduce|mention)\b|인사(?:해|하)|말(?:해|하)|얘기(?:해|하)|전달(?:해|하)|전해|알려|소개(?:해|하)|답(?:해|하)|응답(?:해|하)|말씀(?:해|하))/i;
35
+ if (!instructionPattern.test(normalizedText)) {
36
+ return "";
37
+ }
38
+ const candidates = ensureArray(managedMentions)
39
+ .map((item) => String(item || "").trim().toLowerCase())
40
+ .filter((item) => item && item !== currentSelector);
41
+ for (const selector of candidates) {
42
+ const escapedSelector = escapeRegexText(String(selector || "").replace(/^@+/, ""));
43
+ const targetPattern = new RegExp(
44
+ `(?:@${escapedSelector}\\s*(?:에게|한테|께|보고)?|(?:to|for)\\s+@${escapedSelector}\\b)`,
45
+ "i",
46
+ );
47
+ if (targetPattern.test(normalizedText)) {
48
+ return selector;
49
+ }
50
+ }
51
+ return "";
52
+ }
53
+
20
54
  export async function resolveHumanIntentContext({
21
55
  selectedRecord,
22
56
  normalizedRoute,
@@ -84,6 +118,17 @@ export async function resolveHumanIntentContext({
84
118
  runnerHumanIntentPromises.set(cacheKey, promise);
85
119
  }
86
120
  let humanIntent = await runnerHumanIntentPromises.get(cacheKey);
121
+ const directedReplyTargetSelector = detectDirectedManagedReplyTarget({
122
+ text: parsed.body,
123
+ currentBotSelector,
124
+ managedMentions,
125
+ });
126
+ if (directedReplyTargetSelector) {
127
+ humanIntent = {
128
+ ...safeObject(humanIntent),
129
+ replyTargetBotSelector: directedReplyTargetSelector,
130
+ };
131
+ }
87
132
  if (!isCompleteHumanIntentContract(humanIntent)) {
88
133
  return {
89
134
  currentBotSelector,
@@ -152,6 +197,12 @@ export function buildDirectHumanResponseContract({
152
197
  );
153
198
  const requiresActionableContract = source.requiresActionableContract === true
154
199
  || source.require_actionable_contract === true;
200
+ const replyTargetBotSelector = normalizeMentionSelector(
201
+ source.replyTargetBotSelector
202
+ || source.reply_target_bot
203
+ || source.reply_to_bot_username
204
+ || "",
205
+ );
155
206
  return {
156
207
  intentMode,
157
208
  allowBotToBot,
@@ -163,6 +214,7 @@ export function buildDirectHumanResponseContract({
163
214
  intentType,
164
215
  requiresActionableContract,
165
216
  allowedContractTypes,
217
+ replyTargetBotSelector,
166
218
  };
167
219
  }
168
220
 
@@ -213,6 +265,7 @@ export function mergeDirectHumanResponseContract({
213
265
  const explicitAllowBotToBot = readExplicit(["allow_bot_to_bot", "allowBotToBot"]);
214
266
  const explicitLeadBot = readExplicit(["human_lead_bot"]);
215
267
  const explicitSummaryBot = readExplicit(["human_summary_bot"]);
268
+ const explicitReplyTargetBot = readExplicit(["human_reply_target_bot", "reply_to_bot_username"]);
216
269
  const intentMode = String(
217
270
  explicitIntentMode
218
271
  || base.intentMode
@@ -255,6 +308,11 @@ export function mergeDirectHumanResponseContract({
255
308
  || base.summaryBotSelector
256
309
  || "",
257
310
  );
311
+ const replyTargetBotSelector = normalizeMentionSelector(
312
+ explicitReplyTargetBot
313
+ || base.replyTargetBotSelector
314
+ || "",
315
+ );
258
316
  const requiresActionableContract = base.requiresActionableContract === true;
259
317
  const allowedContractTypes = ensureArray(base.allowedContractTypes)
260
318
  .map((item) => String(item || "").trim().toLowerCase())
@@ -271,6 +329,7 @@ export function mergeDirectHumanResponseContract({
271
329
  intentType,
272
330
  requiresActionableContract,
273
331
  allowedContractTypes,
332
+ replyTargetBotSelector,
274
333
  };
275
334
  }
276
335
 
@@ -26,6 +26,7 @@ export async function prepareRunnerSelectedRecordDeliveryContext({
26
26
  bot,
27
27
  selectedRecord,
28
28
  currentBotSelector = "",
29
+ replyTargetBotSelector = "",
29
30
  executionContract = null,
30
31
  effectiveTriggerDecision,
31
32
  effectiveConversationContext = null,
@@ -55,13 +56,28 @@ export async function prepareRunnerSelectedRecordDeliveryContext({
55
56
  }
56
57
 
57
58
  const normalizedExecutionContractType = String(executionContract?.type || "").trim().toLowerCase();
58
- const sanitizedReplyText = sanitizeForcedDirectReplyText({
59
+ const normalizedReplyTargetBotSelector = normalizeMentionSelector(replyTargetBotSelector);
60
+ let sanitizedReplyText = sanitizeForcedDirectReplyText({
59
61
  replyText: aiResult?.reply,
60
62
  bot,
61
63
  selectedRecord,
62
64
  triggerDecision: effectiveTriggerDecision,
63
65
  conversationContext: effectiveConversationContext,
64
66
  });
67
+ if (
68
+ sanitizedReplyText
69
+ && normalizedReplyTargetBotSelector
70
+ && normalizedReplyTargetBotSelector !== currentBotSelector
71
+ ) {
72
+ const visibleReplyTargets = extractManagedPeerMentionSelectors(
73
+ sanitizedReplyText,
74
+ directHumanPeerMap,
75
+ currentBotSelector,
76
+ );
77
+ if (!visibleReplyTargets.includes(normalizedReplyTargetBotSelector)) {
78
+ sanitizedReplyText = `@${normalizedReplyTargetBotSelector} ${String(sanitizedReplyText || "").trim()}`.trim();
79
+ }
80
+ }
65
81
  const attemptedDeliveryEnvelope = buildTelegramBotReplyEnvelope({
66
82
  sourceEnvelope: sourceMessageEnvelope,
67
83
  messageThreadID: replyMessageThreadID,
@@ -258,6 +258,12 @@ export function buildRunnerInputPayload({
258
258
  .map((value) => normalizeMentionSelector(value))
259
259
  .filter(Boolean),
260
260
  );
261
+ const normalizedReplyTargetBot = normalizeMentionSelector(
262
+ directHumanIntent.replyTargetBotSelector
263
+ || directHumanIntent.reply_target_bot
264
+ || directHumanIntent.reply_to_bot_username
265
+ || parsed.replyToUsername,
266
+ );
261
267
  const requiredDelegationTargets = uniqueOrdered(
262
268
  String(directHumanIntent.intentMode || directHumanIntent.intent_mode || "").trim() === "delegated_single_lead"
263
269
  && currentBotSelector
@@ -353,11 +359,12 @@ export function buildRunnerInputPayload({
353
359
  self_bot_username: String(bot?.username || "").trim(),
354
360
  mentioned_usernames: ensureArray(parsed.mentionUsernames).map((value) => String(value || "").trim()).filter(Boolean),
355
361
  candidate_bot_usernames: candidateBotUsernames,
356
- reply_to_bot_username: String(parsed.replyToUsername || "").trim(),
362
+ reply_to_bot_username: normalizedReplyTargetBot,
357
363
  human_intent_mode: String(directHumanIntent.intentMode || "").trim(),
358
364
  human_intent_type: String(directHumanIntent.intentType || "").trim(),
359
365
  human_lead_bot: String(directHumanIntent.leadBotSelector || "").trim(),
360
366
  human_summary_bot: String(directHumanIntent.summaryBotSelector || "").trim(),
367
+ human_reply_target_bot: normalizedReplyTargetBot,
361
368
  human_allowed_responders: ensureArray(directHumanIntent.allowedResponderSelectors),
362
369
  human_reply_expectation: String(directHumanIntent.replyExpectation || "").trim(),
363
370
  require_actionable_contract: directHumanIntent.requiresActionableContract === true,
@@ -378,6 +385,7 @@ export function buildRunnerInputPayload({
378
385
  body: String(parsed.body || "").trim(),
379
386
  message_id: Number.parseInt(String(parsed.messageID ?? 0), 10) || 0,
380
387
  reply_to_message_id: Number.parseInt(String(parsed.replyToMessageID ?? 0), 10) || 0,
388
+ reply_to_bot_username: normalizedReplyTargetBot,
381
389
  },
382
390
  conversation_contract: {
383
391
  conversation_id: String(directHumanIntent.conversationID || directHumanIntent.conversation_id || parsed.conversationID || "").trim(),
@@ -388,6 +396,7 @@ export function buildRunnerInputPayload({
388
396
  participants: ensureArray(directHumanIntent.participantSelectors || directHumanIntent.participants),
389
397
  initial_responders: ensureArray(directHumanIntent.initialResponderSelectors || directHumanIntent.initial_responders),
390
398
  allowed_responders: ensureArray(directHumanIntent.allowedResponderSelectors || directHumanIntent.allowed_responders),
399
+ reply_target_bot: normalizedReplyTargetBot,
391
400
  reply_expectation: String(directHumanIntent.replyExpectation || directHumanIntent.reply_expectation || "").trim(),
392
401
  execution_contract_type: executionContractType,
393
402
  },
@@ -3477,6 +3486,7 @@ export async function processRunnerSelectedRecord({
3477
3486
  bot,
3478
3487
  selectedRecord,
3479
3488
  currentBotSelector,
3489
+ replyTargetBotSelector: directHumanResponseContract?.replyTargetBotSelector,
3480
3490
  executionContract,
3481
3491
  effectiveTriggerDecision,
3482
3492
  effectiveConversationContext,
@@ -85,6 +85,9 @@ import {
85
85
  import {
86
86
  finalizeRunnerRequestRootReferenceRecorderState,
87
87
  } from "./runner-recorder-request-root-reference-finalization-handoff.mjs";
88
+ import {
89
+ resolveCodexRawTextProcessResult,
90
+ } from "./local-ai-adapters.mjs";
88
91
  import {
89
92
  buildRunnerInheritedRootReferenceRecorderResult,
90
93
  buildRunnerRootThreadRecorderFailure,
@@ -6238,6 +6241,149 @@ export async function runSelftestRunnerScenarios(push, deps) {
6238
6241
  push("single_bot_conversational_greeting_request_skips_planner_and_worker", false, String(err?.message || err));
6239
6242
  }
6240
6243
 
6244
+ try {
6245
+ let aiCalls = 0;
6246
+ let plannerCalls = 0;
6247
+ let deliveryCalls = 0;
6248
+ let deliveredText = "";
6249
+ const processed = await processRunnerSelectedRecord({
6250
+ routeKey: "single-bot-conversation-greeting-target-prefix-key",
6251
+ normalizedRoute: normalizeRunnerRoute({
6252
+ name: "telegram-monitor-single-bot-conversation-greeting-target-prefix",
6253
+ project_id: selftestProjectID,
6254
+ provider: "telegram",
6255
+ role: "monitor",
6256
+ role_profile: "monitor",
6257
+ destination_id: "dest-1",
6258
+ destination_label: "Main Room",
6259
+ server_bot_name: "RyoAI_bot",
6260
+ server_bot_id: "bot-lead-1",
6261
+ trigger_policy: {
6262
+ mentions_only: true,
6263
+ direct_messages: true,
6264
+ reply_to_bot_messages: true,
6265
+ },
6266
+ archive_policy: {
6267
+ mirror_replies: true,
6268
+ dedupe_inbound: true,
6269
+ dedupe_outbound: true,
6270
+ skip_bot_messages: true,
6271
+ },
6272
+ dry_run_delivery: true,
6273
+ }),
6274
+ selectedRecord: {
6275
+ id: "comment-single-bot-conversation-greeting-target-prefix",
6276
+ createdAt: "2026-03-31T08:38:56.000Z",
6277
+ parsedArchive: {
6278
+ kind: "telegram_message",
6279
+ chatID: "-100123",
6280
+ chatType: "supergroup",
6281
+ senderIsBot: false,
6282
+ body: "@RyoAI_bot 당신이 @SangHoon01_bot 에게 인사해보세요.",
6283
+ mentionUsernames: ["RyoAI_bot", "SangHoon01_bot"],
6284
+ messageID: 1058,
6285
+ },
6286
+ },
6287
+ pendingOrdered: [],
6288
+ bot: {
6289
+ id: "bot-lead-1",
6290
+ name: "RyoAI_bot",
6291
+ username: "RyoAI_bot",
6292
+ role: "monitor",
6293
+ provider: "telegram",
6294
+ },
6295
+ destination: {
6296
+ id: "dest-1",
6297
+ label: "Main Room",
6298
+ provider: "telegram",
6299
+ chatID: "-100123",
6300
+ },
6301
+ archiveThread: {
6302
+ threadID: "thread-1",
6303
+ workItemID: "work-item-1",
6304
+ },
6305
+ executionPlan: {
6306
+ mode: "role_profile",
6307
+ roleProfileName: "monitor",
6308
+ roleProfile: {
6309
+ client: "sample",
6310
+ model: "",
6311
+ permissionMode: "read_only",
6312
+ reasoningEffort: "low",
6313
+ },
6314
+ workspaceDir: path.join(os.tmpdir(), "metheus-runner-selftest-single-bot-conversation-greeting-target-prefix"),
6315
+ workspaceSource: "selftest",
6316
+ usedCommandFallback: false,
6317
+ },
6318
+ runtime: {
6319
+ baseURL: "https://example.test",
6320
+ token: "selftest-token",
6321
+ timeoutSeconds: 30,
6322
+ actor: { user_id: "user-1" },
6323
+ },
6324
+ deps: {
6325
+ saveRunnerRouteState: () => {},
6326
+ startRunnerTypingHeartbeat: () => ({ async stop() {} }),
6327
+ runRunnerAIExecution: async () => {
6328
+ aiCalls += 1;
6329
+ return {
6330
+ skip: false,
6331
+ reply: "안녕하세요.",
6332
+ replyToMessageID: 0,
6333
+ };
6334
+ },
6335
+ performLocalBotDelivery: async ({ text }) => {
6336
+ deliveryCalls += 1;
6337
+ deliveredText = String(text || "").trim();
6338
+ return {
6339
+ delivery: { dryRun: true, body: {} },
6340
+ archive: {},
6341
+ };
6342
+ },
6343
+ serializeRunnerTriggerPolicy: (value) => value,
6344
+ serializeRunnerArchivePolicy: (value) => value,
6345
+ buildRunnerExecutionDeps: () => ({
6346
+ analyzeHumanConversationIntentWithAI: async () => ({
6347
+ mode: "single_bot",
6348
+ lead_bot: "ryoai_bot",
6349
+ participants: ["ryoai_bot"],
6350
+ initial_responders: ["ryoai_bot"],
6351
+ allowed_responders: ["ryoai_bot"],
6352
+ summary_bot: "",
6353
+ allow_bot_to_bot: false,
6354
+ reply_expectation: "informational",
6355
+ intent_type: "small_talk",
6356
+ }),
6357
+ planRoleExecutionWithAI: async () => {
6358
+ plannerCalls += 1;
6359
+ return {
6360
+ requiresExecution: true,
6361
+ summaryRole: "worker",
6362
+ steps: [{ role: "worker", goal: "unexpected", artifactsRequired: true }],
6363
+ };
6364
+ },
6365
+ }),
6366
+ buildRunnerDeliveryDeps: () => ({}),
6367
+ buildRunnerRuntimeDeps: () => ({}),
6368
+ resolveConversationPeerBots: () => [
6369
+ { id: "bot-lead-1", name: "RyoAI_bot" },
6370
+ { id: "bot-peer-1", name: "SangHoon01_bot" },
6371
+ ],
6372
+ },
6373
+ });
6374
+ push(
6375
+ "single_bot_direct_reply_target_prefixes_visible_target_when_ai_omits_mention",
6376
+ processed.kind === "replied"
6377
+ && aiCalls === 1
6378
+ && plannerCalls === 0
6379
+ && deliveryCalls === 1
6380
+ && deliveredText === "@sanghoon01_bot 안녕하세요.",
6381
+ `kind=${String(processed.kind || "(none)")} ai_calls=${aiCalls} planner_calls=${plannerCalls} delivery_calls=${deliveryCalls} delivered=${String(deliveredText || "(none)")}`,
6382
+ );
6383
+ } catch (err) {
6384
+ push("single_bot_direct_reply_target_prefixes_visible_target_when_ai_omits_mention", false, String(err?.message || err));
6385
+ }
6386
+
6241
6387
  try {
6242
6388
  let aiCalls = 0;
6243
6389
  let deliveryCalls = 0;
@@ -18558,6 +18704,48 @@ export async function runSelftestRunnerScenarios(push, deps) {
18558
18704
  push("runner_selected_record_terminal_outcome_stays_within_module_4_boundary", false, String(err?.message || err));
18559
18705
  }
18560
18706
 
18707
+ try {
18708
+ const replyText = resolveCodexRawTextProcessResult({
18709
+ outputText: "{\"reply\":\"하이\"}",
18710
+ stdoutText: "",
18711
+ stderrText: "OpenAI Codex v0.114.0\nsession id: test-session\nmcp: metheus ready",
18712
+ status: 1,
18713
+ spawnError: null,
18714
+ });
18715
+ push(
18716
+ "codex_nonzero_exit_uses_final_output_file_when_available",
18717
+ String(replyText || "").trim() === "{\"reply\":\"하이\"}",
18718
+ `reply=${String(replyText || "(none)")}`,
18719
+ );
18720
+ } catch (err) {
18721
+ push("codex_nonzero_exit_uses_final_output_file_when_available", false, String(err?.message || err));
18722
+ }
18723
+
18724
+ try {
18725
+ let errorMessage = "";
18726
+ try {
18727
+ resolveCodexRawTextProcessResult({
18728
+ outputText: "",
18729
+ stdoutText: "",
18730
+ stderrText: "OpenAI Codex v0.114.0\nworkdir: C:\\LUSH KOREA CLI\nsession id: test-session\nmcp: metheus starting\nmcp: metheus ready",
18731
+ status: 1,
18732
+ spawnError: null,
18733
+ });
18734
+ } catch (err) {
18735
+ errorMessage = String(err?.message || err);
18736
+ }
18737
+ push(
18738
+ "codex_failure_summary_does_not_leak_session_transcript",
18739
+ /Codex CLI exited before returning a final reply/i.test(errorMessage)
18740
+ && !/OpenAI Codex v/i.test(errorMessage)
18741
+ && !/session id:/i.test(errorMessage)
18742
+ && !/mcp:/i.test(errorMessage),
18743
+ errorMessage || "(no error message)",
18744
+ );
18745
+ } catch (err) {
18746
+ push("codex_failure_summary_does_not_leak_session_transcript", false, String(err?.message || err));
18747
+ }
18748
+
18561
18749
  try {
18562
18750
  const prepared = await prepareRunnerSelectedRecordContractContext({
18563
18751
  selectedRecord: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.268",
3
+ "version": "0.2.270",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [