metheus-governance-mcp-cli 0.2.269 → 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 });
@@ -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,
@@ -18701,6 +18704,48 @@ export async function runSelftestRunnerScenarios(push, deps) {
18701
18704
  push("runner_selected_record_terminal_outcome_stays_within_module_4_boundary", false, String(err?.message || err));
18702
18705
  }
18703
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
+
18704
18749
  try {
18705
18750
  const prepared = await prepareRunnerSelectedRecordContractContext({
18706
18751
  selectedRecord: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metheus-governance-mcp-cli",
3
- "version": "0.2.269",
3
+ "version": "0.2.270",
4
4
  "description": "Metheus Governance MCP CLI (setup + stdio proxy)",
5
5
  "type": "module",
6
6
  "files": [