nexus-agents 2.82.0 → 2.83.1

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.
Files changed (128) hide show
  1. package/dist/{child-mcp-config-BMSYR7VV.js → child-mcp-config-3ZW2UPKZ.js} +2 -2
  2. package/dist/{chunk-BQ4YXGGQ.js → chunk-3ACDP4E6.js} +124 -2
  3. package/dist/chunk-3ACDP4E6.js.map +1 -0
  4. package/dist/{chunk-S36LIUV2.js → chunk-4XSCU4B3.js} +8 -8
  5. package/dist/{chunk-HJUHDPXJ.js → chunk-5QJPM5CB.js} +3 -3
  6. package/dist/{chunk-633WH2ML.js → chunk-6T3EPABN.js} +1 -1
  7. package/dist/chunk-6T3EPABN.js.map +1 -0
  8. package/dist/{chunk-7VNVDFD5.js → chunk-6UI4NKT4.js} +44 -18
  9. package/dist/{chunk-7VNVDFD5.js.map → chunk-6UI4NKT4.js.map} +1 -1
  10. package/dist/{chunk-NTLJ3INA.js → chunk-6XRNFLPI.js} +2 -2
  11. package/dist/{chunk-U7JXQSEM.js → chunk-7V367KT4.js} +4 -4
  12. package/dist/{chunk-BL5IBHEY.js → chunk-A6WC5I7V.js} +3 -3
  13. package/dist/{chunk-OYDJ3C4N.js → chunk-BICIQYET.js} +3 -3
  14. package/dist/{chunk-SXL744NF.js → chunk-BUXXAN6V.js} +2 -2
  15. package/dist/{chunk-SHWGK7X6.js → chunk-DWOSFYI2.js} +2 -2
  16. package/dist/{chunk-2SQXJQTA.js → chunk-ELRNVADA.js} +16 -13
  17. package/dist/{chunk-2SQXJQTA.js.map → chunk-ELRNVADA.js.map} +1 -1
  18. package/dist/{chunk-2R5UUBGA.js → chunk-FHY7I736.js} +2 -2
  19. package/dist/{chunk-7J7PNOJQ.js → chunk-HFOQKCD2.js} +22 -5
  20. package/dist/chunk-HFOQKCD2.js.map +1 -0
  21. package/dist/{chunk-TXIUCEFT.js → chunk-HGPIHDC4.js} +3 -3
  22. package/dist/{chunk-X3JR3GMT.js → chunk-IM2B3FK2.js} +3 -3
  23. package/dist/{chunk-4XNVJS5A.js → chunk-J4ZBKE4B.js} +866 -892
  24. package/dist/chunk-J4ZBKE4B.js.map +1 -0
  25. package/dist/{chunk-SBZVRH4S.js → chunk-JA6ON2RP.js} +2 -2
  26. package/dist/{chunk-QHL4KGNB.js → chunk-LM2S2QWO.js} +2 -2
  27. package/dist/{chunk-QHL4KGNB.js.map → chunk-LM2S2QWO.js.map} +1 -1
  28. package/dist/{chunk-C7P2HLJX.js → chunk-MATFDJRW.js} +4 -4
  29. package/dist/{chunk-XGUDCUMB.js → chunk-O3XJLOEX.js} +2 -2
  30. package/dist/{chunk-FTT2IYYX.js → chunk-ODKIRXN7.js} +34 -43
  31. package/dist/chunk-ODKIRXN7.js.map +1 -0
  32. package/dist/{chunk-HMXQKDUV.js → chunk-SZZS57X7.js} +23 -7
  33. package/dist/chunk-SZZS57X7.js.map +1 -0
  34. package/dist/{chunk-W2AIGD35.js → chunk-TKGVRHEI.js} +3 -3
  35. package/dist/{chunk-HVZ52LOL.js → chunk-UFUR6RBP.js} +2 -2
  36. package/dist/{chunk-WUUEKFKG.js → chunk-VXIHHHLQ.js} +2 -2
  37. package/dist/{chunk-GNG7URCR.js → chunk-W6MLS2UL.js} +2 -2
  38. package/dist/{chunk-G2DZBEMU.js → chunk-XODXYOFN.js} +2 -2
  39. package/dist/{chunk-JM3R267Z.js → chunk-ZA6AZ7LK.js} +5 -5
  40. package/dist/{chunk-PZESEBD3.js → chunk-ZLGU7T6J.js} +2 -2
  41. package/dist/{cli-circuit-breaker-BIJUQRQI.js → cli-circuit-breaker-LC4NZUGD.js} +4 -4
  42. package/dist/cli.js +367 -345
  43. package/dist/cli.js.map +1 -1
  44. package/dist/codebase-search-ZFJUVMVR.js +8 -0
  45. package/dist/{composite-router-FB7P22L5.js → composite-router-GXQ25DO4.js} +2 -2
  46. package/dist/{consensus-vote-KKAIFULI.js → consensus-vote-MTLP6E72.js} +12 -12
  47. package/dist/{context-retriever-4JCGMWH7.js → context-retriever-GQRC2MVM.js} +6 -6
  48. package/dist/{doctor-deep-7YK4BZIJ.js → doctor-deep-T3UUJX2E.js} +3 -3
  49. package/dist/expert-bridge-7LPGCPPR.js +13 -0
  50. package/dist/{factory-DOWBGVAL.js → factory-3XB5CAAA.js} +5 -5
  51. package/dist/{factory-PK4EZL7K.js → factory-OKNCTJO6.js} +4 -4
  52. package/dist/index.d.ts +98 -194
  53. package/dist/index.js +90 -193
  54. package/dist/index.js.map +1 -1
  55. package/dist/{init-opencode-QP5CAMWN.js → init-opencode-KDTBKLXS.js} +5 -5
  56. package/dist/{issue-triage-T3SKNBH5.js → issue-triage-MURMDN2G.js} +4 -4
  57. package/dist/{registry-command-TH7U6UMC.js → registry-command-D56ROMFJ.js} +2 -2
  58. package/dist/{repo-analyze-D2OY2QSR.js → repo-analyze-JZEMBE6R.js} +2 -2
  59. package/dist/{repo-security-plan-V257RYTW.js → repo-security-plan-N3CDMW6L.js} +4 -4
  60. package/dist/{research-helpers-synthesize-Y3O76PY4.js → research-helpers-synthesize-36QBOKII.js} +3 -3
  61. package/dist/{routing-memory-AAH7NIHD.js → routing-memory-6IEPJ3EP.js} +2 -2
  62. package/dist/{session-memory-MY6YS2VX.js → session-memory-X6SCDFER.js} +3 -3
  63. package/dist/{setup-command-B6EC3OJA.js → setup-command-5AEO5A4Z.js} +11 -11
  64. package/dist/{setup-config-HVO6ZSLW.js → setup-config-RPSVIQJO.js} +3 -3
  65. package/dist/{setup-custom-api-UOIKUQL4.js → setup-custom-api-RBOJT3SS.js} +4 -4
  66. package/dist/{tool-memory-T7ZYIUJ2.js → tool-memory-EEHITQRJ.js} +5 -5
  67. package/dist/{weather-report-O3Z3BBAX.js → weather-report-6BC3JK5H.js} +2 -2
  68. package/package.json +1 -1
  69. package/dist/chunk-4XNVJS5A.js.map +0 -1
  70. package/dist/chunk-633WH2ML.js.map +0 -1
  71. package/dist/chunk-7J7PNOJQ.js.map +0 -1
  72. package/dist/chunk-AP2FD37C.js +0 -127
  73. package/dist/chunk-AP2FD37C.js.map +0 -1
  74. package/dist/chunk-BQ4YXGGQ.js.map +0 -1
  75. package/dist/chunk-ED6VQWNG.js +0 -63
  76. package/dist/chunk-ED6VQWNG.js.map +0 -1
  77. package/dist/chunk-FTT2IYYX.js.map +0 -1
  78. package/dist/chunk-HMXQKDUV.js.map +0 -1
  79. package/dist/codebase-search-PIBRTGBE.js +0 -9
  80. package/dist/expert-bridge-DJM5GAWZ.js +0 -11
  81. package/dist/shared-memory-CM6T2MYE.js +0 -8
  82. package/dist/symbol-extractor-WYXPJH65.js +0 -10
  83. package/dist/tool-memory-T7ZYIUJ2.js.map +0 -1
  84. package/dist/weather-report-O3Z3BBAX.js.map +0 -1
  85. /package/dist/{child-mcp-config-BMSYR7VV.js.map → child-mcp-config-3ZW2UPKZ.js.map} +0 -0
  86. /package/dist/{chunk-S36LIUV2.js.map → chunk-4XSCU4B3.js.map} +0 -0
  87. /package/dist/{chunk-HJUHDPXJ.js.map → chunk-5QJPM5CB.js.map} +0 -0
  88. /package/dist/{chunk-NTLJ3INA.js.map → chunk-6XRNFLPI.js.map} +0 -0
  89. /package/dist/{chunk-U7JXQSEM.js.map → chunk-7V367KT4.js.map} +0 -0
  90. /package/dist/{chunk-BL5IBHEY.js.map → chunk-A6WC5I7V.js.map} +0 -0
  91. /package/dist/{chunk-OYDJ3C4N.js.map → chunk-BICIQYET.js.map} +0 -0
  92. /package/dist/{chunk-SXL744NF.js.map → chunk-BUXXAN6V.js.map} +0 -0
  93. /package/dist/{chunk-SHWGK7X6.js.map → chunk-DWOSFYI2.js.map} +0 -0
  94. /package/dist/{chunk-2R5UUBGA.js.map → chunk-FHY7I736.js.map} +0 -0
  95. /package/dist/{chunk-TXIUCEFT.js.map → chunk-HGPIHDC4.js.map} +0 -0
  96. /package/dist/{chunk-X3JR3GMT.js.map → chunk-IM2B3FK2.js.map} +0 -0
  97. /package/dist/{chunk-SBZVRH4S.js.map → chunk-JA6ON2RP.js.map} +0 -0
  98. /package/dist/{chunk-C7P2HLJX.js.map → chunk-MATFDJRW.js.map} +0 -0
  99. /package/dist/{chunk-XGUDCUMB.js.map → chunk-O3XJLOEX.js.map} +0 -0
  100. /package/dist/{chunk-W2AIGD35.js.map → chunk-TKGVRHEI.js.map} +0 -0
  101. /package/dist/{chunk-HVZ52LOL.js.map → chunk-UFUR6RBP.js.map} +0 -0
  102. /package/dist/{chunk-WUUEKFKG.js.map → chunk-VXIHHHLQ.js.map} +0 -0
  103. /package/dist/{chunk-GNG7URCR.js.map → chunk-W6MLS2UL.js.map} +0 -0
  104. /package/dist/{chunk-G2DZBEMU.js.map → chunk-XODXYOFN.js.map} +0 -0
  105. /package/dist/{chunk-JM3R267Z.js.map → chunk-ZA6AZ7LK.js.map} +0 -0
  106. /package/dist/{chunk-PZESEBD3.js.map → chunk-ZLGU7T6J.js.map} +0 -0
  107. /package/dist/{cli-circuit-breaker-BIJUQRQI.js.map → cli-circuit-breaker-LC4NZUGD.js.map} +0 -0
  108. /package/dist/{codebase-search-PIBRTGBE.js.map → codebase-search-ZFJUVMVR.js.map} +0 -0
  109. /package/dist/{composite-router-FB7P22L5.js.map → composite-router-GXQ25DO4.js.map} +0 -0
  110. /package/dist/{consensus-vote-KKAIFULI.js.map → consensus-vote-MTLP6E72.js.map} +0 -0
  111. /package/dist/{context-retriever-4JCGMWH7.js.map → context-retriever-GQRC2MVM.js.map} +0 -0
  112. /package/dist/{doctor-deep-7YK4BZIJ.js.map → doctor-deep-T3UUJX2E.js.map} +0 -0
  113. /package/dist/{expert-bridge-DJM5GAWZ.js.map → expert-bridge-7LPGCPPR.js.map} +0 -0
  114. /package/dist/{factory-DOWBGVAL.js.map → factory-3XB5CAAA.js.map} +0 -0
  115. /package/dist/{factory-PK4EZL7K.js.map → factory-OKNCTJO6.js.map} +0 -0
  116. /package/dist/{init-opencode-QP5CAMWN.js.map → init-opencode-KDTBKLXS.js.map} +0 -0
  117. /package/dist/{issue-triage-T3SKNBH5.js.map → issue-triage-MURMDN2G.js.map} +0 -0
  118. /package/dist/{registry-command-TH7U6UMC.js.map → registry-command-D56ROMFJ.js.map} +0 -0
  119. /package/dist/{repo-analyze-D2OY2QSR.js.map → repo-analyze-JZEMBE6R.js.map} +0 -0
  120. /package/dist/{repo-security-plan-V257RYTW.js.map → repo-security-plan-N3CDMW6L.js.map} +0 -0
  121. /package/dist/{research-helpers-synthesize-Y3O76PY4.js.map → research-helpers-synthesize-36QBOKII.js.map} +0 -0
  122. /package/dist/{routing-memory-AAH7NIHD.js.map → routing-memory-6IEPJ3EP.js.map} +0 -0
  123. /package/dist/{session-memory-MY6YS2VX.js.map → session-memory-X6SCDFER.js.map} +0 -0
  124. /package/dist/{setup-command-B6EC3OJA.js.map → setup-command-5AEO5A4Z.js.map} +0 -0
  125. /package/dist/{setup-config-HVO6ZSLW.js.map → setup-config-RPSVIQJO.js.map} +0 -0
  126. /package/dist/{setup-custom-api-UOIKUQL4.js.map → setup-custom-api-RBOJT3SS.js.map} +0 -0
  127. /package/dist/{shared-memory-CM6T2MYE.js.map → tool-memory-EEHITQRJ.js.map} +0 -0
  128. /package/dist/{symbol-extractor-WYXPJH65.js.map → weather-report-6BC3JK5H.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli-adapters/subprocess-adapter.ts","../src/cli-adapters/base-adapter.ts","../src/cli-adapters/cli-timeout-helpers.ts","../src/cli-adapters/cli-timeout-profiles.ts","../src/cli-adapters/capacity-tracker.ts","../src/utils/async-utils.ts","../src/cli-adapters/cli-error-helpers.ts","../src/cli-adapters/cli-retry-loop.ts","../src/cli-adapters/subprocess-env.ts","../src/security/output-sanitizer.ts","../src/cli-adapters/cli-error-envelope.ts","../src/utils/type-coercion.ts","../src/cli-adapters/parsers/claude-parser.ts","../src/cli-adapters/adapters/claude-adapter.ts","../src/cli-adapters/adapters/gemini-adapter.ts","../src/cli-adapters/parsers/gemini-parser-resilient-helpers.ts","../src/cli-adapters/parsers/gemini-parser-resilient.ts","../src/cli-adapters/adapters/gemini-adapter-helpers.ts","../src/cli-adapters/adapters/codex-adapter.ts","../src/cli-adapters/parsers/codex-parser.ts","../src/cli-adapters/adapters/codex-adapter-helpers.ts","../src/cli-adapters/adapters/codex-mcp-adapter.ts","../src/cli-adapters/adapters/codex-mcp-adapter-helpers.ts","../src/cli-adapters/adapters/opencode-adapter.ts","../src/cli-adapters/parsers/opencode-parser.ts","../src/cli-adapters/cli-detection-cache.ts","../src/cli/cli-auth-probe.ts","../src/cli-adapters/factory.ts"],"sourcesContent":["/**\n * nexus-agents/cli-adapters - Subprocess Adapter\n *\n * Base class for subprocess-based CLI adapters.\n * Used by ClaudeCliAdapter and GeminiCliAdapter.\n *\n * Extracted from base-adapter.ts per Issue #272 (file size limits).\n */\n\nimport { spawn } from 'node:child_process';\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, getTimeProvider, createLogger } from '../core/index.js';\n\nimport type {\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n ExecutionOptions,\n ICliResponseParser,\n} from './types.js';\nimport { BaseCliAdapter } from './base-adapter.js';\nimport { buildChildEnv } from './subprocess-env.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { parseCliErrorEnvelope } from './cli-error-envelope.js';\n\n/** Minimum length for plaintext fallback to kick in.\n * Lowered from 100→30 to recover short but valid CLI responses (#1401). */\nconst PLAINTEXT_FALLBACK_MIN_LENGTH = 30;\n\n/**\n * Attempts to extract a usable response from raw stdout when the structured\n * parser fails. Returns the trimmed text if it looks like natural language\n * (not JSON/NDJSON) and exceeds the minimum length threshold.\n *\n * Recovers responses from CLIs that output plaintext instead of their\n * expected structured format. (#1401)\n */\nfunction tryPlaintextFallback(stdout: string): string | null {\n const trimmed = stdout.trim();\n if (trimmed.length < PLAINTEXT_FALLBACK_MIN_LENGTH) return null;\n // Skip if it looks like structured output the parser should handle\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) return null;\n return trimmed;\n}\n\n/** Error patterns in stderr that indicate a real failure, not debug output (#1402). */\nconst STDERR_ERROR_PATTERNS = [\n 'error:',\n 'fatal:',\n 'panic:',\n 'unhandled',\n 'not found',\n 'invalid model',\n 'authentication',\n 'unauthorized',\n 'permission denied',\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'timeout',\n 'failed to connect',\n 'invalid api key',\n 'rate limit',\n 'quota exceeded',\n 'service unavailable',\n];\n\n/** Checks if stderr looks like a real error (not just debug/progress output). */\nfunction looksLikeErrorStderr(stderr: string): boolean {\n const lower = stderr.toLowerCase();\n return STDERR_ERROR_PATTERNS.some((pattern) => lower.includes(pattern));\n}\n\n/** Stderr patterns indicating transient connection failures (retryable). */\nconst STDERR_CONNECTION_PATTERNS = [\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'econnreset',\n 'failed to connect',\n 'service unavailable',\n 'eaddrinuse',\n 'address already in use',\n];\n\n/** Stderr patterns indicating timeout (retryable). */\nconst STDERR_TIMEOUT_PATTERNS = ['timeout', 'timed out', 'etimedout'];\n\n/**\n * Classifies a stderr error message into the most specific CliErrorCode.\n * Checks for transient patterns (connection, rate-limit, timeout) before\n * falling back to EXECUTION_ERROR. This ensures transient failures in\n * stderr are retried instead of treated as terminal. (#1401)\n *\n * Rate-limit detection uses shared patterns from rate-limit-detector. (#1596)\n */\nfunction classifyStderrError(stderr: string): CliErrorCode {\n const lower = stderr.toLowerCase();\n if (STDERR_CONNECTION_PATTERNS.some((p) => lower.includes(p))) return 'CONNECTION_ERROR';\n if (isRateLimitText(stderr)) return 'RATE_LIMITED';\n if (STDERR_TIMEOUT_PATTERNS.some((p) => lower.includes(p))) return 'TIMEOUT';\n return 'EXECUTION_ERROR';\n}\n\nconst subprocessLogger = createLogger({ component: 'subprocess-adapter' });\n\n/** Maximum buffer size for stdout/stderr (10 MB). */\nconst MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\n/** CliErrorCodes that represent transient failures safe to retry. */\nconst TRANSIENT_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n 'PARSE_ERROR',\n]);\n\n/** Delay schedule for transient-error retries (ms per attempt index). */\nconst TRANSIENT_RETRY_DELAYS_MS = [500, 1000] as const;\n\n/** Maximum number of transient-error retries. */\nconst MAX_TRANSIENT_RETRIES = TRANSIENT_RETRY_DELAYS_MS.length;\n\n/**\n * Maximum retries for PARSE_ERROR specifically (#1533).\n * Parse errors are less likely to self-heal than timeouts/connection errors,\n * so we cap at 1 retry instead of 2.\n */\nexport const MAX_PARSE_RETRIES = 1;\n\n/** Timeout extension multiplier when retrying a TIMEOUT error. (#1401) */\nexport const TIMEOUT_RETRY_MULTIPLIER = 1.5;\n\n/**\n * Checks whether a CliErrorCode represents a transient failure.\n * Timeout, rate_limit, connection, and parse errors are transient.\n * Parse errors get fewer retries (MAX_PARSE_RETRIES) than others (#1533).\n */\nexport function isTransientError(code: CliErrorCode): boolean {\n return TRANSIENT_ERROR_CODES.has(code);\n}\n\n/**\n * Exit codes that indicate transient process termination (retryable).\n * - 137 = 128 + SIGKILL (9): OOM killer, system resource limits\n * - 143 = 128 + SIGTERM (15): external termination (our timeout SIGTERM\n * is already caught by the timeout handler before close fires)\n */\nconst TRANSIENT_EXIT_CODES = new Set([137, 143]);\n\n/** Human-readable signal names for exit codes (128 + signal number). */\nconst EXIT_CODE_SIGNAL_NAMES: Record<number, string> = {\n 137: 'SIGKILL (OOM or killed)',\n 143: 'SIGTERM (terminated)',\n};\n\n/** Builds an error message for signal exit codes that includes identifiable keywords. */\nfunction buildSignalExitMessage(code: number): string {\n const signalName = EXIT_CODE_SIGNAL_NAMES[code];\n if (signalName !== undefined) return `Process killed by ${signalName}, exit code ${String(code)}`;\n return `Process exited with code ${String(code)}`;\n}\n\n/**\n * Checks whether a process exit code indicates a transient failure\n * that is safe to retry (e.g., OOM kill, external SIGTERM).\n */\nexport function isTransientExitCode(code: number | null): boolean {\n return code !== null && TRANSIENT_EXIT_CODES.has(code);\n}\n\n/** Internal state for buffered stream collection. */\ninterface BufferState {\n stdout: string;\n stderr: string;\n stdoutBytes: number;\n stderrBytes: number;\n stdoutTruncated: boolean;\n stderrTruncated: boolean;\n resolved: boolean;\n /**\n * Wall-clock at first stdout byte (or null if none yet). Used by #2472 to\n * split total subprocess time into spawn-latency (spawn→first byte) and\n * streaming (first byte→close), which is the cheapest way to identify\n * which stage causes stochastic timeouts.\n */\n firstByteTime: number | null;\n}\n\n/** Append data to a buffered stream, respecting the 10 MB cap. */\nfunction appendBuffered(state: BufferState, stream: 'stdout' | 'stderr', data: Buffer): void {\n const bytesKey = stream === 'stdout' ? 'stdoutBytes' : 'stderrBytes';\n const truncKey = stream === 'stdout' ? 'stdoutTruncated' : 'stderrTruncated';\n if (state[bytesKey] < MAX_BUFFER_BYTES) {\n state[stream] += data.toString();\n state[bytesKey] += data.length;\n } else if (!state[truncKey]) {\n state[truncKey] = true;\n subprocessLogger.warn(`${stream} buffer exceeded 10 MB, truncating`);\n }\n}\n\n/**\n * Command configuration returned by getCommand.\n */\nexport interface CommandConfig {\n command: string;\n args: string[];\n /** Optional stdin content (prompt passed via stdin instead of args) */\n stdin?: string;\n /**\n * Optional cleanup callback invoked after the subprocess resolves\n * (success, error, or timeout). Used by adapters that materialize\n * temp files for the subprocess (e.g. codex `model_instructions_file`).\n * Errors thrown by cleanup are logged but do not affect the request result.\n */\n cleanup?: () => void | Promise<void>;\n}\n\n/**\n * Configuration for transient-error retry behaviour.\n */\nexport interface TransientRetryConfig {\n /** Whether transient-error retry is enabled (default: false). */\n enabled: boolean;\n}\n\n/**\n * Base class for subprocess-based CLI adapters.\n * Used by ClaudeCliAdapter and GeminiCliAdapter.\n */\nexport abstract class SubprocessCliAdapter extends BaseCliAdapter {\n readonly transport: CliTransport = 'subprocess';\n\n protected abstract readonly parser: ICliResponseParser;\n\n /** Transient-error retry config. Override in subclass to enable. */\n protected readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n /**\n * The inner {@link retryTransient} layer is the single retry authority\n * for subprocess CLIs. When it is enabled (the default), the shared\n * outer retry loop must not also retry: nesting both meant up to 6\n * subprocess spawns and ~10-minute hangs on a persistent TIMEOUT, since\n * the inner layer's timeout extension compounds on every outer attempt\n * (#2824). The outer loop still runs once, so circuit-breaker failure\n * recording is unaffected.\n */\n protected override shouldOuterRetry(opts: Required<ExecutionOptions>): boolean {\n return opts.allowRetry && !this.transientRetry.enabled;\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * If stdin is provided, it will be written to the process stdin.\n */\n protected abstract getCommand(task: CliTask): CommandConfig;\n\n /**\n * Executes a task via subprocess, with optional transient-error retry.\n * When `transientRetry.enabled` is true, transient errors (timeout,\n * rate_limit, connection, parse) are retried with exponential backoff\n * (500ms, 1000ms). Parse errors get max 1 retry (#1533); others get 2.\n */\n async executeTask(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const result = await this.spawnSubprocess(task, options);\n if (result.ok || !this.transientRetry.enabled) return result;\n if (!isTransientError(result.error.code)) return result;\n\n return this.retryTransient(task, options, result, 0);\n }\n\n /**\n * Retries a transient error with bounded exponential backoff.\n */\n private async retryTransient(\n task: CliTask,\n options: Required<ExecutionOptions>,\n lastResult: Result<CliResponse, CliError>,\n attempt: number\n ): Promise<Result<CliResponse, CliError>> {\n const isParseError = !lastResult.ok && lastResult.error.code === 'PARSE_ERROR';\n const maxRetries = isParseError ? MAX_PARSE_RETRIES : MAX_TRANSIENT_RETRIES;\n if (attempt >= maxRetries) return lastResult;\n\n // Guard above ensures attempt < maxRetries ≤ TRANSIENT_RETRY_DELAYS_MS.length\n const delayMs = TRANSIENT_RETRY_DELAYS_MS[attempt] as number;\n const isTimeout = !lastResult.ok && lastResult.error.code === 'TIMEOUT';\n subprocessLogger.debug('Retrying transient error', {\n cli: this.name,\n attempt: attempt + 1,\n delayMs,\n errorCode: !lastResult.ok ? lastResult.error.code : undefined,\n });\n\n await this.delay(delayMs);\n\n // Extend timeout on TIMEOUT retries so near-miss tasks can complete (#1401)\n const retryOptions = isTimeout\n ? { ...options, timeoutMs: Math.round(options.timeoutMs * TIMEOUT_RETRY_MULTIPLIER) }\n : options;\n const result = await this.spawnSubprocess(task, retryOptions);\n if (result.ok) return result;\n if (!isTransientError(result.error.code)) return result;\n\n return this.retryTransient(task, retryOptions, result, attempt + 1);\n }\n\n /**\n * Spawns a single subprocess execution (no retry).\n */\n private spawnSubprocess(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const cmdConfig = this.getCommand(task);\n const startTime = getTimeProvider().now();\n\n const cleanup = cmdConfig.cleanup;\n const runCleanup = (): void => {\n if (cleanup === undefined) return;\n try {\n const r = cleanup();\n if (r instanceof Promise) {\n r.catch((e: unknown) => {\n this.logger.warn('Subprocess cleanup failed', { error: String(e) });\n });\n }\n } catch (e: unknown) {\n this.logger.warn('Subprocess cleanup threw', { error: String(e) });\n }\n };\n\n return new Promise((resolveOuter) => {\n const resolve = (result: Result<CliResponse, CliError>): void => {\n runCleanup();\n resolveOuter(result);\n };\n // Curated child env: base infrastructure vars + only this CLI's\n // own vendor credentials, so cross-vendor API keys don't leak\n // into the spawned CLI (#2865). Also drops CLAUDECODE — a nested\n // CLI must not believe it's already inside Claude Code.\n const childEnv = buildChildEnv(this.name);\n\n const child = spawn(cmdConfig.command, cmdConfig.args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: childEnv,\n });\n\n const onProgress = options.onProgress;\n const state = this.setupChildProcessHandlers(\n child,\n startTime,\n options.timeoutMs,\n resolve,\n onProgress\n );\n\n // Write stdin content if provided and close stdin\n if (cmdConfig.stdin !== undefined) {\n child.stdin.write(cmdConfig.stdin);\n }\n child.stdin.end();\n\n // Reference state to prevent unused variable warning\n void state;\n });\n }\n\n /**\n * Sets up child process event handlers for output collection and error handling.\n */\n private setupChildProcessHandlers(\n child: ReturnType<typeof spawn>,\n startTime: number,\n timeoutMs: number,\n resolve: (result: Result<CliResponse, CliError>) => void,\n onProgress?: () => void\n ): BufferState {\n const state: BufferState = {\n stdout: '',\n stderr: '',\n resolved: false,\n stdoutBytes: 0,\n stderrBytes: 0,\n stdoutTruncated: false,\n stderrTruncated: false,\n firstByteTime: null,\n };\n\n const resolveOnce = (result: Result<CliResponse, CliError>): void => {\n if (!state.resolved) {\n state.resolved = true;\n resolve(result);\n }\n };\n\n this.attachStdoutHandlers(child, state, onProgress);\n\n child.on('error', (error: Error) => {\n resolveOnce(this.handleSubprocessError(error));\n });\n\n const timeoutId = setTimeout(() => {\n child.kill('SIGTERM');\n resolveOnce(err(this.createError('TIMEOUT', 'Execution timed out')));\n }, timeoutMs);\n\n child.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n this.logTimingBreakdown(state, startTime, code);\n resolveOnce(this.classifyCloseResult(code, state, startTime));\n });\n\n return state;\n }\n\n /** Attach stdout/stderr data handlers + capture first-byte time (#2472). */\n private attachStdoutHandlers(\n child: ReturnType<typeof spawn>,\n state: BufferState,\n onProgress?: () => void\n ): void {\n // stdio: ['pipe', 'pipe', 'pipe'] guarantees non-null streams\n if (child.stdout !== null) {\n child.stdout.on('data', (data: Buffer) => {\n if (state.firstByteTime === null && data.length > 0) {\n state.firstByteTime = getTimeProvider().now();\n }\n appendBuffered(state, 'stdout', data);\n onProgress?.();\n });\n }\n if (child.stderr !== null) {\n child.stderr.on('data', (data: Buffer) => {\n appendBuffered(state, 'stderr', data);\n });\n }\n }\n\n /**\n * Log spawn-latency vs streaming breakdown at info level (#2472). Emits\n * one structured event per subprocess invocation, queryable via the\n * existing trace JSONL infrastructure. The breakdown lets operators\n * identify whether a slow run was caused by:\n * - High spawn-latency: model gateway took its time before producing\n * the first token (cold-start, queueing, network jitter).\n * - High streaming-time: response body was large or generation slow.\n * - Total approaches the timeout cap with no first-byte: hung process.\n *\n * Structured fields chosen so existing query_trace tooling can group by\n * cli + provider + model and surface tail-latency outliers.\n */\n private logTimingBreakdown(state: BufferState, startTime: number, code: number | null): void {\n const now = getTimeProvider().now();\n const totalMs = now - startTime;\n const spawnLatencyMs = state.firstByteTime === null ? null : state.firstByteTime - startTime;\n const streamingMs = state.firstByteTime === null ? null : now - state.firstByteTime;\n this.logger.info('Subprocess timing', {\n cli: this.name,\n totalMs,\n spawnLatencyMs,\n streamingMs,\n sawFirstByte: state.firstByteTime !== null,\n exitCode: code,\n stdoutBytes: state.stdoutBytes,\n stderrBytes: state.stderrBytes,\n });\n }\n\n /** Classify a subprocess close event into a Result. */\n private classifyCloseResult(\n code: number | null,\n state: BufferState,\n startTime: number\n ): Result<CliResponse, CliError> {\n // Redact API keys from output before any processing, logging, or tracing (#1597)\n state.stdout = sanitizeOutput(state.stdout);\n state.stderr = sanitizeOutput(state.stderr);\n\n if (code !== 0 && state.stdout === '') {\n // Stderr classification takes priority over exit code (#1401)\n if (state.stderr !== '') {\n const msg = state.stderr;\n return err(this.createError(classifyStderrError(state.stderr), msg));\n }\n // Signal-killed processes (137=SIGKILL/OOM, 143=SIGTERM) are transient.\n // Message includes signal name for downstream outcome classification.\n const msg = code !== null ? buildSignalExitMessage(code) : 'Process exited with unknown code';\n if (isTransientExitCode(code)) {\n return err(this.createError('CONNECTION_ERROR', msg));\n }\n return err(this.createError('EXECUTION_ERROR', msg));\n }\n // Non-zero exit with stderr errors: classify specifically to enable\n // transient retry for connection/rate-limit/timeout errors (#1401, #1402)\n if (code !== 0 && state.stderr !== '' && looksLikeErrorStderr(state.stderr)) {\n const msg = `Exit code ${String(code)}: ${state.stderr.slice(0, 500).trim()}`;\n return err(this.createError(classifyStderrError(state.stderr), msg));\n }\n return this.handleSubprocessOutput(state.stdout, state.stderr, startTime);\n }\n\n /**\n * Handles successful subprocess output.\n */\n private handleSubprocessOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (stderr !== '' && stdout === '') {\n return err(this.createError('EXECUTION_ERROR', stderr));\n }\n\n const text = this.parser.extractResponse(stdout);\n if (text === null) {\n return this.handleUnparseableOutput(stdout, stderr, startTime);\n }\n\n const usage = this.parser.extractUsage(stdout);\n const sessionId = this.parser.extractSessionId(stdout);\n\n return ok(\n this.normalizeResponse(text, usage ?? undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n ...(sessionId !== null && { sessionId }),\n })\n );\n }\n\n /**\n * Handles the parse-failure branch: when the CLI's structured response\n * parser returned null. Order of recovery attempts (most-specific first):\n * 1. Rate-limit text in raw stdout (#1320)\n * 2. Structured CLI error envelope (#2440)\n * 3. Plaintext fallback for natural-language output (#1401)\n * 4. Generic PARSE_ERROR with truncated snippet\n */\n private handleUnparseableOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (isRateLimitText(stdout)) {\n const snippet = stdout.slice(0, 500).trim();\n return err(this.createError('RATE_LIMITED', snippet));\n }\n const envelope = parseCliErrorEnvelope(stdout, this.name);\n if (envelope !== null) {\n const msg =\n envelope.hint !== undefined\n ? `${envelope.message}\\n → ${envelope.hint}`\n : envelope.message;\n // #2455 ask 3: at debug level, dump the full sanitized envelope so\n // operators can recover context without re-running. Sanitized via\n // output-sanitizer.ts so leaked tokens (some upstreams echo back the\n // bad token in error responses) don't reach logs.\n subprocessLogger.debug('CLI error envelope unwrapped', {\n cli: this.name,\n code: envelope.code,\n rawSanitized: sanitizeOutput(stdout),\n });\n return err(this.createError(envelope.code, msg));\n }\n const plaintext = tryPlaintextFallback(stdout);\n if (plaintext !== null) {\n subprocessLogger.debug('Using plaintext fallback for unparseable output', {\n rawSanitized: sanitizeOutput(stdout),\n });\n return ok(\n this.normalizeResponse(plaintext, undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n })\n );\n }\n const snippet = stdout.slice(0, 500).trim();\n const stderrHint = stderr !== '' ? ` [stderr: ${stderr.slice(0, 300).trim()}]` : '';\n return err(\n this.createError('PARSE_ERROR', `Failed to parse response: ${snippet}${stderrHint}`)\n );\n }\n\n /**\n * Handles subprocess execution errors.\n */\n private handleSubprocessError(error: unknown): Result<CliResponse, CliError> {\n if (!(error instanceof Error)) {\n return err(this.createError('EXECUTION_ERROR', 'Unknown error'));\n }\n\n if (error.message.includes('ETIMEDOUT') || error.message.includes('timeout')) {\n return err(this.createError('TIMEOUT', 'Execution timed out', error));\n }\n\n if (error.message.includes('ENOENT')) {\n return err(this.createError('NOT_FOUND', `${this.name} CLI not found`, error));\n }\n\n return err(this.createError('EXECUTION_ERROR', sanitizeOutput(error.message), error));\n }\n\n /**\n * Initializes the adapter and capacity tracker.\n */\n initialize(): Promise<void> {\n this.initCapacityTracker();\n this.initialized = true;\n return Promise.resolve();\n }\n\n /**\n * Disposes the adapter (no-op for subprocess).\n */\n dispose(): Promise<void> {\n this.initialized = false;\n return Promise.resolve();\n }\n}\n","/**\n * nexus-agents/cli-adapters - Base Adapter\n *\n * Abstract base class for CLI adapters with common functionality.\n * Provides version checking, health checks, and error handling.\n *\n * SubprocessCliAdapter extracted to subprocess-adapter.ts per Issue #272.\n *\n * (Source: cli-project_plan.md v2.1.0)\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport semver from 'semver';\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\n\nimport type { Result } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\n\nimport type {\n ICliAdapter,\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n HealthStatus,\n CapacityStatus,\n ModelInfo,\n CapabilityProfile,\n ExecutionOptions,\n VersionStatus,\n TokenUsage,\n} from './types.js';\nimport { CLI_VERSION_REQUIREMENTS, DEFAULT_CAPABILITIES } from './types.js';\nimport { getTimeoutForTaskAuto } from './cli-timeout-profiles.js';\nimport { CapacityTracker, createCapacityTracker } from './capacity-tracker.js';\nimport { executeCliRetryLoop } from './cli-retry-loop.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Fallback capacity (in tokens) when capacity tracker is uninitialized.\n * Uses a realistic 100k token budget instead of MAX_SAFE_INTEGER to prevent\n * downstream consumers from treating the adapter as having unlimited capacity.\n * Issue #1463.\n */\nexport const DEFAULT_CAPACITY_FALLBACK = 100_000;\n\n/**\n * Default execution options.\n *\n * Timeout reduced from 120s to 60s per Issue #280 to prevent\n * cascading timeouts in multi-agent voting scenarios.\n */\nconst DEFAULT_OPTIONS: Required<ExecutionOptions> = {\n timeoutMs: 60_000, // 1 minute (reduced from 2 minutes per Issue #280)\n allowRetry: true,\n maxRetries: 1, // Reduced from 2 to prevent 3+ minute total wait\n trackUsage: true,\n onProgress: undefined,\n};\n\n/**\n * Abstract base class for CLI adapters.\n * Provides common functionality for version checking, health, and error handling.\n */\nexport abstract class BaseCliAdapter implements ICliAdapter {\n abstract readonly name: CliName;\n abstract readonly transport: CliTransport;\n\n protected readonly logger: ILogger;\n protected capacityTracker: CapacityTracker | null = null;\n protected initialized = false;\n protected lastHealthCheck?: HealthStatus;\n protected cachedVersion?: string;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'cli-adapter' });\n }\n\n /**\n * Initializes the capacity tracker.\n * Called by subclasses after name is set.\n */\n protected initCapacityTracker(): void {\n this.capacityTracker = createCapacityTracker(this.name);\n }\n\n /**\n * Gets the capability profile for this CLI.\n */\n get capabilities(): CapabilityProfile {\n return DEFAULT_CAPABILITIES[this.name];\n }\n\n /**\n * Abstract method for executing a task.\n * Implemented by concrete adapters.\n */\n abstract executeTask(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>>;\n\n /**\n * Abstract method for getting model info.\n * Implemented by concrete adapters.\n */\n abstract getModelInfo(): ModelInfo;\n\n /**\n * Abstract method for initialization.\n * Implemented by concrete adapters.\n */\n abstract initialize(): Promise<void>;\n\n /**\n * Abstract method for cleanup.\n * Implemented by concrete adapters.\n */\n abstract dispose(): Promise<void>;\n\n /**\n * Executes a task with error handling and retries.\n *\n * Timeout priority (highest to lowest):\n * 1. options.timeoutMs - explicit execution option\n * 2. task.timeoutMs - task-level setting\n * 3. getTimeoutForTaskAuto() - computed from task complexity and CLI\n */\n async execute(task: CliTask, options?: ExecutionOptions): Promise<Result<CliResponse, CliError>> {\n const effectiveTimeout = this.computeTimeout(task, options);\n const opts = { ...DEFAULT_OPTIONS, ...options, timeoutMs: effectiveTimeout };\n\n if (!this.initialized) {\n await this.initialize();\n }\n\n this.logger.debug('Executing task', {\n cli: this.name,\n contentLength: task.content.length,\n model: task.model,\n timeoutMs: effectiveTimeout,\n });\n\n return this.executeWithRetry(task, opts);\n }\n\n /**\n * Computes effective timeout for a task.\n */\n private computeTimeout(task: CliTask, options?: ExecutionOptions): number {\n if (options?.timeoutMs !== undefined) return options.timeoutMs;\n if (task.timeoutMs !== undefined) return task.timeoutMs;\n return getTimeoutForTaskAuto(this.name, task.content);\n }\n\n /**\n * Whether the shared outer retry loop ({@link executeCliRetryLoop}) is\n * allowed to retry this adapter's failures. The base adapter honors the\n * caller's `allowRetry`. Subprocess adapters override this to suppress\n * the outer loop when their own transient-retry layer is active, so the\n * two layers do not nest into multiplied spawns (#2824).\n */\n protected shouldOuterRetry(opts: Required<ExecutionOptions>): boolean {\n return opts.allowRetry;\n }\n\n /**\n * Executes task with retry logic via shared retry loop.\n */\n private async executeWithRetry(\n task: CliTask,\n opts: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const result = await executeCliRetryLoop(() => this.executeTask(task, opts), {\n maxRetries: opts.maxRetries,\n allowRetry: this.shouldOuterRetry(opts),\n baseDelayMs: 1_000,\n maxDelayMs: 16_000,\n cli: this.name,\n logger: this.logger,\n });\n\n if (result.ok) {\n this.recordUsage(result.value.response);\n this.logger.info('Task executed successfully', {\n cli: this.name,\n attempt: result.value.retryCount + 1,\n durationMs: result.value.response.durationMs,\n tokensUsed: result.value.response.usage?.totalTokens,\n });\n return { ok: true, value: result.value.response };\n }\n\n this.logger.warn('Task execution failed', {\n cli: this.name,\n error: result.error.message,\n retryable: result.error.retryable,\n });\n return result;\n }\n\n /**\n * Performs a health check.\n */\n async healthCheck(): Promise<HealthStatus> {\n try {\n const version = await this.getVersion();\n const versionStatus = this.checkVersionCompatibility(version);\n\n const message = this.getVersionMessage(versionStatus, version);\n const status: HealthStatus = {\n healthy: versionStatus !== 'unsupported' && versionStatus !== 'breaking',\n version,\n versionStatus,\n lastChecked: new Date(getTimeProvider().now()),\n ...(message !== undefined && { message }),\n };\n\n this.lastHealthCheck = status;\n return status;\n } catch (error) {\n return {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n message: error instanceof Error ? error.message : 'Health check failed',\n lastChecked: new Date(getTimeProvider().now()),\n };\n }\n }\n\n /**\n * Gets CLI version.\n */\n async getVersion(): Promise<string> {\n if (this.cachedVersion !== undefined && this.cachedVersion !== '') {\n return this.cachedVersion;\n }\n\n try {\n const { stdout } = await execAsync(`${this.name} --version`, {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n\n // Extract version number from output\n const version = this.parseVersion(stdout.trim());\n this.cachedVersion = version;\n return version;\n } catch (cause: unknown) {\n throw new Error(`Failed to get ${this.name} version`, { cause });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n * Uses usage-based tracking since CLI subprocess execution\n * doesn't expose HTTP rate limit headers.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n getCapacity(): Promise<CapacityStatus> {\n // Lazy-init the tracker if no caller has run initialize() yet (#2714).\n // Pre-fix every doctor invocation tripped this path: doctor calls\n // adapter.getCapacity() WITHOUT first calling adapter.initialize(),\n // so each of the four adapters logged a \"Capacity tracker uninitialized\"\n // WARN and returned a hardcoded 100k-token fallback. The fallback\n // surfaced in doctor's output as \"Capacity: 100% remaining\" — a\n // fictional reading, not a real one. The tracker is per-process and\n // idempotent under createCapacityTracker, so initializing on first\n // read is safe.\n if (this.capacityTracker === null) {\n this.initCapacityTracker();\n }\n const tracker = this.capacityTracker;\n if (tracker === null) {\n // Unreachable in practice — initCapacityTracker assigns the field —\n // but keep the type-safe path for the impossible case.\n throw new Error(`Capacity tracker initialization failed for ${this.name}`);\n }\n return Promise.resolve(tracker.getCapacity());\n }\n\n /**\n * Records usage from a response for capacity tracking.\n */\n protected recordUsage(response: CliResponse): void {\n if (this.capacityTracker !== null) {\n this.capacityTracker.recordUsage(response.usage);\n }\n }\n\n /**\n * Parses version from CLI output.\n */\n protected parseVersion(output: string): string {\n // Handle common version formats:\n // \"2.0.76 (Claude Code)\"\n // \"0.22.5\"\n // \"codex-cli 0.77.0\"\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output);\n return match?.[1] ?? '0.0.0';\n }\n\n /**\n * Checks version compatibility.\n */\n protected checkVersionCompatibility(version: string): VersionStatus {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n const validVersion = semver.valid(version);\n if (validVersion === null) {\n return 'unsupported';\n }\n\n const isLtMinimum = semver.lt(validVersion, requirements.minimum);\n if (isLtMinimum) {\n return 'unsupported';\n }\n\n const hasBreaking = requirements.breaking.some((v) => semver.gte(validVersion, v));\n if (hasBreaking) {\n return 'breaking';\n }\n\n const isLtRecommended = semver.lt(validVersion, requirements.recommended);\n if (isLtRecommended) {\n return 'outdated';\n }\n\n return 'supported';\n }\n\n /**\n * Gets version status message.\n */\n protected getVersionMessage(status: VersionStatus, version: string): string | undefined {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n switch (status) {\n case 'unsupported':\n return `Version ${version} is not supported. Minimum: ${requirements.minimum}`;\n case 'breaking':\n return `Version ${version} has known compatibility issues`;\n case 'outdated':\n return `Consider upgrading to ${requirements.recommended}`;\n case 'supported':\n return undefined;\n }\n }\n\n /**\n * Creates a CLI error.\n */\n protected createError(code: CliErrorCode, message: string, cause?: Error): CliError {\n const retryable = ['RATE_LIMITED', 'TIMEOUT', 'CONNECTION_ERROR'].includes(code);\n\n return {\n code,\n message,\n cli: this.name,\n retryable,\n ...(cause !== undefined && { cause }),\n };\n }\n\n /**\n * Normalizes CLI response to common format.\n */\n protected normalizeResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n ): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n }\n\n /**\n * Delays for the specified milliseconds.\n */\n protected delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * CLI Timeout Helpers\n *\n * Task complexity estimation for timeout selection.\n * Separated from timeout values (which live in config/timeouts.ts).\n *\n * @module cli-adapters/cli-timeout-helpers\n * (Source: Issue #984 — Centralize timeout configuration)\n */\n\nimport type { TaskComplexity } from '../config/timeouts.js';\nimport { getCliTimeout } from '../config/timeouts.js';\nimport { detectTaskCategory } from '../config/task-specialization.js';\nimport { getOutcomeStore } from '../orchestration/outcomes/outcome-store.js';\nimport type { CliNameLiteral } from '../config/model-capabilities-types.js';\n\n/**\n * Estimate task complexity from task description.\n *\n * Heuristics based on testing:\n * - Simple: Single function, quick query, < 5 files\n * - Standard: Multi-file changes, moderate analysis\n * - Complex: Codebase-wide, deep analysis, architecture\n *\n * @param taskDescription - Description of the task\n * @returns Estimated complexity\n */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n const lower = taskDescription.toLowerCase();\n\n // Complex indicators\n const complexIndicators = [\n 'codebase',\n 'architecture',\n 'refactor',\n 'all files',\n 'entire',\n 'comprehensive',\n 'deep analysis',\n 'system-wide',\n 'security',\n 'audit',\n 'vulnerability',\n ];\n if (complexIndicators.some((indicator) => lower.includes(indicator))) {\n return 'complex';\n }\n\n // Simple indicators\n // Testing and exploration demoted to simple per weather data (99%+ success) (#1401)\n const simpleIndicators = [\n 'single',\n 'quick',\n 'one function',\n 'simple',\n 'small',\n 'brief',\n 'short',\n 'run tests',\n 'test suite',\n 'exploration',\n 'explore',\n ];\n if (simpleIndicators.some((indicator) => lower.includes(indicator))) {\n return 'simple';\n }\n\n // Default to standard\n return 'standard';\n}\n\n// ============================================================================\n// Adaptive Timeout (#1534)\n// ============================================================================\n\n/** Minimum successful outcomes required before adaptive timeout kicks in. */\nexport const ADAPTIVE_TIMEOUT_MIN_SAMPLES = 10;\n\n/** Safety margin applied to p95 duration (p95 * margin = adaptive timeout). */\nexport const ADAPTIVE_TIMEOUT_MARGIN = 1.2;\n\n/**\n * Compute p95 of a sorted array of numbers.\n * Returns the value at the 95th percentile index.\n */\nfunction computeP95(sorted: readonly number[]): number {\n if (sorted.length === 0) return 0;\n const idx = Math.ceil(sorted.length * 0.95) - 1;\n return sorted[Math.min(idx, sorted.length - 1)] as number;\n}\n\n/** Options for adaptive timeout computation. */\nexport interface AdaptiveTimeoutOptions {\n /** Override the outcome store (for testing). */\n readonly store?: import('../orchestration/outcomes/outcome-store.js').OutcomeStore;\n}\n\n/**\n * Get adaptive timeout for a CLI + task description pair.\n *\n * Uses historical outcome data to compute p95 execution duration.\n * When sufficient samples exist, returns max(static_timeout, p95 * 1.2).\n * Falls back to static keyword-based timeout when data is sparse.\n *\n * @param cli - CLI name\n * @param taskDescription - Task description for complexity + category detection\n * @param options - Optional overrides (e.g., custom store for testing)\n * @returns Timeout in milliseconds (never less than static timeout)\n */\nexport function getAdaptiveTimeout(\n cli: string,\n taskDescription: string,\n options?: AdaptiveTimeoutOptions\n): number {\n const complexity = estimateTaskComplexity(taskDescription);\n const staticTimeout = getCliTimeout(cli, complexity);\n\n const match = detectTaskCategory(taskDescription);\n if (match === null) return staticTimeout;\n\n const store = options?.store ?? getOutcomeStore();\n const outcomes = store.query({\n cli: cli as CliNameLiteral,\n category: match.category,\n success: true,\n });\n\n if (outcomes.length < ADAPTIVE_TIMEOUT_MIN_SAMPLES) return staticTimeout;\n\n const durations = outcomes.map((o) => o.durationMs).sort((a, b) => a - b);\n const p95 = computeP95(durations);\n const adaptiveTimeout = Math.round(p95 * ADAPTIVE_TIMEOUT_MARGIN);\n\n return Math.max(staticTimeout, adaptiveTimeout);\n}\n","/**\n * CLI Timeout Profiles - Configurable timeouts per CLI tool.\n *\n * Delegates to `config/timeouts.ts` (canonical source, Issue #984).\n * This file provides backward-compatible re-exports.\n *\n * @module cli-adapters/cli-timeout-profiles\n * (Source: Issue #357, CLI delegation testing 2026-01-18)\n */\n\nimport {\n CLI_TIMEOUTS,\n getCliTimeout,\n type TaskComplexity,\n type TimeoutProfile,\n} from '../config/timeouts.js';\nimport {\n estimateTaskComplexity as _estimateTaskComplexity,\n getAdaptiveTimeout,\n} from './cli-timeout-helpers.js';\n\n// Re-export types for backward compatibility\nexport type { TimeoutProfile, TaskComplexity };\n\n/** Per-CLI timeout profiles. Canonical source: `config/timeouts.ts`. */\nexport const CLI_TIMEOUT_PROFILES: Record<string, TimeoutProfile> = {\n claude: CLI_TIMEOUTS.claude,\n gemini: CLI_TIMEOUTS.gemini,\n codex: CLI_TIMEOUTS.codex,\n};\n\n/** Default timeout profile. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_TIMEOUT_PROFILE: TimeoutProfile = CLI_TIMEOUTS.default;\n\n/** Get timeout for a task. Canonical source: `config/timeouts.ts`. */\nexport function getTimeoutForTask(cli: string, complexity: TaskComplexity): number {\n return getCliTimeout(cli, complexity);\n}\n\n/** Estimate task complexity from description. Canonical: `cli-timeout-helpers.ts`. */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n return _estimateTaskComplexity(taskDescription);\n}\n\n/**\n * Get timeout with automatic complexity estimation.\n * Uses adaptive timeout from outcome history when sufficient data exists (#1534).\n */\nexport function getTimeoutForTaskAuto(cli: string, taskDescription: string): number {\n return getAdaptiveTimeout(cli, taskDescription);\n}\n","/**\n * nexus-agents/cli-adapters - Capacity Tracker\n *\n * Usage-based capacity tracking for CLI adapters.\n * Tracks cumulative token/request usage to estimate remaining capacity.\n *\n * Since CLI subprocess execution doesn't expose HTTP rate limit headers,\n * this tracker estimates capacity based on usage patterns.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n\nimport type { CliName, TokenUsage, CapacityStatus } from './types-core.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { clampPercent } from '../utils/math-utils.js';\n\n/**\n * Default rate limits per CLI provider (tokens per minute).\n * These are conservative estimates based on typical API tiers.\n * Override via environment variables: NEXUS_<CLI>_TOKEN_LIMIT\n */\nexport const DEFAULT_TOKEN_LIMITS: Record<CliName, number> = {\n claude: 100_000, // Claude API Build tier\n gemini: 1_000_000, // Gemini Pro generous limits\n codex: 500_000, // OpenAI tier 1\n opencode: 500_000, // Multi-provider proxy\n};\n\n/**\n * Default request limits per CLI provider (requests per minute).\n * Override via environment variables: NEXUS_<CLI>_REQUEST_LIMIT\n */\nexport const DEFAULT_REQUEST_LIMITS: Record<CliName, number> = {\n claude: 50, // Claude API Build tier\n gemini: 60, // Gemini Pro\n codex: 500, // OpenAI tier 1\n opencode: 300, // Multi-provider proxy\n};\n\n/**\n * Rate limit window in milliseconds (1 minute).\n */\nexport const RATE_LIMIT_WINDOW_MS = 60_000;\n\n/**\n * Configuration for capacity tracker.\n */\nexport interface CapacityTrackerConfig {\n /** Maximum tokens per window */\n readonly tokenLimit: number;\n /** Maximum requests per window */\n readonly requestLimit: number;\n /** Window duration in milliseconds */\n readonly windowMs: number;\n}\n\n/**\n * Tracked usage entry with timestamp.\n */\ninterface UsageEntry {\n readonly timestamp: number;\n readonly tokens: number;\n}\n\n/**\n * Creates default configuration for a CLI from environment or defaults.\n */\nexport function getDefaultConfig(cli: CliName): CapacityTrackerConfig {\n const envPrefix = `NEXUS_${cli.toUpperCase()}`;\n const tokenEnv = process.env[`${envPrefix}_TOKEN_LIMIT`];\n const requestEnv = process.env[`${envPrefix}_REQUEST_LIMIT`];\n\n return {\n tokenLimit:\n tokenEnv !== undefined && tokenEnv !== ''\n ? parseInt(tokenEnv, 10)\n : DEFAULT_TOKEN_LIMITS[cli],\n requestLimit:\n requestEnv !== undefined && requestEnv !== ''\n ? parseInt(requestEnv, 10)\n : DEFAULT_REQUEST_LIMITS[cli],\n windowMs: RATE_LIMIT_WINDOW_MS,\n };\n}\n\n/**\n * Capacity tracker for CLI adapters.\n *\n * Tracks cumulative usage within a sliding window to estimate\n * remaining capacity when HTTP headers are not available.\n *\n * @example\n * ```typescript\n * const tracker = new CapacityTracker(getDefaultConfig('claude'));\n *\n * // Record usage after each request\n * tracker.recordUsage({ inputTokens: 1000, outputTokens: 500 });\n *\n * // Get current capacity status\n * const status = tracker.getCapacity();\n * if (status.exhausted) {\n * // Wait before next request\n * }\n * ```\n */\nexport class CapacityTracker {\n private readonly config: CapacityTrackerConfig;\n private readonly usageHistory: UsageEntry[];\n private requestCount: number;\n private windowStart: number;\n\n constructor(config: CapacityTrackerConfig) {\n this.config = config;\n this.usageHistory = [];\n this.requestCount = 0;\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Records token usage from a completed request.\n */\n recordUsage(usage: TokenUsage | undefined): void {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n this.requestCount++;\n\n if (usage !== undefined) {\n const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;\n this.usageHistory.push({\n timestamp: now,\n tokens,\n });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n */\n getCapacity(): CapacityStatus {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n const usedTokens = this.usageHistory.reduce((sum, entry) => sum + entry.tokens, 0);\n const remainingTokens = Math.max(0, this.config.tokenLimit - usedTokens);\n const remainingRequests = Math.max(0, this.config.requestLimit - this.requestCount);\n\n const tokenUtilization = (usedTokens / this.config.tokenLimit) * 100;\n const requestUtilization = (this.requestCount / this.config.requestLimit) * 100;\n const utilizationPercent = clampPercent(Math.max(tokenUtilization, requestUtilization));\n\n const exhausted = remainingTokens === 0 || remainingRequests === 0;\n const resetTime = new Date(this.windowStart + this.config.windowMs);\n\n return {\n remainingTokens,\n remainingRequests,\n resetTime,\n utilizationPercent: Math.round(utilizationPercent * 100) / 100,\n exhausted,\n };\n }\n\n /**\n * Gets time until the rate limit window resets.\n */\n getTimeUntilReset(): number {\n const now = getTimeProvider().now();\n const resetTime = this.windowStart + this.config.windowMs;\n return Math.max(0, resetTime - now);\n }\n\n /**\n * Resets all tracked usage (for testing or manual reset).\n */\n reset(): void {\n this.usageHistory.length = 0;\n this.requestCount = 0;\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Updates configuration (e.g., after receiving actual rate limit info).\n */\n updateConfig(partial: Partial<CapacityTrackerConfig>): void {\n Object.assign(this.config, partial);\n }\n\n /**\n * Gets current configuration.\n */\n getConfig(): Readonly<CapacityTrackerConfig> {\n return { ...this.config };\n }\n\n /**\n * Removes entries older than the window duration.\n */\n private pruneOldEntries(now: number): void {\n const cutoff = now - this.config.windowMs;\n\n // If window has fully elapsed, reset everything\n if (this.windowStart < cutoff) {\n this.usageHistory.length = 0;\n this.requestCount = 0;\n this.windowStart = now;\n return;\n }\n\n // Remove old entries from history\n let firstEntry = this.usageHistory[0];\n while (firstEntry !== undefined && firstEntry.timestamp < cutoff) {\n this.usageHistory.shift();\n firstEntry = this.usageHistory[0];\n }\n }\n}\n\n/**\n * Creates a capacity tracker for a specific CLI.\n */\nexport function createCapacityTracker(cli: CliName): CapacityTracker {\n return new CapacityTracker(getDefaultConfig(cli));\n}\n","import { getErrorMessage } from '../core/index.js';\n\n/**\n * Async Utilities\n *\n * Centralized async helper functions for delay, timeout, and promise utilities.\n * Consolidates 9+ duplicate sleep/delay implementations across the codebase.\n *\n * @module utils/async-utils\n * (Source: LOOP H-K consolidation)\n */\n\n// ============================================================================\n// Delay / Sleep\n// ============================================================================\n\n/**\n * Creates a promise that resolves after the specified delay.\n * Alias: `delay` (both names are exported for compatibility)\n *\n * @param ms - Delay in milliseconds\n * @returns Promise that resolves after the delay\n *\n * @example\n * ```typescript\n * await sleep(1000); // Wait 1 second\n * await delay(500); // Wait 500ms (alias)\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Alias for `sleep()` - provided for compatibility with existing code.\n */\nexport const delay = sleep;\n\n// ============================================================================\n// Timeout Wrapper\n// ============================================================================\n\n/**\n * Result type for withTimeout operations.\n */\nexport type TimeoutResult<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: string };\n\n/**\n * Wraps a promise with a timeout.\n * Returns an error result if the timeout is exceeded.\n *\n * @param promise - The promise to wrap\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Error message if timeout is exceeded\n * @returns A result object with either the value or an error\n *\n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Request timed out after 5s'\n * );\n *\n * if (result.ok) {\n * console.log(result.value);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage: string\n): Promise<TimeoutResult<T>> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: true, value: result };\n } catch (error) {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: false, error: getErrorMessage(error) };\n }\n}\n\n// ============================================================================\n// Promise Utilities\n// ============================================================================\n\n/**\n * Executes promises in sequence, one at a time.\n *\n * @param tasks - Array of functions that return promises\n * @returns Array of results in order\n *\n * @example\n * ```typescript\n * const results = await sequence([\n * () => fetch('/api/1'),\n * () => fetch('/api/2'),\n * ]);\n * ```\n */\nexport async function sequence<T>(tasks: ReadonlyArray<() => Promise<T>>): Promise<T[]> {\n const results: T[] = [];\n for (const task of tasks) {\n results.push(await task());\n }\n return results;\n}\n","/**\n * Canonical helpers for constructing CliError values with the correct\n * `retryable` flag.\n *\n * Consolidates three previously-duplicated copies:\n * - `cli-retry-loop.ts` (as a module-local set + `isRetryableError`)\n * - `adapters/codex-adapter-helpers.ts` (as `createCodexError`)\n * - `adapters/codex-mcp-adapter-helpers.ts` (as `createCliError`)\n * - `testing/adapters/mock-adapter-helpers.ts` (as `createCliError`)\n *\n * Every call path that classifies retryable CLI errors should now flow\n * through here. Adding a new retryable code is a one-line change in one\n * place instead of four.\n *\n * (Issue #2181 — adapter harness consolidation)\n *\n * @module cli-adapters/cli-error-helpers\n */\n\nimport type { CliError, CliErrorCode, CliName } from './types.js';\n\n/** Error codes the retry machinery treats as transient. */\nexport const RETRYABLE_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set<CliErrorCode>([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n]);\n\n/** Whether a given CLI error code should be retried. */\nexport function isRetryableErrorCode(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Constructs a CliError with `retryable` auto-derived from the code.\n * Every adapter that needs to surface a CliError should prefer this\n * helper (or the `createError` method on `BaseCliAdapter`, which calls\n * into the same logic) rather than building the shape inline.\n */\nexport function createCliError(\n code: CliErrorCode,\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return {\n code,\n message,\n cli,\n retryable: isRetryableErrorCode(code),\n ...(cause !== undefined && { cause }),\n };\n}\n","/**\n * nexus-agents/cli-adapters - Unified CLI Retry Loop\n *\n * CLI-specific retry loop used by all CLI adapters (base + Gemini).\n * Supports optional circuit-breaker integration, returns CliResponse\n * with retryCount, and maps to FailureCategory for breaker tracking.\n *\n * Sibling implementation (see #2230): adapters/retry.ts holds the\n * generic, type-parameterized `withRetry<T>` for non-CLI use. Don't\n * reach for that one when you need circuit-breaker coupling; don't\n * reach for this one from non-CLI code. Math primitives differ\n * deliberately:\n * - this file: 1-indexed attempt, +0..30% jitter, cap-after\n * - adapters/retry.ts: 0-indexed attempt, ±jitterFactor, cap-before-jitter\n *\n * If you find yourself writing a third retry loop: stop, run\n * `consensus_vote` with scope_steward in the panel, and pick whichever\n * of these two fits — don't add a third.\n *\n * (Source: Issue #1596 — Extract shared prompt utils and rate-limit patterns)\n */\n\nimport type { Result } from '../core/index.js';\nimport { err, ok, getRandomProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type { CliResponse, CliError, CliErrorCode, CliName } from './types.js';\nimport type { ICircuitBreaker, FailureCategory } from './circuit-breaker-types.js';\nimport { delay } from '../utils/async-utils.js';\nimport { RETRYABLE_ERROR_CODES } from './cli-error-helpers.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CliRetryLoopConfig {\n readonly maxRetries: number;\n readonly allowRetry: boolean;\n readonly baseDelayMs: number;\n readonly maxDelayMs: number;\n readonly circuitBreaker?: ICircuitBreaker | null;\n readonly cli: CliName;\n readonly logger: ILogger;\n}\n\nexport interface CliRetryResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n}\n\n// ============================================================================\n// Retry Logic (moved from gemini-adapter-helpers.ts)\n// ============================================================================\n\n/**\n * Calculates exponential backoff delay with jitter.\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param baseDelayMs - Base delay in milliseconds\n * @param maxDelayMs - Maximum delay cap in milliseconds\n * @returns Delay in milliseconds with jitter applied\n */\nexport function calculateBackoffDelay(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number\n): number {\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);\n const jitter = getRandomProvider().random() * 0.3 * exponentialDelay;\n const delayMs = exponentialDelay + jitter;\n return Math.min(delayMs, maxDelayMs);\n}\n\n/** Determines if an error code is retryable. */\nexport function isRetryableError(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Categorizes a CLI error for circuit breaker tracking.\n * Returns a FailureCategory compatible with the circuit breaker.\n */\nexport function categorizeError(error: CliError): FailureCategory {\n switch (error.code) {\n case 'TIMEOUT':\n return 'timeout';\n case 'RATE_LIMITED':\n return 'rate_limit';\n case 'NOT_AUTHENTICATED':\n return 'authentication';\n case 'CONNECTION_ERROR':\n return 'connection';\n default:\n return 'unknown';\n }\n}\n\n// ============================================================================\n// Unified Retry Loop\n// ============================================================================\n\n/**\n * Executes a CLI operation with retry logic and optional circuit breaker.\n *\n * Used by both BaseCliAdapter (no circuit breaker) and GeminiCliAdapter\n * (with circuit breaker) to eliminate duplicate retry implementations.\n */\nexport async function executeCliRetryLoop(\n executeFn: () => Promise<Result<CliResponse, CliError>>,\n config: CliRetryLoopConfig\n): Promise<Result<CliRetryResult, CliError>> {\n const maxAttempts = config.allowRetry ? config.maxRetries + 1 : 1;\n let lastError: CliError | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const result = await executeFn();\n\n if (result.ok) {\n return ok({ response: result.value, retryCount: attempt - 1 });\n }\n\n lastError = result.error;\n\n // Record failure with circuit breaker if present\n if (config.circuitBreaker !== undefined && config.circuitBreaker !== null) {\n config.circuitBreaker.recordFailure(categorizeError(lastError));\n }\n\n // Check if we should retry\n if (!shouldRetry(lastError, attempt, maxAttempts, config.circuitBreaker)) {\n return err(lastError);\n }\n\n const delayMs = calculateBackoffDelay(attempt, config.baseDelayMs, config.maxDelayMs);\n config.logger.debug('Retrying CLI execution', {\n cli: config.cli,\n attempt,\n nextAttempt: attempt + 1,\n delayMs: Math.round(delayMs),\n });\n\n await delay(delayMs);\n }\n\n return err(\n lastError ?? {\n code: 'UNKNOWN',\n message: 'Max retries exceeded',\n cli: config.cli,\n retryable: false,\n }\n );\n}\n\nfunction shouldRetry(\n error: CliError,\n attempt: number,\n maxAttempts: number,\n circuitBreaker?: ICircuitBreaker | null\n): boolean {\n if (attempt >= maxAttempts) return false;\n if (!error.retryable) return false;\n if (!isRetryableError(error.code)) return false;\n if (circuitBreaker?.getState() === 'open') return false;\n return true;\n}\n","/**\n * Environment-variable allowlist for spawned CLI subprocesses (#2865).\n *\n * `spawnSubprocess` previously passed the entire `process.env` to every\n * spawned CLI (claude / gemini / codex / opencode) — only `CLAUDECODE`\n * was stripped. That leaked cross-vendor API keys: the gemini CLI\n * received `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`, the codex CLI\n * received `GOOGLE_AI_API_KEY`, and so on. A buggy or malicious CLI\n * could exfiltrate keys it has no business seeing.\n *\n * `buildChildEnv()` constructs a curated child environment instead:\n * base infrastructure vars that every CLI needs, plus ONLY the spawned\n * CLI's own vendor credential(s).\n *\n * @module cli-adapters/subprocess-env\n */\n\nimport type { CliName } from './types.js';\n\n/** Exact-match infrastructure vars every spawned CLI legitimately needs. */\nconst BASE_ENV_EXACT: readonly string[] = [\n 'PATH',\n 'HOME',\n 'USER',\n 'LOGNAME',\n 'SHELL',\n 'LANG',\n 'TERM',\n 'TZ',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'HTTP_PROXY',\n 'HTTPS_PROXY',\n 'NO_PROXY',\n 'ALL_PROXY',\n 'http_proxy',\n 'https_proxy',\n 'no_proxy',\n 'all_proxy',\n 'NODE_OPTIONS',\n 'NODE_PATH',\n 'NODE_ENV',\n 'NODE_EXTRA_CA_CERTS',\n 'SSL_CERT_FILE',\n 'SSL_CERT_DIR',\n];\n\n/** Prefix-match infrastructure var families. */\nconst BASE_ENV_PREFIXES: readonly string[] = [\n 'LC_', // locale: LC_ALL, LC_CTYPE, …\n 'NEXUS_', // nexus-agents config + nested-run credentials (a child may be a nested nexus-agents)\n 'npm_config_', // npm/node resolution config: registry, proxy, …\n];\n\n/**\n * Per-CLI vendor credentials. The spawned CLI gets ONLY its own\n * vendor's key(s) — not every vendor's. `opencode` can route to any\n * provider via its config, so it gets the full set.\n */\nconst CLI_VENDOR_KEYS: Record<CliName, readonly string[]> = {\n claude: ['ANTHROPIC_API_KEY'],\n gemini: ['GOOGLE_AI_API_KEY', 'GEMINI_API_KEY', 'GOOGLE_API_KEY'],\n codex: ['OPENAI_API_KEY'],\n opencode: [\n 'ANTHROPIC_API_KEY',\n 'OPENAI_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'OPENROUTER_API_KEY',\n ],\n};\n\n/** True if `key` is permitted for a CLI whose vendor keys are `vendorKeys`. */\nfunction isAllowed(key: string, vendorKeys: readonly string[]): boolean {\n if (BASE_ENV_EXACT.includes(key)) return true;\n if (vendorKeys.includes(key)) return true;\n return BASE_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n}\n\n/**\n * Builds the environment for a spawned CLI subprocess: base\n * infrastructure vars plus only `cliName`'s own vendor credentials.\n * Cross-vendor API keys are dropped (#2865).\n *\n * `CLAUDECODE` is never forwarded — a nested CLI seeing it would\n * believe it's already inside Claude Code, breaking nested sessions\n * (the pre-#2865 behavior also stripped it explicitly).\n *\n * Escape hatch: `NEXUS_SUBPROCESS_ENV_ALLOWLIST=0` restores the\n * pre-#2865 full-passthrough behavior (minus `CLAUDECODE`) — a\n * field un-break if the allowlist ever drops a var a CLI needs.\n */\nexport function buildChildEnv(cliName: CliName): NodeJS.ProcessEnv {\n const source = process.env;\n const childEnv: NodeJS.ProcessEnv = {};\n\n if (source['NEXUS_SUBPROCESS_ENV_ALLOWLIST'] === '0') {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined && key !== 'CLAUDECODE') childEnv[key] = value;\n }\n return childEnv;\n }\n\n const vendorKeys = CLI_VENDOR_KEYS[cliName];\n for (const [key, value] of Object.entries(source)) {\n if (value === undefined) continue;\n if (key === 'CLAUDECODE') continue;\n if (isAllowed(key, vendorKeys)) childEnv[key] = value;\n }\n return childEnv;\n}\n\n/** Test/introspection accessor for the per-CLI vendor-key map. */\nexport function getCliVendorKeys(): Readonly<Record<CliName, readonly string[]>> {\n return CLI_VENDOR_KEYS;\n}\n","/**\n * nexus-agents/security - Output Sanitizer\n *\n * Redacts API keys and tokens from CLI subprocess stdout/stderr\n * before the output is returned, logged, or traced.\n *\n * @module security/output-sanitizer\n * (Source: Issue #1597 — subprocess output scrubbing gap)\n */\n\n/** Placeholder text that replaces redacted keys. */\nexport const REDACTED_KEY_PLACEHOLDER = '[REDACTED_KEY]';\n\n/**\n * Patterns matching known API key formats.\n *\n * Order matters: more-specific prefixes (sk-ant-, sk-proj-) come before\n * the generic sk-* pattern so they match first.\n *\n * Each pattern requires a minimum token length after the prefix to avoid\n * false positives on short strings like \"sk-ab\".\n */\nconst KEY_PATTERNS: readonly RegExp[] = [\n // Anthropic: sk-ant-api03-... (at least 20 chars after prefix)\n /sk-ant-[A-Za-z0-9_-]{20,}/g,\n // OpenAI project: sk-proj-... (at least 20 chars after prefix)\n /sk-proj-[A-Za-z0-9_-]{20,}/g,\n // Generic OpenAI: sk-... (at least 20 chars after prefix)\n /sk-[A-Za-z0-9_-]{20,}/g,\n // Google AI / Gemini: AIzaSy... (at least 30 chars total)\n /AIzaSy[A-Za-z0-9_-]{24,}/g,\n // GitHub PAT: ghp_...\n /ghp_[A-Za-z0-9]{20,}/g,\n // GitHub OAuth: gho_...\n /gho_[A-Za-z0-9]{20,}/g,\n // GitLab PAT: glpat-...\n /glpat-[A-Za-z0-9_-]{10,}/g,\n // npm token: npm_...\n /npm_[A-Za-z0-9]{20,}/g,\n // PyPI token: pypi-...\n /pypi-[A-Za-z0-9_-]{20,}/g,\n];\n\n/**\n * Redacts known API key patterns from a string.\n *\n * Designed to be called on subprocess stdout/stderr before the output\n * is returned to callers, written to logs, or included in trace data.\n *\n * @param text - Raw subprocess output\n * @returns The same text with API keys replaced by [REDACTED_KEY]\n */\nexport function sanitizeOutput(text: string): string {\n if (text === '') return text;\n\n let result = text;\n for (const pattern of KEY_PATTERNS) {\n // Reset lastIndex for global regex reuse\n pattern.lastIndex = 0;\n result = result.replace(pattern, REDACTED_KEY_PLACEHOLDER);\n }\n return result;\n}\n","/**\n * cli-error-envelope — extract the actionable message from a CLI's\n * structured error envelope.\n *\n * When `claude`, `codex`, etc. return a JSON envelope with `is_error: true`,\n * the response parser correctly fails to find a usable assistant message\n * and falls through to the generic PARSE_ERROR path in `subprocess-adapter`.\n * That path stuffs the first 500 chars of the envelope into the error\n * message, producing the unreadable wall of escaped JSON described in #2440.\n *\n * This module unwraps known envelope shapes so the operator sees:\n *\n * ✗ Claude CLI: Not logged in\n * → claude /login, then retry\n *\n * instead of 600 characters of `{\"timestamp\":\"...\",\"level\":\"warn\",...}`.\n *\n * Source: Issue #2440 (round-14 onboarding audit, ask 1 + ask 2).\n */\n\nimport type { CliErrorCode, CliName } from './types.js';\n\n/**\n * Result of unwrapping a CLI's structured error envelope. `null` when the\n * stdout doesn't match a known shape — caller falls back to the existing\n * snippet behavior.\n */\nexport interface ParsedCliError {\n /** Short, user-facing message — the unwrapped CLI error string. */\n readonly message: string;\n /** Classified code so the retry/fail-closed logic can do the right thing. */\n readonly code: CliErrorCode;\n /** Optional one-line hint with the canonical fix for this CLI. */\n readonly hint?: string;\n}\n\n/**\n * Claude CLI structured envelope shape:\n * {\"type\":\"result\",\"is_error\":true,\"result\":\"<reason>\",\"session_id\":\"...\",...}\n *\n * Use a structural type guard rather than parsing into a strict schema —\n * upstream may add fields and we only care about three of them.\n */\ninterface ClaudeErrorEnvelope {\n readonly type: 'result';\n readonly is_error: true;\n readonly result?: string;\n}\n\nfunction isClaudeErrorEnvelope(v: unknown): v is ClaudeErrorEnvelope {\n if (typeof v !== 'object' || v === null) return false;\n const obj = v as { type?: unknown; is_error?: unknown };\n return obj.type === 'result' && obj.is_error === true;\n}\n\n/**\n * Codex CLI envelope shape (best-effort — codex CLI's error shape is\n * less stable than Claude's):\n * {\"error\":\"<reason>\"} or {\"is_error\":true,\"message\":\"<reason>\"}\n */\nfunction unwrapCodexEnvelope(parsed: unknown): string | null {\n if (typeof parsed !== 'object' || parsed === null) return null;\n const obj = parsed as { error?: unknown; message?: unknown; is_error?: unknown };\n if (typeof obj.error === 'string' && obj.error !== '') return obj.error;\n if (obj.is_error === true && typeof obj.message === 'string' && obj.message !== '') {\n return obj.message;\n }\n return null;\n}\n\n/** Login hint matched against the parsed message text, per CLI. */\nconst LOGIN_HINTS: Record<CliName, string> = {\n claude: 'claude /login',\n codex: 'codex login',\n gemini: 'gemini',\n opencode: 'opencode auth login',\n};\n\nconst NOT_AUTH_PATTERNS: readonly RegExp[] = [\n /not logged in/i,\n /please run \\/?login/i,\n /authentication (?:required|expired|failed)/i,\n /invalid (?:api ?key|credentials)/i,\n /unauthorized/i,\n // #2455 ask 1: catch \"API key expired\" / \"API key revoked\" / \"API key\n // missing\" — the bare /invalid api key/ pattern misses these. Architects\n // explicitly ruled OUT `permission denied` (that's authz, not authn —\n // routing to /login is the wrong fix).\n /api[- ]?key (?:expired|revoked|missing)/i,\n // Token expiry/revocation as a standalone signal, not co-occurring with\n // \"unauthorized\" — some upstreams emit \"Token expired. Please re-auth.\"\n // without the unauthorized keyword.\n /token (?:expired|revoked)/i,\n];\n\nfunction classifyMessage(message: string): { code: CliErrorCode; auth: boolean } {\n for (const re of NOT_AUTH_PATTERNS) {\n if (re.test(message)) return { code: 'NOT_AUTHENTICATED', auth: true };\n }\n return { code: 'EXECUTION_ERROR', auth: false };\n}\n\n/**\n * Try to find the actionable error string inside a CLI's stdout. Returns\n * `null` if the stdout doesn't look like a structured error envelope (the\n * caller then falls back to the existing snippet truncation).\n */\nexport function parseCliErrorEnvelope(stdout: string, cliName: CliName): ParsedCliError | null {\n const trimmed = stdout.trim();\n if (trimmed === '' || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n // Whole-blob parse failed — could be NDJSON (one JSON object per line).\n // Try the last line, which is where Claude/Codex emit the terminal\n // envelope.\n return tryLastLine(trimmed, cliName);\n }\n\n let message: string | undefined;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n message = parsed.result;\n } else {\n const codex = unwrapCodexEnvelope(parsed);\n if (codex !== null) message = codex;\n }\n\n if (message === undefined || message === '') return null;\n\n return buildParsedError(message, cliName);\n}\n\nfunction tryLastLine(stdout: string, cliName: CliName): ParsedCliError | null {\n const lines = stdout.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length < 2) return null;\n const last = lines.at(-1);\n if (last === undefined) return null;\n if (!last.startsWith('{')) return null;\n try {\n const parsed = JSON.parse(last) as unknown;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n return buildParsedError(parsed.result, cliName);\n }\n } catch {\n /* ignore — fall through to null */\n }\n return null;\n}\n\nfunction buildParsedError(message: string, cliName: CliName): ParsedCliError {\n // Trim to first line + cap length — operators don't need 500 chars of envelope.\n const firstLine = (message.split('\\n')[0] ?? message).trim().slice(0, 240);\n const { code, auth } = classifyMessage(firstLine);\n if (auth) {\n return {\n message: firstLine,\n code,\n hint: `Run \\`${LOGIN_HINTS[cliName]}\\` to authenticate, then retry.`,\n };\n }\n return { message: firstLine, code };\n}\n","/**\n * nexus-agents/utils - Type Coercion Utilities\n *\n * Safe type coercion helpers for parsing and validating unknown values.\n * Consolidates patterns used across parsers, validators, and adapters.\n *\n * @module utils/type-coercion\n */\n\n/**\n * Safely casts value to Record if it's a non-null, non-array object.\n *\n * @param value - Value to check\n * @returns Record if valid object, null otherwise\n *\n * @example\n * const data = asRecord(parsed);\n * if (data !== null) {\n * const name = asString(data.name);\n * }\n */\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return null;\n}\n\n/**\n * Type guard version of asRecord for use in conditionals.\n *\n * @param value - Value to check\n * @returns True if value is a non-null, non-array object\n *\n * @example\n * if (isRecord(data)) {\n * console.log(data.field);\n * }\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Safely extracts a string value.\n *\n * @param value - Value to check\n * @returns String if valid, null otherwise\n */\nexport function asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\n/**\n * Safely extracts a number value.\n *\n * @param value - Value to check\n * @returns Number if valid (not NaN, not Infinity), null otherwise\n */\nexport function asNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return null;\n}\n\n/**\n * Safely extracts a boolean value.\n *\n * @param value - Value to check\n * @returns Boolean if valid, null otherwise\n */\nexport function asBoolean(value: unknown): boolean | null {\n return typeof value === 'boolean' ? value : null;\n}\n\n/**\n * Safely extracts an array value.\n *\n * @param value - Value to check\n * @returns Array if valid, null otherwise\n */\nexport function asArray(value: unknown): unknown[] | null {\n return Array.isArray(value) ? value : null;\n}\n\n/**\n * Extracts a string field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns String value or undefined if not found/invalid\n */\nexport function extractStringField(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n const value = record[key];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Extracts a number field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Number value or null if not found/invalid\n */\nexport function extractNumberField(record: Record<string, unknown>, key: string): number | null {\n const value = record[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\n/**\n * Extracts a boolean field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Boolean value or undefined if not found/invalid\n */\nexport function extractBooleanField(\n record: Record<string, unknown>,\n key: string\n): boolean | undefined {\n const value = record[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Extracts a nested record field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Nested record or null if not found/invalid\n */\nexport function extractRecordField(\n record: Record<string, unknown>,\n key: string\n): Record<string, unknown> | null {\n return asRecord(record[key]);\n}\n\n/**\n * Safely parses JSON with fallback to null.\n *\n * @param raw - Raw JSON string\n * @returns Parsed value or null if invalid\n */\nexport function safeJsonParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Safely parses JSON and returns as Record.\n *\n * @param raw - Raw JSON string\n * @returns Parsed record or null if invalid\n */\nexport function safeJsonParseRecord(raw: string): Record<string, unknown> | null {\n const parsed = safeJsonParse(raw);\n return asRecord(parsed);\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Response Parser\n *\n * Defensive parser for Claude CLI JSON output.\n * Handles version 2.0.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'claude-parser' });\n\n/**\n * Claude CLI response structure.\n * (Source: CLI testing 2026-01-04)\n */\nexport interface ClaudeCliResponse {\n readonly type: 'result';\n readonly subtype?: 'success' | 'error';\n readonly is_error: boolean;\n readonly duration_ms?: number;\n readonly result: string;\n readonly session_id?: string;\n readonly total_cost_usd?: number;\n readonly usage?: {\n readonly input_tokens: number;\n readonly output_tokens: number;\n readonly cache_creation_input_tokens?: number;\n readonly cache_read_input_tokens?: number;\n };\n readonly modelUsage?: Record<\n string,\n {\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly cacheReadInputTokens?: number;\n readonly cacheCreationInputTokens?: number;\n readonly costUSD?: number;\n readonly contextWindow?: number;\n }\n >;\n}\n\n/**\n * Parser for Claude CLI JSON output.\n * Implements defensive parsing - only requires essential fields.\n */\nexport class ClaudeResponseParser implements ICliResponseParser<ClaudeCliResponse> {\n readonly name = 'claude-parser';\n readonly supportedVersionRange = '>=2.0.0 <3.0.0';\n\n /**\n * Parses complete Claude CLI response.\n */\n parse(raw: string): ClaudeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n\n if (!this.isValidResponse(data)) {\n return null;\n }\n\n return data;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Returns null if the response contains an error.\n */\n extractResponse(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n // Check for API errors (is_error: true indicates an error occurred)\n if (record.is_error === true) {\n return null;\n }\n\n const result = record.result;\n if (typeof result === 'string') {\n return result;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const usageRecord = asRecord(record.usage);\n if (usageRecord === null) return null;\n\n const inputTokens = extractNumberField(usageRecord, 'input_tokens');\n const outputTokens = extractNumberField(usageRecord, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usageRecord, 'cache_read_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const sessionId = record.session_id;\n if (typeof sessionId === 'string') {\n return sessionId;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Type guard for valid response structure.\n */\n private isValidResponse(data: unknown): data is ClaudeCliResponse {\n const record = asRecord(data);\n if (record === null) return false;\n\n // Only require the essential field\n return typeof record.result === 'string';\n }\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Adapter\n *\n * Subprocess-based adapter for Claude CLI.\n * Uses JSON output format for stable parsing.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ClaudeResponseParser } from '../parsers/claude-parser.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Maps internal model names → Claude CLI aliases. Derived entirely from the\n * canonical registry: every claude entry contributes its `cliAlias` (passthrough),\n * its `cliModelName`, and every legacy-name in `aliases[]`. Migration of these\n * legacy strings into the registry happened in #2200 Child 1.\n */\nconst MODEL_TO_CLI_ALIAS: Record<string, string> = buildClaudeAliasMap();\n\nfunction buildClaudeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('claude')) {\n if (model.cliAlias === undefined) continue;\n const alias = model.cliAlias;\n map[alias] = alias;\n if (model.cliModelName !== undefined) map[model.cliModelName] = alias;\n for (const legacyName of model.aliases ?? []) {\n map[legacyName] = alias;\n }\n }\n return map;\n}\n\n/**\n * Default cost when an unrecognized model id is passed (pricing matches\n * current Opus, the strongest tier — conservative over-estimate). Per-model\n * legacy cost overrides were removed in #2200 Child 1; they're reachable\n * via the registry now.\n */\nconst UNKNOWN_MODEL_DEFAULT_INPUT_COST = 5.0;\nconst UNKNOWN_MODEL_DEFAULT_OUTPUT_COST = 25.0;\n\n/**\n * Claude CLI adapter using subprocess transport.\n * Executes: claude -p --output-format json \"<task>\"\n */\nexport class ClaudeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'claude';\n protected readonly parser: ICliResponseParser = new ClaudeResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('claude'));\n }\n\n /**\n * Gets Claude model information.\n * `buildModelInfo` matches `cliModelName`, `cliAlias`, and `aliases[]` —\n * a single call handles 'opus', 'sonnet', 'haiku', current model names,\n * and the legacy `claude-opus-4` / `claude-haiku-3` / etc. entries that\n * live in the registry's aliases since #2200 Child 1.\n *\n * Truly unrecognized models fall through to conservative defaults\n * (current Opus pricing).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('claude', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: this.model,\n contextWindow: 200_000,\n maxOutput: 64_000,\n costPerMillionInput: UNKNOWN_MODEL_DEFAULT_INPUT_COST,\n costPerMillionOutput: UNKNOWN_MODEL_DEFAULT_OUTPUT_COST,\n };\n }\n\n /** Appends optional string-type task options to CLI args. */\n private appendTaskOptions(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--add-dir', workDir);\n }\n const mcpConfigPath = task.options?.['mcpConfigPath'];\n if (typeof mcpConfigPath === 'string' && mcpConfigPath.length > 0) {\n args.push('--mcp-config', mcpConfigPath);\n }\n // Allow full tool access in non-interactive mode (needed for SWE-bench)\n if (task.options?.['skipPermissions'] === true) {\n args.push('--dangerously-skip-permissions');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses stdin for the prompt to avoid argument escaping issues,\n * especially important when using --add-dir.\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['-p', '--output-format', 'json'];\n\n // Add model - convert internal names to CLI aliases\n const internalModel = task.model ?? this.model;\n const cliModel = MODEL_TO_CLI_ALIAS[internalModel] ?? internalModel;\n args.push('--model', cliModel);\n\n // Add system prompt if provided\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n args.push('--system-prompt', task.systemPrompt);\n }\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n this.appendTaskOptions(args, task);\n\n // Note: maxTokens is intentionally not passed to Claude CLI.\n // The Claude CLI does not support --max-tokens. Use --max-budget-usd instead.\n // The CLI handles token limits internally based on model configuration.\n\n // Pass prompt via stdin to avoid argument escaping issues\n return { command: 'claude', args, stdin: task.content };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter\n *\n * Subprocess-based adapter for Gemini CLI with:\n * - Tiered timeout profiles based on task complexity\n * - Resilient JSON parsing with fallback strategies\n * - Exponential backoff retry logic\n * - Circuit breaker integration for sustained failures\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n * (Source: Issue #389 - Merged enhanced adapter back to canonical)\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Result, ILogger } from '../../core/index.js';\nimport { ok, err, createLogger, getTimeProvider } from '../../core/index.js';\nimport type {\n ICliResponseParser,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n CliName,\n ExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ResilientGeminiParser } from '../parsers/gemini-parser-resilient.js';\nimport {\n getTimeoutForTask,\n estimateTaskComplexity,\n type TaskComplexity,\n} from '../cli-timeout-profiles.js';\nimport {\n CliCircuitBreaker,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n type CircuitBreakerConfig,\n type CircuitBreakerSnapshot,\n} from '../circuit-breaker.js';\nimport { GEMINI_LEGACY_DEFAULTS, createCircuitOpenError } from './gemini-adapter-helpers.js';\nimport { executeCliRetryLoop } from '../cli-retry-loop.js';\nimport {\n buildModelInfo,\n getCliModelName,\n getDefaultModelForCli,\n} from '../../config/model-config-helpers.js';\n\n/** Derive the CLI model name for the default Gemini model from the canonical registry. */\nconst DEFAULT_GEMINI_CLI_MODEL: string = getCliModelName(getDefaultModelForCli('gemini'));\n\n/** Configuration for Gemini adapter. Extends BaseAdapterOptions with retry/circuit breaker. */\nexport interface GeminiConfig extends BaseAdapterOptions {\n /** Maximum retry attempts (default: 3) */\n readonly maxRetries?: number;\n /** Base delay for exponential backoff in ms (default: 1000) */\n readonly baseDelayMs?: number;\n /** Maximum delay for backoff in ms (default: 30000) */\n readonly maxDelayMs?: number;\n /** Circuit breaker configuration */\n readonly circuitBreakerConfig?: Partial<CircuitBreakerConfig>;\n /** Enable circuit breaker (default: true) */\n readonly enableCircuitBreaker?: boolean;\n}\n\n/** Execution result with metadata. */\nexport interface GeminiExecutionResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n readonly totalDurationMs: number;\n readonly complexity: TaskComplexity;\n readonly circuitState: 'closed' | 'open' | 'half-open';\n}\n\nconst DEFAULT_CONFIG: Required<Omit<GeminiConfig, 'logger' | 'circuitBreakerConfig'>> = {\n model: DEFAULT_GEMINI_CLI_MODEL,\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n enableCircuitBreaker: true,\n};\n\n/**\n * Gemini CLI adapter with reliability features.\n *\n * Includes tiered timeouts, resilient parsing, retry logic, and circuit breaker.\n */\nexport class GeminiCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'gemini';\n protected readonly parser: ICliResponseParser;\n\n private readonly model: string;\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n private readonly circuitBreaker: CliCircuitBreaker | null;\n private readonly adapterLogger: ILogger;\n\n constructor(options?: GeminiConfig) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...options };\n super(options?.logger);\n\n this.model = mergedConfig.model;\n this.maxRetries = mergedConfig.maxRetries;\n this.baseDelayMs = mergedConfig.baseDelayMs;\n this.maxDelayMs = mergedConfig.maxDelayMs;\n this.parser = new ResilientGeminiParser();\n this.adapterLogger = options?.logger ?? createLogger({ component: 'gemini-adapter' });\n\n // Initialize circuit breaker if enabled\n if (mergedConfig.enableCircuitBreaker) {\n const cbConfig: CircuitBreakerConfig = {\n ...DEFAULT_CIRCUIT_BREAKER_CONFIG,\n ...options?.circuitBreakerConfig,\n };\n this.circuitBreaker = new CliCircuitBreaker('gemini', cbConfig);\n } else {\n this.circuitBreaker = null;\n }\n }\n\n /**\n * Gets Gemini model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n * Note: maxOutput is capped at 8_192 (Gemini CLI constraint).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('gemini', this.model);\n if (fromRegistry !== undefined) {\n return { ...fromRegistry, maxOutput: 8_192 };\n }\n return {\n id: this.model,\n name: GEMINI_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow:\n GEMINI_LEGACY_DEFAULTS.contextWindows[this.model] ?? GEMINI_LEGACY_DEFAULTS.contextWindow,\n maxOutput: 8_192,\n costPerMillionInput:\n GEMINI_LEGACY_DEFAULTS.inputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n GEMINI_LEGACY_DEFAULTS.outputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Executes a task with reliability features.\n */\n override async execute(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n const result = await this.executeWithMetadata(task, options);\n\n if (result.ok) {\n return ok(result.value.response);\n }\n\n return err(result.error);\n }\n\n /**\n * Executes with full metadata about retry attempts and circuit state.\n */\n async executeWithMetadata(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<GeminiExecutionResult, CliError>> {\n const circuitCheckResult = this.checkCircuitBreaker();\n if (circuitCheckResult !== null) {\n return err(circuitCheckResult);\n }\n\n const startTime = getTimeProvider().now();\n const complexity = estimateTaskComplexity(task.content);\n const effectiveOptions = this.buildExecutionOptions(task.content, options);\n\n const result = await this.executeWithRetryTracking(task, effectiveOptions);\n\n return this.buildExecutionResult(result, startTime, complexity);\n }\n\n /**\n * Gets current circuit breaker snapshot.\n */\n getCircuitBreakerSnapshot(): CircuitBreakerSnapshot | null {\n return this.circuitBreaker?.getSnapshot() ?? null;\n }\n\n /**\n * Resets the circuit breaker to closed state.\n */\n resetCircuitBreaker(): void {\n this.circuitBreaker?.reset();\n }\n\n /**\n * Gets CLI command and arguments for execution.\n */\n protected override getCommand(task: CliTask): CommandConfig {\n const args: string[] = [];\n\n // Add the task content as positional argument\n args.push(task.content);\n\n // Add output format\n args.push('-o', 'json');\n\n // Add model (always present due to default)\n const model = task.model ?? this.model;\n args.push('-m', model);\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n // Note: Sandbox mode (-s) removed - causes npm permission issues\n // and \"rebuilt dependencies successfully\" contamination\n\n // Honor systemPrompt via gemini's --policy flag (#1886).\n // Gemini treats policy files as system-level instructions, preserving\n // the system-role framing (unlike prepending to user content).\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-gemini-sysprompt-'));\n const file = join(dir, 'policy.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('--policy', file);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every gemini call with a systemPrompt leaked\n // one empty `/tmp/nexus-gemini-sysprompt-XXXXXX` dir until the OS\n // reaper ran.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n return cleanup === undefined\n ? { command: 'gemini', args }\n : { command: 'gemini', args, cleanup };\n }\n\n private checkCircuitBreaker(): CliError | null {\n if (this.circuitBreaker === null) {\n return null;\n }\n if (this.circuitBreaker.getState() === 'open') {\n return createCircuitOpenError('gemini');\n }\n return null;\n }\n\n private buildExecutionOptions(\n taskContent: string,\n options?: ExecutionOptions\n ): Required<ExecutionOptions> {\n const complexity = estimateTaskComplexity(taskContent);\n const timeoutMs = options?.timeoutMs ?? getTimeoutForTask(this.name, complexity);\n\n return {\n timeoutMs,\n allowRetry: options?.allowRetry ?? true,\n maxRetries: options?.maxRetries ?? this.maxRetries,\n trackUsage: options?.trackUsage ?? true,\n onProgress: options?.onProgress,\n };\n }\n\n private buildExecutionResult(\n result: Result<{ response: CliResponse; retryCount: number }, CliError>,\n startTime: number,\n complexity: TaskComplexity\n ): Result<GeminiExecutionResult, CliError> {\n const totalDurationMs = getTimeProvider().now() - startTime;\n const circuitState = this.circuitBreaker?.getState() ?? 'closed';\n\n if (result.ok) {\n this.circuitBreaker?.recordSuccess();\n return ok({\n response: result.value.response,\n retryCount: result.value.retryCount,\n totalDurationMs,\n complexity,\n circuitState,\n });\n }\n\n return err(result.error);\n }\n\n private async executeWithRetryTracking(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<{ response: CliResponse; retryCount: number }, CliError>> {\n return executeCliRetryLoop(() => this.executeTask(task, options), {\n maxRetries: options.maxRetries,\n allowRetry: this.shouldOuterRetry(options),\n baseDelayMs: this.baseDelayMs,\n maxDelayMs: this.maxDelayMs,\n circuitBreaker: this.circuitBreaker,\n cli: this.name,\n logger: this.adapterLogger,\n });\n }\n}\n\n/** Creates a Gemini CLI adapter with reliability features. */\nexport function createGeminiAdapter(options?: GeminiConfig): GeminiCliAdapter {\n return new GeminiCliAdapter(options);\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini Parser Helpers\n *\n * Utility functions for parsing Gemini CLI output.\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { TokenUsage } from '../types.js';\nimport type { TokenTotals } from './gemini-parser-resilient-types.js';\nimport { asRecord, extractStringField, extractNumberField } from '../../utils/type-coercion.js';\n\n// Re-export for backward compatibility\nexport { asRecord, extractStringField };\n\n/**\n * Aggregates token counts from model stats.\n */\nexport function aggregateModelTokens(models: Record<string, unknown>): TokenTotals {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCached = 0;\n\n for (const modelStats of Object.values(models)) {\n const modelRecord = asRecord(modelStats);\n if (modelRecord === null) continue;\n\n const tokens = asRecord(modelRecord.tokens);\n if (tokens === null) continue;\n\n const input = extractNumberField(tokens, 'input');\n const candidates = extractNumberField(tokens, 'candidates');\n const cached = extractNumberField(tokens, 'cached');\n\n if (input !== null) totalInput += input;\n if (candidates !== null) totalOutput += candidates;\n if (cached !== null) totalCached += cached;\n }\n\n return { input: totalInput, output: totalOutput, cached: totalCached };\n}\n\n/**\n * Extracts token usage from a parsed record.\n */\nexport function extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | undefined {\n const stats = asRecord(record.stats);\n if (stats === null) return undefined;\n\n const models = asRecord(stats.models);\n if (models === null) return undefined;\n\n const totals = aggregateModelTokens(models);\n if (totals.input === 0 && totals.output === 0) return undefined;\n\n return {\n inputTokens: totals.input,\n outputTokens: totals.output,\n totalTokens: totals.input + totals.output,\n ...(totals.cached > 0 && { cachedInputTokens: totals.cached }),\n };\n}\n\n/**\n * Extracts session ID from text patterns.\n */\nexport function extractSessionIdFromText(raw: string): string | null {\n const patterns = [/session[_-]?id[:\\s]+[\"']?([a-zA-Z0-9_-]+)[\"']?/i, /gem_([a-zA-Z0-9]+)/];\n\n for (const pattern of patterns) {\n const match = pattern.exec(raw);\n const captured = match?.[1];\n if (captured !== undefined) {\n return captured.startsWith('gem_') ? captured : `gem_${captured}`;\n }\n }\n\n return null;\n}\n\n/**\n * Extracts text content from markdown, removing code blocks and formatting.\n */\nexport function extractTextFromMarkdown(raw: string): string {\n let content = raw;\n\n // Remove code blocks\n content = content.replace(/```[\\s\\S]*?```/g, '');\n\n // Remove markdown formatting\n content = content.replace(/#{1,6}\\s+/g, '');\n content = content.replace(/\\*{1,2}([^*]+)\\*{1,2}/g, '$1');\n content = content.replace(/_([^_]+)_/g, '$1');\n\n return content.trim();\n}\n\n/**\n * Extracts a clean error message from raw output.\n */\nexport function extractErrorMessage(raw: string): string {\n const lines = raw.split('\\n').filter((line) => line.trim().length > 0);\n\n // Look for error: prefix\n for (const line of lines) {\n const lower = line.toLowerCase();\n if (lower.includes('error:')) {\n return line.replace(/.*error:\\s*/i, '').trim();\n }\n }\n\n // Return first non-empty line as fallback\n return lines[0]?.trim() ?? 'Unknown error';\n}\n\n/**\n * Checks if output appears to be an error message.\n */\nexport function isLikelyErrorOutput(raw: string): boolean {\n const lower = raw.toLowerCase();\n const errorIndicators = ['error:', 'exception:', 'traceback', 'stack trace', 'fatal:', 'panic:'];\n\n // Check if output starts with error indicators\n for (const indicator of errorIndicators) {\n if (lower.startsWith(indicator)) return true;\n }\n\n // Check if it's a short error message\n if (raw.length < 200) {\n const errorKeywords = ['failed', 'error', 'cannot', 'unable to'];\n const hasErrorKeyword = errorKeywords.some((kw) => lower.includes(kw));\n const hasNoContent = !lower.includes('the ') && !lower.includes('this ');\n if (hasErrorKeyword && hasNoContent) return true;\n }\n\n return false;\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini CLI Response Parser\n *\n * Enhanced parser with multiple fallback strategies for handling\n * various Gemini CLI output formats including:\n * - Standard JSON output\n * - Plain text responses\n * - Multi-line outputs with markdown\n * - Error messages and exit codes\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport type { GeminiCliResponse } from './gemini-parser.js';\nimport type { ResilientParseResult, GeminiErrorInfo } from './gemini-parser-resilient-types.js';\nimport { extractJsonObject } from '../../core/index.js';\nimport {\n asRecord,\n extractStringField,\n extractUsageFromRecord,\n extractSessionIdFromText,\n extractTextFromMarkdown,\n extractErrorMessage,\n isLikelyErrorOutput,\n} from './gemini-parser-resilient-helpers.js';\n\n// Re-export types for backward compatibility\nexport type {\n ResilientParseResult,\n ParseStrategy,\n GeminiErrorInfo,\n} from './gemini-parser-resilient-types.js';\n\n/**\n * Resilient parser for Gemini CLI output.\n * Implements multiple fallback strategies for robust parsing.\n */\nexport class ResilientGeminiParser implements ICliResponseParser<GeminiCliResponse> {\n readonly name = 'gemini-resilient-parser';\n readonly supportedVersionRange = '>=0.20.0 <1.0.0';\n\n /**\n * Parses Gemini CLI output using multiple strategies.\n * Tries JSON first, then falls back to text extraction.\n */\n parse(raw: string): GeminiCliResponse | null {\n const result = this.parseResilient(raw);\n if (result === null) return null;\n\n // Build the response object, only including optional fields when present\n const response: GeminiCliResponse = {\n response: result.response,\n };\n\n // Add stats if usage info is available\n if (result.usage !== undefined) {\n return {\n ...response,\n ...(result.sessionId !== undefined && { session_id: result.sessionId }),\n stats: {\n models: {\n 'gemini-unknown': {\n tokens: {\n input: result.usage.inputTokens,\n candidates: result.usage.outputTokens,\n },\n },\n },\n },\n };\n }\n\n // No usage - just add session_id if it exists\n if (result.sessionId !== undefined) {\n return { ...response, session_id: result.sessionId };\n }\n\n return response;\n }\n\n /**\n * Parses with full metadata about parsing strategy.\n */\n parseResilient(raw: string): ResilientParseResult | null {\n // Strategy 1: Standard JSON parsing\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult !== null) return jsonResult;\n\n // Strategy 2: Extract JSON from mixed output\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson !== null) return extractedJson;\n\n // Strategy 3: Extract from markdown code blocks\n const markdownResult = this.tryExtractFromMarkdown(raw);\n if (markdownResult !== null) return markdownResult;\n\n // Strategy 4: Plain text fallback\n const plainTextResult = this.tryPlainText(raw);\n if (plainTextResult !== null) return plainTextResult;\n\n return null;\n }\n\n /**\n * Extracts just the response text with fallback strategies.\n */\n extractResponse(raw: string): string | null {\n const result = this.parseResilient(raw);\n return result?.response ?? null;\n }\n\n /**\n * Extracts token usage if available.\n */\n extractUsage(raw: string): TokenUsage | null {\n // Try JSON parsing first for structured usage data\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.usage) return jsonResult.usage;\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.usage) return extractedJson.usage;\n\n return null;\n }\n\n /**\n * Extracts session ID if present.\n */\n extractSessionId(raw: string): string | null {\n // Try JSON parsing first\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.sessionId !== undefined && jsonResult.sessionId !== '') {\n return jsonResult.sessionId;\n }\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.sessionId !== undefined && extractedJson.sessionId !== '') {\n return extractedJson.sessionId;\n }\n\n // Try to extract session ID from text patterns\n return extractSessionIdFromText(raw);\n }\n\n /**\n * Detects and extracts error information from output.\n */\n extractError(raw: string): GeminiErrorInfo | null {\n const lower = raw.toLowerCase();\n\n if (lower.includes('timeout') || lower.includes('timed out')) {\n return { type: 'timeout', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('authentication') || lower.includes('unauthorized')) {\n return { type: 'auth', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('rate limit') || lower.includes('quota exceeded')) {\n return { type: 'rate-limit', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('error') || lower.includes('failed')) {\n return { type: 'api-error', message: extractErrorMessage(raw) };\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Private Strategy Methods\n // -------------------------------------------------------------------------\n\n private tryParseJson(raw: string): ResilientParseResult | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const response = record.response;\n if (typeof response !== 'string') return null;\n\n const sessionId = extractStringField(record, 'session_id');\n const usage = extractUsageFromRecord(record);\n\n const result: ResilientParseResult = {\n response,\n parseStrategy: 'json',\n raw,\n };\n\n if (sessionId !== undefined) {\n (result as { sessionId?: string }).sessionId = sessionId;\n }\n if (usage !== undefined) {\n (result as { usage?: TokenUsage }).usage = usage;\n }\n\n return result;\n } catch {\n return null;\n }\n }\n\n private tryExtractJson(raw: string): ResilientParseResult | null {\n // ReDoS-safe extraction (#1912): previously used compound patterns like\n // `/\\{[\\s\\S]*\"response\"\\s*:\\s*\"[\\s\\S]*\"\\s*[\\s\\S]*\\}/` which have THREE\n // `[\\s\\S]*` groups — catastrophic backtracking on large non-matching\n // input. Now we extract the JSON object via indexOf/lastIndexOf (O(n))\n // and let tryParseJson validate the \"response\" field structurally.\n const candidate = extractJsonObject(raw);\n if (candidate === undefined) return null;\n const result = this.tryParseJson(candidate);\n if (result !== null) {\n return { ...result, parseStrategy: 'json-extracted', raw };\n }\n return null;\n }\n\n private tryExtractFromMarkdown(raw: string): ResilientParseResult | null {\n // Extract content from markdown code blocks\n const codeBlockPattern = /```(?:json)?\\s*([\\s\\S]*?)```/g;\n let match: RegExpExecArray | null = codeBlockPattern.exec(raw);\n\n while (match !== null) {\n const captured = match[1];\n if (captured !== undefined) {\n const content = captured.trim();\n\n // Try to parse as JSON\n const jsonResult = this.tryParseJson(content);\n if (jsonResult !== null) {\n return { ...jsonResult, parseStrategy: 'markdown-code-block', raw };\n }\n }\n\n match = codeBlockPattern.exec(raw);\n }\n\n // If no JSON found in code blocks, treat entire content as response\n // but only if it looks like substantive output\n if (raw.includes('```')) {\n const cleanedContent = extractTextFromMarkdown(raw);\n if (cleanedContent.length > 0) {\n return {\n response: cleanedContent,\n parseStrategy: 'markdown-code-block',\n raw,\n };\n }\n }\n\n return null;\n }\n\n private tryPlainText(raw: string): ResilientParseResult | null {\n const trimmed = raw.trim();\n\n // Skip if empty or looks like an error\n if (trimmed.length === 0) return null;\n\n // Skip if it looks like just error output\n if (isLikelyErrorOutput(trimmed)) return null;\n\n // Accept as plain text response\n return {\n response: trimmed,\n parseStrategy: 'plain-text',\n raw,\n };\n }\n}\n\n/**\n * Creates a resilient Gemini parser instance.\n */\nexport function createResilientGeminiParser(): ResilientGeminiParser {\n return new ResilientGeminiParser();\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter Helpers\n *\n * CLI-specific helper functions for retry logic and error handling.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName } from '../types.js';\n\n// -----------------------------------------------------------------------------\n// Fallback Defaults (for unknown models not in canonical registry)\n// -----------------------------------------------------------------------------\n\n/**\n * Fallback defaults for Gemini models not in the canonical registry.\n * All current models are in config/in-tree-data.ts and served by\n * buildModelInfo('gemini', model). This provides sensible defaults\n * when an unknown model name is encountered at runtime.\n *\n * @see config/in-tree-data.ts — single source of truth for current models\n */\nexport const GEMINI_LEGACY_DEFAULTS = {\n displayNames: {} as Readonly<Record<string, string>>,\n contextWindows: {} as Readonly<Record<string, number>>,\n inputCosts: {} as Readonly<Record<string, number>>,\n outputCosts: {} as Readonly<Record<string, number>>,\n contextWindow: 1_000_000,\n inputCost: 0.15,\n outputCost: 0.6,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Re-exports from canonical cli-retry-loop.ts (Issue #1596)\n// -----------------------------------------------------------------------------\n\nexport { calculateBackoffDelay, isRetryableError, categorizeError } from '../cli-retry-loop.js';\n\n// -----------------------------------------------------------------------------\n// Error Factory\n// -----------------------------------------------------------------------------\n\n/** Creates a circuit breaker open error. */\nexport function createCircuitOpenError(cli: CliName): CliError {\n return {\n code: 'EXECUTION_ERROR',\n message: `Circuit breaker is open - ${cli} CLI temporarily unavailable`,\n cli,\n retryable: false,\n };\n}\n\n// -----------------------------------------------------------------------------\n// Utility Functions\n// -----------------------------------------------------------------------------\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter\n *\n * Subprocess-based adapter for Codex CLI.\n * Extends SubprocessCliAdapter to reuse retry logic, health checks,\n * version detection, and capacity tracking.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #1140 — Migrated to SubprocessCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell: true.\n * User task content is passed as a single argv element (no shell interpolation).\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { CodexResponseParser } from '../parsers/codex-parser.js';\nimport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n// Re-export CLI-specific helpers for backward compatibility\nexport { createCodexError, normalizeCodexResponse, delay } from './codex-adapter-helpers.js';\n\n/**\n * Codex CLI adapter using subprocess transport.\n *\n * Extends SubprocessCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Subprocess spawn with timeout handling\n */\nexport class CodexCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'codex';\n protected readonly parser: ICliResponseParser = new CodexResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Task content is passed as a positional argument (not via stdin).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['exec'];\n\n // Add JSON output\n args.push('--json');\n\n // Add model only if specified (use CLI default otherwise)\n const model = task.model ?? this.model;\n if (model !== '') {\n args.push('-m', model);\n }\n\n // Add sandbox mode for safety (read-only by default)\n args.push('-s', 'read-only');\n\n // Skip git repo check for standalone prompts\n args.push('--skip-git-repo-check');\n\n // Honor systemPrompt via codex's `model_instructions_file` config key\n // (per openai/codex#11588 — closed with this workaround). We materialize\n // the prompt into a tempfile, pass it via `-c`, and clean up on exit.\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-codex-sysprompt-'));\n const file = join(dir, 'instructions.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('-c', `model_instructions_file=${file}`);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every codex call with a systemPrompt leaked\n // one empty `/tmp/nexus-codex-sysprompt-XXXXXX` dir until the OS\n // reaper ran — exhausting inodes on long-running MCP daemons.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n // Add the task content (no JSON.stringify needed without shell: true)\n args.push(task.content);\n\n return cleanup === undefined ? { command: 'codex', args } : { command: 'codex', args, cleanup };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Response Parser\n *\n * Defensive parser for Codex CLI NDJSON output.\n * Handles version 0.7x.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'codex-parser' });\n\n/**\n * Codex CLI NDJSON event types.\n */\nexport type CodexEventType =\n | 'thread.started'\n | 'turn.started'\n | 'item.completed'\n | 'turn.completed';\n\n/**\n * Base Codex event structure.\n */\nexport interface CodexEvent {\n readonly type: CodexEventType;\n}\n\n/**\n * Thread started event.\n */\nexport interface CodexThreadStarted extends CodexEvent {\n readonly type: 'thread.started';\n readonly thread_id: string;\n}\n\n/**\n * Item completed event (contains response or reasoning).\n */\nexport interface CodexItemCompleted extends CodexEvent {\n readonly type: 'item.completed';\n readonly item: {\n readonly id: string;\n readonly type: string;\n readonly text: string;\n };\n}\n\n/**\n * Turn completed event (contains usage).\n */\nexport interface CodexTurnCompleted extends CodexEvent {\n readonly type: 'turn.completed';\n readonly usage?: {\n readonly input_tokens: number;\n readonly cached_input_tokens?: number;\n readonly output_tokens: number;\n };\n}\n\n/**\n * Aggregated Codex response from NDJSON stream.\n */\nexport interface CodexCliResponse {\n readonly threadId?: string;\n readonly messages: readonly string[];\n readonly reasoning: readonly string[];\n readonly usage?: TokenUsage;\n}\n\n/**\n * Parser for Codex CLI NDJSON output.\n * Implements defensive parsing - processes stream of events.\n */\nexport class CodexResponseParser implements ICliResponseParser<CodexCliResponse> {\n readonly name = 'codex-parser';\n readonly supportedVersionRange = '>=0.70.0 <1.0.0';\n\n /**\n * Parses complete Codex CLI NDJSON stream.\n */\n parse(raw: string): CodexCliResponse | null {\n const lines = raw.trim().split('\\n');\n let threadId: string | undefined;\n const messages: string[] = [];\n const reasoning: string[] = [];\n let usage: TokenUsage | undefined;\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n this.processLine(\n line,\n messages,\n reasoning,\n (id) => (threadId = id),\n (u) => (usage = u)\n );\n }\n\n if (messages.length === 0 && reasoning.length === 0) {\n return null;\n }\n\n return {\n messages,\n reasoning,\n ...(threadId !== undefined && { threadId }),\n ...(usage !== undefined && { usage }),\n };\n }\n\n /**\n * Processes a single NDJSON line.\n */\n private processLine(\n line: string,\n messages: string[],\n reasoning: string[],\n setThreadId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) return;\n\n const eventType = record.type;\n\n if (eventType === 'thread.started') {\n const tid = record.thread_id;\n if (typeof tid === 'string') setThreadId(tid);\n } else if (eventType === 'item.completed') {\n this.processItemCompleted(record, messages, reasoning);\n } else if (eventType === 'turn.completed') {\n const usage = this.extractUsageFromEvent(record);\n if (usage !== null) setUsage(usage);\n }\n } catch {\n // Skip malformed NDJSON lines\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Concatenates all agent_message items.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.messages.length === 0) {\n return null;\n }\n\n return parsed.messages.join('\\n');\n }\n\n /**\n * Extracts token usage from NDJSON stream.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'turn.completed') {\n return this.extractUsageFromEvent(record);\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID (thread_id) for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'thread.started') {\n const threadId = record.thread_id;\n if (typeof threadId === 'string') {\n return threadId;\n }\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Processes an item.completed event.\n */\n private processItemCompleted(\n record: Record<string, unknown>,\n messages: string[],\n reasoning: string[]\n ): void {\n const item = asRecord(record.item);\n if (item === null) return;\n\n const itemType = item.type;\n const text = item.text;\n\n if (typeof text !== 'string') return;\n\n if (itemType === 'agent_message') {\n messages.push(text);\n } else if (itemType === 'reasoning') {\n reasoning.push(text);\n }\n }\n\n /**\n * Extracts usage from a turn.completed event.\n */\n private extractUsageFromEvent(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens = extractNumberField(usage, 'input_tokens');\n const outputTokens = extractNumberField(usage, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usage, 'cached_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter Helpers\n *\n * CLI-specific helper functions for Codex subprocess adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName, TokenUsage, CliResponse } from '../types.js';\nimport { createCliError as sharedCreateCliError } from '../cli-error-helpers.js';\n\n// -----------------------------------------------------------------------------\n// Legacy Fallback Defaults (for non-canonical models)\n// -----------------------------------------------------------------------------\n\n/** Legacy fallback values for Codex models not in the canonical registry. */\nexport const CODEX_LEGACY_DEFAULTS = {\n displayNames: {\n o3: 'O3',\n 'o3-mini': 'O3 Mini',\n 'o4-mini': 'O4 Mini',\n } as Readonly<Record<string, string>>,\n inputCosts: {\n o3: 10.0,\n 'o3-mini': 1.1,\n 'o4-mini': 1.1,\n } as Readonly<Record<string, number>>,\n outputCosts: {\n o3: 40.0,\n 'o3-mini': 4.4,\n 'o4-mini': 4.4,\n } as Readonly<Record<string, number>>,\n contextWindow: 400_000,\n maxOutput: 100_000,\n inputCost: 1.1,\n outputCost: 4.4,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Creates a CLI error with the canonical retryable-flag logic.\n * Kept as an alias under this name for backward compatibility with callers\n * that imported `createCodexError` before the helper was consolidated in\n * `cli-error-helpers.ts` (#2181). Prefer `createCliError` from the shared\n * helper in new code.\n */\nexport function createCodexError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Response Normalization\n// -----------------------------------------------------------------------------\n\n/** Normalizes CLI response to common format. */\nexport function normalizeCodexResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter\n *\n * MCP-based adapter for Codex CLI. Preferred transport for Codex integration.\n * Extends BaseCliAdapter to reuse retry logic, health checks, version\n * detection, and capacity tracking.\n *\n * (Source: Issue #1140 — Migrated to BaseCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell interpolation.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport type {\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n ExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport type { Result } from '../../core/index.js';\nimport { getErrorMessage, ok, err, getTimeProvider, createLogger } from '../../core/index.js';\nimport { BaseCliAdapter } from '../base-adapter.js';\n\nimport {\n CODEX_LEGACY_DEFAULTS,\n type McpToolResult,\n extractTextFromContent,\n createTimeout,\n determineErrorCode,\n} from './codex-mcp-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Codex CLI adapter using MCP transport.\n *\n * Extends BaseCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Error creation helpers\n */\nexport class CodexMcpAdapter extends BaseCliAdapter {\n readonly name: CliName = 'codex';\n readonly transport: CliTransport = 'mcp';\n\n private readonly model: string;\n private client: Client | undefined;\n private mcpTransport: StdioClientTransport | undefined;\n private connected = false;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger ?? createLogger({ component: 'codex-mcp-adapter' }));\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Initializes the MCP connection to Codex.\n */\n async initialize(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n this.initCapacityTracker();\n this.logger.debug('Initializing Codex MCP connection');\n\n try {\n this.mcpTransport = new StdioClientTransport({\n command: 'codex',\n args: ['mcp-server'],\n stderr: 'pipe',\n });\n\n this.client = new Client({ name: 'nexus-agents', version: '2.0.0' }, { capabilities: {} });\n await this.client.connect(this.mcpTransport);\n this.connected = true;\n this.initialized = true;\n this.logger.info('Codex MCP connection established');\n } catch (error) {\n this.connected = false;\n const connectionError = error instanceof Error ? error : new Error('Connection failed');\n this.logger.error('Failed to initialize Codex MCP connection', connectionError);\n throw error;\n }\n }\n\n /**\n * Executes a task via MCP client.\n * Called by BaseCliAdapter.execute() with retry handling.\n */\n async executeTask(\n _task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const startTime = getTimeProvider().now();\n\n if (this.client === undefined) {\n return err(this.createError('CONNECTION_ERROR', 'MCP client not initialized'));\n }\n\n try {\n const result = await Promise.race([\n this.callCodexTool(_task),\n createTimeout(options.timeoutMs),\n ]);\n\n if (result === null) {\n return err(this.createError('TIMEOUT', 'Execution timed out'));\n }\n\n return this.parseToolResult(result, startTime);\n } catch (error) {\n return this.handleExecutionError(error);\n }\n }\n\n /**\n * Calls the codex or codex-reply tool on Codex MCP server.\n * @see https://developers.openai.com/codex/mcp/\n */\n private async callCodexTool(task: CliTask): Promise<McpToolResult> {\n if (this.client === undefined) {\n throw new Error('Client not initialized');\n }\n\n const isReply = task.sessionId !== undefined && task.sessionId !== '';\n const toolName = isReply ? 'codex-reply' : 'codex';\n\n const baseArgs = {\n prompt: task.content,\n ...(task.model !== undefined && { model: task.model }),\n };\n\n const args = isReply\n ? { ...baseArgs, threadId: task.sessionId }\n : {\n ...baseArgs,\n sandbox: 'read-only' as const,\n 'approval-policy': 'on-failure' as const,\n };\n\n const result = await this.client.callTool({\n name: toolName,\n arguments: args,\n });\n\n return result as McpToolResult;\n }\n\n /**\n * Parses MCP tool result to CLI response.\n */\n private parseToolResult(result: McpToolResult, startTime: number): Result<CliResponse, CliError> {\n if (result.isError === true) {\n const errorText = extractTextFromContent(result.content);\n return err(this.createError('EXECUTION_ERROR', errorText ?? 'Tool execution failed'));\n }\n\n const text = extractTextFromContent(result.content);\n if (text === null) {\n return err(this.createError('PARSE_ERROR', 'No text content in response'));\n }\n\n return ok({\n text,\n durationMs: getTimeProvider().now() - startTime,\n raw: result,\n });\n }\n\n /**\n * Handles execution errors.\n */\n private handleExecutionError(error: unknown): Result<CliResponse, CliError> {\n const message = getErrorMessage(error);\n const errorCode = determineErrorCode(message);\n\n if (errorCode === 'CONNECTION_ERROR') {\n this.connected = false;\n }\n\n return err(this.createError(errorCode, message, error as Error));\n }\n\n /**\n * Disposes the adapter and closes MCP connection.\n */\n async dispose(): Promise<void> {\n if (this.mcpTransport !== undefined) {\n this.logger.debug('Closing Codex MCP connection');\n await this.mcpTransport.close();\n this.mcpTransport = undefined;\n }\n this.client = undefined;\n this.connected = false;\n this.initialized = false;\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter Helpers\n *\n * CLI-specific helper functions for Codex MCP adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n *\n * (Source: cli-project_plan.md v2.1.0, Issue #90)\n */\n\nimport type { ExecutionOptions, CliError, CliName } from '../types.js';\nimport { CODEX_MCP_TIMEOUTS } from '../../config/timeouts.js';\nimport {\n createCliError as sharedCreateCliError,\n isRetryableErrorCode as sharedIsRetryableErrorCode,\n} from '../cli-error-helpers.js';\n\n// Re-export legacy defaults from the subprocess helpers (DRY)\nexport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\n\n/**\n * Default execution options for Codex MCP.\n * Timeout and retry values derived from config/timeouts.ts (#1220).\n */\nexport const DEFAULT_CODEX_MCP_OPTIONS: Required<ExecutionOptions> = {\n timeoutMs: CODEX_MCP_TIMEOUTS.defaultMs,\n allowRetry: true,\n maxRetries: CODEX_MCP_TIMEOUTS.maxRetries,\n trackUsage: true,\n onProgress: undefined,\n};\n\n/**\n * MCP tool call result structure.\n */\nexport interface McpToolResult {\n content?: Array<{ type: string; text?: string }>;\n isError?: boolean;\n}\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Checks if an error code is retryable. Kept exported for backward\n * compatibility with callers that imported from this module; delegates\n * to the canonical helper (#2181).\n */\nexport function isRetryableErrorCode(code: CliError['code']): boolean {\n return sharedIsRetryableErrorCode(code);\n}\n\n/**\n * Creates a CLI error object with the canonical retryable-flag logic.\n * Kept exported for backward compatibility (#2181).\n */\nexport function createCliError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Content Extraction\n// -----------------------------------------------------------------------------\n\n/** Extracts text from MCP content array. */\nexport function extractTextFromContent(\n content?: Array<{ type: string; text?: string }>\n): string | null {\n if (content === undefined || content.length === 0) {\n return null;\n }\n\n const textContents = content\n .filter((c): c is { type: string; text: string } => c.type === 'text' && c.text !== undefined)\n .map((c) => c.text);\n\n return textContents.length > 0 ? textContents.join('\\n') : null;\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n\n/** Creates a timeout promise that resolves to null. */\nexport function createTimeout(ms: number): Promise<null> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve(null);\n }, ms);\n });\n}\n\n/** Determines error code from error message. */\nexport function determineErrorCode(message: string): CliError['code'] {\n if (message.includes('ENOENT') || message.includes('not found')) {\n return 'NOT_FOUND';\n }\n\n if (message.includes('timeout') || message.includes('ETIMEDOUT')) {\n return 'TIMEOUT';\n }\n\n if (message.includes('connection') || message.includes('disconnect')) {\n return 'CONNECTION_ERROR';\n }\n\n return 'EXECUTION_ERROR';\n}\n\n/** Parses version string from codex --version output. */\nexport function parseVersionFromOutput(output: string): string {\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output.trim());\n return match?.[1] ?? '0.0.0';\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Adapter\n *\n * Subprocess-based adapter for OpenCode CLI.\n * Uses `opencode run --format json` for stable parsing.\n *\n * (Source: Issue #1124, opencode.ai/docs/cli/)\n */\n\nimport { execFile } from 'node:child_process';\n\nimport type {\n ICliResponseParser,\n CliTask,\n CliModelInfo,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport {\n SubprocessCliAdapter,\n type CommandConfig,\n type TransientRetryConfig,\n} from '../subprocess-adapter.js';\nimport { OpenCodeResponseParser } from '../parsers/opencode-parser.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n} from '../../config/model-config-helpers.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-adapter' });\n\n/** Strict allowlist for OpenCode --variant flag values. */\nconst ALLOWED_VARIANTS = ['high', 'max', 'minimal'];\n\n/**\n * Maps internal model names to OpenCode CLI --model values.\n * OpenCode uses `provider/model-name` format (e.g., `anthropic/claude-sonnet-4-6`).\n * Built from canonical registry + common alias fallbacks (#1402).\n */\nconst MODEL_TO_CLI_NAME: Record<string, string> = buildOpenCodeAliasMap();\n\nfunction buildOpenCodeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('opencode')) {\n if (model.cliModelName === undefined) continue;\n // Map internal ID → CLI model name\n map[model.id] = model.cliModelName;\n // Map CLI alias → CLI model name\n if (model.cliAlias !== undefined) {\n map[model.cliAlias] = model.cliModelName;\n }\n // Pass through cliModelName itself\n map[model.cliModelName] = model.cliModelName;\n }\n return map;\n}\n\n/** Resolves an internal model name to OpenCode CLI format. */\nfunction resolveOpenCodeModel(model: string): string {\n return MODEL_TO_CLI_NAME[model] ?? model;\n}\n\n/** Timeout for `opencode models` probe (ms). */\nconst PROBE_TIMEOUT_MS = 10_000;\n\n/**\n * Probes available models by running `opencode models`.\n * Returns a Set of model IDs (e.g., \"opencode/big-pickle\").\n * Caches result in a module-level variable for the process lifetime.\n */\nlet cachedModels: Set<string> | undefined;\n/** Inflight probe promise for coalescing concurrent calls (Issue #1438). */\nlet probePromise: Promise<Set<string>> | undefined;\n\nfunction probeAvailableModels(): Promise<Set<string>> {\n if (cachedModels !== undefined) return Promise.resolve(cachedModels);\n if (probePromise !== undefined) return probePromise;\n\n probePromise = new Promise<Set<string>>((resolve) => {\n execFile('opencode', ['models'], { timeout: PROBE_TIMEOUT_MS }, (error, stdout) => {\n if (error !== null || stdout.trim() === '') {\n logger.debug('Failed to probe OpenCode models, will omit --model flag', {\n error: error?.message,\n });\n cachedModels = new Set();\n resolve(cachedModels);\n return;\n }\n const models = new Set(\n stdout\n .trim()\n .split('\\n')\n .map((l) => l.trim())\n .filter((l) => l.length > 0)\n );\n logger.debug('Probed OpenCode models', { count: models.size });\n cachedModels = models;\n resolve(cachedModels);\n });\n }).finally(() => {\n probePromise = undefined;\n });\n\n return probePromise;\n}\n\n/** Patterns indicating an Anthropic provider in OpenCode models list. */\nconst ANTHROPIC_MODEL_PATTERNS = ['anthropic/', 'custom/claude'];\n\n/**\n * Logs a warning if OpenCode has an Anthropic provider configured (#1429).\n * Claude Code subscription API keys must NOT be used with third-party tools.\n */\nfunction warnIfAnthropicProvider(models: Set<string>): void {\n const anthropicModels = [...models].filter((m) =>\n ANTHROPIC_MODEL_PATTERNS.some((p) => m.toLowerCase().includes(p))\n );\n if (anthropicModels.length > 0) {\n logger.warn(\n 'OpenCode has Anthropic/Claude models configured. ' +\n 'Ensure these use a SEPARATE API key from console.anthropic.com, ' +\n 'NOT a Claude Code subscription key (which is restricted to Claude Code only).',\n { detectedModels: anthropicModels }\n );\n }\n}\n\n/**\n * OpenCode CLI adapter using subprocess transport.\n * Executes: opencode run --format json \"<task>\"\n *\n * Probes available models on first use and omits --model flag\n * when the requested model isn't available (#1402).\n */\nexport class OpenCodeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'opencode';\n protected readonly parser: ICliResponseParser = new OpenCodeResponseParser();\n\n /** Enable transient-error retry for OpenCode (#1456). */\n protected override readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n private readonly model: string;\n private availableModels: Set<string> | undefined;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('opencode'));\n }\n\n /**\n * Gets OpenCode model information from canonical registry.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('opencode', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: `OpenCode (${this.model})`,\n contextWindow: 200_000,\n maxOutput: 64_000,\n costPerMillionInput: 3.0,\n costPerMillionOutput: 15.0,\n };\n }\n\n /**\n * Initializes the adapter — probes available models.\n * Warns if Anthropic provider is configured (#1429 — API key boundaries).\n */\n override async initialize(): Promise<void> {\n this.availableModels = await probeAvailableModels();\n warnIfAnthropicProvider(this.availableModels);\n await super.initialize();\n }\n\n /** Returns true if the model is available in the OpenCode installation. */\n private isModelAvailable(cliModel: string): boolean {\n if (this.availableModels === undefined || this.availableModels.size === 0) return false;\n return this.availableModels.has(cliModel);\n }\n\n /** Appends --model if the resolved model is available (#1402). */\n private appendModelArg(args: string[], task: CliTask): void {\n const internalModel = task.model ?? this.model;\n const cliModel = resolveOpenCodeModel(internalModel);\n\n if (this.isModelAvailable(cliModel)) {\n args.push('--model', cliModel);\n } else {\n logger.debug('Model not available, using OpenCode default', {\n requested: cliModel,\n available: this.availableModels?.size ?? 0,\n });\n }\n }\n\n /** Appends optional task flags (workDir, variant, thinking). */\n private appendTaskFlags(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--dir', workDir);\n }\n const variant = task.options?.['variant'];\n if (typeof variant === 'string' && ALLOWED_VARIANTS.includes(variant)) {\n args.push('--variant', variant);\n }\n if (task.options?.['thinking'] === true) {\n args.push('--thinking');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses `opencode run` with JSON format for stable parsing.\n * Omits --model when the requested model isn't available (#1402).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['run', '--format', 'json'];\n this.appendModelArg(args, task);\n this.appendTaskFlags(args, task);\n\n // Honor systemPrompt by prepending to stdin content (#1886).\n // OpenCode CLI has no --system-prompt or --policy equivalent, so\n // prepend is the only option. This loses the formal system-role\n // distinction, but satisfies the contract that systemPrompt\n // influences the call (far better than silently dropping it).\n const content =\n task.systemPrompt !== undefined && task.systemPrompt !== ''\n ? `${task.systemPrompt}\\n\\n---\\n\\n${task.content}`\n : task.content;\n\n return { command: 'opencode', args, stdin: content };\n }\n\n /**\n * (#2540) Lists models the local OpenCode installation can route to.\n * Wraps the existing `probeAvailableModels()` (cached for the process\n * lifetime — see `cachedModels` at the top of this file) and reshapes\n * the result into the CliModelInfo schema. Splits `provider/model` ids\n * when present.\n */\n async listModels(): Promise<readonly CliModelInfo[]> {\n const ids = await probeAvailableModels();\n const out: CliModelInfo[] = [];\n for (const raw of ids) {\n const slash = raw.indexOf('/');\n if (slash > 0 && slash < raw.length - 1) {\n out.push({ id: raw, provider: raw.slice(0, slash) });\n } else {\n out.push({ id: raw });\n }\n }\n return out;\n }\n}\n\n/**\n * Factory function for creating OpenCode adapter.\n */\nexport function createOpenCodeAdapter(options?: BaseAdapterOptions): OpenCodeCliAdapter {\n return new OpenCodeCliAdapter(options);\n}\n\n/** Resets model probe cache (for testing). */\nexport function resetOpenCodeModelCache(): void {\n cachedModels = undefined;\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Response Parser\n *\n * Defensive parser for OpenCode CLI JSON output.\n * Handles `opencode run --format json` NDJSON event stream.\n *\n * Real opencode v1.2.x NDJSON format (verified via E2E testing):\n * {\"type\":\"step_start\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-start\",...}}\n * {\"type\":\"text\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"text\",\"text\":\"Hello!\",...}}\n * {\"type\":\"step_finish\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-finish\",\"tokens\":{...},...}}\n *\n * (Source: Issue #1124, #1244, opencode.ai/docs/cli/)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-parser' });\n\n/** Minimum raw text length for plaintext fallback (#1402). */\nconst PLAINTEXT_MIN_LENGTH = 10;\n\n/** Returns true if text looks like NDJSON (most non-empty lines start with '{' ). */\nfunction looksLikeNdjson(text: string): boolean {\n const lines = text.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length === 0) return false;\n const jsonLineCount = lines.filter((l) => l.trimStart().startsWith('{')).length;\n return jsonLineCount > lines.length / 2;\n}\n\n/**\n * OpenCode CLI NDJSON event types.\n * Includes both real v1.2.x types and legacy assumed types for compatibility.\n */\nexport type OpenCodeEventType =\n // Real opencode v1.2.x event types\n | 'step_start'\n | 'text'\n | 'tool_use'\n | 'step_finish'\n | 'error'\n // Legacy assumed types (maintained for backward compatibility)\n | 'session.start'\n | 'message.start'\n | 'message.delta'\n | 'message.complete'\n | 'session.complete';\n\n/**\n * Aggregated OpenCode response from NDJSON stream.\n */\nexport interface OpenCodeCliResponse {\n readonly sessionId?: string;\n readonly content: string;\n readonly usage?: TokenUsage;\n /**\n * Concatenated error-event messages emitted during the NDJSON stream.\n * Set whenever `{\"type\":\"error\",...}` events appeared. Independent of\n * whether `content` is empty — if both are populated the model produced\n * text and then errored, callers can decide what to do.\n * #2821: previously error events were folded into `content` (making\n * failures look like successful responses to consensus voters/routers).\n */\n readonly errorMessage?: string;\n}\n\n/** Internal state from processing NDJSON lines. */\ninterface NdjsonParseState {\n readonly sessionId: string | undefined;\n readonly contentParts: string[];\n readonly errorMessages: string[];\n readonly usage: TokenUsage | undefined;\n readonly hasStepEvents: boolean;\n readonly hasAnyRecognizedEvent: boolean;\n}\n\n/**\n * Parser for OpenCode CLI JSON output.\n * Handles NDJSON event stream from `opencode run --format json`.\n *\n * Supports both real opencode v1.2.x format and legacy assumed format.\n */\nexport class OpenCodeResponseParser implements ICliResponseParser<OpenCodeCliResponse> {\n readonly name = 'opencode-parser';\n readonly supportedVersionRange = '>=1.0.0 <2.0.0';\n\n /**\n * Parses complete OpenCode CLI NDJSON stream.\n */\n parse(raw: string): OpenCodeCliResponse | null {\n const lines = raw.trim().split('\\n');\n const state = this.processAllLines(lines);\n\n const errorMessage =\n state.errorMessages.length > 0 ? state.errorMessages.join('; ') : undefined;\n\n if (state.contentParts.length === 0) {\n // #2821: error-only streams must surface as failure. Empty content +\n // errorMessage set causes extractResponse() to return null, which the\n // subprocess-adapter then classifies as EXECUTION_ERROR — instead of\n // wrapping `[OpenCode error: ...]` in ok() and feeding it to voters.\n if (errorMessage !== undefined) {\n return this.buildResponse('', state.sessionId, state.usage, errorMessage);\n }\n return this.handleEmptyContent(raw, lines.length, state);\n }\n\n return this.buildResponse(\n state.contentParts.join(''),\n state.sessionId,\n state.usage,\n errorMessage\n );\n }\n\n /** Processes all NDJSON lines and returns aggregated state. */\n private processAllLines(lines: readonly string[]): NdjsonParseState {\n let sessionId: string | undefined;\n const contentParts: string[] = [];\n const errorMessages: string[] = [];\n let usage: TokenUsage | undefined;\n let hasStepEvents = false;\n let hasAnyRecognizedEvent = false;\n\n for (let idx = 0; idx < lines.length; idx++) {\n const line = lines[idx];\n if (line === undefined || line.trim() === '') continue;\n const hadEvent = this.processLine(\n line,\n { contentParts, errorMessages },\n (id) => (sessionId = id),\n (u) => (usage = u),\n idx\n );\n if (hadEvent) hasStepEvents = true;\n if (hadEvent || this.isRecognizedLegacyEvent(line)) hasAnyRecognizedEvent = true;\n }\n\n return {\n sessionId,\n contentParts,\n errorMessages,\n usage,\n hasStepEvents,\n hasAnyRecognizedEvent,\n };\n }\n\n /** Handles the case where no text content was extracted from NDJSON. */\n private handleEmptyContent(\n raw: string,\n lineCount: number,\n state: NdjsonParseState\n ): OpenCodeCliResponse | null {\n // Tool-only responses have step_start/step_finish but no text events.\n if (state.hasStepEvents) {\n return this.buildResponse(\n '[Tool-only response — no text output]',\n state.sessionId,\n state.usage\n );\n }\n // Fallback: try parsing as plain JSON (non-streaming mode)\n logger.debug('No NDJSON content extracted, trying JSON fallback', {\n rawLength: raw.length,\n lineCount,\n hasStepEvents: state.hasStepEvents,\n hasAnyRecognizedEvent: state.hasAnyRecognizedEvent,\n });\n return this.parsePlainJson(raw, state.hasAnyRecognizedEvent);\n }\n\n /** Builds an OpenCodeCliResponse from parsed components. */\n private buildResponse(\n content: string,\n sessionId: string | undefined,\n usage: TokenUsage | undefined,\n errorMessage?: string\n ): OpenCodeCliResponse {\n return {\n content,\n ...(sessionId !== undefined && { sessionId }),\n ...(usage !== undefined && { usage }),\n ...(errorMessage !== undefined && { errorMessage }),\n };\n }\n\n /**\n * Extracts just the response text.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.content === '') {\n logger.debug('extractResponse returned null', {\n rawLength: raw.length,\n snippet: raw.slice(0, 100),\n parsedNull: parsed === null,\n });\n return null;\n }\n return parsed.content;\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n // Real format: step_finish with nested part.tokens\n if (record.type === 'step_finish') {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) return usage;\n }\n\n // Legacy format: session.complete or message.complete with usage field\n if (record.type === 'session.complete' || record.type === 'message.complete') {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) return usage;\n }\n } catch {\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n const sid = this.extractSessionIdFromLine(line);\n if (sid !== null) return sid;\n }\n\n return null;\n }\n\n /** Extracts session ID from a single NDJSON line. */\n private extractSessionIdFromLine(line: string): string | null {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return null;\n\n // Real format: sessionID at top level (step_start, text, step_finish)\n if (typeof record.sessionID === 'string') return record.sessionID;\n\n // Legacy format: session_id/sessionId in session events\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') return sid;\n\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * Processes a single NDJSON line.\n * Handles both real v1.2.x format and legacy assumed format.\n * Returns true if a real v1.2.x step event was processed (step_start/text/tool_use/step_finish).\n * Legacy events return false since they don't indicate tool-only responses.\n */\n private processLine(\n line: string,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void,\n lineIndex: number\n ): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n\n const isReal = this.processRealEvent(record, collectors, setSessionId, setUsage);\n if (isReal) return true;\n\n this.processLegacyEvent(record, collectors.contentParts, setSessionId, setUsage);\n return false;\n } catch {\n logger.debug('Skipped malformed NDJSON line', {\n lineNumber: lineIndex + 1,\n snippet: line.slice(0, 100),\n });\n return false;\n }\n }\n\n /** Processes real opencode v1.2.x event types. Returns true if handled. */\n private processRealEvent(\n record: Record<string, unknown>,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): boolean {\n switch (record.type) {\n case 'step_start':\n case 'tool_use':\n this.handleRealSessionId(record, setSessionId);\n return true;\n case 'text':\n this.handleRealSessionId(record, setSessionId);\n this.pushRealTextContent(record, collectors.contentParts);\n return true;\n case 'step_finish':\n this.handleRealSessionId(record, setSessionId);\n this.emitRealUsage(record, setUsage);\n return true;\n case 'error':\n this.handleRealSessionId(record, setSessionId);\n this.captureErrorMessage(record, collectors.errorMessages);\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Captures an error-event message for the response's `errorMessage` field\n * (#2821). Previously this pushed `[OpenCode error: ...]` into `contentParts`,\n * which made error-only streams look like successful responses to consensus\n * voters and the routing learner.\n */\n private captureErrorMessage(record: Record<string, unknown>, errorMessages: string[]): void {\n const errorObj = asRecord(record.error);\n if (errorObj === null) return;\n\n const data = asRecord(errorObj.data);\n const message =\n data !== null && typeof data.message === 'string'\n ? data.message\n : typeof errorObj.name === 'string'\n ? errorObj.name\n : 'Unknown error';\n\n logger.warn('OpenCode returned error event', { message });\n errorMessages.push(message);\n }\n\n /** Processes legacy assumed event types. */\n private processLegacyEvent(\n record: Record<string, unknown>,\n contentParts: string[],\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n switch (record.type) {\n case 'session.start':\n this.handleLegacySessionStart(record, setSessionId);\n break;\n case 'message.delta':\n this.pushLegacyTextContent(record, contentParts);\n break;\n case 'message.complete':\n this.pushLegacyTextContent(record, contentParts);\n this.emitLegacyUsage(record, setUsage);\n break;\n case 'session.complete':\n this.emitLegacyUsage(record, setUsage);\n break;\n }\n }\n\n // --- Real v1.2.x format handlers ---\n\n /** Extracts sessionID from top-level field (real format). */\n private handleRealSessionId(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n if (typeof record.sessionID === 'string') setSessionId(record.sessionID);\n }\n\n /** Extracts text from nested part.text field (real format). */\n private pushRealTextContent(record: Record<string, unknown>, parts: string[]): void {\n const part = asRecord(record.part);\n if (part === null) return;\n\n if (typeof part.text === 'string') parts.push(part.text);\n }\n\n /** Extracts usage from nested part.tokens field (real format). */\n private emitRealUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Extracts usage from part.tokens (real opencode v1.2.x format). */\n private extractUsageFromPart(record: Record<string, unknown>): TokenUsage | null {\n const part = asRecord(record.part);\n if (part === null) return null;\n\n const tokens = asRecord(part.tokens);\n if (tokens === null) return null;\n\n const inputTokens = extractNumberField(tokens, 'input');\n const outputTokens = extractNumberField(tokens, 'output');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n\n // --- Legacy format handlers ---\n\n /** Extracts session ID from a session event record (legacy format). */\n private handleLegacySessionStart(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') setSessionId(sid);\n }\n\n /** Pushes text content from a message event (legacy format). */\n private pushLegacyTextContent(record: Record<string, unknown>, parts: string[]): void {\n const text = record.content ?? record.delta ?? record.text;\n if (typeof text === 'string') parts.push(text);\n }\n\n /** Emits usage from a record (legacy format). */\n private emitLegacyUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Checks if a line contains a recognized legacy event type (without full parsing). */\n private isRecognizedLegacyEvent(line: string): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n const t = record.type;\n return (\n t === 'session.start' ||\n t === 'message.start' ||\n t === 'message.delta' ||\n t === 'message.complete' ||\n t === 'session.complete'\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Fallback parser for plain JSON output (non-streaming).\n * Falls back to raw plaintext if JSON parsing fails and content is substantial (#1402).\n * When hasAnyRecognizedEvent is true, NDJSON-like plaintext is rejected (it was\n * recognized NDJSON that simply had no content — not malformed output).\n */\n private parsePlainJson(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n\n // Try common response field names\n const content = record.content ?? record.result ?? record.text ?? record.output;\n if (typeof content !== 'string') return null; // Valid JSON but no recognized fields\n\n const usage = this.extractUsageFromRecord(record);\n const sid = record.session_id ?? record.sessionId;\n\n return {\n content,\n ...(typeof sid === 'string' ? { sessionId: sid } : {}),\n ...(usage !== null ? { usage } : {}),\n };\n } catch {\n return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n }\n }\n\n /**\n * Last-resort plaintext fallback for non-JSON CLI output (#1402).\n * Returns raw text as content when it has substantial length.\n * Accepts NDJSON-like content only when no recognized events were found\n * (meaning it's truly unrecognized/malformed output, not valid NDJSON with no text).\n */\n private parsePlaintext(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n const trimmed = raw.trim();\n if (trimmed.length < PLAINTEXT_MIN_LENGTH) {\n logger.debug('Plaintext fallback rejected: too short', { length: trimmed.length });\n return null;\n }\n if (looksLikeNdjson(trimmed)) {\n if (hasAnyRecognizedEvent) {\n logger.debug('Plaintext fallback rejected: recognized NDJSON with no content', {\n length: trimmed.length,\n });\n return null;\n }\n logger.debug('Plaintext fallback: accepting malformed NDJSON as text', {\n length: trimmed.length,\n });\n }\n return { content: trimmed };\n }\n\n /**\n * Extracts usage from a record with usage/token fields (legacy format).\n */\n private extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens =\n extractNumberField(usage, 'input_tokens') ?? extractNumberField(usage, 'inputTokens');\n const outputTokens =\n extractNumberField(usage, 'output_tokens') ?? extractNumberField(usage, 'outputTokens');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n}\n","/**\n * nexus-agents/cli-adapters - CLI Detection Cache\n *\n * Caches CLI health check results to avoid repeated subprocess calls.\n * Invalidates on circuit breaker trips or manual invalidation.\n *\n * @module cli-adapters/cli-detection-cache\n * (Source: Issue #165, Proposal adapter-architecture-review.md)\n */\n\nimport { z } from 'zod';\nimport { createLogger } from '../core/logger.js';\nimport type { ILogger } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { CliName, HealthStatus, VersionStatus } from './types.js';\n\n/**\n * Cached health result for a CLI.\n */\nexport interface CliHealthResult {\n /** Whether the CLI is healthy and available */\n readonly healthy: boolean;\n /** CLI version detected */\n readonly version: string;\n /** Version compatibility status */\n readonly versionStatus: VersionStatus;\n /** When this result was captured */\n readonly checkedAt: Date;\n /** Optional status message */\n readonly message?: string | undefined;\n}\n\n/**\n * Configuration for the CLI detection cache.\n */\nexport interface CliDetectionCacheConfig {\n /** Base time-to-live in milliseconds (default: 5 minutes) */\n readonly ttlMs: number;\n /** Enable adaptive TTL based on health history (default: true) */\n readonly adaptiveTtl?: boolean | undefined;\n /** Logger instance */\n readonly logger?: ILogger | undefined;\n}\n\n/**\n * Zod schema for cache configuration validation.\n */\nexport const CliDetectionCacheConfigSchema = z.object({\n ttlMs: z.number().min(1000).max(3600_000).default(300_000),\n});\n\n/**\n * Default cache configuration.\n */\nexport const DEFAULT_CACHE_CONFIG: CliDetectionCacheConfig = {\n ttlMs: 300_000, // 5 minutes\n adaptiveTtl: true,\n};\n\n/** Adaptive TTL multipliers. Healthy CLIs are polled less often; unhealthy more often. */\nconst ADAPTIVE_MULTIPLIER_HEALTHY = 2.0;\nconst ADAPTIVE_MULTIPLIER_UNHEALTHY = 0.25;\n/** Number of consecutive same-status results before the multiplier kicks in. */\nconst ADAPTIVE_STREAK_THRESHOLD = 2;\n\n/**\n * Interface for CLI detection cache.\n * Allows dependency injection for testing.\n */\nexport interface ICliDetectionCache {\n /** Get cached health result for a CLI */\n get(cli: CliName): CliHealthResult | undefined;\n\n /** Set health result for a CLI */\n set(cli: CliName, result: CliHealthResult): void;\n\n /** Check if cache entry is stale */\n isStale(cli: CliName): boolean;\n\n /** Invalidate cache for a specific CLI or all CLIs */\n invalidate(cli?: CliName): void;\n\n /** Get all cached results */\n getAll(): ReadonlyMap<CliName, CliHealthResult>;\n\n /** Get cache statistics */\n getStats(): CacheStats;\n\n /** Get effective TTL for a CLI (accounts for adaptive adjustments) */\n getEffectiveTtl(cli: CliName): number;\n}\n\n/**\n * Cache statistics for observability.\n */\nexport interface CacheStats {\n /** Number of cached entries */\n readonly size: number;\n /** Cache hits since last reset */\n readonly hits: number;\n /** Cache misses since last reset */\n readonly misses: number;\n /** Hit rate (0-1) */\n readonly hitRate: number;\n /** When stats were last reset */\n readonly lastReset: Date;\n}\n\n/**\n * CLI detection cache implementation.\n * Thread-safe for Node.js single-threaded execution.\n */\nexport class CliDetectionCache implements ICliDetectionCache {\n private readonly config: CliDetectionCacheConfig;\n private readonly logger: ILogger;\n private readonly cache: Map<CliName, CliHealthResult> = new Map();\n /** Consecutive same-health-status count per CLI (for adaptive TTL). */\n private readonly streaks: Map<CliName, { healthy: boolean; count: number }> = new Map();\n private hits = 0;\n private misses = 0;\n private lastReset: Date = new Date(getTimeProvider().now());\n\n constructor(config?: Partial<CliDetectionCacheConfig>) {\n const validated = CliDetectionCacheConfigSchema.parse({\n ttlMs: config?.ttlMs ?? DEFAULT_CACHE_CONFIG.ttlMs,\n });\n this.config = {\n ...validated,\n adaptiveTtl: config?.adaptiveTtl ?? DEFAULT_CACHE_CONFIG.adaptiveTtl,\n logger: config?.logger,\n };\n this.logger = config?.logger ?? createLogger({ component: 'CliDetectionCache' });\n\n this.logger.debug('CliDetectionCache initialized', { ttlMs: this.config.ttlMs });\n }\n\n get(cli: CliName): CliHealthResult | undefined {\n const result = this.cache.get(cli);\n\n if (result === undefined) {\n this.misses++;\n this.logger.debug('Cache miss', { cli });\n return undefined;\n }\n\n if (this.isStale(cli)) {\n this.misses++;\n this.logger.debug('Cache stale', { cli, checkedAt: result.checkedAt });\n return undefined;\n }\n\n this.hits++;\n this.logger.debug('Cache hit', { cli, healthy: result.healthy });\n return result;\n }\n\n set(cli: CliName, result: CliHealthResult): void {\n this.cache.set(cli, result);\n this.updateStreak(cli, result.healthy);\n this.logger.debug('Cache updated', {\n cli,\n healthy: result.healthy,\n version: result.version,\n });\n }\n\n isStale(cli: CliName): boolean {\n const result = this.cache.get(cli);\n if (result === undefined) return true;\n\n const age = getTimeProvider().now() - result.checkedAt.getTime();\n return age > this.getEffectiveTtl(cli);\n }\n\n /** Returns the effective TTL for a CLI, applying adaptive multiplier if enabled. */\n getEffectiveTtl(cli: CliName): number {\n if (this.config.adaptiveTtl === false) return this.config.ttlMs;\n const streak = this.streaks.get(cli);\n if (streak === undefined || streak.count < ADAPTIVE_STREAK_THRESHOLD) {\n return this.config.ttlMs;\n }\n const multiplier = streak.healthy ? ADAPTIVE_MULTIPLIER_HEALTHY : ADAPTIVE_MULTIPLIER_UNHEALTHY;\n return this.config.ttlMs * multiplier;\n }\n\n private updateStreak(cli: CliName, healthy: boolean): void {\n const prev = this.streaks.get(cli);\n if (prev?.healthy === healthy) {\n this.streaks.set(cli, { healthy, count: prev.count + 1 });\n } else {\n this.streaks.set(cli, { healthy, count: 1 });\n }\n }\n\n invalidate(cli?: CliName): void {\n if (cli !== undefined) {\n this.cache.delete(cli);\n this.streaks.delete(cli);\n this.logger.info('Cache invalidated', { cli });\n } else {\n this.cache.clear();\n this.streaks.clear();\n this.logger.info('Cache cleared');\n }\n }\n\n getAll(): ReadonlyMap<CliName, CliHealthResult> {\n return this.cache;\n }\n\n getStats(): CacheStats {\n const total = this.hits + this.misses;\n return {\n size: this.cache.size,\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n lastReset: this.lastReset,\n };\n }\n\n /**\n * Resets cache statistics.\n */\n resetStats(): void {\n this.hits = 0;\n this.misses = 0;\n this.lastReset = new Date(getTimeProvider().now());\n this.logger.debug('Cache stats reset');\n }\n\n /**\n * Converts HealthStatus to CliHealthResult for caching.\n */\n static fromHealthStatus(status: HealthStatus): CliHealthResult {\n return {\n healthy: status.healthy,\n version: status.version,\n versionStatus: status.versionStatus,\n checkedAt: status.lastChecked,\n message: status.message,\n };\n }\n}\n\n/**\n * Creates a CLI detection cache instance.\n *\n * @param config - Optional cache configuration\n * @returns CLI detection cache\n *\n * @example\n * ```typescript\n * const cache = createCliDetectionCache({ ttlMs: 60_000 }); // 1 minute TTL\n * const result = cache.get('claude');\n * if (!result) {\n * const health = await adapter.healthCheck();\n * cache.set('claude', CliDetectionCache.fromHealthStatus(health));\n * }\n * ```\n */\nexport function createCliDetectionCache(\n config?: Partial<CliDetectionCacheConfig>\n): ICliDetectionCache {\n return new CliDetectionCache(config);\n}\n","/**\n * cli-auth-probe — real authentication probes for the four AI CLIs.\n *\n * The existing `adapter.healthCheck()` only confirms the CLI binary exists +\n * the version is supported. It does NOT probe whether the CLI can actually\n * authenticate. Result: doctor reports \"✓ Auth: CLI auth\" for installed-but-\n * unauthed CLIs, then downstream commands fail with unreadable errors.\n *\n * This module fixes that. Per-CLI probes use the cheapest reliable signal:\n *\n * - claude → presence + non-expired `~/.claude/.credentials.json`\n * (or env: ANTHROPIC_API_KEY)\n * - codex → `codex login status` (returns auth state)\n * (or env: OPENAI_API_KEY)\n * - gemini → presence + non-expired `~/.gemini/oauth_creds.json`\n * (or env: GOOGLE_AI_API_KEY)\n * - opencode → `opencode auth list` (parses credential count)\n *\n * No live API calls. Tokens are not decoded or sent anywhere — only their\n * presence/expiry is read locally.\n *\n * Source: Issue #2447. Replaces the binary-detection-only path in doctor.ts\n * (Issue #2439 follow-up).\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\nimport type { CliName } from '../cli-adapters/types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Result of probing a single CLI's authentication state. Discriminated so\n * callers can render auth | needs-login | not-installed | error states\n * without re-checking flags.\n */\nexport type AuthProbeResult =\n | {\n readonly cli: CliName;\n readonly state: 'authenticated';\n /** How auth was satisfied — informational, not load-bearing. */\n readonly via: 'env-var' | 'cli-credentials';\n /** Optional metadata (e.g. expiry timestamp) if cheap to extract. */\n readonly meta?: Readonly<Record<string, unknown>>;\n }\n | {\n readonly cli: CliName;\n readonly state: 'needs-login';\n /** Short, human-readable reason to surface to the operator. */\n readonly reason: string;\n /** Exact command the operator should run to fix this. */\n readonly fixCommand: string;\n /** Optional canonical URL for credentials/console. */\n readonly fixUrl?: string;\n /** Env-var alternative if applicable. */\n readonly envFallback?: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'not-installed';\n readonly reason: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'error';\n readonly reason: string;\n };\n\nconst HOME = homedir();\n\n// ============================================================================\n// Per-CLI probes\n// ============================================================================\n\nfunction claudeNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'claude',\n state: 'needs-login',\n reason,\n fixCommand: 'claude /login',\n envFallback: 'ANTHROPIC_API_KEY',\n fixUrl: 'https://console.anthropic.com/account/keys',\n };\n}\n\nfunction probeClaude(): AuthProbeResult {\n if (process.env['ANTHROPIC_API_KEY'] !== undefined && process.env['ANTHROPIC_API_KEY'] !== '') {\n return { cli: 'claude', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.claude', '.credentials.json');\n if (!existsSync(credPath)) {\n return claudeNeedsLogin(\n 'No credentials at ~/.claude/.credentials.json and ANTHROPIC_API_KEY is not set'\n );\n }\n try {\n const parsed: unknown = JSON.parse(readFileSync(credPath, 'utf-8'));\n if (!isClaudeCredsShape(parsed)) {\n return claudeNeedsLogin(\n 'Credentials file present but not in expected shape (missing claudeAiOauth.accessToken)'\n );\n }\n const expiresAt = parsed.claudeAiOauth.expiresAt;\n if (typeof expiresAt === 'number' && expiresAt < Date.now()) {\n return claudeNeedsLogin(`OAuth token expired ${new Date(expiresAt).toISOString()}`);\n }\n return {\n cli: 'claude',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof expiresAt === 'number' ? { meta: { expiresAt } } : {}),\n };\n } catch (e: unknown) {\n return {\n cli: 'claude',\n state: 'error',\n reason: `Failed to read claude credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nfunction codexNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'codex',\n state: 'needs-login',\n reason,\n fixCommand: 'codex login',\n envFallback: 'OPENAI_API_KEY',\n fixUrl: 'https://platform.openai.com/api-keys',\n };\n}\n\nfunction classifyCodexStdout(stdout: string): AuthProbeResult {\n // Check 'not logged in' BEFORE 'logged in' — substring shadowing.\n if (/not logged/i.test(stdout) || /no.*token/i.test(stdout)) {\n return codexNeedsLogin(stdout.trim().split('\\n')[0] ?? 'Not logged in');\n }\n // Probe succeeded; treat unrecognized output as authed (defensive default).\n return { cli: 'codex', state: 'authenticated', via: 'cli-credentials' };\n}\n\nasync function probeCodex(): Promise<AuthProbeResult> {\n if (process.env['OPENAI_API_KEY'] !== undefined && process.env['OPENAI_API_KEY'] !== '') {\n return { cli: 'codex', state: 'authenticated', via: 'env-var' };\n }\n try {\n const { stdout } = await execFileAsync('codex', ['login', 'status'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n return classifyCodexStdout(stdout);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'codex', state: 'not-installed', reason: 'codex binary not on PATH' };\n }\n return codexNeedsLogin('Not logged in (codex login status returned non-zero)');\n }\n}\n\nfunction geminiNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'gemini',\n state: 'needs-login',\n reason,\n fixCommand: 'gemini',\n envFallback: 'GOOGLE_AI_API_KEY',\n fixUrl: 'https://aistudio.google.com/apikey',\n };\n}\n\nfunction classifyGeminiCreds(parsed: unknown): AuthProbeResult {\n if (!isGeminiCredsShape(parsed)) {\n return geminiNeedsLogin('OAuth credentials file present but not in expected shape');\n }\n if (typeof parsed.expiry_date === 'number' && parsed.expiry_date < Date.now()) {\n return geminiNeedsLogin(\n `OAuth access token expired ${new Date(parsed.expiry_date).toISOString()} (refresh may still work)`\n );\n }\n return {\n cli: 'gemini',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof parsed.expiry_date === 'number' ? { meta: { expiresAt: parsed.expiry_date } } : {}),\n };\n}\n\nfunction probeGemini(): AuthProbeResult {\n const env = process.env['GOOGLE_AI_API_KEY'] ?? process.env['GEMINI_API_KEY'];\n if (env !== undefined && env !== '') {\n return { cli: 'gemini', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.gemini', 'oauth_creds.json');\n if (!existsSync(credPath)) {\n return geminiNeedsLogin(\n 'No OAuth credentials at ~/.gemini/oauth_creds.json and GOOGLE_AI_API_KEY/GEMINI_API_KEY are not set'\n );\n }\n try {\n return classifyGeminiCreds(JSON.parse(readFileSync(credPath, 'utf-8')));\n } catch (e: unknown) {\n return {\n cli: 'gemini',\n state: 'error',\n reason: `Failed to read gemini credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nasync function probeOpencode(): Promise<AuthProbeResult> {\n // OpenCode's auth is per-provider (anthropic/openai/etc) configured in\n // ~/.config/opencode/opencode.json or via env. Probe by listing credentials.\n try {\n const { stdout } = await execFileAsync('opencode', ['auth', 'list'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n if (/0 credentials/i.test(stdout)) {\n return {\n cli: 'opencode',\n state: 'needs-login',\n reason: 'No providers configured in opencode',\n fixCommand: 'opencode auth login',\n fixUrl: 'https://opencode.ai/docs/config',\n };\n }\n return { cli: 'opencode', state: 'authenticated', via: 'cli-credentials' };\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'opencode', state: 'not-installed', reason: 'opencode binary not on PATH' };\n }\n return {\n cli: 'opencode',\n state: 'error',\n reason: msg.split('\\n')[0] ?? 'opencode auth list failed',\n };\n }\n}\n\n// ============================================================================\n// Type guards (no `any`, no untyped JSON)\n// ============================================================================\n\ninterface ClaudeCreds {\n readonly claudeAiOauth: {\n readonly accessToken: string;\n readonly expiresAt?: number;\n };\n}\n\nfunction isClaudeCredsShape(v: unknown): v is ClaudeCreds {\n if (typeof v !== 'object' || v === null) return false;\n const oauth = (v as { claudeAiOauth?: unknown }).claudeAiOauth;\n if (typeof oauth !== 'object' || oauth === null) return false;\n return typeof (oauth as { accessToken?: unknown }).accessToken === 'string';\n}\n\ninterface GeminiCreds {\n readonly access_token: string;\n readonly expiry_date?: number;\n}\n\nfunction isGeminiCredsShape(v: unknown): v is GeminiCreds {\n if (typeof v !== 'object' || v === null) return false;\n return typeof (v as { access_token?: unknown }).access_token === 'string';\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/** Probe a single CLI. */\nexport async function probeCli(cli: CliName): Promise<AuthProbeResult> {\n switch (cli) {\n case 'claude':\n return Promise.resolve(probeClaude());\n case 'codex':\n return probeCodex();\n case 'gemini':\n return Promise.resolve(probeGemini());\n case 'opencode':\n return probeOpencode();\n }\n}\n\n/** Probe all four CLIs in parallel. Order in returned array matches input. */\nexport async function probeAllClis(): Promise<readonly AuthProbeResult[]> {\n const clis: readonly CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n return Promise.all(clis.map((c) => probeCli(c)));\n}\n","/**\n * nexus-agents/cli-adapters - Adapter Factory\n *\n * Factory for creating CLI adapters based on configuration.\n * Supports optional caching of CLI health check results.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #90 - Codex MCP adapter)\n * (Source: Issue #165 - CLI detection cache)\n */\n\nimport type { ICliAdapter, CliName, CliTransport } from './types.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { ClaudeCliAdapter } from './adapters/claude-adapter.js';\nimport { GeminiCliAdapter } from './adapters/gemini-adapter.js';\nimport { CodexCliAdapter } from './adapters/codex-adapter.js';\nimport { CodexMcpAdapter } from './adapters/codex-mcp-adapter.js';\nimport { OpenCodeCliAdapter } from './adapters/opencode-adapter.js';\nimport type { ILogger } from '../core/index.js';\nimport type { ICliDetectionCache } from './cli-detection-cache.js';\nimport { CliDetectionCache } from './cli-detection-cache.js';\nimport { probeCli } from '../cli/cli-auth-probe.js';\n\n/**\n * Configuration for creating a CLI adapter.\n */\nexport interface CliAdapterConfig {\n /** Which CLI to use */\n readonly cli: CliName;\n /** Optional model override */\n readonly model?: string;\n /** Optional logger */\n readonly logger?: ILogger;\n /** Preferred transport (for Codex: 'mcp' or 'subprocess') */\n readonly transport?: CliTransport;\n}\n\n/**\n * Creates a CLI adapter based on configuration.\n *\n * @param config - Adapter configuration\n * @returns The configured CLI adapter\n * @throws Error if CLI name is not supported\n *\n * @example\n * ```typescript\n * const adapter = createCliAdapter({ cli: 'claude', model: 'claude-opus-4' });\n * const result = await adapter.execute({ content: 'Hello!' });\n * ```\n */\nexport function createCliAdapter(config: CliAdapterConfig): ICliAdapter {\n const options = {\n ...(config.model !== undefined && { model: config.model }),\n ...(config.logger !== undefined && { logger: config.logger }),\n };\n\n switch (config.cli) {\n case 'claude':\n return new ClaudeCliAdapter(options);\n\n case 'gemini':\n return new GeminiCliAdapter(options);\n\n case 'codex':\n return createCodexAdapter(config.transport, options);\n\n case 'opencode':\n return new OpenCodeCliAdapter(options);\n\n default: {\n const exhaustiveCheck: never = config.cli;\n throw new Error(`Unsupported CLI: ${String(exhaustiveCheck)}`);\n }\n }\n}\n\n/**\n * Creates a Codex adapter with preferred transport.\n * Defaults to MCP transport (most stable).\n *\n * @param transport - Preferred transport ('mcp' or 'subprocess')\n * @param options - Adapter options\n * @returns Codex CLI adapter\n */\nfunction createCodexAdapter(\n transport: CliTransport | undefined,\n options: { model?: string; logger?: ILogger }\n): ICliAdapter {\n // Default to MCP transport (preferred per Issue #90)\n if (transport === 'subprocess') {\n return new CodexCliAdapter(options);\n }\n return new CodexMcpAdapter(options);\n}\n\n/**\n * Creates all available CLI adapters.\n * Uses MCP transport for Codex by default (preferred).\n *\n * @param logger - Optional shared logger\n * @param codexTransport - Transport for Codex (default: 'mcp')\n * @returns Map of CLI name to adapter\n */\nexport function createAllAdapters(\n logger?: ILogger,\n codexTransport: CliTransport = 'mcp'\n): Map<CliName, ICliAdapter> {\n const adapters = new Map<CliName, ICliAdapter>();\n const options = logger !== undefined ? { logger } : undefined;\n\n adapters.set('claude', new ClaudeCliAdapter(options));\n adapters.set('gemini', new GeminiCliAdapter(options));\n adapters.set('codex', createCodexAdapter(codexTransport, options ?? {}));\n adapters.set('opencode', new OpenCodeCliAdapter(options));\n\n return adapters;\n}\n\n/**\n * Checks if a CLI is available by running a health check.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cli - CLI name to check\n * @param cache - Optional cache to use\n * @returns True if CLI is healthy\n */\nexport async function isCliAvailable(cli: CliName, cache?: ICliDetectionCache): Promise<boolean> {\n // Check cache first\n if (cache !== undefined) {\n const cached = cache.get(cli);\n if (cached !== undefined) {\n return cached.healthy;\n }\n }\n\n try {\n const adapter = createCliAdapter({ cli });\n // Pre-#2725 only ran healthCheck() — which confirms the binary exists\n // and runs but does NOT probe authentication. Result: orchestrate listed\n // opencode as \"Available\" when the user wasn't logged in, and the next\n // call failed with an opaque subprocess error. Auth must agree with the\n // probe doctor already uses (cli-auth-probe.ts, #2447).\n const [health, auth] = await Promise.all([adapter.healthCheck(), probeCli(cli)]);\n const available = health.healthy && auth.state === 'authenticated';\n\n // Store in cache if provided. Synthesize a degraded health record when\n // the binary is healthy but auth failed, so downstream consumers see\n // \"unavailable\" without losing the version string.\n if (cache !== undefined) {\n if (available) {\n cache.set(cli, CliDetectionCache.fromHealthStatus(health));\n } else {\n cache.set(cli, {\n healthy: false,\n version: health.version,\n versionStatus: health.versionStatus,\n checkedAt: new Date(),\n message:\n auth.state === 'authenticated'\n ? health.message\n : `auth: ${auth.state}` + ('reason' in auth ? ` (${auth.reason})` : ''),\n });\n }\n }\n\n return available;\n } catch {\n // Store negative result in cache\n if (cache !== undefined) {\n cache.set(cli, {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n checkedAt: new Date(getTimeProvider().now()),\n message: 'Health check failed',\n });\n }\n return false;\n }\n}\n\n/**\n * Gets all available CLIs by running health checks.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cache - Optional cache to use\n * @returns Array of available CLI names\n */\nexport async function getAvailableClis(cache?: ICliDetectionCache): Promise<CliName[]> {\n const clis: CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n\n // Check all CLIs in parallel to avoid sequential timeout penalties\n const results = await Promise.allSettled(\n clis.map(async (cli) => ({ cli, available: await isCliAvailable(cli, cache) }))\n );\n\n return results\n .filter(\n (r): r is PromiseFulfilledResult<{ cli: CliName; available: boolean }> =>\n r.status === 'fulfilled' && r.value.available\n )\n .map((r) => r.value.cli);\n}\n"],"mappings":"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","names":["estimateTaskComplexity","logger","msg","snippet","estimateTaskComplexity","writeFileSync","rmSync","mkdtempSync","tmpdir","join","logger","mkdtempSync","join","tmpdir","writeFileSync","rmSync","logger","logger","execFile","promisify","join","promisify","execFile","join","logger"]}
1
+ {"version":3,"sources":["../src/cli-adapters/subprocess-adapter.ts","../src/cli-adapters/base-adapter.ts","../src/cli-adapters/cli-timeout-helpers.ts","../src/cli-adapters/cli-timeout-profiles.ts","../src/cli-adapters/capacity-tracker.ts","../src/utils/async-utils.ts","../src/cli-adapters/cli-error-helpers.ts","../src/cli-adapters/cli-retry-loop.ts","../src/cli-adapters/subprocess-env.ts","../src/security/output-sanitizer.ts","../src/cli-adapters/cli-error-envelope.ts","../src/utils/type-coercion.ts","../src/cli-adapters/parsers/claude-parser.ts","../src/cli-adapters/adapters/claude-adapter.ts","../src/cli-adapters/adapters/gemini-adapter.ts","../src/cli-adapters/parsers/gemini-parser-resilient-helpers.ts","../src/cli-adapters/parsers/gemini-parser-resilient.ts","../src/cli-adapters/adapters/gemini-adapter-helpers.ts","../src/cli-adapters/adapters/codex-adapter.ts","../src/cli-adapters/parsers/codex-parser.ts","../src/cli-adapters/adapters/codex-adapter-helpers.ts","../src/cli-adapters/adapters/codex-mcp-adapter.ts","../src/cli-adapters/adapters/codex-mcp-adapter-helpers.ts","../src/cli-adapters/adapters/opencode-adapter.ts","../src/cli-adapters/parsers/opencode-parser.ts","../src/cli-adapters/cli-detection-cache.ts","../src/cli/cli-auth-probe.ts","../src/cli-adapters/factory.ts"],"sourcesContent":["/**\n * nexus-agents/cli-adapters - Subprocess Adapter\n *\n * Base class for subprocess-based CLI adapters.\n * Used by ClaudeCliAdapter and GeminiCliAdapter.\n *\n * Extracted from base-adapter.ts per Issue #272 (file size limits).\n */\n\nimport { spawn } from 'node:child_process';\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, getTimeProvider, createLogger } from '../core/index.js';\n\nimport type {\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n ExecutionOptions,\n ICliResponseParser,\n} from './types.js';\nimport { BaseCliAdapter } from './base-adapter.js';\nimport { buildChildEnv } from './subprocess-env.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { parseCliErrorEnvelope } from './cli-error-envelope.js';\n\n/** Minimum length for plaintext fallback to kick in.\n * Lowered from 100→30 to recover short but valid CLI responses (#1401). */\nconst PLAINTEXT_FALLBACK_MIN_LENGTH = 30;\n\n/**\n * Attempts to extract a usable response from raw stdout when the structured\n * parser fails. Returns the trimmed text if it looks like natural language\n * (not JSON/NDJSON) and exceeds the minimum length threshold.\n *\n * Recovers responses from CLIs that output plaintext instead of their\n * expected structured format. (#1401)\n */\nfunction tryPlaintextFallback(stdout: string): string | null {\n const trimmed = stdout.trim();\n if (trimmed.length < PLAINTEXT_FALLBACK_MIN_LENGTH) return null;\n // Skip if it looks like structured output the parser should handle\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) return null;\n return trimmed;\n}\n\n/** Error patterns in stderr that indicate a real failure, not debug output (#1402). */\nconst STDERR_ERROR_PATTERNS = [\n 'error:',\n 'fatal:',\n 'panic:',\n 'unhandled',\n 'not found',\n 'invalid model',\n 'authentication',\n 'unauthorized',\n 'permission denied',\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'timeout',\n 'failed to connect',\n 'invalid api key',\n 'rate limit',\n 'quota exceeded',\n 'service unavailable',\n];\n\n/** Checks if stderr looks like a real error (not just debug/progress output). */\nfunction looksLikeErrorStderr(stderr: string): boolean {\n const lower = stderr.toLowerCase();\n return STDERR_ERROR_PATTERNS.some((pattern) => lower.includes(pattern));\n}\n\n/** Stderr patterns indicating transient connection failures (retryable). */\nconst STDERR_CONNECTION_PATTERNS = [\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'econnreset',\n 'failed to connect',\n 'service unavailable',\n 'eaddrinuse',\n 'address already in use',\n];\n\n/** Stderr patterns indicating timeout (retryable). */\nconst STDERR_TIMEOUT_PATTERNS = ['timeout', 'timed out', 'etimedout'];\n\n/**\n * Classifies a stderr error message into the most specific CliErrorCode.\n * Checks for transient patterns (connection, rate-limit, timeout) before\n * falling back to EXECUTION_ERROR. This ensures transient failures in\n * stderr are retried instead of treated as terminal. (#1401)\n *\n * Rate-limit detection uses shared patterns from rate-limit-detector. (#1596)\n */\nfunction classifyStderrError(stderr: string): CliErrorCode {\n const lower = stderr.toLowerCase();\n if (STDERR_CONNECTION_PATTERNS.some((p) => lower.includes(p))) return 'CONNECTION_ERROR';\n if (isRateLimitText(stderr)) return 'RATE_LIMITED';\n if (STDERR_TIMEOUT_PATTERNS.some((p) => lower.includes(p))) return 'TIMEOUT';\n return 'EXECUTION_ERROR';\n}\n\nconst subprocessLogger = createLogger({ component: 'subprocess-adapter' });\n\n/** Maximum buffer size for stdout/stderr (10 MB). */\nconst MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\n/** CliErrorCodes that represent transient failures safe to retry. */\nconst TRANSIENT_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n 'PARSE_ERROR',\n]);\n\n/** Delay schedule for transient-error retries (ms per attempt index). */\nconst TRANSIENT_RETRY_DELAYS_MS = [500, 1000] as const;\n\n/** Maximum number of transient-error retries. */\nconst MAX_TRANSIENT_RETRIES = TRANSIENT_RETRY_DELAYS_MS.length;\n\n/**\n * Maximum retries for PARSE_ERROR specifically (#1533).\n * Parse errors are less likely to self-heal than timeouts/connection errors,\n * so we cap at 1 retry instead of 2.\n */\nexport const MAX_PARSE_RETRIES = 1;\n\n/** Timeout extension multiplier when retrying a TIMEOUT error. (#1401) */\nexport const TIMEOUT_RETRY_MULTIPLIER = 1.5;\n\n/**\n * Checks whether a CliErrorCode represents a transient failure.\n * Timeout, rate_limit, connection, and parse errors are transient.\n * Parse errors get fewer retries (MAX_PARSE_RETRIES) than others (#1533).\n */\nexport function isTransientError(code: CliErrorCode): boolean {\n return TRANSIENT_ERROR_CODES.has(code);\n}\n\n/**\n * Exit codes that indicate transient process termination (retryable).\n * - 137 = 128 + SIGKILL (9): OOM killer, system resource limits\n * - 143 = 128 + SIGTERM (15): external termination (our timeout SIGTERM\n * is already caught by the timeout handler before close fires)\n */\nconst TRANSIENT_EXIT_CODES = new Set([137, 143]);\n\n/** Human-readable signal names for exit codes (128 + signal number). */\nconst EXIT_CODE_SIGNAL_NAMES: Record<number, string> = {\n 137: 'SIGKILL (OOM or killed)',\n 143: 'SIGTERM (terminated)',\n};\n\n/** Builds an error message for signal exit codes that includes identifiable keywords. */\nfunction buildSignalExitMessage(code: number): string {\n const signalName = EXIT_CODE_SIGNAL_NAMES[code];\n if (signalName !== undefined) return `Process killed by ${signalName}, exit code ${String(code)}`;\n return `Process exited with code ${String(code)}`;\n}\n\n/**\n * Checks whether a process exit code indicates a transient failure\n * that is safe to retry (e.g., OOM kill, external SIGTERM).\n */\nexport function isTransientExitCode(code: number | null): boolean {\n return code !== null && TRANSIENT_EXIT_CODES.has(code);\n}\n\n/** Internal state for buffered stream collection. */\ninterface BufferState {\n stdout: string;\n stderr: string;\n stdoutBytes: number;\n stderrBytes: number;\n stdoutTruncated: boolean;\n stderrTruncated: boolean;\n resolved: boolean;\n /**\n * Wall-clock at first stdout byte (or null if none yet). Used by #2472 to\n * split total subprocess time into spawn-latency (spawn→first byte) and\n * streaming (first byte→close), which is the cheapest way to identify\n * which stage causes stochastic timeouts.\n */\n firstByteTime: number | null;\n}\n\n/** Append data to a buffered stream, respecting the 10 MB cap. */\nfunction appendBuffered(state: BufferState, stream: 'stdout' | 'stderr', data: Buffer): void {\n const bytesKey = stream === 'stdout' ? 'stdoutBytes' : 'stderrBytes';\n const truncKey = stream === 'stdout' ? 'stdoutTruncated' : 'stderrTruncated';\n if (state[bytesKey] < MAX_BUFFER_BYTES) {\n state[stream] += data.toString();\n state[bytesKey] += data.length;\n } else if (!state[truncKey]) {\n state[truncKey] = true;\n subprocessLogger.warn(`${stream} buffer exceeded 10 MB, truncating`);\n }\n}\n\n/**\n * Command configuration returned by getCommand.\n */\nexport interface CommandConfig {\n command: string;\n args: string[];\n /** Optional stdin content (prompt passed via stdin instead of args) */\n stdin?: string;\n /**\n * Optional cleanup callback invoked after the subprocess resolves\n * (success, error, or timeout). Used by adapters that materialize\n * temp files for the subprocess (e.g. codex `model_instructions_file`).\n * Errors thrown by cleanup are logged but do not affect the request result.\n */\n cleanup?: () => void | Promise<void>;\n}\n\n/**\n * Configuration for transient-error retry behaviour.\n */\nexport interface TransientRetryConfig {\n /** Whether transient-error retry is enabled (default: false). */\n enabled: boolean;\n}\n\n/**\n * Base class for subprocess-based CLI adapters.\n * Used by ClaudeCliAdapter and GeminiCliAdapter.\n */\nexport abstract class SubprocessCliAdapter extends BaseCliAdapter {\n readonly transport: CliTransport = 'subprocess';\n\n protected abstract readonly parser: ICliResponseParser;\n\n /** Transient-error retry config. Override in subclass to enable. */\n protected readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n /**\n * The inner {@link retryTransient} layer is the single retry authority\n * for subprocess CLIs. When it is enabled (the default), the shared\n * outer retry loop must not also retry: nesting both meant up to 6\n * subprocess spawns and ~10-minute hangs on a persistent TIMEOUT, since\n * the inner layer's timeout extension compounds on every outer attempt\n * (#2824). The outer loop still runs once, so circuit-breaker failure\n * recording is unaffected.\n */\n protected override shouldOuterRetry(opts: Required<ExecutionOptions>): boolean {\n return opts.allowRetry && !this.transientRetry.enabled;\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * If stdin is provided, it will be written to the process stdin.\n */\n protected abstract getCommand(task: CliTask): CommandConfig;\n\n /**\n * Executes a task via subprocess, with optional transient-error retry.\n * When `transientRetry.enabled` is true, transient errors (timeout,\n * rate_limit, connection, parse) are retried with exponential backoff\n * (500ms, 1000ms). Parse errors get max 1 retry (#1533); others get 2.\n */\n async executeTask(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const result = await this.spawnSubprocess(task, options);\n if (result.ok || !this.transientRetry.enabled) return result;\n if (!isTransientError(result.error.code)) return result;\n\n return this.retryTransient(task, options, result, 0);\n }\n\n /**\n * Retries a transient error with bounded exponential backoff.\n */\n private async retryTransient(\n task: CliTask,\n options: Required<ExecutionOptions>,\n lastResult: Result<CliResponse, CliError>,\n attempt: number\n ): Promise<Result<CliResponse, CliError>> {\n const isParseError = !lastResult.ok && lastResult.error.code === 'PARSE_ERROR';\n const maxRetries = isParseError ? MAX_PARSE_RETRIES : MAX_TRANSIENT_RETRIES;\n if (attempt >= maxRetries) return lastResult;\n\n // Guard above ensures attempt < maxRetries ≤ TRANSIENT_RETRY_DELAYS_MS.length\n const delayMs = TRANSIENT_RETRY_DELAYS_MS[attempt] as number;\n const isTimeout = !lastResult.ok && lastResult.error.code === 'TIMEOUT';\n subprocessLogger.debug('Retrying transient error', {\n cli: this.name,\n attempt: attempt + 1,\n delayMs,\n errorCode: !lastResult.ok ? lastResult.error.code : undefined,\n });\n\n await this.delay(delayMs);\n\n // Extend timeout on TIMEOUT retries so near-miss tasks can complete (#1401)\n const retryOptions = isTimeout\n ? { ...options, timeoutMs: Math.round(options.timeoutMs * TIMEOUT_RETRY_MULTIPLIER) }\n : options;\n const result = await this.spawnSubprocess(task, retryOptions);\n if (result.ok) return result;\n if (!isTransientError(result.error.code)) return result;\n\n return this.retryTransient(task, retryOptions, result, attempt + 1);\n }\n\n /**\n * Spawns a single subprocess execution (no retry).\n */\n private spawnSubprocess(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const cmdConfig = this.getCommand(task);\n const startTime = getTimeProvider().now();\n\n const cleanup = cmdConfig.cleanup;\n const runCleanup = (): void => {\n if (cleanup === undefined) return;\n try {\n const r = cleanup();\n if (r instanceof Promise) {\n r.catch((e: unknown) => {\n this.logger.warn('Subprocess cleanup failed', { error: String(e) });\n });\n }\n } catch (e: unknown) {\n this.logger.warn('Subprocess cleanup threw', { error: String(e) });\n }\n };\n\n return new Promise((resolveOuter) => {\n const resolve = (result: Result<CliResponse, CliError>): void => {\n runCleanup();\n resolveOuter(result);\n };\n // Curated child env: base infrastructure vars + only this CLI's\n // own vendor credentials, so cross-vendor API keys don't leak\n // into the spawned CLI (#2865). Also drops CLAUDECODE — a nested\n // CLI must not believe it's already inside Claude Code.\n const childEnv = buildChildEnv(this.name);\n\n const child = spawn(cmdConfig.command, cmdConfig.args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: childEnv,\n });\n\n const onProgress = options.onProgress;\n const state = this.setupChildProcessHandlers(\n child,\n startTime,\n options.timeoutMs,\n resolve,\n onProgress\n );\n\n // Write stdin content if provided and close stdin\n if (cmdConfig.stdin !== undefined) {\n child.stdin.write(cmdConfig.stdin);\n }\n child.stdin.end();\n\n // Reference state to prevent unused variable warning\n void state;\n });\n }\n\n /**\n * Sets up child process event handlers for output collection and error handling.\n */\n private setupChildProcessHandlers(\n child: ReturnType<typeof spawn>,\n startTime: number,\n timeoutMs: number,\n resolve: (result: Result<CliResponse, CliError>) => void,\n onProgress?: () => void\n ): BufferState {\n const state: BufferState = {\n stdout: '',\n stderr: '',\n resolved: false,\n stdoutBytes: 0,\n stderrBytes: 0,\n stdoutTruncated: false,\n stderrTruncated: false,\n firstByteTime: null,\n };\n\n const resolveOnce = (result: Result<CliResponse, CliError>): void => {\n if (!state.resolved) {\n state.resolved = true;\n resolve(result);\n }\n };\n\n this.attachStdoutHandlers(child, state, onProgress);\n\n child.on('error', (error: Error) => {\n resolveOnce(this.handleSubprocessError(error));\n });\n\n const timeoutId = setTimeout(() => {\n child.kill('SIGTERM');\n resolveOnce(err(this.createError('TIMEOUT', 'Execution timed out')));\n }, timeoutMs);\n\n child.on('close', (code: number | null) => {\n clearTimeout(timeoutId);\n this.logTimingBreakdown(state, startTime, code);\n resolveOnce(this.classifyCloseResult(code, state, startTime));\n });\n\n return state;\n }\n\n /** Attach stdout/stderr data handlers + capture first-byte time (#2472). */\n private attachStdoutHandlers(\n child: ReturnType<typeof spawn>,\n state: BufferState,\n onProgress?: () => void\n ): void {\n // stdio: ['pipe', 'pipe', 'pipe'] guarantees non-null streams\n if (child.stdout !== null) {\n child.stdout.on('data', (data: Buffer) => {\n if (state.firstByteTime === null && data.length > 0) {\n state.firstByteTime = getTimeProvider().now();\n }\n appendBuffered(state, 'stdout', data);\n onProgress?.();\n });\n }\n if (child.stderr !== null) {\n child.stderr.on('data', (data: Buffer) => {\n appendBuffered(state, 'stderr', data);\n });\n }\n }\n\n /**\n * Log spawn-latency vs streaming breakdown at info level (#2472). Emits\n * one structured event per subprocess invocation, queryable via the\n * existing trace JSONL infrastructure. The breakdown lets operators\n * identify whether a slow run was caused by:\n * - High spawn-latency: model gateway took its time before producing\n * the first token (cold-start, queueing, network jitter).\n * - High streaming-time: response body was large or generation slow.\n * - Total approaches the timeout cap with no first-byte: hung process.\n *\n * Structured fields chosen so existing query_trace tooling can group by\n * cli + provider + model and surface tail-latency outliers.\n */\n private logTimingBreakdown(state: BufferState, startTime: number, code: number | null): void {\n const now = getTimeProvider().now();\n const totalMs = now - startTime;\n const spawnLatencyMs = state.firstByteTime === null ? null : state.firstByteTime - startTime;\n const streamingMs = state.firstByteTime === null ? null : now - state.firstByteTime;\n this.logger.info('Subprocess timing', {\n cli: this.name,\n totalMs,\n spawnLatencyMs,\n streamingMs,\n sawFirstByte: state.firstByteTime !== null,\n exitCode: code,\n stdoutBytes: state.stdoutBytes,\n stderrBytes: state.stderrBytes,\n });\n }\n\n /** Classify a subprocess close event into a Result. */\n private classifyCloseResult(\n code: number | null,\n state: BufferState,\n startTime: number\n ): Result<CliResponse, CliError> {\n // Redact API keys from output before any processing, logging, or tracing (#1597)\n state.stdout = sanitizeOutput(state.stdout);\n state.stderr = sanitizeOutput(state.stderr);\n\n if (code !== 0 && state.stdout === '') {\n // Stderr classification takes priority over exit code (#1401)\n if (state.stderr !== '') {\n const msg = state.stderr;\n return err(this.createError(classifyStderrError(state.stderr), msg));\n }\n // Signal-killed processes (137=SIGKILL/OOM, 143=SIGTERM) are transient.\n // Message includes signal name for downstream outcome classification.\n const msg = code !== null ? buildSignalExitMessage(code) : 'Process exited with unknown code';\n if (isTransientExitCode(code)) {\n return err(this.createError('CONNECTION_ERROR', msg));\n }\n return err(this.createError('EXECUTION_ERROR', msg));\n }\n // Non-zero exit with stderr errors: classify specifically to enable\n // transient retry for connection/rate-limit/timeout errors (#1401, #1402)\n if (code !== 0 && state.stderr !== '' && looksLikeErrorStderr(state.stderr)) {\n const msg = `Exit code ${String(code)}: ${state.stderr.slice(0, 500).trim()}`;\n return err(this.createError(classifyStderrError(state.stderr), msg));\n }\n return this.handleSubprocessOutput(state.stdout, state.stderr, startTime);\n }\n\n /**\n * Handles successful subprocess output.\n */\n private handleSubprocessOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (stderr !== '' && stdout === '') {\n return err(this.createError('EXECUTION_ERROR', stderr));\n }\n\n const text = this.parser.extractResponse(stdout);\n if (text === null) {\n return this.handleUnparseableOutput(stdout, stderr, startTime);\n }\n\n const usage = this.parser.extractUsage(stdout);\n const sessionId = this.parser.extractSessionId(stdout);\n\n return ok(\n this.normalizeResponse(text, usage ?? undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n ...(sessionId !== null && { sessionId }),\n })\n );\n }\n\n /**\n * Handles the parse-failure branch: when the CLI's structured response\n * parser returned null. Order of recovery attempts (most-specific first):\n * 1. Rate-limit text in raw stdout (#1320)\n * 2. Structured CLI error envelope (#2440)\n * 3. Plaintext fallback for natural-language output (#1401)\n * 4. Generic PARSE_ERROR with truncated snippet\n */\n private handleUnparseableOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (isRateLimitText(stdout)) {\n const snippet = stdout.slice(0, 500).trim();\n return err(this.createError('RATE_LIMITED', snippet));\n }\n const envelope = parseCliErrorEnvelope(stdout, this.name);\n if (envelope !== null) {\n const msg =\n envelope.hint !== undefined\n ? `${envelope.message}\\n → ${envelope.hint}`\n : envelope.message;\n // #2455 ask 3: at debug level, dump the full sanitized envelope so\n // operators can recover context without re-running. Sanitized via\n // output-sanitizer.ts so leaked tokens (some upstreams echo back the\n // bad token in error responses) don't reach logs.\n subprocessLogger.debug('CLI error envelope unwrapped', {\n cli: this.name,\n code: envelope.code,\n rawSanitized: sanitizeOutput(stdout),\n });\n return err(this.createError(envelope.code, msg));\n }\n const plaintext = tryPlaintextFallback(stdout);\n if (plaintext !== null) {\n subprocessLogger.debug('Using plaintext fallback for unparseable output', {\n rawSanitized: sanitizeOutput(stdout),\n });\n return ok(\n this.normalizeResponse(plaintext, undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n })\n );\n }\n const snippet = stdout.slice(0, 500).trim();\n const stderrHint = stderr !== '' ? ` [stderr: ${stderr.slice(0, 300).trim()}]` : '';\n return err(\n this.createError('PARSE_ERROR', `Failed to parse response: ${snippet}${stderrHint}`)\n );\n }\n\n /**\n * Handles subprocess execution errors.\n */\n private handleSubprocessError(error: unknown): Result<CliResponse, CliError> {\n if (!(error instanceof Error)) {\n return err(this.createError('EXECUTION_ERROR', 'Unknown error'));\n }\n\n if (error.message.includes('ETIMEDOUT') || error.message.includes('timeout')) {\n return err(this.createError('TIMEOUT', 'Execution timed out', error));\n }\n\n if (error.message.includes('ENOENT')) {\n return err(this.createError('NOT_FOUND', `${this.name} CLI not found`, error));\n }\n\n return err(this.createError('EXECUTION_ERROR', sanitizeOutput(error.message), error));\n }\n\n /**\n * Initializes the adapter and capacity tracker.\n */\n initialize(): Promise<void> {\n this.initCapacityTracker();\n this.initialized = true;\n return Promise.resolve();\n }\n\n /**\n * Disposes the adapter (no-op for subprocess).\n */\n dispose(): Promise<void> {\n this.initialized = false;\n return Promise.resolve();\n }\n}\n","/**\n * nexus-agents/cli-adapters - Base Adapter\n *\n * Abstract base class for CLI adapters with common functionality.\n * Provides version checking, health checks, and error handling.\n *\n * SubprocessCliAdapter extracted to subprocess-adapter.ts per Issue #272.\n *\n * (Source: cli-project_plan.md v2.1.0)\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport semver from 'semver';\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\n\nimport type { Result } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\n\nimport type {\n ICliAdapter,\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n HealthStatus,\n CapacityStatus,\n ModelInfo,\n CapabilityProfile,\n ExecutionOptions,\n VersionStatus,\n TokenUsage,\n} from './types.js';\nimport { CLI_VERSION_REQUIREMENTS, DEFAULT_CAPABILITIES } from './types.js';\nimport { getTimeoutForTaskAuto } from './cli-timeout-profiles.js';\nimport { CapacityTracker, createCapacityTracker } from './capacity-tracker.js';\nimport { executeCliRetryLoop } from './cli-retry-loop.js';\n\nconst execAsync = promisify(exec);\n\n/**\n * Fallback capacity (in tokens) when capacity tracker is uninitialized.\n * Uses a realistic 100k token budget instead of MAX_SAFE_INTEGER to prevent\n * downstream consumers from treating the adapter as having unlimited capacity.\n * Issue #1463.\n */\nexport const DEFAULT_CAPACITY_FALLBACK = 100_000;\n\n/**\n * Default execution options.\n *\n * Timeout reduced from 120s to 60s per Issue #280 to prevent\n * cascading timeouts in multi-agent voting scenarios.\n */\nconst DEFAULT_OPTIONS: Required<ExecutionOptions> = {\n timeoutMs: 60_000, // 1 minute (reduced from 2 minutes per Issue #280)\n allowRetry: true,\n maxRetries: 1, // Reduced from 2 to prevent 3+ minute total wait\n trackUsage: true,\n onProgress: undefined,\n};\n\n/**\n * Abstract base class for CLI adapters.\n * Provides common functionality for version checking, health, and error handling.\n */\nexport abstract class BaseCliAdapter implements ICliAdapter {\n abstract readonly name: CliName;\n abstract readonly transport: CliTransport;\n\n protected readonly logger: ILogger;\n protected capacityTracker: CapacityTracker | null = null;\n protected initialized = false;\n protected lastHealthCheck?: HealthStatus;\n protected cachedVersion?: string;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'cli-adapter' });\n }\n\n /**\n * Initializes the capacity tracker.\n * Called by subclasses after name is set.\n */\n protected initCapacityTracker(): void {\n this.capacityTracker = createCapacityTracker(this.name);\n }\n\n /**\n * Gets the capability profile for this CLI.\n */\n get capabilities(): CapabilityProfile {\n return DEFAULT_CAPABILITIES[this.name];\n }\n\n /**\n * Abstract method for executing a task.\n * Implemented by concrete adapters.\n */\n abstract executeTask(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>>;\n\n /**\n * Abstract method for getting model info.\n * Implemented by concrete adapters.\n */\n abstract getModelInfo(): ModelInfo;\n\n /**\n * Abstract method for initialization.\n * Implemented by concrete adapters.\n */\n abstract initialize(): Promise<void>;\n\n /**\n * Abstract method for cleanup.\n * Implemented by concrete adapters.\n */\n abstract dispose(): Promise<void>;\n\n /**\n * Executes a task with error handling and retries.\n *\n * Timeout priority (highest to lowest):\n * 1. options.timeoutMs - explicit execution option\n * 2. task.timeoutMs - task-level setting\n * 3. getTimeoutForTaskAuto() - computed from task complexity and CLI\n */\n async execute(task: CliTask, options?: ExecutionOptions): Promise<Result<CliResponse, CliError>> {\n const effectiveTimeout = this.computeTimeout(task, options);\n const opts = { ...DEFAULT_OPTIONS, ...options, timeoutMs: effectiveTimeout };\n\n if (!this.initialized) {\n await this.initialize();\n }\n\n this.logger.debug('Executing task', {\n cli: this.name,\n contentLength: task.content.length,\n model: task.model,\n timeoutMs: effectiveTimeout,\n });\n\n return this.executeWithRetry(task, opts);\n }\n\n /**\n * Computes effective timeout for a task.\n */\n private computeTimeout(task: CliTask, options?: ExecutionOptions): number {\n if (options?.timeoutMs !== undefined) return options.timeoutMs;\n if (task.timeoutMs !== undefined) return task.timeoutMs;\n return getTimeoutForTaskAuto(this.name, task.content);\n }\n\n /**\n * Whether the shared outer retry loop ({@link executeCliRetryLoop}) is\n * allowed to retry this adapter's failures. The base adapter honors the\n * caller's `allowRetry`. Subprocess adapters override this to suppress\n * the outer loop when their own transient-retry layer is active, so the\n * two layers do not nest into multiplied spawns (#2824).\n */\n protected shouldOuterRetry(opts: Required<ExecutionOptions>): boolean {\n return opts.allowRetry;\n }\n\n /**\n * Executes task with retry logic via shared retry loop.\n */\n private async executeWithRetry(\n task: CliTask,\n opts: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const result = await executeCliRetryLoop(() => this.executeTask(task, opts), {\n maxRetries: opts.maxRetries,\n allowRetry: this.shouldOuterRetry(opts),\n baseDelayMs: 1_000,\n maxDelayMs: 16_000,\n cli: this.name,\n logger: this.logger,\n });\n\n if (result.ok) {\n this.recordUsage(result.value.response);\n this.logger.info('Task executed successfully', {\n cli: this.name,\n attempt: result.value.retryCount + 1,\n durationMs: result.value.response.durationMs,\n tokensUsed: result.value.response.usage?.totalTokens,\n });\n return { ok: true, value: result.value.response };\n }\n\n this.logger.warn('Task execution failed', {\n cli: this.name,\n error: result.error.message,\n retryable: result.error.retryable,\n });\n return result;\n }\n\n /**\n * Performs a health check.\n */\n async healthCheck(): Promise<HealthStatus> {\n try {\n const version = await this.getVersion();\n const versionStatus = this.checkVersionCompatibility(version);\n\n const message = this.getVersionMessage(versionStatus, version);\n const status: HealthStatus = {\n healthy: versionStatus !== 'unsupported' && versionStatus !== 'breaking',\n version,\n versionStatus,\n lastChecked: new Date(getTimeProvider().now()),\n ...(message !== undefined && { message }),\n };\n\n this.lastHealthCheck = status;\n return status;\n } catch (error) {\n return {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n message: error instanceof Error ? error.message : 'Health check failed',\n lastChecked: new Date(getTimeProvider().now()),\n };\n }\n }\n\n /**\n * Gets CLI version.\n */\n async getVersion(): Promise<string> {\n if (this.cachedVersion !== undefined && this.cachedVersion !== '') {\n return this.cachedVersion;\n }\n\n try {\n const { stdout } = await execAsync(`${this.name} --version`, {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n\n // Extract version number from output\n const version = this.parseVersion(stdout.trim());\n this.cachedVersion = version;\n return version;\n } catch (cause: unknown) {\n throw new Error(`Failed to get ${this.name} version`, { cause });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n * Uses usage-based tracking since CLI subprocess execution\n * doesn't expose HTTP rate limit headers.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n getCapacity(): Promise<CapacityStatus> {\n // Lazy-init the tracker if no caller has run initialize() yet (#2714).\n // Pre-fix every doctor invocation tripped this path: doctor calls\n // adapter.getCapacity() WITHOUT first calling adapter.initialize(),\n // so each of the four adapters logged a \"Capacity tracker uninitialized\"\n // WARN and returned a hardcoded 100k-token fallback. The fallback\n // surfaced in doctor's output as \"Capacity: 100% remaining\" — a\n // fictional reading, not a real one. The tracker is per-process and\n // idempotent under createCapacityTracker, so initializing on first\n // read is safe.\n if (this.capacityTracker === null) {\n this.initCapacityTracker();\n }\n const tracker = this.capacityTracker;\n if (tracker === null) {\n // Unreachable in practice — initCapacityTracker assigns the field —\n // but keep the type-safe path for the impossible case.\n throw new Error(`Capacity tracker initialization failed for ${this.name}`);\n }\n return Promise.resolve(tracker.getCapacity());\n }\n\n /**\n * Records usage from a response for capacity tracking.\n */\n protected recordUsage(response: CliResponse): void {\n if (this.capacityTracker !== null) {\n this.capacityTracker.recordUsage(response.usage);\n }\n }\n\n /**\n * Parses version from CLI output.\n */\n protected parseVersion(output: string): string {\n // Handle common version formats:\n // \"2.0.76 (Claude Code)\"\n // \"0.22.5\"\n // \"codex-cli 0.77.0\"\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output);\n return match?.[1] ?? '0.0.0';\n }\n\n /**\n * Checks version compatibility.\n */\n protected checkVersionCompatibility(version: string): VersionStatus {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n const validVersion = semver.valid(version);\n if (validVersion === null) {\n return 'unsupported';\n }\n\n const isLtMinimum = semver.lt(validVersion, requirements.minimum);\n if (isLtMinimum) {\n return 'unsupported';\n }\n\n const hasBreaking = requirements.breaking.some((v) => semver.gte(validVersion, v));\n if (hasBreaking) {\n return 'breaking';\n }\n\n const isLtRecommended = semver.lt(validVersion, requirements.recommended);\n if (isLtRecommended) {\n return 'outdated';\n }\n\n return 'supported';\n }\n\n /**\n * Gets version status message.\n */\n protected getVersionMessage(status: VersionStatus, version: string): string | undefined {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n switch (status) {\n case 'unsupported':\n return `Version ${version} is not supported. Minimum: ${requirements.minimum}`;\n case 'breaking':\n return `Version ${version} has known compatibility issues`;\n case 'outdated':\n return `Consider upgrading to ${requirements.recommended}`;\n case 'supported':\n return undefined;\n }\n }\n\n /**\n * Creates a CLI error.\n */\n protected createError(code: CliErrorCode, message: string, cause?: Error): CliError {\n const retryable = ['RATE_LIMITED', 'TIMEOUT', 'CONNECTION_ERROR'].includes(code);\n\n return {\n code,\n message,\n cli: this.name,\n retryable,\n ...(cause !== undefined && { cause }),\n };\n }\n\n /**\n * Normalizes CLI response to common format.\n */\n protected normalizeResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n ): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n }\n\n /**\n * Delays for the specified milliseconds.\n */\n protected delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * CLI Timeout Helpers\n *\n * Task complexity estimation for timeout selection.\n * Separated from timeout values (which live in config/timeouts.ts).\n *\n * @module cli-adapters/cli-timeout-helpers\n * (Source: Issue #984 — Centralize timeout configuration)\n */\n\nimport type { TaskComplexity } from '../config/timeouts.js';\nimport { getCliTimeout } from '../config/timeouts.js';\nimport { detectTaskCategory } from '../config/task-specialization.js';\nimport { getOutcomeStore } from '../orchestration/outcomes/outcome-store.js';\nimport type { CliNameLiteral } from '../config/model-capabilities-types.js';\n\n/**\n * Estimate task complexity from task description.\n *\n * Heuristics based on testing:\n * - Simple: Single function, quick query, < 5 files\n * - Standard: Multi-file changes, moderate analysis\n * - Complex: Codebase-wide, deep analysis, architecture\n *\n * @param taskDescription - Description of the task\n * @returns Estimated complexity\n */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n const lower = taskDescription.toLowerCase();\n\n // Complex indicators\n const complexIndicators = [\n 'codebase',\n 'architecture',\n 'refactor',\n 'all files',\n 'entire',\n 'comprehensive',\n 'deep analysis',\n 'system-wide',\n 'security',\n 'audit',\n 'vulnerability',\n ];\n if (complexIndicators.some((indicator) => lower.includes(indicator))) {\n return 'complex';\n }\n\n // Simple indicators\n // Testing and exploration demoted to simple per weather data (99%+ success) (#1401)\n const simpleIndicators = [\n 'single',\n 'quick',\n 'one function',\n 'simple',\n 'small',\n 'brief',\n 'short',\n 'run tests',\n 'test suite',\n 'exploration',\n 'explore',\n ];\n if (simpleIndicators.some((indicator) => lower.includes(indicator))) {\n return 'simple';\n }\n\n // Default to standard\n return 'standard';\n}\n\n// ============================================================================\n// Adaptive Timeout (#1534)\n// ============================================================================\n\n/** Minimum successful outcomes required before adaptive timeout kicks in. */\nexport const ADAPTIVE_TIMEOUT_MIN_SAMPLES = 10;\n\n/** Safety margin applied to p95 duration (p95 * margin = adaptive timeout). */\nexport const ADAPTIVE_TIMEOUT_MARGIN = 1.2;\n\n/**\n * Compute p95 of a sorted array of numbers.\n * Returns the value at the 95th percentile index.\n */\nfunction computeP95(sorted: readonly number[]): number {\n if (sorted.length === 0) return 0;\n const idx = Math.ceil(sorted.length * 0.95) - 1;\n return sorted[Math.min(idx, sorted.length - 1)] as number;\n}\n\n/** Options for adaptive timeout computation. */\nexport interface AdaptiveTimeoutOptions {\n /** Override the outcome store (for testing). */\n readonly store?: import('../orchestration/outcomes/outcome-store.js').OutcomeStore;\n}\n\n/**\n * Get adaptive timeout for a CLI + task description pair.\n *\n * Uses historical outcome data to compute p95 execution duration.\n * When sufficient samples exist, returns max(static_timeout, p95 * 1.2).\n * Falls back to static keyword-based timeout when data is sparse.\n *\n * @param cli - CLI name\n * @param taskDescription - Task description for complexity + category detection\n * @param options - Optional overrides (e.g., custom store for testing)\n * @returns Timeout in milliseconds (never less than static timeout)\n */\nexport function getAdaptiveTimeout(\n cli: string,\n taskDescription: string,\n options?: AdaptiveTimeoutOptions\n): number {\n const complexity = estimateTaskComplexity(taskDescription);\n const staticTimeout = getCliTimeout(cli, complexity);\n\n const match = detectTaskCategory(taskDescription);\n if (match === null) return staticTimeout;\n\n const store = options?.store ?? getOutcomeStore();\n const outcomes = store.query({\n cli: cli as CliNameLiteral,\n category: match.category,\n success: true,\n });\n\n if (outcomes.length < ADAPTIVE_TIMEOUT_MIN_SAMPLES) return staticTimeout;\n\n const durations = outcomes.map((o) => o.durationMs).sort((a, b) => a - b);\n const p95 = computeP95(durations);\n const adaptiveTimeout = Math.round(p95 * ADAPTIVE_TIMEOUT_MARGIN);\n\n return Math.max(staticTimeout, adaptiveTimeout);\n}\n","/**\n * CLI Timeout Profiles - Configurable timeouts per CLI tool.\n *\n * Delegates to `config/timeouts.ts` (canonical source, Issue #984).\n * This file provides backward-compatible re-exports.\n *\n * @module cli-adapters/cli-timeout-profiles\n * (Source: Issue #357, CLI delegation testing 2026-01-18)\n */\n\nimport {\n CLI_TIMEOUTS,\n getCliTimeout,\n type TaskComplexity,\n type TimeoutProfile,\n} from '../config/timeouts.js';\nimport {\n estimateTaskComplexity as _estimateTaskComplexity,\n getAdaptiveTimeout,\n} from './cli-timeout-helpers.js';\n\n// Re-export types for backward compatibility\nexport type { TimeoutProfile, TaskComplexity };\n\n/** Per-CLI timeout profiles. Canonical source: `config/timeouts.ts`. */\nexport const CLI_TIMEOUT_PROFILES: Record<string, TimeoutProfile> = {\n claude: CLI_TIMEOUTS.claude,\n gemini: CLI_TIMEOUTS.gemini,\n codex: CLI_TIMEOUTS.codex,\n};\n\n/** Default timeout profile. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_TIMEOUT_PROFILE: TimeoutProfile = CLI_TIMEOUTS.default;\n\n/** Get timeout for a task. Canonical source: `config/timeouts.ts`. */\nexport function getTimeoutForTask(cli: string, complexity: TaskComplexity): number {\n return getCliTimeout(cli, complexity);\n}\n\n/** Estimate task complexity from description. Canonical: `cli-timeout-helpers.ts`. */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n return _estimateTaskComplexity(taskDescription);\n}\n\n/**\n * Get timeout with automatic complexity estimation.\n * Uses adaptive timeout from outcome history when sufficient data exists (#1534).\n */\nexport function getTimeoutForTaskAuto(cli: string, taskDescription: string): number {\n return getAdaptiveTimeout(cli, taskDescription);\n}\n","/**\n * nexus-agents/cli-adapters - Capacity Tracker\n *\n * Usage-based capacity tracking for CLI adapters.\n * Tracks cumulative token/request usage to estimate remaining capacity.\n *\n * Since CLI subprocess execution doesn't expose HTTP rate limit headers,\n * this tracker estimates capacity based on usage patterns.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n\nimport type { CliName, TokenUsage, CapacityStatus } from './types-core.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { clampPercent } from '../utils/math-utils.js';\n\n/**\n * Default rate limits per CLI provider (tokens per minute).\n * These are conservative estimates based on typical API tiers.\n * Override via environment variables: NEXUS_<CLI>_TOKEN_LIMIT\n */\nexport const DEFAULT_TOKEN_LIMITS: Record<CliName, number> = {\n claude: 100_000, // Claude API Build tier\n gemini: 1_000_000, // Gemini Pro generous limits\n codex: 500_000, // OpenAI tier 1\n opencode: 500_000, // Multi-provider proxy\n};\n\n/**\n * Default request limits per CLI provider (requests per minute).\n * Override via environment variables: NEXUS_<CLI>_REQUEST_LIMIT\n */\nexport const DEFAULT_REQUEST_LIMITS: Record<CliName, number> = {\n claude: 50, // Claude API Build tier\n gemini: 60, // Gemini Pro\n codex: 500, // OpenAI tier 1\n opencode: 300, // Multi-provider proxy\n};\n\n/**\n * Rate limit window in milliseconds (1 minute).\n */\nexport const RATE_LIMIT_WINDOW_MS = 60_000;\n\n/**\n * Configuration for capacity tracker.\n */\nexport interface CapacityTrackerConfig {\n /** Maximum tokens per window */\n readonly tokenLimit: number;\n /** Maximum requests per window */\n readonly requestLimit: number;\n /** Window duration in milliseconds */\n readonly windowMs: number;\n}\n\n/**\n * Tracked usage entry with timestamp.\n */\ninterface UsageEntry {\n readonly timestamp: number;\n readonly tokens: number;\n}\n\n/**\n * Creates default configuration for a CLI from environment or defaults.\n */\nexport function getDefaultConfig(cli: CliName): CapacityTrackerConfig {\n const envPrefix = `NEXUS_${cli.toUpperCase()}`;\n const tokenEnv = process.env[`${envPrefix}_TOKEN_LIMIT`];\n const requestEnv = process.env[`${envPrefix}_REQUEST_LIMIT`];\n\n return {\n tokenLimit:\n tokenEnv !== undefined && tokenEnv !== ''\n ? parseInt(tokenEnv, 10)\n : DEFAULT_TOKEN_LIMITS[cli],\n requestLimit:\n requestEnv !== undefined && requestEnv !== ''\n ? parseInt(requestEnv, 10)\n : DEFAULT_REQUEST_LIMITS[cli],\n windowMs: RATE_LIMIT_WINDOW_MS,\n };\n}\n\n/**\n * Capacity tracker for CLI adapters.\n *\n * Tracks cumulative usage within a sliding window to estimate\n * remaining capacity when HTTP headers are not available.\n *\n * @example\n * ```typescript\n * const tracker = new CapacityTracker(getDefaultConfig('claude'));\n *\n * // Record usage after each request\n * tracker.recordUsage({ inputTokens: 1000, outputTokens: 500 });\n *\n * // Get current capacity status\n * const status = tracker.getCapacity();\n * if (status.exhausted) {\n * // Wait before next request\n * }\n * ```\n */\nexport class CapacityTracker {\n private readonly config: CapacityTrackerConfig;\n private readonly usageHistory: UsageEntry[];\n private requestCount: number;\n private windowStart: number;\n\n constructor(config: CapacityTrackerConfig) {\n this.config = config;\n this.usageHistory = [];\n this.requestCount = 0;\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Records token usage from a completed request.\n */\n recordUsage(usage: TokenUsage | undefined): void {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n this.requestCount++;\n\n if (usage !== undefined) {\n const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;\n this.usageHistory.push({\n timestamp: now,\n tokens,\n });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n */\n getCapacity(): CapacityStatus {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n const usedTokens = this.usageHistory.reduce((sum, entry) => sum + entry.tokens, 0);\n const remainingTokens = Math.max(0, this.config.tokenLimit - usedTokens);\n const remainingRequests = Math.max(0, this.config.requestLimit - this.requestCount);\n\n const tokenUtilization = (usedTokens / this.config.tokenLimit) * 100;\n const requestUtilization = (this.requestCount / this.config.requestLimit) * 100;\n const utilizationPercent = clampPercent(Math.max(tokenUtilization, requestUtilization));\n\n const exhausted = remainingTokens === 0 || remainingRequests === 0;\n const resetTime = new Date(this.windowStart + this.config.windowMs);\n\n return {\n remainingTokens,\n remainingRequests,\n resetTime,\n utilizationPercent: Math.round(utilizationPercent * 100) / 100,\n exhausted,\n };\n }\n\n /**\n * Gets time until the rate limit window resets.\n */\n getTimeUntilReset(): number {\n const now = getTimeProvider().now();\n const resetTime = this.windowStart + this.config.windowMs;\n return Math.max(0, resetTime - now);\n }\n\n /**\n * Resets all tracked usage (for testing or manual reset).\n */\n reset(): void {\n this.usageHistory.length = 0;\n this.requestCount = 0;\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Updates configuration (e.g., after receiving actual rate limit info).\n */\n updateConfig(partial: Partial<CapacityTrackerConfig>): void {\n Object.assign(this.config, partial);\n }\n\n /**\n * Gets current configuration.\n */\n getConfig(): Readonly<CapacityTrackerConfig> {\n return { ...this.config };\n }\n\n /**\n * Removes entries older than the window duration.\n */\n private pruneOldEntries(now: number): void {\n const cutoff = now - this.config.windowMs;\n\n // If window has fully elapsed, reset everything\n if (this.windowStart < cutoff) {\n this.usageHistory.length = 0;\n this.requestCount = 0;\n this.windowStart = now;\n return;\n }\n\n // Remove old entries from history\n let firstEntry = this.usageHistory[0];\n while (firstEntry !== undefined && firstEntry.timestamp < cutoff) {\n this.usageHistory.shift();\n firstEntry = this.usageHistory[0];\n }\n }\n}\n\n/**\n * Creates a capacity tracker for a specific CLI.\n */\nexport function createCapacityTracker(cli: CliName): CapacityTracker {\n return new CapacityTracker(getDefaultConfig(cli));\n}\n","import { getErrorMessage } from '../core/index.js';\n\n/**\n * Async Utilities\n *\n * Centralized async helper functions for delay, timeout, and promise utilities.\n * Consolidates 9+ duplicate sleep/delay implementations across the codebase.\n *\n * @module utils/async-utils\n * (Source: LOOP H-K consolidation)\n */\n\n// ============================================================================\n// Delay / Sleep\n// ============================================================================\n\n/**\n * Creates a promise that resolves after the specified delay.\n * Alias: `delay` (both names are exported for compatibility)\n *\n * @param ms - Delay in milliseconds\n * @returns Promise that resolves after the delay\n *\n * @example\n * ```typescript\n * await sleep(1000); // Wait 1 second\n * await delay(500); // Wait 500ms (alias)\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Alias for `sleep()` - provided for compatibility with existing code.\n */\nexport const delay = sleep;\n\n// ============================================================================\n// Timeout Wrapper\n// ============================================================================\n\n/**\n * Result type for withTimeout operations.\n */\nexport type TimeoutResult<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: string };\n\n/**\n * Wraps a promise with a timeout.\n * Returns an error result if the timeout is exceeded.\n *\n * @param promise - The promise to wrap\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Error message if timeout is exceeded\n * @returns A result object with either the value or an error\n *\n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Request timed out after 5s'\n * );\n *\n * if (result.ok) {\n * console.log(result.value);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage: string\n): Promise<TimeoutResult<T>> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: true, value: result };\n } catch (error) {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: false, error: getErrorMessage(error) };\n }\n}\n\n// ============================================================================\n// Promise Utilities\n// ============================================================================\n\n/**\n * Executes promises in sequence, one at a time.\n *\n * @param tasks - Array of functions that return promises\n * @returns Array of results in order\n *\n * @example\n * ```typescript\n * const results = await sequence([\n * () => fetch('/api/1'),\n * () => fetch('/api/2'),\n * ]);\n * ```\n */\nexport async function sequence<T>(tasks: ReadonlyArray<() => Promise<T>>): Promise<T[]> {\n const results: T[] = [];\n for (const task of tasks) {\n results.push(await task());\n }\n return results;\n}\n","/**\n * Canonical helpers for constructing CliError values with the correct\n * `retryable` flag.\n *\n * Consolidates three previously-duplicated copies:\n * - `cli-retry-loop.ts` (as a module-local set + `isRetryableError`)\n * - `adapters/codex-adapter-helpers.ts` (as `createCodexError`)\n * - `adapters/codex-mcp-adapter-helpers.ts` (as `createCliError`)\n * - `testing/adapters/mock-adapter-helpers.ts` (as `createCliError`)\n *\n * Every call path that classifies retryable CLI errors should now flow\n * through here. Adding a new retryable code is a one-line change in one\n * place instead of four.\n *\n * (Issue #2181 — adapter harness consolidation)\n *\n * @module cli-adapters/cli-error-helpers\n */\n\nimport type { CliError, CliErrorCode, CliName } from './types.js';\n\n/** Error codes the retry machinery treats as transient. */\nexport const RETRYABLE_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set<CliErrorCode>([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n]);\n\n/** Whether a given CLI error code should be retried. */\nexport function isRetryableErrorCode(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Constructs a CliError with `retryable` auto-derived from the code.\n * Every adapter that needs to surface a CliError should prefer this\n * helper (or the `createError` method on `BaseCliAdapter`, which calls\n * into the same logic) rather than building the shape inline.\n */\nexport function createCliError(\n code: CliErrorCode,\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return {\n code,\n message,\n cli,\n retryable: isRetryableErrorCode(code),\n ...(cause !== undefined && { cause }),\n };\n}\n","/**\n * nexus-agents/cli-adapters - Unified CLI Retry Loop\n *\n * CLI-specific retry loop used by all CLI adapters (base + Gemini).\n * Supports optional circuit-breaker integration, returns CliResponse\n * with retryCount, and maps to FailureCategory for breaker tracking.\n *\n * Sibling implementation (see #2230): adapters/retry.ts holds the\n * generic, type-parameterized `withRetry<T>` for non-CLI use. Don't\n * reach for that one when you need circuit-breaker coupling; don't\n * reach for this one from non-CLI code. Math primitives differ\n * deliberately:\n * - this file: 1-indexed attempt, +0..30% jitter, cap-after\n * - adapters/retry.ts: 0-indexed attempt, ±jitterFactor, cap-before-jitter\n *\n * If you find yourself writing a third retry loop: stop, run\n * `consensus_vote` with scope_steward in the panel, and pick whichever\n * of these two fits — don't add a third.\n *\n * (Source: Issue #1596 — Extract shared prompt utils and rate-limit patterns)\n */\n\nimport type { Result } from '../core/index.js';\nimport { err, ok, getRandomProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type { CliResponse, CliError, CliErrorCode, CliName } from './types.js';\nimport type { ICircuitBreaker, FailureCategory } from './circuit-breaker-types.js';\nimport { delay } from '../utils/async-utils.js';\nimport { RETRYABLE_ERROR_CODES } from './cli-error-helpers.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CliRetryLoopConfig {\n readonly maxRetries: number;\n readonly allowRetry: boolean;\n readonly baseDelayMs: number;\n readonly maxDelayMs: number;\n readonly circuitBreaker?: ICircuitBreaker | null;\n readonly cli: CliName;\n readonly logger: ILogger;\n}\n\nexport interface CliRetryResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n}\n\n// ============================================================================\n// Retry Logic (moved from gemini-adapter-helpers.ts)\n// ============================================================================\n\n/**\n * Calculates exponential backoff delay with jitter.\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param baseDelayMs - Base delay in milliseconds\n * @param maxDelayMs - Maximum delay cap in milliseconds\n * @returns Delay in milliseconds with jitter applied\n */\nexport function calculateBackoffDelay(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number\n): number {\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);\n const jitter = getRandomProvider().random() * 0.3 * exponentialDelay;\n const delayMs = exponentialDelay + jitter;\n return Math.min(delayMs, maxDelayMs);\n}\n\n/** Determines if an error code is retryable. */\nexport function isRetryableError(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Categorizes a CLI error for circuit breaker tracking.\n * Returns a FailureCategory compatible with the circuit breaker.\n */\nexport function categorizeError(error: CliError): FailureCategory {\n switch (error.code) {\n case 'TIMEOUT':\n return 'timeout';\n case 'RATE_LIMITED':\n return 'rate_limit';\n case 'NOT_AUTHENTICATED':\n return 'authentication';\n case 'CONNECTION_ERROR':\n return 'connection';\n default:\n return 'unknown';\n }\n}\n\n// ============================================================================\n// Unified Retry Loop\n// ============================================================================\n\n/**\n * Executes a CLI operation with retry logic and optional circuit breaker.\n *\n * Used by both BaseCliAdapter (no circuit breaker) and GeminiCliAdapter\n * (with circuit breaker) to eliminate duplicate retry implementations.\n */\nexport async function executeCliRetryLoop(\n executeFn: () => Promise<Result<CliResponse, CliError>>,\n config: CliRetryLoopConfig\n): Promise<Result<CliRetryResult, CliError>> {\n const maxAttempts = config.allowRetry ? config.maxRetries + 1 : 1;\n let lastError: CliError | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const result = await executeFn();\n\n if (result.ok) {\n return ok({ response: result.value, retryCount: attempt - 1 });\n }\n\n lastError = result.error;\n\n // Record failure with circuit breaker if present\n if (config.circuitBreaker !== undefined && config.circuitBreaker !== null) {\n config.circuitBreaker.recordFailure(categorizeError(lastError));\n }\n\n // Check if we should retry\n if (!shouldRetry(lastError, attempt, maxAttempts, config.circuitBreaker)) {\n return err(lastError);\n }\n\n const delayMs = calculateBackoffDelay(attempt, config.baseDelayMs, config.maxDelayMs);\n config.logger.debug('Retrying CLI execution', {\n cli: config.cli,\n attempt,\n nextAttempt: attempt + 1,\n delayMs: Math.round(delayMs),\n });\n\n await delay(delayMs);\n }\n\n return err(\n lastError ?? {\n code: 'UNKNOWN',\n message: 'Max retries exceeded',\n cli: config.cli,\n retryable: false,\n }\n );\n}\n\nfunction shouldRetry(\n error: CliError,\n attempt: number,\n maxAttempts: number,\n circuitBreaker?: ICircuitBreaker | null\n): boolean {\n if (attempt >= maxAttempts) return false;\n if (!error.retryable) return false;\n if (!isRetryableError(error.code)) return false;\n if (circuitBreaker?.getState() === 'open') return false;\n return true;\n}\n","/**\n * Environment-variable allowlist for spawned CLI subprocesses (#2865).\n *\n * `spawnSubprocess` previously passed the entire `process.env` to every\n * spawned CLI (claude / gemini / codex / opencode) — only `CLAUDECODE`\n * was stripped. That leaked cross-vendor API keys: the gemini CLI\n * received `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`, the codex CLI\n * received `GOOGLE_AI_API_KEY`, and so on. A buggy or malicious CLI\n * could exfiltrate keys it has no business seeing.\n *\n * `buildChildEnv()` constructs a curated child environment instead:\n * base infrastructure vars that every CLI needs, plus ONLY the spawned\n * CLI's own vendor credential(s).\n *\n * @module cli-adapters/subprocess-env\n */\n\nimport type { CliName } from './types.js';\n\n/** Exact-match infrastructure vars every spawned CLI legitimately needs. */\nconst BASE_ENV_EXACT: readonly string[] = [\n 'PATH',\n 'HOME',\n 'USER',\n 'LOGNAME',\n 'SHELL',\n 'LANG',\n 'TERM',\n 'TZ',\n 'TMPDIR',\n 'TEMP',\n 'TMP',\n 'HTTP_PROXY',\n 'HTTPS_PROXY',\n 'NO_PROXY',\n 'ALL_PROXY',\n 'http_proxy',\n 'https_proxy',\n 'no_proxy',\n 'all_proxy',\n 'NODE_OPTIONS',\n 'NODE_PATH',\n 'NODE_ENV',\n 'NODE_EXTRA_CA_CERTS',\n 'SSL_CERT_FILE',\n 'SSL_CERT_DIR',\n];\n\n/** Prefix-match infrastructure var families. */\nconst BASE_ENV_PREFIXES: readonly string[] = [\n 'LC_', // locale: LC_ALL, LC_CTYPE, …\n 'NEXUS_', // nexus-agents config + nested-run credentials (a child may be a nested nexus-agents)\n 'npm_config_', // npm/node resolution config: registry, proxy, …\n];\n\n/**\n * Per-CLI vendor credentials. The spawned CLI gets ONLY its own\n * vendor's key(s) — not every vendor's. `opencode` can route to any\n * provider via its config, so it gets the full set.\n */\nconst CLI_VENDOR_KEYS: Record<CliName, readonly string[]> = {\n claude: ['ANTHROPIC_API_KEY'],\n gemini: ['GOOGLE_AI_API_KEY', 'GEMINI_API_KEY', 'GOOGLE_API_KEY'],\n codex: ['OPENAI_API_KEY'],\n opencode: [\n 'ANTHROPIC_API_KEY',\n 'OPENAI_API_KEY',\n 'GOOGLE_AI_API_KEY',\n 'GEMINI_API_KEY',\n 'GOOGLE_API_KEY',\n 'OPENROUTER_API_KEY',\n ],\n};\n\n/** True if `key` is permitted for a CLI whose vendor keys are `vendorKeys`. */\nfunction isAllowed(key: string, vendorKeys: readonly string[]): boolean {\n if (BASE_ENV_EXACT.includes(key)) return true;\n if (vendorKeys.includes(key)) return true;\n return BASE_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n}\n\n/**\n * Builds the environment for a spawned CLI subprocess: base\n * infrastructure vars plus only `cliName`'s own vendor credentials.\n * Cross-vendor API keys are dropped (#2865).\n *\n * `CLAUDECODE` is never forwarded — a nested CLI seeing it would\n * believe it's already inside Claude Code, breaking nested sessions\n * (the pre-#2865 behavior also stripped it explicitly).\n *\n * Escape hatch: `NEXUS_SUBPROCESS_ENV_ALLOWLIST=0` restores the\n * pre-#2865 full-passthrough behavior (minus `CLAUDECODE`) — a\n * field un-break if the allowlist ever drops a var a CLI needs.\n */\nexport function buildChildEnv(cliName: CliName): NodeJS.ProcessEnv {\n const source = process.env;\n const childEnv: NodeJS.ProcessEnv = {};\n\n if (source['NEXUS_SUBPROCESS_ENV_ALLOWLIST'] === '0') {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined && key !== 'CLAUDECODE') childEnv[key] = value;\n }\n return childEnv;\n }\n\n const vendorKeys = CLI_VENDOR_KEYS[cliName];\n for (const [key, value] of Object.entries(source)) {\n if (value === undefined) continue;\n if (key === 'CLAUDECODE') continue;\n if (isAllowed(key, vendorKeys)) childEnv[key] = value;\n }\n return childEnv;\n}\n\n/** Test/introspection accessor for the per-CLI vendor-key map. */\nexport function getCliVendorKeys(): Readonly<Record<CliName, readonly string[]>> {\n return CLI_VENDOR_KEYS;\n}\n","/**\n * nexus-agents/security - Output Sanitizer\n *\n * Redacts API keys and tokens from CLI subprocess stdout/stderr\n * before the output is returned, logged, or traced.\n *\n * @module security/output-sanitizer\n * (Source: Issue #1597 — subprocess output scrubbing gap)\n */\n\n/** Placeholder text that replaces redacted keys. */\nexport const REDACTED_KEY_PLACEHOLDER = '[REDACTED_KEY]';\n\n/**\n * Patterns matching known API key formats.\n *\n * Order matters: more-specific prefixes (sk-ant-, sk-proj-) come before\n * the generic sk-* pattern so they match first.\n *\n * Each pattern requires a minimum token length after the prefix to avoid\n * false positives on short strings like \"sk-ab\".\n */\nconst KEY_PATTERNS: readonly RegExp[] = [\n // Anthropic: sk-ant-api03-... (at least 20 chars after prefix)\n /sk-ant-[A-Za-z0-9_-]{20,}/g,\n // OpenAI project: sk-proj-... (at least 20 chars after prefix)\n /sk-proj-[A-Za-z0-9_-]{20,}/g,\n // Generic OpenAI: sk-... (at least 20 chars after prefix)\n /sk-[A-Za-z0-9_-]{20,}/g,\n // Google AI / Gemini: AIzaSy... (at least 30 chars total)\n /AIzaSy[A-Za-z0-9_-]{24,}/g,\n // GitHub PAT: ghp_...\n /ghp_[A-Za-z0-9]{20,}/g,\n // GitHub OAuth: gho_...\n /gho_[A-Za-z0-9]{20,}/g,\n // GitLab PAT: glpat-...\n /glpat-[A-Za-z0-9_-]{10,}/g,\n // npm token: npm_...\n /npm_[A-Za-z0-9]{20,}/g,\n // PyPI token: pypi-...\n /pypi-[A-Za-z0-9_-]{20,}/g,\n];\n\n/**\n * Redacts known API key patterns from a string.\n *\n * Designed to be called on subprocess stdout/stderr before the output\n * is returned to callers, written to logs, or included in trace data.\n *\n * @param text - Raw subprocess output\n * @returns The same text with API keys replaced by [REDACTED_KEY]\n */\nexport function sanitizeOutput(text: string): string {\n if (text === '') return text;\n\n let result = text;\n for (const pattern of KEY_PATTERNS) {\n // Reset lastIndex for global regex reuse\n pattern.lastIndex = 0;\n result = result.replace(pattern, REDACTED_KEY_PLACEHOLDER);\n }\n return result;\n}\n","/**\n * cli-error-envelope — extract the actionable message from a CLI's\n * structured error envelope.\n *\n * When `claude`, `codex`, etc. return a JSON envelope with `is_error: true`,\n * the response parser correctly fails to find a usable assistant message\n * and falls through to the generic PARSE_ERROR path in `subprocess-adapter`.\n * That path stuffs the first 500 chars of the envelope into the error\n * message, producing the unreadable wall of escaped JSON described in #2440.\n *\n * This module unwraps known envelope shapes so the operator sees:\n *\n * ✗ Claude CLI: Not logged in\n * → claude /login, then retry\n *\n * instead of 600 characters of `{\"timestamp\":\"...\",\"level\":\"warn\",...}`.\n *\n * Source: Issue #2440 (round-14 onboarding audit, ask 1 + ask 2).\n */\n\nimport type { CliErrorCode, CliName } from './types.js';\n\n/**\n * Result of unwrapping a CLI's structured error envelope. `null` when the\n * stdout doesn't match a known shape — caller falls back to the existing\n * snippet behavior.\n */\nexport interface ParsedCliError {\n /** Short, user-facing message — the unwrapped CLI error string. */\n readonly message: string;\n /** Classified code so the retry/fail-closed logic can do the right thing. */\n readonly code: CliErrorCode;\n /** Optional one-line hint with the canonical fix for this CLI. */\n readonly hint?: string;\n}\n\n/**\n * Claude CLI structured envelope shape:\n * {\"type\":\"result\",\"is_error\":true,\"result\":\"<reason>\",\"session_id\":\"...\",...}\n *\n * Use a structural type guard rather than parsing into a strict schema —\n * upstream may add fields and we only care about three of them.\n */\ninterface ClaudeErrorEnvelope {\n readonly type: 'result';\n readonly is_error: true;\n readonly result?: string;\n}\n\nfunction isClaudeErrorEnvelope(v: unknown): v is ClaudeErrorEnvelope {\n if (typeof v !== 'object' || v === null) return false;\n const obj = v as { type?: unknown; is_error?: unknown };\n return obj.type === 'result' && obj.is_error === true;\n}\n\n/**\n * Codex CLI envelope shape (best-effort — codex CLI's error shape is\n * less stable than Claude's):\n * {\"error\":\"<reason>\"} or {\"is_error\":true,\"message\":\"<reason>\"}\n */\nfunction unwrapCodexEnvelope(parsed: unknown): string | null {\n if (typeof parsed !== 'object' || parsed === null) return null;\n const obj = parsed as { error?: unknown; message?: unknown; is_error?: unknown };\n if (typeof obj.error === 'string' && obj.error !== '') return obj.error;\n if (obj.is_error === true && typeof obj.message === 'string' && obj.message !== '') {\n return obj.message;\n }\n return null;\n}\n\n/** Login hint matched against the parsed message text, per CLI. */\nconst LOGIN_HINTS: Record<CliName, string> = {\n claude: 'claude /login',\n codex: 'codex login',\n gemini: 'gemini',\n opencode: 'opencode auth login',\n};\n\nconst NOT_AUTH_PATTERNS: readonly RegExp[] = [\n /not logged in/i,\n /please run \\/?login/i,\n /authentication (?:required|expired|failed)/i,\n /invalid (?:api ?key|credentials)/i,\n /unauthorized/i,\n // #2455 ask 1: catch \"API key expired\" / \"API key revoked\" / \"API key\n // missing\" — the bare /invalid api key/ pattern misses these. Architects\n // explicitly ruled OUT `permission denied` (that's authz, not authn —\n // routing to /login is the wrong fix).\n /api[- ]?key (?:expired|revoked|missing)/i,\n // Token expiry/revocation as a standalone signal, not co-occurring with\n // \"unauthorized\" — some upstreams emit \"Token expired. Please re-auth.\"\n // without the unauthorized keyword.\n /token (?:expired|revoked)/i,\n];\n\nfunction classifyMessage(message: string): { code: CliErrorCode; auth: boolean } {\n for (const re of NOT_AUTH_PATTERNS) {\n if (re.test(message)) return { code: 'NOT_AUTHENTICATED', auth: true };\n }\n return { code: 'EXECUTION_ERROR', auth: false };\n}\n\n/**\n * Try to find the actionable error string inside a CLI's stdout. Returns\n * `null` if the stdout doesn't look like a structured error envelope (the\n * caller then falls back to the existing snippet truncation).\n */\nexport function parseCliErrorEnvelope(stdout: string, cliName: CliName): ParsedCliError | null {\n const trimmed = stdout.trim();\n if (trimmed === '' || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n // Whole-blob parse failed — could be NDJSON (one JSON object per line).\n // Try the last line, which is where Claude/Codex emit the terminal\n // envelope.\n return tryLastLine(trimmed, cliName);\n }\n\n let message: string | undefined;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n message = parsed.result;\n } else {\n const codex = unwrapCodexEnvelope(parsed);\n if (codex !== null) message = codex;\n }\n\n if (message === undefined || message === '') return null;\n\n return buildParsedError(message, cliName);\n}\n\nfunction tryLastLine(stdout: string, cliName: CliName): ParsedCliError | null {\n const lines = stdout.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length < 2) return null;\n const last = lines.at(-1);\n if (last === undefined) return null;\n if (!last.startsWith('{')) return null;\n try {\n const parsed = JSON.parse(last) as unknown;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n return buildParsedError(parsed.result, cliName);\n }\n } catch {\n /* ignore — fall through to null */\n }\n return null;\n}\n\nfunction buildParsedError(message: string, cliName: CliName): ParsedCliError {\n // Trim to first line + cap length — operators don't need 500 chars of envelope.\n const firstLine = (message.split('\\n')[0] ?? message).trim().slice(0, 240);\n const { code, auth } = classifyMessage(firstLine);\n if (auth) {\n return {\n message: firstLine,\n code,\n hint: `Run \\`${LOGIN_HINTS[cliName]}\\` to authenticate, then retry.`,\n };\n }\n return { message: firstLine, code };\n}\n","/**\n * nexus-agents/utils - Type Coercion Utilities\n *\n * Safe type coercion helpers for parsing and validating unknown values.\n * Consolidates patterns used across parsers, validators, and adapters.\n *\n * @module utils/type-coercion\n */\n\n/**\n * Safely casts value to Record if it's a non-null, non-array object.\n *\n * @param value - Value to check\n * @returns Record if valid object, null otherwise\n *\n * @example\n * const data = asRecord(parsed);\n * if (data !== null) {\n * const name = asString(data.name);\n * }\n */\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return null;\n}\n\n/**\n * Type guard version of asRecord for use in conditionals.\n *\n * @param value - Value to check\n * @returns True if value is a non-null, non-array object\n *\n * @example\n * if (isRecord(data)) {\n * console.log(data.field);\n * }\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Safely extracts a string value.\n *\n * @param value - Value to check\n * @returns String if valid, null otherwise\n */\nexport function asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\n/**\n * Safely extracts a number value.\n *\n * @param value - Value to check\n * @returns Number if valid (not NaN, not Infinity), null otherwise\n */\nexport function asNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return null;\n}\n\n/**\n * Safely extracts a boolean value.\n *\n * @param value - Value to check\n * @returns Boolean if valid, null otherwise\n */\nexport function asBoolean(value: unknown): boolean | null {\n return typeof value === 'boolean' ? value : null;\n}\n\n/**\n * Safely extracts an array value.\n *\n * @param value - Value to check\n * @returns Array if valid, null otherwise\n */\nexport function asArray(value: unknown): unknown[] | null {\n return Array.isArray(value) ? value : null;\n}\n\n/**\n * Extracts a string field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns String value or undefined if not found/invalid\n */\nexport function extractStringField(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n const value = record[key];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Extracts a number field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Number value or null if not found/invalid\n */\nexport function extractNumberField(record: Record<string, unknown>, key: string): number | null {\n const value = record[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\n/**\n * Extracts a boolean field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Boolean value or undefined if not found/invalid\n */\nexport function extractBooleanField(\n record: Record<string, unknown>,\n key: string\n): boolean | undefined {\n const value = record[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Extracts a nested record field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Nested record or null if not found/invalid\n */\nexport function extractRecordField(\n record: Record<string, unknown>,\n key: string\n): Record<string, unknown> | null {\n return asRecord(record[key]);\n}\n\n/**\n * Safely parses JSON with fallback to null.\n *\n * @param raw - Raw JSON string\n * @returns Parsed value or null if invalid\n */\nexport function safeJsonParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Safely parses JSON and returns as Record.\n *\n * @param raw - Raw JSON string\n * @returns Parsed record or null if invalid\n */\nexport function safeJsonParseRecord(raw: string): Record<string, unknown> | null {\n const parsed = safeJsonParse(raw);\n return asRecord(parsed);\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Response Parser\n *\n * Defensive parser for Claude CLI JSON output.\n * Handles version 2.0.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'claude-parser' });\n\n/**\n * Claude CLI response structure.\n * (Source: CLI testing 2026-01-04)\n */\nexport interface ClaudeCliResponse {\n readonly type: 'result';\n readonly subtype?: 'success' | 'error';\n readonly is_error: boolean;\n readonly duration_ms?: number;\n readonly result: string;\n readonly session_id?: string;\n readonly total_cost_usd?: number;\n readonly usage?: {\n readonly input_tokens: number;\n readonly output_tokens: number;\n readonly cache_creation_input_tokens?: number;\n readonly cache_read_input_tokens?: number;\n };\n readonly modelUsage?: Record<\n string,\n {\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly cacheReadInputTokens?: number;\n readonly cacheCreationInputTokens?: number;\n readonly costUSD?: number;\n readonly contextWindow?: number;\n }\n >;\n}\n\n/**\n * Parser for Claude CLI JSON output.\n * Implements defensive parsing - only requires essential fields.\n */\nexport class ClaudeResponseParser implements ICliResponseParser<ClaudeCliResponse> {\n readonly name = 'claude-parser';\n readonly supportedVersionRange = '>=2.0.0 <3.0.0';\n\n /**\n * Parses complete Claude CLI response.\n */\n parse(raw: string): ClaudeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n\n if (!this.isValidResponse(data)) {\n return null;\n }\n\n return data;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Returns null if the response contains an error.\n */\n extractResponse(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n // Check for API errors (is_error: true indicates an error occurred)\n if (record.is_error === true) {\n return null;\n }\n\n const result = record.result;\n if (typeof result === 'string') {\n return result;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const usageRecord = asRecord(record.usage);\n if (usageRecord === null) return null;\n\n const inputTokens = extractNumberField(usageRecord, 'input_tokens');\n const outputTokens = extractNumberField(usageRecord, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usageRecord, 'cache_read_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const sessionId = record.session_id;\n if (typeof sessionId === 'string') {\n return sessionId;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Type guard for valid response structure.\n */\n private isValidResponse(data: unknown): data is ClaudeCliResponse {\n const record = asRecord(data);\n if (record === null) return false;\n\n // Only require the essential field\n return typeof record.result === 'string';\n }\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Adapter\n *\n * Subprocess-based adapter for Claude CLI.\n * Uses JSON output format for stable parsing.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ClaudeResponseParser } from '../parsers/claude-parser.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Maps internal model names → Claude CLI aliases. Derived entirely from the\n * canonical registry: every claude entry contributes its `cliAlias` (passthrough),\n * its `cliModelName`, and every legacy-name in `aliases[]`. Migration of these\n * legacy strings into the registry happened in #2200 Child 1.\n */\nconst MODEL_TO_CLI_ALIAS: Record<string, string> = buildClaudeAliasMap();\n\nfunction buildClaudeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('claude')) {\n if (model.cliAlias === undefined) continue;\n const alias = model.cliAlias;\n map[alias] = alias;\n if (model.cliModelName !== undefined) map[model.cliModelName] = alias;\n for (const legacyName of model.aliases ?? []) {\n map[legacyName] = alias;\n }\n }\n return map;\n}\n\n/**\n * Default cost when an unrecognized model id is passed (pricing matches\n * current Opus, the strongest tier — conservative over-estimate). Per-model\n * legacy cost overrides were removed in #2200 Child 1; they're reachable\n * via the registry now.\n */\nconst UNKNOWN_MODEL_DEFAULT_INPUT_COST = 5.0;\nconst UNKNOWN_MODEL_DEFAULT_OUTPUT_COST = 25.0;\n\n/**\n * Claude CLI adapter using subprocess transport.\n * Executes: claude -p --output-format json \"<task>\"\n */\nexport class ClaudeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'claude';\n protected readonly parser: ICliResponseParser = new ClaudeResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('claude'));\n }\n\n /**\n * Gets Claude model information.\n * `buildModelInfo` matches `cliModelName`, `cliAlias`, and `aliases[]` —\n * a single call handles 'opus', 'sonnet', 'haiku', current model names,\n * and the legacy `claude-opus-4` / `claude-haiku-3` / etc. entries that\n * live in the registry's aliases since #2200 Child 1.\n *\n * Truly unrecognized models fall through to conservative defaults\n * (current Opus pricing).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('claude', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: this.model,\n contextWindow: 200_000,\n maxOutput: 64_000,\n costPerMillionInput: UNKNOWN_MODEL_DEFAULT_INPUT_COST,\n costPerMillionOutput: UNKNOWN_MODEL_DEFAULT_OUTPUT_COST,\n };\n }\n\n /** Appends optional string-type task options to CLI args. */\n private appendTaskOptions(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--add-dir', workDir);\n }\n const mcpConfigPath = task.options?.['mcpConfigPath'];\n if (typeof mcpConfigPath === 'string' && mcpConfigPath.length > 0) {\n args.push('--mcp-config', mcpConfigPath);\n }\n // Allow full tool access in non-interactive mode (needed for SWE-bench)\n if (task.options?.['skipPermissions'] === true) {\n args.push('--dangerously-skip-permissions');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses stdin for the prompt to avoid argument escaping issues,\n * especially important when using --add-dir.\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['-p', '--output-format', 'json'];\n\n // Add model - convert internal names to CLI aliases\n const internalModel = task.model ?? this.model;\n const cliModel = MODEL_TO_CLI_ALIAS[internalModel] ?? internalModel;\n args.push('--model', cliModel);\n\n // Add system prompt if provided\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n args.push('--system-prompt', task.systemPrompt);\n }\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n this.appendTaskOptions(args, task);\n\n // Note: maxTokens is intentionally not passed to Claude CLI.\n // The Claude CLI does not support --max-tokens. Use --max-budget-usd instead.\n // The CLI handles token limits internally based on model configuration.\n\n // Pass prompt via stdin to avoid argument escaping issues\n return { command: 'claude', args, stdin: task.content };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter\n *\n * Subprocess-based adapter for Gemini CLI with:\n * - Tiered timeout profiles based on task complexity\n * - Resilient JSON parsing with fallback strategies\n * - Exponential backoff retry logic\n * - Circuit breaker integration for sustained failures\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n * (Source: Issue #389 - Merged enhanced adapter back to canonical)\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Result, ILogger } from '../../core/index.js';\nimport { ok, err, createLogger, getTimeProvider } from '../../core/index.js';\nimport type {\n ICliResponseParser,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n CliName,\n ExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ResilientGeminiParser } from '../parsers/gemini-parser-resilient.js';\nimport {\n getTimeoutForTask,\n estimateTaskComplexity,\n type TaskComplexity,\n} from '../cli-timeout-profiles.js';\nimport {\n CliCircuitBreaker,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n type CircuitBreakerConfig,\n type CircuitBreakerSnapshot,\n} from '../circuit-breaker.js';\nimport { GEMINI_LEGACY_DEFAULTS, createCircuitOpenError } from './gemini-adapter-helpers.js';\nimport { executeCliRetryLoop } from '../cli-retry-loop.js';\nimport {\n buildModelInfo,\n getCliModelName,\n getDefaultModelForCli,\n} from '../../config/model-config-helpers.js';\n\n/** Derive the CLI model name for the default Gemini model from the canonical registry. */\nconst DEFAULT_GEMINI_CLI_MODEL: string = getCliModelName(getDefaultModelForCli('gemini'));\n\n/** Configuration for Gemini adapter. Extends BaseAdapterOptions with retry/circuit breaker. */\nexport interface GeminiConfig extends BaseAdapterOptions {\n /** Maximum retry attempts (default: 3) */\n readonly maxRetries?: number;\n /** Base delay for exponential backoff in ms (default: 1000) */\n readonly baseDelayMs?: number;\n /** Maximum delay for backoff in ms (default: 30000) */\n readonly maxDelayMs?: number;\n /** Circuit breaker configuration */\n readonly circuitBreakerConfig?: Partial<CircuitBreakerConfig>;\n /** Enable circuit breaker (default: true) */\n readonly enableCircuitBreaker?: boolean;\n}\n\n/** Execution result with metadata. */\nexport interface GeminiExecutionResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n readonly totalDurationMs: number;\n readonly complexity: TaskComplexity;\n readonly circuitState: 'closed' | 'open' | 'half-open';\n}\n\nconst DEFAULT_CONFIG: Required<Omit<GeminiConfig, 'logger' | 'circuitBreakerConfig'>> = {\n model: DEFAULT_GEMINI_CLI_MODEL,\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n enableCircuitBreaker: true,\n};\n\n/**\n * Gemini CLI adapter with reliability features.\n *\n * Includes tiered timeouts, resilient parsing, retry logic, and circuit breaker.\n */\nexport class GeminiCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'gemini';\n protected readonly parser: ICliResponseParser;\n\n private readonly model: string;\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n private readonly circuitBreaker: CliCircuitBreaker | null;\n private readonly adapterLogger: ILogger;\n\n constructor(options?: GeminiConfig) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...options };\n super(options?.logger);\n\n this.model = mergedConfig.model;\n this.maxRetries = mergedConfig.maxRetries;\n this.baseDelayMs = mergedConfig.baseDelayMs;\n this.maxDelayMs = mergedConfig.maxDelayMs;\n this.parser = new ResilientGeminiParser();\n this.adapterLogger = options?.logger ?? createLogger({ component: 'gemini-adapter' });\n\n // Initialize circuit breaker if enabled\n if (mergedConfig.enableCircuitBreaker) {\n const cbConfig: CircuitBreakerConfig = {\n ...DEFAULT_CIRCUIT_BREAKER_CONFIG,\n ...options?.circuitBreakerConfig,\n };\n this.circuitBreaker = new CliCircuitBreaker('gemini', cbConfig);\n } else {\n this.circuitBreaker = null;\n }\n }\n\n /**\n * Gets Gemini model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n * Note: maxOutput is capped at 8_192 (Gemini CLI constraint).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('gemini', this.model);\n if (fromRegistry !== undefined) {\n return { ...fromRegistry, maxOutput: 8_192 };\n }\n return {\n id: this.model,\n name: GEMINI_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow:\n GEMINI_LEGACY_DEFAULTS.contextWindows[this.model] ?? GEMINI_LEGACY_DEFAULTS.contextWindow,\n maxOutput: 8_192,\n costPerMillionInput:\n GEMINI_LEGACY_DEFAULTS.inputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n GEMINI_LEGACY_DEFAULTS.outputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Executes a task with reliability features.\n */\n override async execute(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n const result = await this.executeWithMetadata(task, options);\n\n if (result.ok) {\n return ok(result.value.response);\n }\n\n return err(result.error);\n }\n\n /**\n * Executes with full metadata about retry attempts and circuit state.\n */\n async executeWithMetadata(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<GeminiExecutionResult, CliError>> {\n const circuitCheckResult = this.checkCircuitBreaker();\n if (circuitCheckResult !== null) {\n return err(circuitCheckResult);\n }\n\n const startTime = getTimeProvider().now();\n const complexity = estimateTaskComplexity(task.content);\n const effectiveOptions = this.buildExecutionOptions(task.content, options);\n\n const result = await this.executeWithRetryTracking(task, effectiveOptions);\n\n return this.buildExecutionResult(result, startTime, complexity);\n }\n\n /**\n * Gets current circuit breaker snapshot.\n */\n getCircuitBreakerSnapshot(): CircuitBreakerSnapshot | null {\n return this.circuitBreaker?.getSnapshot() ?? null;\n }\n\n /**\n * Resets the circuit breaker to closed state.\n */\n resetCircuitBreaker(): void {\n this.circuitBreaker?.reset();\n }\n\n /**\n * Gets CLI command and arguments for execution.\n */\n protected override getCommand(task: CliTask): CommandConfig {\n const args: string[] = [];\n\n // Add the task content as positional argument\n args.push(task.content);\n\n // Add output format\n args.push('-o', 'json');\n\n // Add model (always present due to default)\n const model = task.model ?? this.model;\n args.push('-m', model);\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n // Note: Sandbox mode (-s) removed - causes npm permission issues\n // and \"rebuilt dependencies successfully\" contamination\n\n // Honor systemPrompt via gemini's --policy flag (#1886).\n // Gemini treats policy files as system-level instructions, preserving\n // the system-role framing (unlike prepending to user content).\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-gemini-sysprompt-'));\n const file = join(dir, 'policy.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('--policy', file);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every gemini call with a systemPrompt leaked\n // one empty `/tmp/nexus-gemini-sysprompt-XXXXXX` dir until the OS\n // reaper ran.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n return cleanup === undefined\n ? { command: 'gemini', args }\n : { command: 'gemini', args, cleanup };\n }\n\n private checkCircuitBreaker(): CliError | null {\n if (this.circuitBreaker === null) {\n return null;\n }\n if (this.circuitBreaker.getState() === 'open') {\n return createCircuitOpenError('gemini');\n }\n return null;\n }\n\n private buildExecutionOptions(\n taskContent: string,\n options?: ExecutionOptions\n ): Required<ExecutionOptions> {\n const complexity = estimateTaskComplexity(taskContent);\n const timeoutMs = options?.timeoutMs ?? getTimeoutForTask(this.name, complexity);\n\n return {\n timeoutMs,\n allowRetry: options?.allowRetry ?? true,\n maxRetries: options?.maxRetries ?? this.maxRetries,\n trackUsage: options?.trackUsage ?? true,\n onProgress: options?.onProgress,\n };\n }\n\n private buildExecutionResult(\n result: Result<{ response: CliResponse; retryCount: number }, CliError>,\n startTime: number,\n complexity: TaskComplexity\n ): Result<GeminiExecutionResult, CliError> {\n const totalDurationMs = getTimeProvider().now() - startTime;\n const circuitState = this.circuitBreaker?.getState() ?? 'closed';\n\n if (result.ok) {\n this.circuitBreaker?.recordSuccess();\n return ok({\n response: result.value.response,\n retryCount: result.value.retryCount,\n totalDurationMs,\n complexity,\n circuitState,\n });\n }\n\n return err(result.error);\n }\n\n private async executeWithRetryTracking(\n task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<{ response: CliResponse; retryCount: number }, CliError>> {\n return executeCliRetryLoop(() => this.executeTask(task, options), {\n maxRetries: options.maxRetries,\n allowRetry: this.shouldOuterRetry(options),\n baseDelayMs: this.baseDelayMs,\n maxDelayMs: this.maxDelayMs,\n circuitBreaker: this.circuitBreaker,\n cli: this.name,\n logger: this.adapterLogger,\n });\n }\n}\n\n/** Creates a Gemini CLI adapter with reliability features. */\nexport function createGeminiAdapter(options?: GeminiConfig): GeminiCliAdapter {\n return new GeminiCliAdapter(options);\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini Parser Helpers\n *\n * Utility functions for parsing Gemini CLI output.\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { TokenUsage } from '../types.js';\nimport type { TokenTotals } from './gemini-parser-resilient-types.js';\nimport { asRecord, extractStringField, extractNumberField } from '../../utils/type-coercion.js';\n\n// Re-export for backward compatibility\nexport { asRecord, extractStringField };\n\n/**\n * Aggregates token counts from model stats.\n */\nexport function aggregateModelTokens(models: Record<string, unknown>): TokenTotals {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCached = 0;\n\n for (const modelStats of Object.values(models)) {\n const modelRecord = asRecord(modelStats);\n if (modelRecord === null) continue;\n\n const tokens = asRecord(modelRecord.tokens);\n if (tokens === null) continue;\n\n const input = extractNumberField(tokens, 'input');\n const candidates = extractNumberField(tokens, 'candidates');\n const cached = extractNumberField(tokens, 'cached');\n\n if (input !== null) totalInput += input;\n if (candidates !== null) totalOutput += candidates;\n if (cached !== null) totalCached += cached;\n }\n\n return { input: totalInput, output: totalOutput, cached: totalCached };\n}\n\n/**\n * Extracts token usage from a parsed record.\n */\nexport function extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | undefined {\n const stats = asRecord(record.stats);\n if (stats === null) return undefined;\n\n const models = asRecord(stats.models);\n if (models === null) return undefined;\n\n const totals = aggregateModelTokens(models);\n if (totals.input === 0 && totals.output === 0) return undefined;\n\n return {\n inputTokens: totals.input,\n outputTokens: totals.output,\n totalTokens: totals.input + totals.output,\n ...(totals.cached > 0 && { cachedInputTokens: totals.cached }),\n };\n}\n\n/**\n * Extracts session ID from text patterns.\n */\nexport function extractSessionIdFromText(raw: string): string | null {\n const patterns = [/session[_-]?id[:\\s]+[\"']?([a-zA-Z0-9_-]+)[\"']?/i, /gem_([a-zA-Z0-9]+)/];\n\n for (const pattern of patterns) {\n const match = pattern.exec(raw);\n const captured = match?.[1];\n if (captured !== undefined) {\n return captured.startsWith('gem_') ? captured : `gem_${captured}`;\n }\n }\n\n return null;\n}\n\n/**\n * Extracts text content from markdown, removing code blocks and formatting.\n */\nexport function extractTextFromMarkdown(raw: string): string {\n let content = raw;\n\n // Remove code blocks\n content = content.replace(/```[\\s\\S]*?```/g, '');\n\n // Remove markdown formatting\n content = content.replace(/#{1,6}\\s+/g, '');\n content = content.replace(/\\*{1,2}([^*]+)\\*{1,2}/g, '$1');\n content = content.replace(/_([^_]+)_/g, '$1');\n\n return content.trim();\n}\n\n/**\n * Extracts a clean error message from raw output.\n */\nexport function extractErrorMessage(raw: string): string {\n const lines = raw.split('\\n').filter((line) => line.trim().length > 0);\n\n // Look for error: prefix\n for (const line of lines) {\n const lower = line.toLowerCase();\n if (lower.includes('error:')) {\n return line.replace(/.*error:\\s*/i, '').trim();\n }\n }\n\n // Return first non-empty line as fallback\n return lines[0]?.trim() ?? 'Unknown error';\n}\n\n/**\n * Checks if output appears to be an error message.\n */\nexport function isLikelyErrorOutput(raw: string): boolean {\n const lower = raw.toLowerCase();\n const errorIndicators = ['error:', 'exception:', 'traceback', 'stack trace', 'fatal:', 'panic:'];\n\n // Check if output starts with error indicators\n for (const indicator of errorIndicators) {\n if (lower.startsWith(indicator)) return true;\n }\n\n // Check if it's a short error message\n if (raw.length < 200) {\n const errorKeywords = ['failed', 'error', 'cannot', 'unable to'];\n const hasErrorKeyword = errorKeywords.some((kw) => lower.includes(kw));\n const hasNoContent = !lower.includes('the ') && !lower.includes('this ');\n if (hasErrorKeyword && hasNoContent) return true;\n }\n\n return false;\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini CLI Response Parser\n *\n * Enhanced parser with multiple fallback strategies for handling\n * various Gemini CLI output formats including:\n * - Standard JSON output\n * - Plain text responses\n * - Multi-line outputs with markdown\n * - Error messages and exit codes\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport type { GeminiCliResponse } from './gemini-parser.js';\nimport type { ResilientParseResult, GeminiErrorInfo } from './gemini-parser-resilient-types.js';\nimport { extractJsonObject } from '../../core/index.js';\nimport {\n asRecord,\n extractStringField,\n extractUsageFromRecord,\n extractSessionIdFromText,\n extractTextFromMarkdown,\n extractErrorMessage,\n isLikelyErrorOutput,\n} from './gemini-parser-resilient-helpers.js';\n\n// Re-export types for backward compatibility\nexport type {\n ResilientParseResult,\n ParseStrategy,\n GeminiErrorInfo,\n} from './gemini-parser-resilient-types.js';\n\n/**\n * Resilient parser for Gemini CLI output.\n * Implements multiple fallback strategies for robust parsing.\n */\nexport class ResilientGeminiParser implements ICliResponseParser<GeminiCliResponse> {\n readonly name = 'gemini-resilient-parser';\n readonly supportedVersionRange = '>=0.20.0 <1.0.0';\n\n /**\n * Parses Gemini CLI output using multiple strategies.\n * Tries JSON first, then falls back to text extraction.\n */\n parse(raw: string): GeminiCliResponse | null {\n const result = this.parseResilient(raw);\n if (result === null) return null;\n\n // Build the response object, only including optional fields when present\n const response: GeminiCliResponse = {\n response: result.response,\n };\n\n // Add stats if usage info is available\n if (result.usage !== undefined) {\n return {\n ...response,\n ...(result.sessionId !== undefined && { session_id: result.sessionId }),\n stats: {\n models: {\n 'gemini-unknown': {\n tokens: {\n input: result.usage.inputTokens,\n candidates: result.usage.outputTokens,\n },\n },\n },\n },\n };\n }\n\n // No usage - just add session_id if it exists\n if (result.sessionId !== undefined) {\n return { ...response, session_id: result.sessionId };\n }\n\n return response;\n }\n\n /**\n * Parses with full metadata about parsing strategy.\n */\n parseResilient(raw: string): ResilientParseResult | null {\n // Strategy 1: Standard JSON parsing\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult !== null) return jsonResult;\n\n // Strategy 2: Extract JSON from mixed output\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson !== null) return extractedJson;\n\n // Strategy 3: Extract from markdown code blocks\n const markdownResult = this.tryExtractFromMarkdown(raw);\n if (markdownResult !== null) return markdownResult;\n\n // Strategy 4: Plain text fallback\n const plainTextResult = this.tryPlainText(raw);\n if (plainTextResult !== null) return plainTextResult;\n\n return null;\n }\n\n /**\n * Extracts just the response text with fallback strategies.\n */\n extractResponse(raw: string): string | null {\n const result = this.parseResilient(raw);\n return result?.response ?? null;\n }\n\n /**\n * Extracts token usage if available.\n */\n extractUsage(raw: string): TokenUsage | null {\n // Try JSON parsing first for structured usage data\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.usage) return jsonResult.usage;\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.usage) return extractedJson.usage;\n\n return null;\n }\n\n /**\n * Extracts session ID if present.\n */\n extractSessionId(raw: string): string | null {\n // Try JSON parsing first\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.sessionId !== undefined && jsonResult.sessionId !== '') {\n return jsonResult.sessionId;\n }\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.sessionId !== undefined && extractedJson.sessionId !== '') {\n return extractedJson.sessionId;\n }\n\n // Try to extract session ID from text patterns\n return extractSessionIdFromText(raw);\n }\n\n /**\n * Detects and extracts error information from output.\n */\n extractError(raw: string): GeminiErrorInfo | null {\n const lower = raw.toLowerCase();\n\n if (lower.includes('timeout') || lower.includes('timed out')) {\n return { type: 'timeout', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('authentication') || lower.includes('unauthorized')) {\n return { type: 'auth', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('rate limit') || lower.includes('quota exceeded')) {\n return { type: 'rate-limit', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('error') || lower.includes('failed')) {\n return { type: 'api-error', message: extractErrorMessage(raw) };\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Private Strategy Methods\n // -------------------------------------------------------------------------\n\n private tryParseJson(raw: string): ResilientParseResult | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const response = record.response;\n if (typeof response !== 'string') return null;\n\n const sessionId = extractStringField(record, 'session_id');\n const usage = extractUsageFromRecord(record);\n\n const result: ResilientParseResult = {\n response,\n parseStrategy: 'json',\n raw,\n };\n\n if (sessionId !== undefined) {\n (result as { sessionId?: string }).sessionId = sessionId;\n }\n if (usage !== undefined) {\n (result as { usage?: TokenUsage }).usage = usage;\n }\n\n return result;\n } catch {\n return null;\n }\n }\n\n private tryExtractJson(raw: string): ResilientParseResult | null {\n // ReDoS-safe extraction (#1912): previously used compound patterns like\n // `/\\{[\\s\\S]*\"response\"\\s*:\\s*\"[\\s\\S]*\"\\s*[\\s\\S]*\\}/` which have THREE\n // `[\\s\\S]*` groups — catastrophic backtracking on large non-matching\n // input. Now we extract the JSON object via indexOf/lastIndexOf (O(n))\n // and let tryParseJson validate the \"response\" field structurally.\n const candidate = extractJsonObject(raw);\n if (candidate === undefined) return null;\n const result = this.tryParseJson(candidate);\n if (result !== null) {\n return { ...result, parseStrategy: 'json-extracted', raw };\n }\n return null;\n }\n\n private tryExtractFromMarkdown(raw: string): ResilientParseResult | null {\n // Extract content from markdown code blocks\n const codeBlockPattern = /```(?:json)?\\s*([\\s\\S]*?)```/g;\n let match: RegExpExecArray | null = codeBlockPattern.exec(raw);\n\n while (match !== null) {\n const captured = match[1];\n if (captured !== undefined) {\n const content = captured.trim();\n\n // Try to parse as JSON\n const jsonResult = this.tryParseJson(content);\n if (jsonResult !== null) {\n return { ...jsonResult, parseStrategy: 'markdown-code-block', raw };\n }\n }\n\n match = codeBlockPattern.exec(raw);\n }\n\n // If no JSON found in code blocks, treat entire content as response\n // but only if it looks like substantive output\n if (raw.includes('```')) {\n const cleanedContent = extractTextFromMarkdown(raw);\n if (cleanedContent.length > 0) {\n return {\n response: cleanedContent,\n parseStrategy: 'markdown-code-block',\n raw,\n };\n }\n }\n\n return null;\n }\n\n private tryPlainText(raw: string): ResilientParseResult | null {\n const trimmed = raw.trim();\n\n // Skip if empty or looks like an error\n if (trimmed.length === 0) return null;\n\n // Skip if it looks like just error output\n if (isLikelyErrorOutput(trimmed)) return null;\n\n // Accept as plain text response\n return {\n response: trimmed,\n parseStrategy: 'plain-text',\n raw,\n };\n }\n}\n\n/**\n * Creates a resilient Gemini parser instance.\n */\nexport function createResilientGeminiParser(): ResilientGeminiParser {\n return new ResilientGeminiParser();\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter Helpers\n *\n * CLI-specific helper functions for retry logic and error handling.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName } from '../types.js';\n\n// -----------------------------------------------------------------------------\n// Fallback Defaults (for unknown models not in canonical registry)\n// -----------------------------------------------------------------------------\n\n/**\n * Fallback defaults for Gemini models not in the canonical registry.\n * All current models are in config/in-tree-data.ts and served by\n * buildModelInfo('gemini', model). This provides sensible defaults\n * when an unknown model name is encountered at runtime.\n *\n * @see config/in-tree-data.ts — single source of truth for current models\n */\nexport const GEMINI_LEGACY_DEFAULTS = {\n displayNames: {} as Readonly<Record<string, string>>,\n contextWindows: {} as Readonly<Record<string, number>>,\n inputCosts: {} as Readonly<Record<string, number>>,\n outputCosts: {} as Readonly<Record<string, number>>,\n contextWindow: 1_000_000,\n inputCost: 0.15,\n outputCost: 0.6,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Re-exports from canonical cli-retry-loop.ts (Issue #1596)\n// -----------------------------------------------------------------------------\n\nexport { calculateBackoffDelay, isRetryableError, categorizeError } from '../cli-retry-loop.js';\n\n// -----------------------------------------------------------------------------\n// Error Factory\n// -----------------------------------------------------------------------------\n\n/** Creates a circuit breaker open error. */\nexport function createCircuitOpenError(cli: CliName): CliError {\n return {\n code: 'EXECUTION_ERROR',\n message: `Circuit breaker is open - ${cli} CLI temporarily unavailable`,\n cli,\n retryable: false,\n };\n}\n\n// -----------------------------------------------------------------------------\n// Utility Functions\n// -----------------------------------------------------------------------------\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter\n *\n * Subprocess-based adapter for Codex CLI.\n * Extends SubprocessCliAdapter to reuse retry logic, health checks,\n * version detection, and capacity tracking.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #1140 — Migrated to SubprocessCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell: true.\n * User task content is passed as a single argv element (no shell interpolation).\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { CodexResponseParser } from '../parsers/codex-parser.js';\nimport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n// Re-export CLI-specific helpers for backward compatibility\nexport { createCodexError, normalizeCodexResponse, delay } from './codex-adapter-helpers.js';\n\n/**\n * Codex CLI adapter using subprocess transport.\n *\n * Extends SubprocessCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Subprocess spawn with timeout handling\n */\nexport class CodexCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'codex';\n protected readonly parser: ICliResponseParser = new CodexResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Task content is passed as a positional argument (not via stdin).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['exec'];\n\n // Add JSON output\n args.push('--json');\n\n // Add model only if specified (use CLI default otherwise)\n const model = task.model ?? this.model;\n if (model !== '') {\n args.push('-m', model);\n }\n\n // Add sandbox mode for safety (read-only by default)\n args.push('-s', 'read-only');\n\n // Skip git repo check for standalone prompts\n args.push('--skip-git-repo-check');\n\n // Honor systemPrompt via codex's `model_instructions_file` config key\n // (per openai/codex#11588 — closed with this workaround). We materialize\n // the prompt into a tempfile, pass it via `-c`, and clean up on exit.\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-codex-sysprompt-'));\n const file = join(dir, 'instructions.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('-c', `model_instructions_file=${file}`);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every codex call with a systemPrompt leaked\n // one empty `/tmp/nexus-codex-sysprompt-XXXXXX` dir until the OS\n // reaper ran — exhausting inodes on long-running MCP daemons.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n // Add the task content (no JSON.stringify needed without shell: true)\n args.push(task.content);\n\n return cleanup === undefined ? { command: 'codex', args } : { command: 'codex', args, cleanup };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Response Parser\n *\n * Defensive parser for Codex CLI NDJSON output.\n * Handles version 0.7x.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'codex-parser' });\n\n/**\n * Codex CLI NDJSON event types.\n */\nexport type CodexEventType =\n | 'thread.started'\n | 'turn.started'\n | 'item.completed'\n | 'turn.completed';\n\n/**\n * Base Codex event structure.\n */\nexport interface CodexEvent {\n readonly type: CodexEventType;\n}\n\n/**\n * Thread started event.\n */\nexport interface CodexThreadStarted extends CodexEvent {\n readonly type: 'thread.started';\n readonly thread_id: string;\n}\n\n/**\n * Item completed event (contains response or reasoning).\n */\nexport interface CodexItemCompleted extends CodexEvent {\n readonly type: 'item.completed';\n readonly item: {\n readonly id: string;\n readonly type: string;\n readonly text: string;\n };\n}\n\n/**\n * Turn completed event (contains usage).\n */\nexport interface CodexTurnCompleted extends CodexEvent {\n readonly type: 'turn.completed';\n readonly usage?: {\n readonly input_tokens: number;\n readonly cached_input_tokens?: number;\n readonly output_tokens: number;\n };\n}\n\n/**\n * Aggregated Codex response from NDJSON stream.\n */\nexport interface CodexCliResponse {\n readonly threadId?: string;\n readonly messages: readonly string[];\n readonly reasoning: readonly string[];\n readonly usage?: TokenUsage;\n}\n\n/**\n * Parser for Codex CLI NDJSON output.\n * Implements defensive parsing - processes stream of events.\n */\nexport class CodexResponseParser implements ICliResponseParser<CodexCliResponse> {\n readonly name = 'codex-parser';\n readonly supportedVersionRange = '>=0.70.0 <1.0.0';\n\n /**\n * Parses complete Codex CLI NDJSON stream.\n */\n parse(raw: string): CodexCliResponse | null {\n const lines = raw.trim().split('\\n');\n let threadId: string | undefined;\n const messages: string[] = [];\n const reasoning: string[] = [];\n let usage: TokenUsage | undefined;\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n this.processLine(\n line,\n messages,\n reasoning,\n (id) => (threadId = id),\n (u) => (usage = u)\n );\n }\n\n if (messages.length === 0 && reasoning.length === 0) {\n return null;\n }\n\n return {\n messages,\n reasoning,\n ...(threadId !== undefined && { threadId }),\n ...(usage !== undefined && { usage }),\n };\n }\n\n /**\n * Processes a single NDJSON line.\n */\n private processLine(\n line: string,\n messages: string[],\n reasoning: string[],\n setThreadId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) return;\n\n const eventType = record.type;\n\n if (eventType === 'thread.started') {\n const tid = record.thread_id;\n if (typeof tid === 'string') setThreadId(tid);\n } else if (eventType === 'item.completed') {\n this.processItemCompleted(record, messages, reasoning);\n } else if (eventType === 'turn.completed') {\n const usage = this.extractUsageFromEvent(record);\n if (usage !== null) setUsage(usage);\n }\n } catch {\n // Skip malformed NDJSON lines\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Concatenates all agent_message items.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.messages.length === 0) {\n return null;\n }\n\n return parsed.messages.join('\\n');\n }\n\n /**\n * Extracts token usage from NDJSON stream.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'turn.completed') {\n return this.extractUsageFromEvent(record);\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID (thread_id) for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'thread.started') {\n const threadId = record.thread_id;\n if (typeof threadId === 'string') {\n return threadId;\n }\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Processes an item.completed event.\n */\n private processItemCompleted(\n record: Record<string, unknown>,\n messages: string[],\n reasoning: string[]\n ): void {\n const item = asRecord(record.item);\n if (item === null) return;\n\n const itemType = item.type;\n const text = item.text;\n\n if (typeof text !== 'string') return;\n\n if (itemType === 'agent_message') {\n messages.push(text);\n } else if (itemType === 'reasoning') {\n reasoning.push(text);\n }\n }\n\n /**\n * Extracts usage from a turn.completed event.\n */\n private extractUsageFromEvent(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens = extractNumberField(usage, 'input_tokens');\n const outputTokens = extractNumberField(usage, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usage, 'cached_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter Helpers\n *\n * CLI-specific helper functions for Codex subprocess adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName, TokenUsage, CliResponse } from '../types.js';\nimport { createCliError as sharedCreateCliError } from '../cli-error-helpers.js';\n\n// -----------------------------------------------------------------------------\n// Legacy Fallback Defaults (for non-canonical models)\n// -----------------------------------------------------------------------------\n\n/** Legacy fallback values for Codex models not in the canonical registry. */\nexport const CODEX_LEGACY_DEFAULTS = {\n displayNames: {\n o3: 'O3',\n 'o3-mini': 'O3 Mini',\n 'o4-mini': 'O4 Mini',\n } as Readonly<Record<string, string>>,\n inputCosts: {\n o3: 10.0,\n 'o3-mini': 1.1,\n 'o4-mini': 1.1,\n } as Readonly<Record<string, number>>,\n outputCosts: {\n o3: 40.0,\n 'o3-mini': 4.4,\n 'o4-mini': 4.4,\n } as Readonly<Record<string, number>>,\n contextWindow: 400_000,\n maxOutput: 100_000,\n inputCost: 1.1,\n outputCost: 4.4,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Creates a CLI error with the canonical retryable-flag logic.\n * Kept as an alias under this name for backward compatibility with callers\n * that imported `createCodexError` before the helper was consolidated in\n * `cli-error-helpers.ts` (#2181). Prefer `createCliError` from the shared\n * helper in new code.\n */\nexport function createCodexError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Response Normalization\n// -----------------------------------------------------------------------------\n\n/** Normalizes CLI response to common format. */\nexport function normalizeCodexResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter\n *\n * MCP-based adapter for Codex CLI. Preferred transport for Codex integration.\n * Extends BaseCliAdapter to reuse retry logic, health checks, version\n * detection, and capacity tracking.\n *\n * (Source: Issue #1140 — Migrated to BaseCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell interpolation.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport type {\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n ExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport type { Result } from '../../core/index.js';\nimport { getErrorMessage, ok, err, getTimeProvider, createLogger } from '../../core/index.js';\nimport { BaseCliAdapter } from '../base-adapter.js';\n\nimport {\n CODEX_LEGACY_DEFAULTS,\n type McpToolResult,\n extractTextFromContent,\n createTimeout,\n determineErrorCode,\n} from './codex-mcp-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Codex CLI adapter using MCP transport.\n *\n * Extends BaseCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Error creation helpers\n */\nexport class CodexMcpAdapter extends BaseCliAdapter {\n readonly name: CliName = 'codex';\n readonly transport: CliTransport = 'mcp';\n\n private readonly model: string;\n private client: Client | undefined;\n private mcpTransport: StdioClientTransport | undefined;\n private connected = false;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger ?? createLogger({ component: 'codex-mcp-adapter' }));\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Initializes the MCP connection to Codex.\n */\n async initialize(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n this.initCapacityTracker();\n this.logger.debug('Initializing Codex MCP connection');\n\n try {\n this.mcpTransport = new StdioClientTransport({\n command: 'codex',\n args: ['mcp-server'],\n stderr: 'pipe',\n });\n\n this.client = new Client({ name: 'nexus-agents', version: '2.0.0' }, { capabilities: {} });\n await this.client.connect(this.mcpTransport);\n this.connected = true;\n this.initialized = true;\n this.logger.info('Codex MCP connection established');\n } catch (error) {\n this.connected = false;\n const connectionError = error instanceof Error ? error : new Error('Connection failed');\n this.logger.error('Failed to initialize Codex MCP connection', connectionError);\n throw error;\n }\n }\n\n /**\n * Executes a task via MCP client.\n * Called by BaseCliAdapter.execute() with retry handling.\n */\n async executeTask(\n _task: CliTask,\n options: Required<ExecutionOptions>\n ): Promise<Result<CliResponse, CliError>> {\n const startTime = getTimeProvider().now();\n\n if (this.client === undefined) {\n return err(this.createError('CONNECTION_ERROR', 'MCP client not initialized'));\n }\n\n try {\n const result = await Promise.race([\n this.callCodexTool(_task),\n createTimeout(options.timeoutMs),\n ]);\n\n if (result === null) {\n return err(this.createError('TIMEOUT', 'Execution timed out'));\n }\n\n return this.parseToolResult(result, startTime);\n } catch (error) {\n return this.handleExecutionError(error);\n }\n }\n\n /**\n * Calls the codex or codex-reply tool on Codex MCP server.\n * @see https://developers.openai.com/codex/mcp/\n */\n private async callCodexTool(task: CliTask): Promise<McpToolResult> {\n if (this.client === undefined) {\n throw new Error('Client not initialized');\n }\n\n const isReply = task.sessionId !== undefined && task.sessionId !== '';\n const toolName = isReply ? 'codex-reply' : 'codex';\n\n const baseArgs = {\n prompt: task.content,\n ...(task.model !== undefined && { model: task.model }),\n };\n\n const args = isReply\n ? { ...baseArgs, threadId: task.sessionId }\n : {\n ...baseArgs,\n sandbox: 'read-only' as const,\n 'approval-policy': 'on-failure' as const,\n };\n\n const result = await this.client.callTool({\n name: toolName,\n arguments: args,\n });\n\n return result as McpToolResult;\n }\n\n /**\n * Parses MCP tool result to CLI response.\n */\n private parseToolResult(result: McpToolResult, startTime: number): Result<CliResponse, CliError> {\n if (result.isError === true) {\n const errorText = extractTextFromContent(result.content);\n return err(this.createError('EXECUTION_ERROR', errorText ?? 'Tool execution failed'));\n }\n\n const text = extractTextFromContent(result.content);\n if (text === null) {\n return err(this.createError('PARSE_ERROR', 'No text content in response'));\n }\n\n return ok({\n text,\n durationMs: getTimeProvider().now() - startTime,\n raw: result,\n });\n }\n\n /**\n * Handles execution errors.\n */\n private handleExecutionError(error: unknown): Result<CliResponse, CliError> {\n const message = getErrorMessage(error);\n const errorCode = determineErrorCode(message);\n\n if (errorCode === 'CONNECTION_ERROR') {\n this.connected = false;\n }\n\n return err(this.createError(errorCode, message, error as Error));\n }\n\n /**\n * Disposes the adapter and closes MCP connection.\n */\n async dispose(): Promise<void> {\n if (this.mcpTransport !== undefined) {\n this.logger.debug('Closing Codex MCP connection');\n await this.mcpTransport.close();\n this.mcpTransport = undefined;\n }\n this.client = undefined;\n this.connected = false;\n this.initialized = false;\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter Helpers\n *\n * CLI-specific helper functions for Codex MCP adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n *\n * (Source: cli-project_plan.md v2.1.0, Issue #90)\n */\n\nimport type { ExecutionOptions, CliError, CliName } from '../types.js';\nimport { CODEX_MCP_TIMEOUTS } from '../../config/timeouts.js';\nimport {\n createCliError as sharedCreateCliError,\n isRetryableErrorCode as sharedIsRetryableErrorCode,\n} from '../cli-error-helpers.js';\n\n// Re-export legacy defaults from the subprocess helpers (DRY)\nexport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\n\n/**\n * Default execution options for Codex MCP.\n * Timeout and retry values derived from config/timeouts.ts (#1220).\n */\nexport const DEFAULT_CODEX_MCP_OPTIONS: Required<ExecutionOptions> = {\n timeoutMs: CODEX_MCP_TIMEOUTS.defaultMs,\n allowRetry: true,\n maxRetries: CODEX_MCP_TIMEOUTS.maxRetries,\n trackUsage: true,\n onProgress: undefined,\n};\n\n/**\n * MCP tool call result structure.\n */\nexport interface McpToolResult {\n content?: Array<{ type: string; text?: string }>;\n isError?: boolean;\n}\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Checks if an error code is retryable. Kept exported for backward\n * compatibility with callers that imported from this module; delegates\n * to the canonical helper (#2181).\n */\nexport function isRetryableErrorCode(code: CliError['code']): boolean {\n return sharedIsRetryableErrorCode(code);\n}\n\n/**\n * Creates a CLI error object with the canonical retryable-flag logic.\n * Kept exported for backward compatibility (#2181).\n */\nexport function createCliError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Content Extraction\n// -----------------------------------------------------------------------------\n\n/** Extracts text from MCP content array. */\nexport function extractTextFromContent(\n content?: Array<{ type: string; text?: string }>\n): string | null {\n if (content === undefined || content.length === 0) {\n return null;\n }\n\n const textContents = content\n .filter((c): c is { type: string; text: string } => c.type === 'text' && c.text !== undefined)\n .map((c) => c.text);\n\n return textContents.length > 0 ? textContents.join('\\n') : null;\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n\n/** Creates a timeout promise that resolves to null. */\nexport function createTimeout(ms: number): Promise<null> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve(null);\n }, ms);\n });\n}\n\n/** Determines error code from error message. */\nexport function determineErrorCode(message: string): CliError['code'] {\n if (message.includes('ENOENT') || message.includes('not found')) {\n return 'NOT_FOUND';\n }\n\n if (message.includes('timeout') || message.includes('ETIMEDOUT')) {\n return 'TIMEOUT';\n }\n\n if (message.includes('connection') || message.includes('disconnect')) {\n return 'CONNECTION_ERROR';\n }\n\n return 'EXECUTION_ERROR';\n}\n\n/** Parses version string from codex --version output. */\nexport function parseVersionFromOutput(output: string): string {\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output.trim());\n return match?.[1] ?? '0.0.0';\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Adapter\n *\n * Subprocess-based adapter for OpenCode CLI.\n * Uses `opencode run --format json` for stable parsing.\n *\n * (Source: Issue #1124, opencode.ai/docs/cli/)\n */\n\nimport { execFile } from 'node:child_process';\n\nimport type {\n ICliResponseParser,\n CliTask,\n CliModelInfo,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport {\n SubprocessCliAdapter,\n type CommandConfig,\n type TransientRetryConfig,\n} from '../subprocess-adapter.js';\nimport { OpenCodeResponseParser } from '../parsers/opencode-parser.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n} from '../../config/model-config-helpers.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-adapter' });\n\n/** Strict allowlist for OpenCode --variant flag values. */\nconst ALLOWED_VARIANTS = ['high', 'max', 'minimal'];\n\n/**\n * Maps internal model names to OpenCode CLI --model values.\n * OpenCode uses `provider/model-name` format (e.g., `anthropic/claude-sonnet-4-6`).\n * Built from canonical registry + common alias fallbacks (#1402).\n */\nconst MODEL_TO_CLI_NAME: Record<string, string> = buildOpenCodeAliasMap();\n\nfunction buildOpenCodeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('opencode')) {\n if (model.cliModelName === undefined) continue;\n // Map internal ID → CLI model name\n map[model.id] = model.cliModelName;\n // Map CLI alias → CLI model name\n if (model.cliAlias !== undefined) {\n map[model.cliAlias] = model.cliModelName;\n }\n // Pass through cliModelName itself\n map[model.cliModelName] = model.cliModelName;\n }\n return map;\n}\n\n/** Resolves an internal model name to OpenCode CLI format. */\nfunction resolveOpenCodeModel(model: string): string {\n return MODEL_TO_CLI_NAME[model] ?? model;\n}\n\n/** Timeout for `opencode models` probe (ms). */\nconst PROBE_TIMEOUT_MS = 10_000;\n\n/**\n * Probes available models by running `opencode models`.\n * Returns a Set of model IDs (e.g., \"opencode/big-pickle\").\n * Caches result in a module-level variable for the process lifetime.\n */\nlet cachedModels: Set<string> | undefined;\n/** Inflight probe promise for coalescing concurrent calls (Issue #1438). */\nlet probePromise: Promise<Set<string>> | undefined;\n\nfunction probeAvailableModels(): Promise<Set<string>> {\n if (cachedModels !== undefined) return Promise.resolve(cachedModels);\n if (probePromise !== undefined) return probePromise;\n\n probePromise = new Promise<Set<string>>((resolve) => {\n execFile('opencode', ['models'], { timeout: PROBE_TIMEOUT_MS }, (error, stdout) => {\n if (error !== null || stdout.trim() === '') {\n logger.debug('Failed to probe OpenCode models, will omit --model flag', {\n error: error?.message,\n });\n cachedModels = new Set();\n resolve(cachedModels);\n return;\n }\n const models = new Set(\n stdout\n .trim()\n .split('\\n')\n .map((l) => l.trim())\n .filter((l) => l.length > 0)\n );\n logger.debug('Probed OpenCode models', { count: models.size });\n cachedModels = models;\n resolve(cachedModels);\n });\n }).finally(() => {\n probePromise = undefined;\n });\n\n return probePromise;\n}\n\n/** Patterns indicating an Anthropic provider in OpenCode models list. */\nconst ANTHROPIC_MODEL_PATTERNS = ['anthropic/', 'custom/claude'];\n\n/**\n * Logs a warning if OpenCode has an Anthropic provider configured (#1429).\n * Claude Code subscription API keys must NOT be used with third-party tools.\n */\nfunction warnIfAnthropicProvider(models: Set<string>): void {\n const anthropicModels = [...models].filter((m) =>\n ANTHROPIC_MODEL_PATTERNS.some((p) => m.toLowerCase().includes(p))\n );\n if (anthropicModels.length > 0) {\n logger.warn(\n 'OpenCode has Anthropic/Claude models configured. ' +\n 'Ensure these use a SEPARATE API key from console.anthropic.com, ' +\n 'NOT a Claude Code subscription key (which is restricted to Claude Code only).',\n { detectedModels: anthropicModels }\n );\n }\n}\n\n/**\n * OpenCode CLI adapter using subprocess transport.\n * Executes: opencode run --format json \"<task>\"\n *\n * Probes available models on first use and omits --model flag\n * when the requested model isn't available (#1402).\n */\nexport class OpenCodeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'opencode';\n protected readonly parser: ICliResponseParser = new OpenCodeResponseParser();\n\n /** Enable transient-error retry for OpenCode (#1456). */\n protected override readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n private readonly model: string;\n private availableModels: Set<string> | undefined;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('opencode'));\n }\n\n /**\n * Gets OpenCode model information from canonical registry.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('opencode', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: `OpenCode (${this.model})`,\n contextWindow: 200_000,\n maxOutput: 64_000,\n costPerMillionInput: 3.0,\n costPerMillionOutput: 15.0,\n };\n }\n\n /**\n * Initializes the adapter — probes available models.\n * Warns if Anthropic provider is configured (#1429 — API key boundaries).\n */\n override async initialize(): Promise<void> {\n this.availableModels = await probeAvailableModels();\n warnIfAnthropicProvider(this.availableModels);\n await super.initialize();\n }\n\n /** Returns true if the model is available in the OpenCode installation. */\n private isModelAvailable(cliModel: string): boolean {\n if (this.availableModels === undefined || this.availableModels.size === 0) return false;\n return this.availableModels.has(cliModel);\n }\n\n /** Appends --model if the resolved model is available (#1402). */\n private appendModelArg(args: string[], task: CliTask): void {\n const internalModel = task.model ?? this.model;\n const cliModel = resolveOpenCodeModel(internalModel);\n\n if (this.isModelAvailable(cliModel)) {\n args.push('--model', cliModel);\n } else {\n logger.debug('Model not available, using OpenCode default', {\n requested: cliModel,\n available: this.availableModels?.size ?? 0,\n });\n }\n }\n\n /** Appends optional task flags (workDir, variant, thinking). */\n private appendTaskFlags(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--dir', workDir);\n }\n const variant = task.options?.['variant'];\n if (typeof variant === 'string' && ALLOWED_VARIANTS.includes(variant)) {\n args.push('--variant', variant);\n }\n if (task.options?.['thinking'] === true) {\n args.push('--thinking');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses `opencode run` with JSON format for stable parsing.\n * Omits --model when the requested model isn't available (#1402).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['run', '--format', 'json'];\n this.appendModelArg(args, task);\n this.appendTaskFlags(args, task);\n\n // Honor systemPrompt by prepending to stdin content (#1886).\n // OpenCode CLI has no --system-prompt or --policy equivalent, so\n // prepend is the only option. This loses the formal system-role\n // distinction, but satisfies the contract that systemPrompt\n // influences the call (far better than silently dropping it).\n const content =\n task.systemPrompt !== undefined && task.systemPrompt !== ''\n ? `${task.systemPrompt}\\n\\n---\\n\\n${task.content}`\n : task.content;\n\n return { command: 'opencode', args, stdin: content };\n }\n\n /**\n * (#2540) Lists models the local OpenCode installation can route to.\n * Wraps the existing `probeAvailableModels()` (cached for the process\n * lifetime — see `cachedModels` at the top of this file) and reshapes\n * the result into the CliModelInfo schema. Splits `provider/model` ids\n * when present.\n */\n async listModels(): Promise<readonly CliModelInfo[]> {\n const ids = await probeAvailableModels();\n const out: CliModelInfo[] = [];\n for (const raw of ids) {\n const slash = raw.indexOf('/');\n if (slash > 0 && slash < raw.length - 1) {\n out.push({ id: raw, provider: raw.slice(0, slash) });\n } else {\n out.push({ id: raw });\n }\n }\n return out;\n }\n}\n\n/**\n * Factory function for creating OpenCode adapter.\n */\nexport function createOpenCodeAdapter(options?: BaseAdapterOptions): OpenCodeCliAdapter {\n return new OpenCodeCliAdapter(options);\n}\n\n/** Resets model probe cache (for testing). */\nexport function resetOpenCodeModelCache(): void {\n cachedModels = undefined;\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Response Parser\n *\n * Defensive parser for OpenCode CLI JSON output.\n * Handles `opencode run --format json` NDJSON event stream.\n *\n * Real opencode v1.2.x NDJSON format (verified via E2E testing):\n * {\"type\":\"step_start\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-start\",...}}\n * {\"type\":\"text\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"text\",\"text\":\"Hello!\",...}}\n * {\"type\":\"step_finish\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-finish\",\"tokens\":{...},...}}\n *\n * (Source: Issue #1124, #1244, opencode.ai/docs/cli/)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-parser' });\n\n/** Minimum raw text length for plaintext fallback (#1402). */\nconst PLAINTEXT_MIN_LENGTH = 10;\n\n/** Returns true if text looks like NDJSON (most non-empty lines start with '{' ). */\nfunction looksLikeNdjson(text: string): boolean {\n const lines = text.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length === 0) return false;\n const jsonLineCount = lines.filter((l) => l.trimStart().startsWith('{')).length;\n return jsonLineCount > lines.length / 2;\n}\n\n/**\n * OpenCode CLI NDJSON event types.\n * Includes both real v1.2.x types and legacy assumed types for compatibility.\n */\nexport type OpenCodeEventType =\n // Real opencode v1.2.x event types\n | 'step_start'\n | 'text'\n | 'tool_use'\n | 'step_finish'\n | 'error'\n // Legacy assumed types (maintained for backward compatibility)\n | 'session.start'\n | 'message.start'\n | 'message.delta'\n | 'message.complete'\n | 'session.complete';\n\n/**\n * Aggregated OpenCode response from NDJSON stream.\n */\nexport interface OpenCodeCliResponse {\n readonly sessionId?: string;\n readonly content: string;\n readonly usage?: TokenUsage;\n /**\n * Concatenated error-event messages emitted during the NDJSON stream.\n * Set whenever `{\"type\":\"error\",...}` events appeared. Independent of\n * whether `content` is empty — if both are populated the model produced\n * text and then errored, callers can decide what to do.\n * #2821: previously error events were folded into `content` (making\n * failures look like successful responses to consensus voters/routers).\n */\n readonly errorMessage?: string;\n}\n\n/** Internal state from processing NDJSON lines. */\ninterface NdjsonParseState {\n readonly sessionId: string | undefined;\n readonly contentParts: string[];\n readonly errorMessages: string[];\n readonly usage: TokenUsage | undefined;\n readonly hasStepEvents: boolean;\n readonly hasAnyRecognizedEvent: boolean;\n}\n\n/**\n * Parser for OpenCode CLI JSON output.\n * Handles NDJSON event stream from `opencode run --format json`.\n *\n * Supports both real opencode v1.2.x format and legacy assumed format.\n */\nexport class OpenCodeResponseParser implements ICliResponseParser<OpenCodeCliResponse> {\n readonly name = 'opencode-parser';\n readonly supportedVersionRange = '>=1.0.0 <2.0.0';\n\n /**\n * Parses complete OpenCode CLI NDJSON stream.\n */\n parse(raw: string): OpenCodeCliResponse | null {\n const lines = raw.trim().split('\\n');\n const state = this.processAllLines(lines);\n\n const errorMessage =\n state.errorMessages.length > 0 ? state.errorMessages.join('; ') : undefined;\n\n if (state.contentParts.length === 0) {\n // #2821: error-only streams must surface as failure. Empty content +\n // errorMessage set causes extractResponse() to return null, which the\n // subprocess-adapter then classifies as EXECUTION_ERROR — instead of\n // wrapping `[OpenCode error: ...]` in ok() and feeding it to voters.\n if (errorMessage !== undefined) {\n return this.buildResponse('', state.sessionId, state.usage, errorMessage);\n }\n return this.handleEmptyContent(raw, lines.length, state);\n }\n\n return this.buildResponse(\n state.contentParts.join(''),\n state.sessionId,\n state.usage,\n errorMessage\n );\n }\n\n /** Processes all NDJSON lines and returns aggregated state. */\n private processAllLines(lines: readonly string[]): NdjsonParseState {\n let sessionId: string | undefined;\n const contentParts: string[] = [];\n const errorMessages: string[] = [];\n let usage: TokenUsage | undefined;\n let hasStepEvents = false;\n let hasAnyRecognizedEvent = false;\n\n for (let idx = 0; idx < lines.length; idx++) {\n const line = lines[idx];\n if (line === undefined || line.trim() === '') continue;\n const hadEvent = this.processLine(\n line,\n { contentParts, errorMessages },\n (id) => (sessionId = id),\n (u) => (usage = u),\n idx\n );\n if (hadEvent) hasStepEvents = true;\n if (hadEvent || this.isRecognizedLegacyEvent(line)) hasAnyRecognizedEvent = true;\n }\n\n return {\n sessionId,\n contentParts,\n errorMessages,\n usage,\n hasStepEvents,\n hasAnyRecognizedEvent,\n };\n }\n\n /** Handles the case where no text content was extracted from NDJSON. */\n private handleEmptyContent(\n raw: string,\n lineCount: number,\n state: NdjsonParseState\n ): OpenCodeCliResponse | null {\n // Tool-only responses have step_start/step_finish but no text events.\n if (state.hasStepEvents) {\n return this.buildResponse(\n '[Tool-only response — no text output]',\n state.sessionId,\n state.usage\n );\n }\n // Fallback: try parsing as plain JSON (non-streaming mode)\n logger.debug('No NDJSON content extracted, trying JSON fallback', {\n rawLength: raw.length,\n lineCount,\n hasStepEvents: state.hasStepEvents,\n hasAnyRecognizedEvent: state.hasAnyRecognizedEvent,\n });\n return this.parsePlainJson(raw, state.hasAnyRecognizedEvent);\n }\n\n /** Builds an OpenCodeCliResponse from parsed components. */\n private buildResponse(\n content: string,\n sessionId: string | undefined,\n usage: TokenUsage | undefined,\n errorMessage?: string\n ): OpenCodeCliResponse {\n return {\n content,\n ...(sessionId !== undefined && { sessionId }),\n ...(usage !== undefined && { usage }),\n ...(errorMessage !== undefined && { errorMessage }),\n };\n }\n\n /**\n * Extracts just the response text.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.content === '') {\n logger.debug('extractResponse returned null', {\n rawLength: raw.length,\n snippet: raw.slice(0, 100),\n parsedNull: parsed === null,\n });\n return null;\n }\n return parsed.content;\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n // Real format: step_finish with nested part.tokens\n if (record.type === 'step_finish') {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) return usage;\n }\n\n // Legacy format: session.complete or message.complete with usage field\n if (record.type === 'session.complete' || record.type === 'message.complete') {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) return usage;\n }\n } catch {\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n const sid = this.extractSessionIdFromLine(line);\n if (sid !== null) return sid;\n }\n\n return null;\n }\n\n /** Extracts session ID from a single NDJSON line. */\n private extractSessionIdFromLine(line: string): string | null {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return null;\n\n // Real format: sessionID at top level (step_start, text, step_finish)\n if (typeof record.sessionID === 'string') return record.sessionID;\n\n // Legacy format: session_id/sessionId in session events\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') return sid;\n\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * Processes a single NDJSON line.\n * Handles both real v1.2.x format and legacy assumed format.\n * Returns true if a real v1.2.x step event was processed (step_start/text/tool_use/step_finish).\n * Legacy events return false since they don't indicate tool-only responses.\n */\n private processLine(\n line: string,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void,\n lineIndex: number\n ): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n\n const isReal = this.processRealEvent(record, collectors, setSessionId, setUsage);\n if (isReal) return true;\n\n this.processLegacyEvent(record, collectors.contentParts, setSessionId, setUsage);\n return false;\n } catch {\n logger.debug('Skipped malformed NDJSON line', {\n lineNumber: lineIndex + 1,\n snippet: line.slice(0, 100),\n });\n return false;\n }\n }\n\n /** Processes real opencode v1.2.x event types. Returns true if handled. */\n private processRealEvent(\n record: Record<string, unknown>,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): boolean {\n switch (record.type) {\n case 'step_start':\n case 'tool_use':\n this.handleRealSessionId(record, setSessionId);\n return true;\n case 'text':\n this.handleRealSessionId(record, setSessionId);\n this.pushRealTextContent(record, collectors.contentParts);\n return true;\n case 'step_finish':\n this.handleRealSessionId(record, setSessionId);\n this.emitRealUsage(record, setUsage);\n return true;\n case 'error':\n this.handleRealSessionId(record, setSessionId);\n this.captureErrorMessage(record, collectors.errorMessages);\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Captures an error-event message for the response's `errorMessage` field\n * (#2821). Previously this pushed `[OpenCode error: ...]` into `contentParts`,\n * which made error-only streams look like successful responses to consensus\n * voters and the routing learner.\n */\n private captureErrorMessage(record: Record<string, unknown>, errorMessages: string[]): void {\n const errorObj = asRecord(record.error);\n if (errorObj === null) return;\n\n const data = asRecord(errorObj.data);\n const message =\n data !== null && typeof data.message === 'string'\n ? data.message\n : typeof errorObj.name === 'string'\n ? errorObj.name\n : 'Unknown error';\n\n logger.warn('OpenCode returned error event', { message });\n errorMessages.push(message);\n }\n\n /** Processes legacy assumed event types. */\n private processLegacyEvent(\n record: Record<string, unknown>,\n contentParts: string[],\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n switch (record.type) {\n case 'session.start':\n this.handleLegacySessionStart(record, setSessionId);\n break;\n case 'message.delta':\n this.pushLegacyTextContent(record, contentParts);\n break;\n case 'message.complete':\n this.pushLegacyTextContent(record, contentParts);\n this.emitLegacyUsage(record, setUsage);\n break;\n case 'session.complete':\n this.emitLegacyUsage(record, setUsage);\n break;\n }\n }\n\n // --- Real v1.2.x format handlers ---\n\n /** Extracts sessionID from top-level field (real format). */\n private handleRealSessionId(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n if (typeof record.sessionID === 'string') setSessionId(record.sessionID);\n }\n\n /** Extracts text from nested part.text field (real format). */\n private pushRealTextContent(record: Record<string, unknown>, parts: string[]): void {\n const part = asRecord(record.part);\n if (part === null) return;\n\n if (typeof part.text === 'string') parts.push(part.text);\n }\n\n /** Extracts usage from nested part.tokens field (real format). */\n private emitRealUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Extracts usage from part.tokens (real opencode v1.2.x format). */\n private extractUsageFromPart(record: Record<string, unknown>): TokenUsage | null {\n const part = asRecord(record.part);\n if (part === null) return null;\n\n const tokens = asRecord(part.tokens);\n if (tokens === null) return null;\n\n const inputTokens = extractNumberField(tokens, 'input');\n const outputTokens = extractNumberField(tokens, 'output');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n\n // --- Legacy format handlers ---\n\n /** Extracts session ID from a session event record (legacy format). */\n private handleLegacySessionStart(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') setSessionId(sid);\n }\n\n /** Pushes text content from a message event (legacy format). */\n private pushLegacyTextContent(record: Record<string, unknown>, parts: string[]): void {\n const text = record.content ?? record.delta ?? record.text;\n if (typeof text === 'string') parts.push(text);\n }\n\n /** Emits usage from a record (legacy format). */\n private emitLegacyUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Checks if a line contains a recognized legacy event type (without full parsing). */\n private isRecognizedLegacyEvent(line: string): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n const t = record.type;\n return (\n t === 'session.start' ||\n t === 'message.start' ||\n t === 'message.delta' ||\n t === 'message.complete' ||\n t === 'session.complete'\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Fallback parser for plain JSON output (non-streaming).\n * Falls back to raw plaintext if JSON parsing fails and content is substantial (#1402).\n * When hasAnyRecognizedEvent is true, NDJSON-like plaintext is rejected (it was\n * recognized NDJSON that simply had no content — not malformed output).\n */\n private parsePlainJson(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n\n // Try common response field names\n const content = record.content ?? record.result ?? record.text ?? record.output;\n if (typeof content !== 'string') return null; // Valid JSON but no recognized fields\n\n const usage = this.extractUsageFromRecord(record);\n const sid = record.session_id ?? record.sessionId;\n\n return {\n content,\n ...(typeof sid === 'string' ? { sessionId: sid } : {}),\n ...(usage !== null ? { usage } : {}),\n };\n } catch {\n return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n }\n }\n\n /**\n * Last-resort plaintext fallback for non-JSON CLI output (#1402).\n * Returns raw text as content when it has substantial length.\n * Accepts NDJSON-like content only when no recognized events were found\n * (meaning it's truly unrecognized/malformed output, not valid NDJSON with no text).\n */\n private parsePlaintext(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n const trimmed = raw.trim();\n if (trimmed.length < PLAINTEXT_MIN_LENGTH) {\n logger.debug('Plaintext fallback rejected: too short', { length: trimmed.length });\n return null;\n }\n if (looksLikeNdjson(trimmed)) {\n if (hasAnyRecognizedEvent) {\n logger.debug('Plaintext fallback rejected: recognized NDJSON with no content', {\n length: trimmed.length,\n });\n return null;\n }\n logger.debug('Plaintext fallback: accepting malformed NDJSON as text', {\n length: trimmed.length,\n });\n }\n return { content: trimmed };\n }\n\n /**\n * Extracts usage from a record with usage/token fields (legacy format).\n */\n private extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens =\n extractNumberField(usage, 'input_tokens') ?? extractNumberField(usage, 'inputTokens');\n const outputTokens =\n extractNumberField(usage, 'output_tokens') ?? extractNumberField(usage, 'outputTokens');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n}\n","/**\n * nexus-agents/cli-adapters - CLI Detection Cache\n *\n * Caches CLI health check results to avoid repeated subprocess calls.\n * Invalidates on circuit breaker trips or manual invalidation.\n *\n * @module cli-adapters/cli-detection-cache\n * (Source: Issue #165, Proposal adapter-architecture-review.md)\n */\n\nimport { z } from 'zod';\nimport { createLogger } from '../core/logger.js';\nimport type { ILogger } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { CliName, HealthStatus, VersionStatus } from './types.js';\n\n/**\n * Cached health result for a CLI.\n */\nexport interface CliHealthResult {\n /** Whether the CLI is healthy and available */\n readonly healthy: boolean;\n /** CLI version detected */\n readonly version: string;\n /** Version compatibility status */\n readonly versionStatus: VersionStatus;\n /** When this result was captured */\n readonly checkedAt: Date;\n /** Optional status message */\n readonly message?: string | undefined;\n}\n\n/**\n * Configuration for the CLI detection cache.\n */\nexport interface CliDetectionCacheConfig {\n /** Base time-to-live in milliseconds (default: 5 minutes) */\n readonly ttlMs: number;\n /** Enable adaptive TTL based on health history (default: true) */\n readonly adaptiveTtl?: boolean | undefined;\n /** Logger instance */\n readonly logger?: ILogger | undefined;\n}\n\n/**\n * Zod schema for cache configuration validation.\n */\nexport const CliDetectionCacheConfigSchema = z.object({\n ttlMs: z.number().min(1000).max(3600_000).default(300_000),\n});\n\n/**\n * Default cache configuration.\n */\nexport const DEFAULT_CACHE_CONFIG: CliDetectionCacheConfig = {\n ttlMs: 300_000, // 5 minutes\n adaptiveTtl: true,\n};\n\n/** Adaptive TTL multipliers. Healthy CLIs are polled less often; unhealthy more often. */\nconst ADAPTIVE_MULTIPLIER_HEALTHY = 2.0;\nconst ADAPTIVE_MULTIPLIER_UNHEALTHY = 0.25;\n/** Number of consecutive same-status results before the multiplier kicks in. */\nconst ADAPTIVE_STREAK_THRESHOLD = 2;\n\n/**\n * Interface for CLI detection cache.\n * Allows dependency injection for testing.\n */\nexport interface ICliDetectionCache {\n /** Get cached health result for a CLI */\n get(cli: CliName): CliHealthResult | undefined;\n\n /** Set health result for a CLI */\n set(cli: CliName, result: CliHealthResult): void;\n\n /** Check if cache entry is stale */\n isStale(cli: CliName): boolean;\n\n /** Invalidate cache for a specific CLI or all CLIs */\n invalidate(cli?: CliName): void;\n\n /** Get all cached results */\n getAll(): ReadonlyMap<CliName, CliHealthResult>;\n\n /** Get cache statistics */\n getStats(): CacheStats;\n\n /** Get effective TTL for a CLI (accounts for adaptive adjustments) */\n getEffectiveTtl(cli: CliName): number;\n}\n\n/**\n * Cache statistics for observability.\n */\nexport interface CacheStats {\n /** Number of cached entries */\n readonly size: number;\n /** Cache hits since last reset */\n readonly hits: number;\n /** Cache misses since last reset */\n readonly misses: number;\n /** Hit rate (0-1) */\n readonly hitRate: number;\n /** When stats were last reset */\n readonly lastReset: Date;\n}\n\n/**\n * CLI detection cache implementation.\n * Thread-safe for Node.js single-threaded execution.\n */\nexport class CliDetectionCache implements ICliDetectionCache {\n private readonly config: CliDetectionCacheConfig;\n private readonly logger: ILogger;\n private readonly cache: Map<CliName, CliHealthResult> = new Map();\n /** Consecutive same-health-status count per CLI (for adaptive TTL). */\n private readonly streaks: Map<CliName, { healthy: boolean; count: number }> = new Map();\n private hits = 0;\n private misses = 0;\n private lastReset: Date = new Date(getTimeProvider().now());\n\n constructor(config?: Partial<CliDetectionCacheConfig>) {\n const validated = CliDetectionCacheConfigSchema.parse({\n ttlMs: config?.ttlMs ?? DEFAULT_CACHE_CONFIG.ttlMs,\n });\n this.config = {\n ...validated,\n adaptiveTtl: config?.adaptiveTtl ?? DEFAULT_CACHE_CONFIG.adaptiveTtl,\n logger: config?.logger,\n };\n this.logger = config?.logger ?? createLogger({ component: 'CliDetectionCache' });\n\n this.logger.debug('CliDetectionCache initialized', { ttlMs: this.config.ttlMs });\n }\n\n get(cli: CliName): CliHealthResult | undefined {\n const result = this.cache.get(cli);\n\n if (result === undefined) {\n this.misses++;\n this.logger.debug('Cache miss', { cli });\n return undefined;\n }\n\n if (this.isStale(cli)) {\n this.misses++;\n this.logger.debug('Cache stale', { cli, checkedAt: result.checkedAt });\n return undefined;\n }\n\n this.hits++;\n this.logger.debug('Cache hit', { cli, healthy: result.healthy });\n return result;\n }\n\n set(cli: CliName, result: CliHealthResult): void {\n this.cache.set(cli, result);\n this.updateStreak(cli, result.healthy);\n this.logger.debug('Cache updated', {\n cli,\n healthy: result.healthy,\n version: result.version,\n });\n }\n\n isStale(cli: CliName): boolean {\n const result = this.cache.get(cli);\n if (result === undefined) return true;\n\n const age = getTimeProvider().now() - result.checkedAt.getTime();\n return age > this.getEffectiveTtl(cli);\n }\n\n /** Returns the effective TTL for a CLI, applying adaptive multiplier if enabled. */\n getEffectiveTtl(cli: CliName): number {\n if (this.config.adaptiveTtl === false) return this.config.ttlMs;\n const streak = this.streaks.get(cli);\n if (streak === undefined || streak.count < ADAPTIVE_STREAK_THRESHOLD) {\n return this.config.ttlMs;\n }\n const multiplier = streak.healthy ? ADAPTIVE_MULTIPLIER_HEALTHY : ADAPTIVE_MULTIPLIER_UNHEALTHY;\n return this.config.ttlMs * multiplier;\n }\n\n private updateStreak(cli: CliName, healthy: boolean): void {\n const prev = this.streaks.get(cli);\n if (prev?.healthy === healthy) {\n this.streaks.set(cli, { healthy, count: prev.count + 1 });\n } else {\n this.streaks.set(cli, { healthy, count: 1 });\n }\n }\n\n invalidate(cli?: CliName): void {\n if (cli !== undefined) {\n this.cache.delete(cli);\n this.streaks.delete(cli);\n this.logger.info('Cache invalidated', { cli });\n } else {\n this.cache.clear();\n this.streaks.clear();\n this.logger.info('Cache cleared');\n }\n }\n\n getAll(): ReadonlyMap<CliName, CliHealthResult> {\n return this.cache;\n }\n\n getStats(): CacheStats {\n const total = this.hits + this.misses;\n return {\n size: this.cache.size,\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n lastReset: this.lastReset,\n };\n }\n\n /**\n * Resets cache statistics.\n */\n resetStats(): void {\n this.hits = 0;\n this.misses = 0;\n this.lastReset = new Date(getTimeProvider().now());\n this.logger.debug('Cache stats reset');\n }\n\n /**\n * Converts HealthStatus to CliHealthResult for caching.\n */\n static fromHealthStatus(status: HealthStatus): CliHealthResult {\n return {\n healthy: status.healthy,\n version: status.version,\n versionStatus: status.versionStatus,\n checkedAt: status.lastChecked,\n message: status.message,\n };\n }\n}\n\n/**\n * Creates a CLI detection cache instance.\n *\n * @param config - Optional cache configuration\n * @returns CLI detection cache\n *\n * @example\n * ```typescript\n * const cache = createCliDetectionCache({ ttlMs: 60_000 }); // 1 minute TTL\n * const result = cache.get('claude');\n * if (!result) {\n * const health = await adapter.healthCheck();\n * cache.set('claude', CliDetectionCache.fromHealthStatus(health));\n * }\n * ```\n */\nexport function createCliDetectionCache(\n config?: Partial<CliDetectionCacheConfig>\n): ICliDetectionCache {\n return new CliDetectionCache(config);\n}\n","/**\n * cli-auth-probe — real authentication probes for the four AI CLIs.\n *\n * The existing `adapter.healthCheck()` only confirms the CLI binary exists +\n * the version is supported. It does NOT probe whether the CLI can actually\n * authenticate. Result: doctor reports \"✓ Auth: CLI auth\" for installed-but-\n * unauthed CLIs, then downstream commands fail with unreadable errors.\n *\n * This module fixes that. Per-CLI probes use the cheapest reliable signal:\n *\n * - claude → presence + non-expired `~/.claude/.credentials.json`\n * (or env: ANTHROPIC_API_KEY)\n * - codex → `codex login status` (returns auth state)\n * (or env: OPENAI_API_KEY)\n * - gemini → presence + non-expired `~/.gemini/oauth_creds.json`\n * (or env: GOOGLE_AI_API_KEY)\n * - opencode → `opencode auth list` (parses credential count)\n *\n * No live API calls. Tokens are not decoded or sent anywhere — only their\n * presence/expiry is read locally.\n *\n * Source: Issue #2447. Replaces the binary-detection-only path in doctor.ts\n * (Issue #2439 follow-up).\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\nimport type { CliName } from '../cli-adapters/types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Result of probing a single CLI's authentication state. Discriminated so\n * callers can render auth | needs-login | not-installed | error states\n * without re-checking flags.\n */\nexport type AuthProbeResult =\n | {\n readonly cli: CliName;\n readonly state: 'authenticated';\n /** How auth was satisfied — informational, not load-bearing. */\n readonly via: 'env-var' | 'cli-credentials';\n /** Optional metadata (e.g. expiry timestamp) if cheap to extract. */\n readonly meta?: Readonly<Record<string, unknown>>;\n }\n | {\n readonly cli: CliName;\n readonly state: 'needs-login';\n /** Short, human-readable reason to surface to the operator. */\n readonly reason: string;\n /** Exact command the operator should run to fix this. */\n readonly fixCommand: string;\n /** Optional canonical URL for credentials/console. */\n readonly fixUrl?: string;\n /** Env-var alternative if applicable. */\n readonly envFallback?: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'not-installed';\n readonly reason: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'error';\n readonly reason: string;\n };\n\nconst HOME = homedir();\n\n// ============================================================================\n// Per-CLI probes\n// ============================================================================\n\nfunction claudeNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'claude',\n state: 'needs-login',\n reason,\n fixCommand: 'claude /login',\n envFallback: 'ANTHROPIC_API_KEY',\n fixUrl: 'https://console.anthropic.com/account/keys',\n };\n}\n\nfunction probeClaude(): AuthProbeResult {\n if (process.env['ANTHROPIC_API_KEY'] !== undefined && process.env['ANTHROPIC_API_KEY'] !== '') {\n return { cli: 'claude', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.claude', '.credentials.json');\n if (!existsSync(credPath)) {\n return claudeNeedsLogin(\n 'No credentials at ~/.claude/.credentials.json and ANTHROPIC_API_KEY is not set'\n );\n }\n try {\n const parsed: unknown = JSON.parse(readFileSync(credPath, 'utf-8'));\n if (!isClaudeCredsShape(parsed)) {\n return claudeNeedsLogin(\n 'Credentials file present but not in expected shape (missing claudeAiOauth.accessToken)'\n );\n }\n const expiresAt = parsed.claudeAiOauth.expiresAt;\n if (typeof expiresAt === 'number' && expiresAt < Date.now()) {\n return claudeNeedsLogin(`OAuth token expired ${new Date(expiresAt).toISOString()}`);\n }\n return {\n cli: 'claude',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof expiresAt === 'number' ? { meta: { expiresAt } } : {}),\n };\n } catch (e: unknown) {\n return {\n cli: 'claude',\n state: 'error',\n reason: `Failed to read claude credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nfunction codexNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'codex',\n state: 'needs-login',\n reason,\n fixCommand: 'codex login',\n envFallback: 'OPENAI_API_KEY',\n fixUrl: 'https://platform.openai.com/api-keys',\n };\n}\n\nfunction classifyCodexStdout(stdout: string): AuthProbeResult {\n // Check 'not logged in' BEFORE 'logged in' — substring shadowing.\n if (/not logged/i.test(stdout) || /no.*token/i.test(stdout)) {\n return codexNeedsLogin(stdout.trim().split('\\n')[0] ?? 'Not logged in');\n }\n // Probe succeeded; treat unrecognized output as authed (defensive default).\n return { cli: 'codex', state: 'authenticated', via: 'cli-credentials' };\n}\n\nasync function probeCodex(): Promise<AuthProbeResult> {\n if (process.env['OPENAI_API_KEY'] !== undefined && process.env['OPENAI_API_KEY'] !== '') {\n return { cli: 'codex', state: 'authenticated', via: 'env-var' };\n }\n try {\n const { stdout } = await execFileAsync('codex', ['login', 'status'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n return classifyCodexStdout(stdout);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'codex', state: 'not-installed', reason: 'codex binary not on PATH' };\n }\n return codexNeedsLogin('Not logged in (codex login status returned non-zero)');\n }\n}\n\nfunction geminiNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'gemini',\n state: 'needs-login',\n reason,\n fixCommand: 'gemini',\n envFallback: 'GOOGLE_AI_API_KEY',\n fixUrl: 'https://aistudio.google.com/apikey',\n };\n}\n\nfunction classifyGeminiCreds(parsed: unknown): AuthProbeResult {\n if (!isGeminiCredsShape(parsed)) {\n return geminiNeedsLogin('OAuth credentials file present but not in expected shape');\n }\n if (typeof parsed.expiry_date === 'number' && parsed.expiry_date < Date.now()) {\n return geminiNeedsLogin(\n `OAuth access token expired ${new Date(parsed.expiry_date).toISOString()} (refresh may still work)`\n );\n }\n return {\n cli: 'gemini',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof parsed.expiry_date === 'number' ? { meta: { expiresAt: parsed.expiry_date } } : {}),\n };\n}\n\nfunction probeGemini(): AuthProbeResult {\n const env = process.env['GOOGLE_AI_API_KEY'] ?? process.env['GEMINI_API_KEY'];\n if (env !== undefined && env !== '') {\n return { cli: 'gemini', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.gemini', 'oauth_creds.json');\n if (!existsSync(credPath)) {\n return geminiNeedsLogin(\n 'No OAuth credentials at ~/.gemini/oauth_creds.json and GOOGLE_AI_API_KEY/GEMINI_API_KEY are not set'\n );\n }\n try {\n return classifyGeminiCreds(JSON.parse(readFileSync(credPath, 'utf-8')));\n } catch (e: unknown) {\n return {\n cli: 'gemini',\n state: 'error',\n reason: `Failed to read gemini credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nasync function probeOpencode(): Promise<AuthProbeResult> {\n // OpenCode's auth is per-provider (anthropic/openai/etc) configured in\n // ~/.config/opencode/opencode.json or via env. Probe by listing credentials.\n try {\n const { stdout } = await execFileAsync('opencode', ['auth', 'list'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n if (/0 credentials/i.test(stdout)) {\n return {\n cli: 'opencode',\n state: 'needs-login',\n reason: 'No providers configured in opencode',\n fixCommand: 'opencode auth login',\n fixUrl: 'https://opencode.ai/docs/config',\n };\n }\n return { cli: 'opencode', state: 'authenticated', via: 'cli-credentials' };\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'opencode', state: 'not-installed', reason: 'opencode binary not on PATH' };\n }\n return {\n cli: 'opencode',\n state: 'error',\n reason: msg.split('\\n')[0] ?? 'opencode auth list failed',\n };\n }\n}\n\n// ============================================================================\n// Type guards (no `any`, no untyped JSON)\n// ============================================================================\n\ninterface ClaudeCreds {\n readonly claudeAiOauth: {\n readonly accessToken: string;\n readonly expiresAt?: number;\n };\n}\n\nfunction isClaudeCredsShape(v: unknown): v is ClaudeCreds {\n if (typeof v !== 'object' || v === null) return false;\n const oauth = (v as { claudeAiOauth?: unknown }).claudeAiOauth;\n if (typeof oauth !== 'object' || oauth === null) return false;\n return typeof (oauth as { accessToken?: unknown }).accessToken === 'string';\n}\n\ninterface GeminiCreds {\n readonly access_token: string;\n readonly expiry_date?: number;\n}\n\nfunction isGeminiCredsShape(v: unknown): v is GeminiCreds {\n if (typeof v !== 'object' || v === null) return false;\n return typeof (v as { access_token?: unknown }).access_token === 'string';\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/** Probe a single CLI. */\nexport async function probeCli(cli: CliName): Promise<AuthProbeResult> {\n switch (cli) {\n case 'claude':\n return Promise.resolve(probeClaude());\n case 'codex':\n return probeCodex();\n case 'gemini':\n return Promise.resolve(probeGemini());\n case 'opencode':\n return probeOpencode();\n }\n}\n\n/** Probe all four CLIs in parallel. Order in returned array matches input. */\nexport async function probeAllClis(): Promise<readonly AuthProbeResult[]> {\n const clis: readonly CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n return Promise.all(clis.map((c) => probeCli(c)));\n}\n","/**\n * nexus-agents/cli-adapters - Adapter Factory\n *\n * Factory for creating CLI adapters based on configuration.\n * Supports optional caching of CLI health check results.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #90 - Codex MCP adapter)\n * (Source: Issue #165 - CLI detection cache)\n */\n\nimport type { ICliAdapter, CliName, CliTransport } from './types.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { ClaudeCliAdapter } from './adapters/claude-adapter.js';\nimport { GeminiCliAdapter } from './adapters/gemini-adapter.js';\nimport { CodexCliAdapter } from './adapters/codex-adapter.js';\nimport { CodexMcpAdapter } from './adapters/codex-mcp-adapter.js';\nimport { OpenCodeCliAdapter } from './adapters/opencode-adapter.js';\nimport type { ILogger } from '../core/index.js';\nimport type { ICliDetectionCache } from './cli-detection-cache.js';\nimport { CliDetectionCache } from './cli-detection-cache.js';\nimport { probeCli } from '../cli/cli-auth-probe.js';\n\n/**\n * Configuration for creating a CLI adapter.\n */\nexport interface CliAdapterConfig {\n /** Which CLI to use */\n readonly cli: CliName;\n /** Optional model override */\n readonly model?: string;\n /** Optional logger */\n readonly logger?: ILogger;\n /** Preferred transport (for Codex: 'mcp' or 'subprocess') */\n readonly transport?: CliTransport;\n}\n\n/**\n * Creates a CLI adapter based on configuration.\n *\n * @param config - Adapter configuration\n * @returns The configured CLI adapter\n * @throws Error if CLI name is not supported\n *\n * @example\n * ```typescript\n * const adapter = createCliAdapter({ cli: 'claude', model: 'claude-opus-4' });\n * const result = await adapter.execute({ content: 'Hello!' });\n * ```\n */\nexport function createCliAdapter(config: CliAdapterConfig): ICliAdapter {\n const options = {\n ...(config.model !== undefined && { model: config.model }),\n ...(config.logger !== undefined && { logger: config.logger }),\n };\n\n switch (config.cli) {\n case 'claude':\n return new ClaudeCliAdapter(options);\n\n case 'gemini':\n return new GeminiCliAdapter(options);\n\n case 'codex':\n return createCodexAdapter(config.transport, options);\n\n case 'opencode':\n return new OpenCodeCliAdapter(options);\n\n default: {\n const exhaustiveCheck: never = config.cli;\n throw new Error(`Unsupported CLI: ${String(exhaustiveCheck)}`);\n }\n }\n}\n\n/**\n * Creates a Codex adapter with preferred transport.\n * Defaults to MCP transport (most stable).\n *\n * @param transport - Preferred transport ('mcp' or 'subprocess')\n * @param options - Adapter options\n * @returns Codex CLI adapter\n */\nfunction createCodexAdapter(\n transport: CliTransport | undefined,\n options: { model?: string; logger?: ILogger }\n): ICliAdapter {\n // Default to MCP transport (preferred per Issue #90)\n if (transport === 'subprocess') {\n return new CodexCliAdapter(options);\n }\n return new CodexMcpAdapter(options);\n}\n\n/**\n * Creates all available CLI adapters.\n * Uses MCP transport for Codex by default (preferred).\n *\n * @param logger - Optional shared logger\n * @param codexTransport - Transport for Codex (default: 'mcp')\n * @returns Map of CLI name to adapter\n */\nexport function createAllAdapters(\n logger?: ILogger,\n codexTransport: CliTransport = 'mcp'\n): Map<CliName, ICliAdapter> {\n const adapters = new Map<CliName, ICliAdapter>();\n const options = logger !== undefined ? { logger } : undefined;\n\n adapters.set('claude', new ClaudeCliAdapter(options));\n adapters.set('gemini', new GeminiCliAdapter(options));\n adapters.set('codex', createCodexAdapter(codexTransport, options ?? {}));\n adapters.set('opencode', new OpenCodeCliAdapter(options));\n\n return adapters;\n}\n\n/**\n * Checks if a CLI is available by running a health check.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cli - CLI name to check\n * @param cache - Optional cache to use\n * @returns True if CLI is healthy\n */\nexport async function isCliAvailable(cli: CliName, cache?: ICliDetectionCache): Promise<boolean> {\n // Check cache first\n if (cache !== undefined) {\n const cached = cache.get(cli);\n if (cached !== undefined) {\n return cached.healthy;\n }\n }\n\n try {\n const adapter = createCliAdapter({ cli });\n // Pre-#2725 only ran healthCheck() — which confirms the binary exists\n // and runs but does NOT probe authentication. Result: orchestrate listed\n // opencode as \"Available\" when the user wasn't logged in, and the next\n // call failed with an opaque subprocess error. Auth must agree with the\n // probe doctor already uses (cli-auth-probe.ts, #2447).\n const [health, auth] = await Promise.all([adapter.healthCheck(), probeCli(cli)]);\n const available = health.healthy && auth.state === 'authenticated';\n\n // Store in cache if provided. Synthesize a degraded health record when\n // the binary is healthy but auth failed, so downstream consumers see\n // \"unavailable\" without losing the version string.\n if (cache !== undefined) {\n if (available) {\n cache.set(cli, CliDetectionCache.fromHealthStatus(health));\n } else {\n cache.set(cli, {\n healthy: false,\n version: health.version,\n versionStatus: health.versionStatus,\n checkedAt: new Date(),\n message:\n auth.state === 'authenticated'\n ? health.message\n : `auth: ${auth.state}` + ('reason' in auth ? ` (${auth.reason})` : ''),\n });\n }\n }\n\n return available;\n } catch (error: unknown) {\n // Closes #2952 (medium): pre-fix the bare `catch {}` dropped the error\n // entirely — operators saw `<cli>: unavailable` with no way to tell\n // whether the binary was missing, the probe timed out, or some other\n // failure occurred. Now include the message in the cached entry.\n cacheHealthCheckFailure(cache, cli, error);\n return false;\n }\n}\n\n/** Records a health-check exception in the cache with the error message preserved. */\nfunction cacheHealthCheckFailure(\n cache: ICliDetectionCache | undefined,\n cli: CliName,\n error: unknown\n): void {\n if (cache === undefined) return;\n const message = error instanceof Error ? error.message : String(error);\n cache.set(cli, {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n checkedAt: new Date(getTimeProvider().now()),\n message: `Health check failed: ${message}`,\n });\n}\n\n/**\n * Gets all available CLIs by running health checks.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cache - Optional cache to use\n * @returns Array of available CLI names\n */\nexport async function getAvailableClis(cache?: ICliDetectionCache): Promise<CliName[]> {\n const clis: CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n\n // Check all CLIs in parallel to avoid sequential timeout penalties\n const results = await Promise.allSettled(\n clis.map(async (cli) => ({ cli, available: await isCliAvailable(cli, cache) }))\n );\n\n return results\n .filter(\n (r): r is PromiseFulfilledResult<{ cli: CliName; available: boolean }> =>\n r.status === 'fulfilled' && r.value.available\n )\n .map((r) => r.value.cli);\n}\n"],"mappings":"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","names":["estimateTaskComplexity","logger","msg","snippet","estimateTaskComplexity","writeFileSync","rmSync","mkdtempSync","tmpdir","join","logger","mkdtempSync","join","tmpdir","writeFileSync","rmSync","logger","logger","execFile","promisify","join","promisify","execFile","join","logger"]}