@brutalist/mcp 1.11.2 → 1.13.0

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.
@@ -171,11 +171,75 @@ export class GeminiAdapter {
171
171
  * Parses a single JSON object and returns the `response` field.
172
172
  */
173
173
  decodeOutput(rawOutput, args, log) {
174
- // Only decode if Gemini was run with --output-format json
174
+ // Legacy text-only API.
175
+ const result = this.decode(rawOutput, '', args, log);
176
+ return result.kind === 'ok' ? result.text : '';
177
+ }
178
+ decode(stdout, stderr, args, log) {
179
+ // Only structured-decode if Gemini was run with --output-format json
175
180
  if (!(args.includes('--output-format') && args.includes('json'))) {
176
- return rawOutput;
181
+ return { kind: 'ok', text: stdout };
182
+ }
183
+ return this.decodeJson(stdout, stderr, log ?? rootLogger);
184
+ }
185
+ /**
186
+ * Structured decode of Gemini --output-format json output.
187
+ *
188
+ * Gemini exits 0 on quota and bakes the refusal text into the
189
+ * `response` field itself — there is no envelope-level signal in the
190
+ * stdout JSON to distinguish a real answer from a refusal. So:
191
+ * - parse stdout; non-empty `response` → ok (best-effort; we can't
192
+ * tell the difference here without prose matching, which we
193
+ * explicitly refuse to do)
194
+ * - empty/missing `response`, or unparseable stdout, AND stderr
195
+ * matches anchored Google API quota markers → refused (quota)
196
+ * - empty + no anchored markers → error (empty/malformed)
197
+ *
198
+ * Per the user direction for Phase 2: anchored stderr markers only.
199
+ * No fallback to loose patterns. The honest residual is that a
200
+ * gemini quota that prints ONLY to `response` (no stderr signal)
201
+ * passes through as a normal response — surfaced to the caller as
202
+ * agent output. That is documented and accepted.
203
+ */
204
+ decodeJson(jsonOutput, stderr, log) {
205
+ if (!jsonOutput || !jsonOutput.trim()) {
206
+ // Stdout empty — check stderr for anchored quota markers before
207
+ // declaring this an empty error.
208
+ if (classifyGeminiStderrReason(stderr) === 'quota') {
209
+ return { kind: 'refused', reason: 'quota' };
210
+ }
211
+ log.debug('extractGeminiResponse: empty input');
212
+ return { kind: 'error', reason: 'empty' };
213
+ }
214
+ try {
215
+ const parsed = JSON.parse(jsonOutput);
216
+ if (parsed.response && typeof parsed.response === 'string') {
217
+ log.info(`✅ extractGeminiResponse: extracted response with ${parsed.response.length} chars`);
218
+ return { kind: 'ok', text: parsed.response };
219
+ }
220
+ log.warn('extractGeminiResponse: no response field in JSON output', {
221
+ keys: Object.keys(parsed)
222
+ });
223
+ // No response field — check anchored stderr markers before
224
+ // treating as error.
225
+ if (classifyGeminiStderrReason(stderr) === 'quota') {
226
+ return { kind: 'refused', reason: 'quota' };
227
+ }
228
+ return { kind: 'error', reason: 'empty' };
229
+ }
230
+ catch (e) {
231
+ // Redacted: raw jsonOutput is never emitted — only its length plus
232
+ // the parse error reason. Prevents prompt / response leakage
233
+ // through log aggregators.
234
+ log.warn('extractGeminiResponse: failed to parse JSON', {
235
+ error: e instanceof Error ? e.message : String(e),
236
+ length: jsonOutput.length
237
+ });
238
+ if (classifyGeminiStderrReason(stderr) === 'quota') {
239
+ return { kind: 'refused', reason: 'quota' };
240
+ }
241
+ return { kind: 'error', reason: 'malformed' };
177
242
  }
178
- return this.extractGeminiResponse(rawOutput, log ?? rootLogger);
179
243
  }
180
244
  extractGeminiResponse(jsonOutput, log) {
181
245
  if (!jsonOutput || !jsonOutput.trim()) {
@@ -205,4 +269,37 @@ export class GeminiAdapter {
205
269
  }
206
270
  }
207
271
  }
272
+ /**
273
+ * Classify Gemini stderr against anchored Google API quota markers.
274
+ * Operates only on stderr, never on the `response` field or any other
275
+ * assistant-author surface.
276
+ *
277
+ * Anchored markers chosen against the literal strings Google's API and
278
+ * gemini-cli surface on quota:
279
+ * - "RESOURCE_EXHAUSTED" — gRPC / Google API status code
280
+ * - "Quota exceeded for quota metric" — Google API canonical phrase
281
+ * - "Quota exhausted" — alt phrasing
282
+ * - "rateLimitExceeded" — Google API error reason
283
+ * - "userRateLimitExceeded" — per-user variant
284
+ * - "429" — HTTP status
285
+ *
286
+ * No loose `rate limit` / `usage limit` / `plan.*limit` patterns. The
287
+ * known residual: a quota state that prints only to gemini's `response`
288
+ * field (no stderr signal) passes through as a normal answer. We
289
+ * document and accept that — gemini's protocol gives us no honest way
290
+ * to distinguish that case from a real reply.
291
+ */
292
+ function classifyGeminiStderrReason(stderr) {
293
+ if (!stderr)
294
+ return 'unknown';
295
+ const markers = [
296
+ /RESOURCE_EXHAUSTED/,
297
+ /Quota exceeded for quota metric/i,
298
+ /Quota exhausted/i,
299
+ /rateLimitExceeded/i,
300
+ /userRateLimitExceeded/i,
301
+ /\b429\b/,
302
+ ];
303
+ return markers.some((p) => p.test(stderr)) ? 'quota' : 'unknown';
304
+ }
208
305
  //# sourceMappingURL=gemini-adapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gemini-adapter.js","sourceRoot":"","sources":["../../src/cli-adapters/gemini-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gemini-adapter.js","sourceRoot":"","sources":["../../src/cli-adapters/gemini-adapter.ts"],"names":[],"mappings":"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"}
@@ -34,6 +34,34 @@ export interface CLIBuilderConfig {
34
34
  mpcEnvCleanup?: string[];
35
35
  mcpSupport?: MCPSupportConfig;
36
36
  }
37
+ /**
38
+ * Structured outcome of decoding a CLI's raw output.
39
+ *
40
+ * Replaces the previous `decodeOutput(): string` shape, which collapsed
41
+ * three distinct states (success / refusal / error) into one string and
42
+ * forced the orchestrator to re-grep the assistant prose for refusal
43
+ * markers — a brittle layer that produced the 2026-05-21 false-positive
44
+ * class (see Phase 1 fix in cli-agents.ts).
45
+ *
46
+ * Each provider adapter populates this from its own protocol-level
47
+ * signals (Claude: `result.subtype` / `is_error`; Codex: error events;
48
+ * Gemini: anchored stderr markers). The orchestrator never inspects
49
+ * assistant prose to classify refusals.
50
+ */
51
+ export type DecodeRefusalReason = 'quota' | 'auth' | 'policy';
52
+ export type DecodeErrorReason = 'malformed' | 'empty' | 'unknown';
53
+ export type DecodeResult = {
54
+ kind: 'ok';
55
+ text: string;
56
+ } | {
57
+ kind: 'refused';
58
+ reason: DecodeRefusalReason;
59
+ detail?: string;
60
+ } | {
61
+ kind: 'error';
62
+ reason: DecodeErrorReason;
63
+ detail?: string;
64
+ };
37
65
  export interface CLIProvider {
38
66
  readonly name: CLIName;
39
67
  /** Return the static configuration for this provider */
@@ -51,16 +79,34 @@ export interface CLIProvider {
51
79
  model?: string;
52
80
  }>;
53
81
  /**
54
- * Decode raw CLI output into clean text.
55
- * Claude decodes stream-json NDJSON, Codex extracts agent_messages,
56
- * Gemini extracts the response field from JSON.
82
+ * Decode raw CLI output into a structured outcome (preferred API).
83
+ *
84
+ * Each adapter inspects ITS OWN protocol-level signals to classify the
85
+ * run — refusal markers must come from the CLI's structured error
86
+ * channel (stream-json `result` events for Claude, error items for
87
+ * Codex, anchored stderr envelopes for Gemini) and never from the
88
+ * assistant text the CLI returned.
89
+ *
90
+ * The orchestrator consumes `DecodeResult.kind` directly; no caller
91
+ * grep the prose for "rate limit"-style strings (Phase 1 hot-fix
92
+ * scoped that pattern set to stderr; Phase 2 removes it entirely).
93
+ *
94
+ * stderr is passed in alongside stdout because two of the three CLIs
95
+ * (Codex error envelopes, Gemini quota errors) surface refusal state
96
+ * on stderr, not in the JSON event stream.
97
+ */
98
+ decode(stdout: string, stderr: string, args: string[], log?: StructuredLogger): DecodeResult;
99
+ /**
100
+ * Decode raw CLI output into clean text (legacy API).
101
+ *
102
+ * Delegates to `decode()` and returns the assistant text on success,
103
+ * empty string on refusal/error. Retained for the legacy test proxies
104
+ * at `cli-agents.ts:716-728` and any external consumers; new code
105
+ * should call `decode()` and switch on `kind`.
57
106
  *
58
- * Pattern A: `log` is optional. When provided (passed from the
59
- * orchestrator via `this.log?.forOperation('<cli>_spawn')`), adapter
60
- * warnings/errors during decode emit with the scoped logger. When
61
- * absent, adapters fall back to the root logger so the legacy test
62
- * proxies (cli-agents.ts decodeClaudeStreamJson / extractCodexAgentMessage
63
- * / extractGeminiResponse) keep working with no args.
107
+ * Pattern A: `log` is optional. When provided, adapter warnings/errors
108
+ * during decode emit with the scoped logger. When absent, adapters
109
+ * fall back to the root logger.
64
110
  */
65
111
  decodeOutput(rawOutput: string, args: string[], log?: StructuredLogger): string;
66
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli-adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI1C,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,YAAY,EAAE,WAAW,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;IAGnE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,yDAAyD;IACzD,eAAe,EAAE;QACf,MAAM,EAAE,kBAAkB,GAAG,SAAS,GAAG,eAAe,CAAC;QACzD,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,EAAE,CAAC;IACvD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAID,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAEvB,wDAAwD;IACxD,SAAS,IAAI,gBAAgB,CAAC;IAE9B;;;OAGG;IACH,YAAY,CACV,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,eAAe,EACxB,aAAa,EAAE,aAAa,EAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAK3B,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IAEH;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;CACjF;AAcD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,CAMtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,EAAE,CAE5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli-adapters/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli-adapters/index.ts"],"names":[],"mappings":"AAUA,6BAA6B;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAsF1C,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,SAAS,GAAiC;IAC9C,MAAM,EAAE,IAAI,aAAa,EAAE;IAC3B,KAAK,EAAE,IAAI,YAAY,EAAE;IACzB,MAAM,EAAE,IAAI,aAAa,EAAE;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAc,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli-adapters/index.ts"],"names":[],"mappings":"AAUA,6BAA6B;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA0I1C,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,SAAS,GAAiC;IAC9C,MAAM,EAAE,IAAI,aAAa,EAAE;IAC3B,KAAK,EAAE,IAAI,YAAY,EAAE;IACzB,MAAM,EAAE,IAAI,aAAa,EAAE;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAc,CAAC;AAC7C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cli-agents.d.ts","sourceRoot":"","sources":["../src/cli-agents.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-agents.d.ts","sourceRoot":"","sources":["../src/cli-agents.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import { promises as fs, realpathSync } from 'fs';
3
3
  import { promisify } from 'util';
4
4
  import { logger } from './logger.js';
5
5
  import { ModelResolver } from './model-resolver.js';
6
- import { cleanupTempConfig, } from './mcp-registry.js';
6
+ import { cleanupTempConfig } from './mcp-registry.js';
7
7
  import { getProvider, parseNDJSON } from './cli-adapters/index.js';
8
8
  import { GEMINI_FRONTIER_CHAIN } from './cli-adapters/gemini-adapter.js';
9
9
  import { safeMetric } from './metrics/index.js';
@@ -794,46 +794,29 @@ export class CLIAgentOrchestrator {
794
794
  });
795
795
  }
796
796
  // Post-process CLI output via provider adapter. Thread the scoped
797
- // logger through decodeOutput so adapter warnings/errors carry
797
+ // logger through decode so adapter warnings/errors carry
798
798
  // module=cli-orchestrator + operation=<provider>_spawn context.
799
+ //
800
+ // Phase 2: consume the structured DecodeResult from `decode()`
801
+ // instead of grepping the returned string for refusal markers.
802
+ // Each adapter classifies refusal from its own protocol-level
803
+ // signals (Claude `result.subtype`, Codex error events / stderr
804
+ // markers, Gemini anchored stderr markers). The orchestrator
805
+ // does not inspect assistant prose to classify outcomes.
799
806
  let finalOutput = stdout;
800
807
  const providerAdapter = getProvider(cliName);
801
808
  const decodeLog = this.log?.forOperation(`${cliName}_spawn`);
802
- const decodedText = providerAdapter.decodeOutput(stdout, args, decodeLog);
803
- if (decodedText) {
804
- finalOutput = decodedText;
805
- }
806
- // Fallback: If stdout is empty but stderr has content and exit was successful,
807
- // Claude might have written to stderr (common in non-TTY environments)
808
- if (!finalOutput.trim() && stderr && stderr.trim()) {
809
- this.emitLog().info(`📝 Using stderr as output for ${cliName} (stdout was empty)`);
810
- finalOutput = stderr;
811
- }
812
- // Detect CLI errors that exit 0 but contain fatal error output
813
- // (e.g., Gemini CLI returns exit code 0 on quota exhaustion,
814
- // Codex CLI may return usage limit errors in output)
815
- const combinedOutput = `${finalOutput}\n${stderr}`;
816
- const quotaPatterns = [
817
- /TerminalQuotaError/i,
818
- /exhausted your capacity/i,
819
- /quota will reset/i,
820
- /rateLimitExceeded/i,
821
- /rate limit/i,
822
- /usage limit/i,
823
- /Too Many Requests/i,
824
- /\b429\b/,
825
- /token limit exceeded/i,
826
- /billing.*limit/i,
827
- /spending.*limit/i,
828
- /plan.*limit/i,
829
- ];
830
- const quotaMatch = quotaPatterns.find(p => p.test(combinedOutput));
831
- if (quotaMatch) {
832
- // Extract reset time if present
833
- const resetMatch = combinedOutput.match(/reset(?:s)? (?:in|after) (\d+h\s*\d+m(?:\s*\d+s)?)/i);
834
- const resetInfo = resetMatch ? ` (resets in ${resetMatch[1]})` : '';
835
- const errorMsg = `${cliName.toUpperCase()} quota exhausted${resetInfo}. The CLI exited 0 but returned a quota error instead of analysis output.`;
836
- this.emitLog().warn(`⏱️ ${errorMsg}`);
809
+ const decoded = providerAdapter.decode(stdout, stderr, args, decodeLog);
810
+ if (decoded.kind === 'refused') {
811
+ // Structured refusal — the adapter saw the CLI's own
812
+ // protocol-level signal that this run hit a wall (quota / auth /
813
+ // policy). No prose matching.
814
+ const errorMsg = `${cliName.toUpperCase()} ${decoded.reason} refused. The CLI exited 0 but its own protocol returned a refusal instead of analysis output.`;
815
+ this.emitLog().warn(`⏱️ ${errorMsg}`, {
816
+ reason: decoded.reason,
817
+ detail: decoded.detail,
818
+ stderrLength: stderr.length,
819
+ });
837
820
  if (options.onStreamingEvent) {
838
821
  options.onStreamingEvent({
839
822
  type: 'agent_error',
@@ -843,19 +826,12 @@ export class CLIAgentOrchestrator {
843
826
  sessionId: options.sessionId
844
827
  });
845
828
  }
846
- // Spawn counter: outcome=refused (quota exhaustion — CLI exited 0
847
- // with a quota error in stdout/stderr). Labels annotated against
848
- // CLI_SPAWN_LABELS so a future label-set change fails at compile
849
- // time. Wrapped in `safeMetric` so a label-validation throw or
850
- // other metric-layer exception cannot propagate into the outer
851
- // spawn try/catch and be misclassified as a spawn failure
852
- // (Cycle 3 Task CLI-B' — parity with debate's safeMetric).
853
- const quotaLabels = {
829
+ const refusedLabels = {
854
830
  provider,
855
831
  outcome: 'refused',
856
832
  };
857
- safeMetric(this.emitLog(), 'cliSpawnTotal.inc(refused:quota)', () => {
858
- this.metrics?.cliSpawnTotal.inc(quotaLabels, 1);
833
+ safeMetric(this.emitLog(), `cliSpawnTotal.inc(refused:${decoded.reason})`, () => {
834
+ this.metrics?.cliSpawnTotal.inc(refusedLabels, 1);
859
835
  });
860
836
  return {
861
837
  agent: cliName,
@@ -863,18 +839,26 @@ export class CLIAgentOrchestrator {
863
839
  output: '',
864
840
  error: errorMsg,
865
841
  executionTime: Date.now() - startTime,
866
- // Cycle 4 Task T18 (F9): match the failure-path redaction
867
- // parity — `command` is a diagnostic display field; the
868
- // static placeholder preserves the response shape without
869
- // leaking raw command + args (which may include Codex TOML
870
- // MCP overrides, Claude temp config paths, or prompt
871
- // fragments that crossed the trust boundary).
872
842
  command: `(redacted command for ${cliName})`,
873
843
  workingDirectory: workingDir,
874
844
  exitCode: 0,
875
845
  model: built?.model
876
846
  };
877
847
  }
848
+ if (decoded.kind === 'ok') {
849
+ finalOutput = decoded.text;
850
+ }
851
+ // For `kind: 'error'` (empty/malformed/unknown) we fall through
852
+ // and keep finalOutput as the raw stdout — preserving the legacy
853
+ // "if decode returned nothing useful, pass raw stdout through"
854
+ // behavior. The success path below then surfaces the raw output
855
+ // and the caller can see what the CLI emitted.
856
+ // Fallback: If stdout is empty but stderr has content and exit was successful,
857
+ // Claude might have written to stderr (common in non-TTY environments)
858
+ if (!finalOutput.trim() && stderr && stderr.trim()) {
859
+ this.emitLog().info(`📝 Using stderr as output for ${cliName} (stdout was empty)`);
860
+ finalOutput = stderr;
861
+ }
878
862
  // Spawn counter: outcome=success (normal completion path). Labels
879
863
  // annotated against CLI_SPAWN_LABELS so a future label-set change
880
864
  // fails at compile time. Wrapped in `safeMetric` so a metric-layer
@@ -910,14 +894,22 @@ export class CLIAgentOrchestrator {
910
894
  catch (error) {
911
895
  const execError = error;
912
896
  const exitCode = execError.code || -1;
913
- // Detect rate limiting / usage limit errors across all CLIs
897
+ // Detect rate limiting / usage limit errors across all CLIs.
898
+ //
899
+ // Scoped to `message + stderr`. The previous scope of
900
+ // `message + stdout + stderr` ran these substrings against the
901
+ // child's captured stdout — which on a partial/aborted run is
902
+ // assistant prose that crossed the same trust boundary as the
903
+ // success path. `message` is the spawn-layer error string from
904
+ // Node (e.g., "Command failed with exit code 1"), not user
905
+ // content; safe to keep.
914
906
  const rateLimitPatterns = [
915
907
  '429', 'rate limit', 'rate_limit', 'rateLimitExceeded',
916
908
  'Too Many Requests', 'usage limit', 'usage_limit',
917
909
  'quota', 'exhausted', 'billing', 'spending limit',
918
910
  'token limit', 'plan limit',
919
911
  ];
920
- const errorText = `${execError.message || ''} ${execError.stdout || ''} ${execError.stderr || ''}`.toLowerCase();
912
+ const errorText = `${execError.message || ''} ${execError.stderr || ''}`.toLowerCase();
921
913
  const isRateLimit = rateLimitPatterns.some(p => errorText.includes(p.toLowerCase()));
922
914
  const unsupportedCodexModel = cliName === 'codex'
923
915
  && isCodexUnsupportedChatGPTModelError(execError, options.models?.codex);
@@ -1005,7 +997,12 @@ export class CLIAgentOrchestrator {
1005
997
  };
1006
998
  }
1007
999
  finally {
1008
- // Clean up temp MCP config file (Claude flag-file method)
1000
+ // Clean up the temp MCP config file when the Claude adapter
1001
+ // wrote one. The Claude path always uses `writeClaudeMcpConfigSecure`
1002
+ // when MCP is enabled, so `tempMcpConfigPath` is set whenever the
1003
+ // run had `--mcp-config <path>` on argv. When MCP is disabled
1004
+ // (no servers requested) the adapter never writes a file and
1005
+ // this finally is a no-op.
1009
1006
  if (tempMcpConfigPath) {
1010
1007
  await cleanupTempConfig(tempMcpConfigPath);
1011
1008
  }