nexus-agents 11.6.2 → 11.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ast-rule-runner-GRU2OC5H.js → ast-rule-runner-PIIAHXDA.js} +5 -5
- package/dist/{child-mcp-config-DNZN7CMS.js → child-mcp-config-B6BTYZT4.js} +4 -4
- package/dist/{chunk-L4QFWMXB.js → chunk-26WUCAGU.js} +4 -4
- package/dist/{chunk-MFBTGXR6.js → chunk-3QKRY72I.js} +8 -435
- package/dist/chunk-3QKRY72I.js.map +1 -0
- package/dist/{chunk-UMG4PRKT.js → chunk-4HOSKAB3.js} +4 -4
- package/dist/{chunk-2URHVZJR.js → chunk-4MKZAA6W.js} +5 -4
- package/dist/chunk-4MKZAA6W.js.map +1 -0
- package/dist/{chunk-JLJVZP7U.js → chunk-4NNCB7O2.js} +5 -5
- package/dist/{chunk-Z5XFIY4Q.js → chunk-5BEFQVPR.js} +2 -2
- package/dist/chunk-6IP3FOEC.js +365 -0
- package/dist/chunk-6IP3FOEC.js.map +1 -0
- package/dist/{chunk-4X4RJ6AP.js → chunk-6T6YL7MV.js} +4 -4
- package/dist/{chunk-RWBF3Y4A.js → chunk-7HI6EWY5.js} +2 -2
- package/dist/{chunk-45G5ZV3K.js → chunk-7Y6SB623.js} +2 -2
- package/dist/{chunk-N5YTX4UL.js → chunk-BSX3PMNN.js} +2 -2
- package/dist/{chunk-6A6YA4C4.js → chunk-BVUPPTAD.js} +6 -6
- package/dist/{chunk-L3VR5RXX.js → chunk-E5XKXB3G.js} +2 -2
- package/dist/chunk-ENX4WYFX.js +441 -0
- package/dist/chunk-ENX4WYFX.js.map +1 -0
- package/dist/{chunk-6WCFWNIR.js → chunk-FOJ2INSI.js} +3 -3
- package/dist/{chunk-OMQC4NWX.js → chunk-GCRXO43T.js} +2 -2
- package/dist/{chunk-U36QOTW3.js → chunk-HCTKX472.js} +8 -8
- package/dist/{chunk-2UEI7ZZ5.js → chunk-HT7QZ3JB.js} +5 -5
- package/dist/{chunk-7GTIW25A.js → chunk-IHGMXLLO.js} +6 -5
- package/dist/chunk-IHGMXLLO.js.map +1 -0
- package/dist/{chunk-UBK5LSLD.js → chunk-IJCEGKCM.js} +222 -152
- package/dist/{chunk-UBK5LSLD.js.map → chunk-IJCEGKCM.js.map} +1 -1
- package/dist/{chunk-4X3HAJWZ.js → chunk-IKGAI6ES.js} +2 -2
- package/dist/{chunk-GIW4L5PI.js → chunk-INVGMQKJ.js} +2 -2
- package/dist/{chunk-GP2O652R.js → chunk-JMKK6UBR.js} +34 -389
- package/dist/chunk-JMKK6UBR.js.map +1 -0
- package/dist/{chunk-STKHXNVO.js → chunk-ML7FSBBM.js} +4 -4
- package/dist/{chunk-CHYLIBKP.js → chunk-OHI6P6GE.js} +4 -4
- package/dist/{chunk-ZYZIRL4X.js → chunk-OMWOFIK5.js} +2657 -2525
- package/dist/chunk-OMWOFIK5.js.map +1 -0
- package/dist/{chunk-HWAJUCPO.js → chunk-PHLASJD2.js} +31 -26
- package/dist/chunk-PHLASJD2.js.map +1 -0
- package/dist/{chunk-2SFOJPJH.js → chunk-PYTN5UNL.js} +2 -2
- package/dist/{chunk-6KIQF3UT.js → chunk-RRZOCS22.js} +4 -4
- package/dist/{chunk-3QBKZZKE.js → chunk-U4GRHZRQ.js} +1705 -1490
- package/dist/chunk-U4GRHZRQ.js.map +1 -0
- package/dist/{chunk-UL2JGKCQ.js → chunk-VPRBPMVL.js} +3 -3
- package/dist/{chunk-O3FMPRQH.js → chunk-VVDPRJU7.js} +3 -1
- package/dist/chunk-VVDPRJU7.js.map +1 -0
- package/dist/{chunk-AZPPUDUR.js → chunk-YHW6FXKC.js} +7 -7
- package/dist/{chunk-PO2CMGVP.js → chunk-YI6DZGN6.js} +2 -2
- package/dist/{cli-circuit-breaker-KAOHEKYP.js → cli-circuit-breaker-HV7WXCVP.js} +5 -5
- package/dist/{cli-readiness-X7O3LCWW.js → cli-readiness-N4WWAROI.js} +10 -9
- package/dist/{cli-server-gateway-P4F66L2K.js → cli-server-gateway-5N7MHUO6.js} +15 -13
- package/dist/cli.js +88 -85
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-4QGXSANU.js → composite-router-TXGVXX56.js} +4 -4
- package/dist/{consensus-vote-ZCZJT3HS.js → consensus-vote-BYEM44JH.js} +19 -17
- package/dist/{context-retriever-2XMORQMD.js → context-retriever-NT2DYPFG.js} +11 -11
- package/dist/{doctor-deep-RLYWXUJX.js → doctor-deep-RUWHL6R5.js} +5 -5
- package/dist/{doctor-gateway-report-AKE3S2UH.js → doctor-gateway-report-BBMWMMVQ.js} +8 -8
- package/dist/{doctor-live-MA7S3NS7.js → doctor-live-NI27JU6K.js} +15 -13
- package/dist/{doctor-live-MA7S3NS7.js.map → doctor-live-NI27JU6K.js.map} +1 -1
- package/dist/{expert-bridge-2TNU6HKC.js → expert-bridge-V2R5PAXS.js} +6 -6
- package/dist/{factory-UCKSPZ5G.js → factory-3PBQNM44.js} +14 -12
- package/dist/{factory-5UWGAQOB.js → factory-YZILOS2Z.js} +7 -7
- package/dist/gemini-adapter-IZ3TS6KZ.js +28 -0
- package/dist/{improvement-review-PHNGPUYO.js → improvement-review-N6W2FWFO.js} +7 -7
- package/dist/index.d.ts +68 -2
- package/dist/index.js +132 -128
- package/dist/index.js.map +1 -1
- package/dist/{init-opencode-CII5S6XH.js → init-opencode-PLMPOB55.js} +7 -7
- package/dist/{issue-triage-DO6ATHBV.js → issue-triage-W5XKE324.js} +7 -7
- package/dist/{model-config-helpers-3U6IEHM6.js → model-config-helpers-5DTFDWYR.js} +7 -3
- package/dist/{openai-compat-adapter-7G6JYZLY.js → openai-compat-adapter-4VREPXZT.js} +7 -7
- package/dist/{pr-reviewer-helpers-JSLG5YYG.js → pr-reviewer-helpers-RAPVW52Y.js} +6 -6
- package/dist/{registry-command-X5NLFI3D.js → registry-command-3XWS7G6F.js} +2 -2
- package/dist/{repo-security-plan-DLROWMDR.js → repo-security-plan-BITATHGO.js} +4 -4
- package/dist/{research-helpers-synthesize-NE3I56IC.js → research-helpers-synthesize-FW47ZIMK.js} +6 -6
- package/dist/{routing-memory-YFSHH2AN.js → routing-memory-POESZPDJ.js} +4 -4
- package/dist/{session-memory-ZE2FUHO3.js → session-memory-TBBFP3XP.js} +5 -5
- package/dist/{setup-config-SFNU2QL4.js → setup-config-AKFLKDMP.js} +5 -5
- package/dist/{setup-custom-api-JBCH5YAW.js → setup-custom-api-WQMO2OV7.js} +5 -5
- package/dist/{tool-memory-Z3X6EFMS.js → tool-memory-RLCP6WVV.js} +7 -7
- package/dist/{unified-registry-2YSSICSB.js → unified-registry-MIANRTCJ.js} +14 -12
- package/dist/{weather-report-YSGMEYVV.js → weather-report-QB2TYTYU.js} +4 -4
- package/dist/weather-report-QB2TYTYU.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2URHVZJR.js.map +0 -1
- package/dist/chunk-3QBKZZKE.js.map +0 -1
- package/dist/chunk-7GTIW25A.js.map +0 -1
- package/dist/chunk-GP2O652R.js.map +0 -1
- package/dist/chunk-HWAJUCPO.js.map +0 -1
- package/dist/chunk-MFBTGXR6.js.map +0 -1
- package/dist/chunk-O3FMPRQH.js.map +0 -1
- package/dist/chunk-ZYZIRL4X.js.map +0 -1
- /package/dist/{ast-rule-runner-GRU2OC5H.js.map → ast-rule-runner-PIIAHXDA.js.map} +0 -0
- /package/dist/{child-mcp-config-DNZN7CMS.js.map → child-mcp-config-B6BTYZT4.js.map} +0 -0
- /package/dist/{chunk-L4QFWMXB.js.map → chunk-26WUCAGU.js.map} +0 -0
- /package/dist/{chunk-UMG4PRKT.js.map → chunk-4HOSKAB3.js.map} +0 -0
- /package/dist/{chunk-JLJVZP7U.js.map → chunk-4NNCB7O2.js.map} +0 -0
- /package/dist/{chunk-Z5XFIY4Q.js.map → chunk-5BEFQVPR.js.map} +0 -0
- /package/dist/{chunk-4X4RJ6AP.js.map → chunk-6T6YL7MV.js.map} +0 -0
- /package/dist/{chunk-RWBF3Y4A.js.map → chunk-7HI6EWY5.js.map} +0 -0
- /package/dist/{chunk-45G5ZV3K.js.map → chunk-7Y6SB623.js.map} +0 -0
- /package/dist/{chunk-N5YTX4UL.js.map → chunk-BSX3PMNN.js.map} +0 -0
- /package/dist/{chunk-6A6YA4C4.js.map → chunk-BVUPPTAD.js.map} +0 -0
- /package/dist/{chunk-L3VR5RXX.js.map → chunk-E5XKXB3G.js.map} +0 -0
- /package/dist/{chunk-6WCFWNIR.js.map → chunk-FOJ2INSI.js.map} +0 -0
- /package/dist/{chunk-OMQC4NWX.js.map → chunk-GCRXO43T.js.map} +0 -0
- /package/dist/{chunk-U36QOTW3.js.map → chunk-HCTKX472.js.map} +0 -0
- /package/dist/{chunk-2UEI7ZZ5.js.map → chunk-HT7QZ3JB.js.map} +0 -0
- /package/dist/{chunk-4X3HAJWZ.js.map → chunk-IKGAI6ES.js.map} +0 -0
- /package/dist/{chunk-GIW4L5PI.js.map → chunk-INVGMQKJ.js.map} +0 -0
- /package/dist/{chunk-STKHXNVO.js.map → chunk-ML7FSBBM.js.map} +0 -0
- /package/dist/{chunk-CHYLIBKP.js.map → chunk-OHI6P6GE.js.map} +0 -0
- /package/dist/{chunk-2SFOJPJH.js.map → chunk-PYTN5UNL.js.map} +0 -0
- /package/dist/{chunk-6KIQF3UT.js.map → chunk-RRZOCS22.js.map} +0 -0
- /package/dist/{chunk-UL2JGKCQ.js.map → chunk-VPRBPMVL.js.map} +0 -0
- /package/dist/{chunk-AZPPUDUR.js.map → chunk-YHW6FXKC.js.map} +0 -0
- /package/dist/{chunk-PO2CMGVP.js.map → chunk-YI6DZGN6.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-KAOHEKYP.js.map → cli-circuit-breaker-HV7WXCVP.js.map} +0 -0
- /package/dist/{cli-readiness-X7O3LCWW.js.map → cli-readiness-N4WWAROI.js.map} +0 -0
- /package/dist/{cli-server-gateway-P4F66L2K.js.map → cli-server-gateway-5N7MHUO6.js.map} +0 -0
- /package/dist/{composite-router-4QGXSANU.js.map → composite-router-TXGVXX56.js.map} +0 -0
- /package/dist/{consensus-vote-ZCZJT3HS.js.map → consensus-vote-BYEM44JH.js.map} +0 -0
- /package/dist/{context-retriever-2XMORQMD.js.map → context-retriever-NT2DYPFG.js.map} +0 -0
- /package/dist/{doctor-deep-RLYWXUJX.js.map → doctor-deep-RUWHL6R5.js.map} +0 -0
- /package/dist/{doctor-gateway-report-AKE3S2UH.js.map → doctor-gateway-report-BBMWMMVQ.js.map} +0 -0
- /package/dist/{expert-bridge-2TNU6HKC.js.map → expert-bridge-V2R5PAXS.js.map} +0 -0
- /package/dist/{factory-5UWGAQOB.js.map → factory-3PBQNM44.js.map} +0 -0
- /package/dist/{factory-UCKSPZ5G.js.map → factory-YZILOS2Z.js.map} +0 -0
- /package/dist/{improvement-review-PHNGPUYO.js.map → gemini-adapter-IZ3TS6KZ.js.map} +0 -0
- /package/dist/{issue-triage-DO6ATHBV.js.map → improvement-review-N6W2FWFO.js.map} +0 -0
- /package/dist/{init-opencode-CII5S6XH.js.map → init-opencode-PLMPOB55.js.map} +0 -0
- /package/dist/{model-config-helpers-3U6IEHM6.js.map → issue-triage-W5XKE324.js.map} +0 -0
- /package/dist/{openai-compat-adapter-7G6JYZLY.js.map → model-config-helpers-5DTFDWYR.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-JSLG5YYG.js.map → openai-compat-adapter-4VREPXZT.js.map} +0 -0
- /package/dist/{repo-security-plan-DLROWMDR.js.map → pr-reviewer-helpers-RAPVW52Y.js.map} +0 -0
- /package/dist/{registry-command-X5NLFI3D.js.map → registry-command-3XWS7G6F.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-NE3I56IC.js.map → repo-security-plan-BITATHGO.js.map} +0 -0
- /package/dist/{routing-memory-YFSHH2AN.js.map → research-helpers-synthesize-FW47ZIMK.js.map} +0 -0
- /package/dist/{session-memory-ZE2FUHO3.js.map → routing-memory-POESZPDJ.js.map} +0 -0
- /package/dist/{setup-config-SFNU2QL4.js.map → session-memory-TBBFP3XP.js.map} +0 -0
- /package/dist/{tool-memory-Z3X6EFMS.js.map → setup-config-AKFLKDMP.js.map} +0 -0
- /package/dist/{setup-custom-api-JBCH5YAW.js.map → setup-custom-api-WQMO2OV7.js.map} +0 -0
- /package/dist/{unified-registry-2YSSICSB.js.map → tool-memory-RLCP6WVV.js.map} +0 -0
- /package/dist/{weather-report-YSGMEYVV.js.map → unified-registry-MIANRTCJ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-adapters/cli-timeout-helpers.ts","../src/cli-adapters/cli-timeout-profiles.ts","../src/utils/async-utils.ts","../src/cli-adapters/cli-retry-loop.ts","../src/cli-adapters/base-adapter.ts","../src/cli-adapters/subprocess-adapter.ts","../src/cli-adapters/subprocess-env.ts","../src/cli-adapters/process-tree-kill.ts","../src/cli-adapters/proc-start-time.ts","../src/adapters/abort-observation.ts"],"sourcesContent":["/**\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","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 * 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';\nimport { isCallerCancelled } from '../adapters/abort-utils.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/**\n * Resolve how long to wait before the next attempt (#4373).\n *\n * Prefers a provider-supplied `retryAfterMs` over the computed exponential\n * backoff — a provider that names its window knows better than our guess — but\n * still clamps to the caller's ceiling so a CLI claiming a multi-hour window\n * cannot wedge the retry loop. A zero or negative hint is ignored rather than\n * retried instantly.\n */\nexport function resolveRetryDelayMs(\n error: CliError,\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number\n): number {\n const hint = error.retryAfterMs;\n if (hint !== undefined && hint > 0) {\n return Math.min(hint, maxDelayMs);\n }\n return calculateBackoffDelay(attempt, baseDelayMs, 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 // #6691: a caller cancel is neither a health signal nor worth retrying.\n if (isCallerCancelled(lastError)) return err(lastError);\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 = resolveRetryDelayMs(lastError, 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 * 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 { err, ok, 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 ResolvedExecutionOptions,\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';\nimport { getDefaultCliCircuitBreakerRegistry } from './cli-circuit-breaker.js';\nimport { breakerKeys } from './breaker-key.js';\nimport { createCliError } from './cli-error-helpers.js';\nimport { unenforcedAccessModeRefusal, withEnforcedAccessMode } from './access-mode.js';\nimport type { AuthProbeResult } from '../cli/cli-auth-probe.js';\nimport type { LevelOutcome } from '../cli/cli-readiness.js';\nimport { adapterReadiness, servesListedModel } from './cli-admission.js';\n\nconst execAsync = promisify(exec);\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: ResolvedExecutionOptions = {\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 /**\n * The executable this adapter actually runs.\n *\n * Defaults to {@link name} because for most arms the routing identity and the\n * binary are the same word. They are NOT always the same: the `gemini` arm\n * runs `agy` (Antigravity) after Google retired the standalone gemini CLI\n * (#4346). Conflating the two is how that arm ended up executing `agy` for\n * work while shelling `gemini --version` for its health check — reporting the\n * dead binary's version against the live one's floor, and failing its own\n * availability gate while working perfectly.\n */\n get binaryName(): string {\n return this.name;\n }\n\n /**\n * Whether this adapter maps `accessMode: 'read-only-analysis'` to its CLI's\n * own enforcement (#6754). False here so a new adapter fails closed until it\n * implements the mode and says so.\n */\n readonly enforcesReadOnlyAnalysis: boolean = false;\n\n /**\n * Whether this adapter maps `accessMode: 'workspace-edit'` to its CLI's own\n * enforcement (#6792). False here for the same reason: a new adapter fails\n * closed until it implements the mode and says so.\n */\n readonly enforcesWorkspaceEdit: boolean = false;\n\n protected readonly logger: ILogger;\n protected capacityTracker: CapacityTracker | null = null;\n protected initialized = false;\n protected cachedVersion?: string;\n /**\n * Epoch ms at which {@link cachedVersion} was read off the binary.\n *\n * The cache never expires, so this is what lets `healthCheck` say whether\n * its `reachable` rests on a probe that just ran or on one from minutes ago\n * (#5864).\n */\n protected cachedVersionAt?: number;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'cli-adapter' });\n }\n\n /** Local CLI auth evidence from the canonical probe; makes no live API call. */\n async authStatus(): Promise<AuthProbeResult> {\n const { probeCli } = await import('../cli/cli-auth-probe.js');\n return probeCli(this.name);\n }\n\n /** Unmeasured by default; live opt-in delegates to the bounded completion probe. */\n readiness(options?: {\n readonly live?: boolean;\n readonly timeoutMs?: number;\n }): Promise<LevelOutcome> {\n return adapterReadiness(this, options);\n }\n\n /** Catalog evidence; absent, empty, failed or unlisted models remain unknown. */\n serves(modelId: string): Promise<'yes' | 'no' | 'unknown'> {\n return servesListedModel(this as ICliAdapter, modelId, this.name);\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: ResolvedExecutionOptions\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 // #6754/#6792: checked before anything else runs, so a refused restricted task\n // never initializes, spawns or counts against the breaker.\n const refusal = await this.accessModeRefusal(task);\n if (refusal !== undefined) return err(refusal);\n\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 const result = await this.executeWithRetry(task, opts);\n // #6792: the refusal above passed, so this adapter ran the task under the\n // task's mode; the response says so for the caller's record.\n return result.ok ? ok(withEnforcedAccessMode(result.value, task)) : result;\n }\n\n /**\n * The refusal for a task this adapter cannot run in its requested access\n * mode, or `undefined` (#6754). Adapters override it to add conflicts their\n * own options can create, and call `super` first.\n */\n protected accessModeRefusal(task: CliTask): Promise<CliError | undefined> {\n return Promise.resolve(unenforcedAccessModeRefusal(this, task));\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: ResolvedExecutionOptions): 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: ResolvedExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n // #4330: this used to pass no breaker, which made the `recordFailure` in\n // `executeCliRetryLoop` unreachable for every subprocess CLI. The voter\n // serving-gate reads exactly this registry, so a quota-dead CLI's snapshot\n // stayed `undefined` and the gate fail-opened on every panel — #4325's\n // exclusion could never fire because nothing produced the signal.\n const circuitBreaker = getDefaultCliCircuitBreakerRegistry().getArmBreaker(\n breakerKeys.forArm({ name: this.name, model: task.model })\n );\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 circuitBreaker,\n cli: this.name,\n logger: this.logger,\n });\n\n if (result.ok) {\n // Recording the success is the caller's job (`executeCliRetryLoop` only\n // records failures — see its test), and it matters: in the closed state\n // `recordSuccess` zeroes the failure count, which is what makes the\n // threshold mean \"consecutive failures\". Without it a long-lived process\n // accumulates scattered blips and eventually evicts a healthy CLI.\n circuitBreaker.recordSuccess();\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.recordQuotaSignal(result.error);\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 * Feed a provider's own rate-limit assertion into capacity tracking (#4456).\n *\n * A `retry-after` the provider stated is far stronger evidence than local\n * counting: the tracker otherwise sees only this process's spend and cannot\n * observe a plan quota burned gradually or burned elsewhere, which is the\n * incident #4351 reported. Only RATE_LIMITED carries that assertion; the\n * tracker itself decides whether the stated wait is long enough to mean\n * durable quota rather than a per-minute throttle.\n */\n protected recordQuotaSignal(error: CliError): void {\n if (error.code !== 'RATE_LIMITED') return;\n if (this.capacityTracker === null) return;\n\n const recorded = this.capacityTracker.recordProviderQuotaExhaustion(error.retryAfterMs);\n if (recorded) {\n this.logger.warn('Provider asserted durable quota exhaustion', {\n cli: this.name,\n retryAfterMs: error.retryAfterMs,\n });\n }\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 // The binary answered `--version`, whatever it said (#5060) — though\n // not necessarily on THIS call, which is what versionProbedAt says.\n reachable: true,\n lastChecked: new Date(getTimeProvider().now()),\n ...(this.cachedVersionAt !== undefined && {\n versionProbedAt: new Date(this.cachedVersionAt),\n }),\n ...(message !== undefined && { message }),\n };\n\n return status;\n } catch (error) {\n return {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n // `getVersion` could not run the binary — absent, not merely outdated.\n reachable: false,\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.binaryName} --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 this.cachedVersionAt = getTimeProvider().now();\n return version;\n } catch (cause: unknown) {\n throw new Error(`Failed to get ${this.binaryName} 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 // One construction path (#6120): this carried its own copy of the\n // retryable-code list and its own `parseRetryAfterMs` call (#4373), so the\n // durable-capacity rule added to `createCliError` would otherwise have\n // applied only to adapters that happened to use the helper.\n return createCliError(code, message, this.name, cause);\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","/* eslint-disable max-lines -- Cohesive subprocess adapter base class; governance 400-600 OK if cohesive */\n/**\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';\nimport type { ChildProcess, ChildProcessWithoutNullStreams } from 'node:child_process';\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, getTimeProvider, createLogger, getErrorMessage } from '../core/index.js';\n\nimport type {\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n ResolvedExecutionOptions,\n ICliResponseParser,\n} from './types.js';\nimport { BaseCliAdapter } from './base-adapter.js';\nimport { buildChildEnv } from './subprocess-env.js';\nimport { SIGKILL_GRACE_MS, terminateProcessTree, trackProcessTree } from './process-tree-kill.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\nimport { isRateLimitText, isDurableCapacityText } from '../adapters/rate-limit-detector.js';\nimport {\n parseCliErrorEnvelope,\n classifyExtractedError,\n isAuthFailureText,\n} from './cli-error-envelope.js';\nimport { createCallerAbortCliError, isTimeoutText } from './cli-error-helpers.js';\nimport { generateHyphenId } from '../utils/id-utils.js';\nimport { recordAbortObservation } from '../adapters/abort-observation.js';\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/**\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 (isTimeoutText(stderr)) return 'TIMEOUT';\n // #6269: a credential failure is terminal for this CLI (not in\n // RETRYABLE_ERROR_CODES) and counts as `authentication` on the breaker.\n if (isAuthFailureText(stderr)) return 'NOT_AUTHENTICATED';\n return 'EXECUTION_ERROR';\n}\n\n/**\n * The first non-blank stderr line, for an error message that names the cause\n * without the stack frames and tier tables that follow it (#6269). `stderr`\n * is already sanitized by the caller.\n */\nfunction firstStderrLine(stderr: string): string {\n return (\n stderr\n .split('\\n')\n .find((line) => line.trim() !== '')\n ?.trim() ?? ''\n );\n}\n\nconst subprocessLogger = createLogger({ component: 'subprocess-adapter' });\n\n/**\n * Longest stderr carried on a SUCCESSFUL response (#6094). The buffer above\n * caps capture at 10 MB; the response field exists so a classifier can read a\n * failure line, not to ship a log. Kept from the head: the sandbox failure is\n * written when the CLI's tool loop first tries the shell.\n */\nexport const MAX_RESPONSE_STDERR_CHARS = 8_000;\n\n/**\n * The `stderr` field of a SUCCESSFUL response (#6094). A run's stderr was\n * captured and dropped here: a sandboxed shell failure inside the CLI's tool\n * loop is written to it while stdout still carries a parsed answer, and that\n * is the voter classifier's structured signal. Present only when non-empty.\n */\nfunction successStderrField(stderr: string): { stderr?: string } {\n return stderr === '' ? {} : { stderr: stderr.slice(0, MAX_RESPONSE_STDERR_CHARS) };\n}\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 * Grace period before escalating SIGTERM to SIGKILL on timeout (#3026\n * finding 1). Defined beside the tree kill, which every subprocess runner\n * shares (#6747); re-exported so tests can assert against the threshold.\n */\nexport { SIGKILL_GRACE_MS };\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 * Spawn the CLI and track it so server shutdown ends it (#6680). It stays in\n * the server's process group, so a signal to that group reaches it too.\n */\nfunction spawnCliChild(\n cliName: CliName,\n cmdConfig: CommandConfig,\n task: CliTask,\n timeoutMs: number\n): ChildProcessWithoutNullStreams {\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 // #6754: a command's own variables (e.g. a read-only permission config) are\n // applied last, so an inherited value of the same name cannot override them.\n const childEnv = { ...buildChildEnv(cliName), ...cmdConfig.env };\n const cwd = spawnCwd(task.options?.['workDir']);\n const wrapped = task.wrapper?.(cmdConfig.command, cmdConfig.args, {\n cwd,\n env: childEnv,\n timeoutMs,\n });\n const command = wrapped?.command ?? cmdConfig.command;\n const args = wrapped?.args ?? cmdConfig.args;\n const options = wrapped?.options ?? { cwd, env: childEnv };\n return trackProcessTree(\n spawn(command, [...args], {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: options.env,\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n })\n );\n}\n\n/**\n * The working directory a CLI child is spawned in for a task's `workDir`\n * option, or `undefined` when it inherits this process's cwd. Exported so a\n * command builder that reads the child's config files resolves the same\n * directory the spawn uses (#6970).\n */\nexport function spawnCwd(workDir: unknown): string | undefined {\n return typeof workDir === 'string' && workDir.trim().length > 0 ? workDir : undefined;\n}\n\n/**\n * Whether a failed spawn is worth spawning again (#6120).\n *\n * A transient CODE is not the whole answer: a durable capacity cap arrives as\n * RATE_LIMITED too, and re-running the same model against a spend ceiling is\n * the futile work #5359 named. The claude out-of-credits envelope cost two\n * extra spawns and 1.5 s per call this way, then still failed.\n */\nfunction shouldRetryInPlace(error: CliError, signal: AbortSignal | undefined): boolean {\n // #6680: an aborted call is not transient — retrying it only sleeps through\n // the backoff to fast-fail again.\n if (signal?.aborted === true) return false;\n return isTransientError(error.code) && !isDurableCapacityText(error.message);\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 /** All stdout received, including chunks excluded by the capture cap (#6851). */\n receivedStdoutBytes: 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 * Variables set on the child's environment on top of the curated base\n * (#6754). They win over any inherited value of the same name.\n */\n env?: Readonly<Record<string, 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: ResolvedExecutionOptions): 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 * Invokes the optional cleanup hook supplied by getCommand(). Sync\n * throws are swallowed (warn-only) and async rejections are caught\n * so cleanup failures never bubble up and mask the real subprocess\n * result.\n */\n private runSubprocessCleanup(cleanup: CommandConfig['cleanup']): 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 /**\n * #3026 finding 2: SIGTERM the child when the caller's AbortSignal\n * aborts mid-execution. Listener auto-detaches on `'close'` so we\n * don't leak across child lifetimes.\n */\n private attachAbortSignal(\n child: ChildProcess,\n signal: AbortSignal,\n resolve: (r: Result<CliResponse, CliError>) => void,\n state: BufferState\n ): void {\n const onAbort = (): void => {\n recordAbortObservation(signal.reason, {\n stdoutBytes: state.receivedStdoutBytes,\n sawFirstByte: state.firstByteTime !== null,\n });\n if (child.exitCode === null && child.signalCode === null) {\n // #6680: the child and its descendants, so a relaunched CLI worker is\n // not orphaned; a tree that ignores SIGTERM is force-reaped rather than\n // left running after the cancel.\n void terminateProcessTree(child, SIGKILL_GRACE_MS, () => {\n this.logger.warn('Child ignored SIGTERM after abort, escalating to SIGKILL', {\n cli: this.name,\n sigkillGraceMs: SIGKILL_GRACE_MS,\n });\n });\n }\n // #6691: the adapter's own watchdog is the timer in `spawnSubprocess`,\n // not this listener, so a caller abort is a cancel unless its reason\n // names a deadline.\n resolve(err(createCallerAbortCliError(signal.reason, 'Aborted by caller signal', this.name)));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n child.once('close', () => {\n signal.removeEventListener('abort', onAbort);\n });\n }\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: ResolvedExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n // #2963 site 3: per-execute request ID for log correlation. CliTask\n // doesn't carry a task-id field; generate one here so every\n // log-line for this invocation (including the per-retry timing\n // breakdown emitted by `logTimingBreakdown`) can be grouped by a\n // single ID. Doesn't propagate up to MCP — it's purely an\n // adapter-internal correlation key.\n const requestId = generateHyphenId('cli-req', 8);\n const result = await this.spawnSubprocess(task, options, requestId);\n if (result.ok || !this.transientRetry.enabled || !options.allowRetry) return result;\n if (!shouldRetryInPlace(result.error, options.signal)) return result;\n\n return this.retryTransient(task, options, result, 0, requestId);\n }\n\n /**\n * Retries a transient error with bounded exponential backoff.\n */\n private async retryTransient(\n task: CliTask,\n options: ResolvedExecutionOptions,\n lastResult: Result<CliResponse, CliError>,\n attempt: number,\n requestId: string\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 requestId,\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, requestId);\n if (result.ok) return result;\n if (!shouldRetryInPlace(result.error, options.signal)) return result;\n\n return this.retryTransient(task, retryOptions, result, attempt + 1, requestId);\n }\n\n /**\n * Spawns a single subprocess execution (no retry).\n *\n * `requestId` (#2963 site 3) correlates the timing-breakdown log emitted\n * on subprocess close back to the parent `executeTask` invocation —\n * essential when multiple subprocesses for the same CLI run concurrently\n * (pipelines, votes) and the JSDoc's stated goal (\"group by cli + provider\n * + model and surface tail-latency outliers\") requires a way to\n * disambiguate which timing row belongs to which call.\n */\n /**\n * Wraps a command's cleanup in a once-guard (#4488).\n *\n * `CommandConfig.cleanup` removes a tempdir the command builder created (e.g.\n * codex's `nexus-codex-sysprompt-*` holding the system prompt). It must run on\n * EVERY exit path — a path that skips it leaks a directory per invocation, the\n * leak codex-adapter's own comment records as having exhausted inodes on\n * long-running MCP daemons — and exactly ONCE, since a second rm could hit a\n * path the OS has already handed to someone else.\n */\n /**\n * Result for a synchronous spawn failure (#4488).\n *\n * `spawn()` throws synchronously on some failures (EACCES, and ENOENT on\n * certain platforms), and handler setup can throw too. Those paths never\n * reach `resolve`, so without catching them the tempdir leaks AND the promise\n * rejects instead of returning a Result — breaking the never-throws contract\n * this adapter is supposed to honour.\n */\n private spawnFailure(command: string, error: unknown): Result<CliResponse, CliError> {\n return err(\n this.createError('EXECUTION_ERROR', `Failed to spawn ${command}: ${getErrorMessage(error)}`)\n );\n }\n\n private onceCleanup(cleanup: CommandConfig['cleanup']): () => void {\n let done = false;\n return (): void => {\n if (done) return;\n done = true;\n this.runSubprocessCleanup(cleanup);\n };\n }\n\n private spawnSubprocess(\n task: CliTask,\n options: ResolvedExecutionOptions,\n requestId: string\n ): Promise<Result<CliResponse, CliError>> {\n // #3026 finding 2: fast-fail if the caller already aborted before we\n // bothered to spawn. Saves a child process start when an upstream\n // wave/loop has already moved on. Checked before getCommand (#6680): a\n // command builder can create a tempdir that only the spawn path cleans up.\n const signal = options.signal;\n if (signal?.aborted === true) {\n return Promise.resolve(\n err(createCallerAbortCliError(signal.reason, 'Aborted before spawn', this.name))\n );\n }\n // #6277: the resolved guard reaches getCommand on the task, so an adapter\n // whose CLI has its own wait (agy --print-timeout) can size it to the\n // budget instead of a default that races the guard.\n const cmdConfig = this.getCommand(\n task.timeoutMs === undefined ? { ...task, timeoutMs: options.timeoutMs } : task\n );\n const startTime = getTimeProvider().now();\n\n return new Promise((resolveOuter) => {\n const runCleanupOnce = this.onceCleanup(cmdConfig.cleanup);\n const resolve = (r: Result<CliResponse, CliError>): void => {\n runCleanupOnce();\n resolveOuter(r);\n };\n try {\n const child = spawnCliChild(this.name, cmdConfig, task, options.timeoutMs);\n\n const onProgress = options.onProgress;\n // Keep stdout evidence available to the caller-deadline abort path (#6851).\n const state = this.setupChildProcessHandlers({\n child,\n startTime,\n timeoutMs: options.timeoutMs,\n resolve,\n requestId,\n ...(onProgress !== undefined ? { onProgress } : {}),\n });\n\n if (signal !== undefined) {\n this.attachAbortSignal(child, signal, resolve, state);\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 } catch (error: unknown) {\n runCleanupOnce();\n resolveOuter(this.spawnFailure(cmdConfig.command, error));\n }\n });\n }\n\n /**\n * Sets up child process event handlers for output collection and error handling.\n */\n private setupChildProcessHandlers(args: {\n child: ReturnType<typeof spawn>;\n startTime: number;\n timeoutMs: number;\n resolve: (result: Result<CliResponse, CliError>) => void;\n requestId: string;\n onProgress?: () => void;\n }): BufferState {\n const { child, startTime, timeoutMs, resolve, requestId, onProgress } = args;\n const state: BufferState = {\n stdout: '',\n stderr: '',\n resolved: false,\n stdoutBytes: 0,\n receivedStdoutBytes: 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 = this.scheduleTimeoutWithSigkillEscalation({\n child,\n timeoutMs,\n requestId,\n resolveOnce,\n });\n\n child.on('close', (code: number | null) => {\n // #6680: the SIGKILL escalation is terminateProcessTree's; a descendant\n // can outlive the child's close, so only an empty tree cancels it there.\n clearTimeout(timeoutId);\n this.logTimingBreakdown(state, startTime, code, requestId);\n resolveOnce(this.classifyCloseResult(code, state, startTime));\n });\n\n return state;\n }\n\n /**\n * Schedules the SIGTERM-on-timeout + SIGKILL-on-grace escalation\n * (#3026 finding 1).\n *\n * The timer SIGTERMs the tree and resolves the caller's promise\n * immediately so it doesn't wait on a hung child. The escalation\n * (`SIGKILL_GRACE_MS` later, in {@link terminateProcessTree}) checks\n * whether the tree actually exited and force-reaps it with SIGKILL if\n * not — preventing zombie accumulation when a child ignores SIGTERM\n * (Node CLIs that install graceful-shutdown handlers can hang on a broken\n * stream). Off Linux the descendants are collected by an async `ps`\n * first (#6718). Returns the timeout timer, for the `'close'` handler.\n */\n private scheduleTimeoutWithSigkillEscalation(opts: {\n child: ReturnType<typeof spawn>;\n timeoutMs: number;\n requestId: string;\n resolveOnce: (result: Result<CliResponse, CliError>) => void;\n }): NodeJS.Timeout {\n const { child, timeoutMs, requestId, resolveOnce } = opts;\n return setTimeout(() => {\n void terminateProcessTree(child, SIGKILL_GRACE_MS, () => {\n this.logger.warn('Child ignored SIGTERM, escalating to SIGKILL', {\n cli: this.name,\n requestId,\n sigkillGraceMs: SIGKILL_GRACE_MS,\n });\n });\n resolveOnce(err(this.createError('TIMEOUT', 'Execution timed out')));\n }, timeoutMs);\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 state.receivedStdoutBytes += data.length;\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(\n state: BufferState,\n startTime: number,\n code: number | null,\n requestId: string\n ): 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 requestId,\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 protected handleSubprocessOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (stderr !== '' && stdout === '') {\n return err(this.createError(classifyStderrError(stderr), stderr));\n }\n\n const text = this.parser.extractResponse(stdout);\n if (text === null) return this.handleNoAnswer(stdout, stderr);\n const authFailure = this.classifyEmptyAnswer(text, stderr);\n if (authFailure !== null) return authFailure;\n\n const usage = this.parser.extractUsage(stdout);\n const sessionId = this.parser.extractSessionId(stdout);\n // #5241: a vendor-reported cost is a MEASUREMENT and was being dropped, so\n // `CliResponse.costUsd` had no producer at all — leaving budget-router's\n // `result.value.costUsd ?? estimatedCostUsd` unable to take its left branch\n // and debiting an estimate under a field named `actual`. Parsers whose CLI\n // reports no cost do not implement the method, so absence here means \"this\n // vendor does not report cost\", not \"cost unknown this call\".\n const costUsd = this.parser.extractCostUsd?.(stdout) ?? null;\n\n return ok(\n this.normalizeResponse(text, usage ?? undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n ...(sessionId !== null && { sessionId }),\n ...(costUsd !== null && { costUsd }),\n ...successStderrField(stderr),\n })\n );\n }\n\n /**\n * The parser found no usable content. An error-only stream (e.g. OpenCode\n * NDJSON `{\"type\":\"error\"}`) surfaced an `errorMessage`: classify it before\n * the generic PARSE_ERROR path, which would mask the real cause.\n */\n private handleNoAnswer(stdout: string, stderr: string): Result<CliResponse, CliError> {\n const errorOnly = this.classifyErrorOnlyStream(stdout);\n if (errorOnly !== null) return errorOnly;\n return this.handleUnparseableOutput(stdout, stderr);\n }\n\n /**\n * #6269: a well-formed envelope carrying NO answer while stderr names a\n * credential failure is that failure, not a completion. `agy` exits 0 with\n * `{\"status\":\"SUCCESS\",\"response\":\"\"}` and \"Error authenticating: …\" on\n * stderr; handing \"\" downstream had the vote path parse it (and retry the\n * parse) for the whole panel budget. Returns `null` — no reclassification —\n * for a non-empty answer, and for an empty answer with stderr that names no\n * auth failure: empty stderr is NOT evidence, so that case still flows\n * through as the empty answer it is.\n */\n private classifyEmptyAnswer(text: string, stderr: string): Result<CliResponse, CliError> | null {\n if (text.trim() !== '' || !isAuthFailureText(stderr)) return null;\n const msg = `${this.name}: ${firstStderrLine(stderr)}`;\n return err(this.createError('NOT_AUTHENTICATED', msg));\n }\n\n /**\n * Classify an error-only stream — one where the parser surfaced an\n * `errorMessage` but no usable content (so `extractResponse` returned null).\n * Returns a typed error (NOT_AUTHENTICATED / RATE_LIMITED with a remediation\n * hint, or EXECUTION_ERROR) so an upstream 401 / 429 isn't masked as\n * PARSE_ERROR. Returns `null` when the parser exposes no error message (no\n * `extractErrorMessage`, or empty) — the caller then falls back to the\n * generic unparseable-output recovery.\n */\n private classifyErrorOnlyStream(stdout: string): Result<CliResponse, CliError> | null {\n const errorMessage = this.parser.extractErrorMessage?.(stdout) ?? null;\n if (errorMessage === null || errorMessage === '') return null;\n const classified = classifyExtractedError(errorMessage, this.name);\n const msg =\n classified.hint !== undefined\n ? `${classified.message}\\n → ${classified.hint}`\n : classified.message;\n return err(this.createError(classified.code, msg));\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. Generic PARSE_ERROR with truncated snippet\n * Only the adapter parser can authorize a successful response (#7073).\n */\n private handleUnparseableOutput(stdout: string, stderr: string): 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 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.binaryName} 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 * 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). Sensitive credentials and secrets\n * (including `NEXUS_*` keys, tokens, and secrets) are stripped by\n * default unless explicitly allowed via {@link NEXUS_SUBPROCESS_EXTRA_ENV}.\n *\n * @module cli-adapters/subprocess-env\n */\n\nimport type { CliName } from './types.js';\nimport { parseBoolValue } from '../config/defaults-env.js';\n\n/**\n * Marker stamped on EVERY spawned-CLI child env (#4033): how deep we are in the\n * nexus → CLI subprocess nesting. A child CLI (e.g. `opencode run`) that is\n * itself configured to auto-start a `nexus-agents --mode=server` MCP server\n * would otherwise deadlock the voter — the nested server attaches to the child's\n * stdio and blocks the child's MCP handshake, so the voter never returns its\n * JSON. The server bootstrap reads this marker and refuses to start when nested\n * (see `cli-server.ts`). Distinct from the codex-only `NEXUS_MCP_DEPTH` guard so\n * the two cannot interfere. `NEXUS_`-prefixed, so it survives the allowlist (and\n * the `=0` full-passthrough hatch) and reaches the grandchild MCP server.\n */\nexport const NEXUS_SUBPROCESS_DEPTH_ENV = 'NEXUS_SUBPROCESS_DEPTH';\n\n/** Read the subprocess nesting depth from an env bag; clamps missing/junk to 0. */\nexport function readSubprocessDepth(env: NodeJS.ProcessEnv = process.env): number {\n const raw = Number.parseInt(env[NEXUS_SUBPROCESS_DEPTH_ENV] ?? '0', 10);\n return Number.isFinite(raw) && raw > 0 ? raw : 0;\n}\n\n/** Exact-match infrastructure vars every spawned CLI legitimately needs. */\nconst BASE_ENV_EXACT: readonly string[] = [\n 'PATH',\n 'HOME',\n // CLI config/data locations hold paths, not credentials (#6982).\n 'CODEX_HOME',\n 'CLAUDE_CONFIG_DIR',\n 'XDG_CONFIG_HOME',\n 'XDG_DATA_HOME',\n 'XDG_STATE_HOME',\n 'XDG_CACHE_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/**\n * Env var naming ADDITIONAL var names to forward to spawned CLIs\n * (comma/whitespace-separated). The granular alternative to the\n * `NEXUS_SUBPROCESS_ENV_ALLOWLIST=false` hammer: for a custom gateway whose auth key\n * is neither `NEXUS_`-prefixed nor a known vendor key (#4037), name it here to\n * forward ONLY that var while keeping full cross-vendor isolation for everything\n * else. `NEXUS_`-prefixed itself, so it also reaches nested runs.\n */\nexport const NEXUS_SUBPROCESS_EXTRA_ENV = 'NEXUS_SUBPROCESS_EXTRA_ENV';\n\n/** Parse the operator-configured extra-forward var names (empty when unset). */\nfunction readExtraEnvNames(env: NodeJS.ProcessEnv): readonly string[] {\n const raw = env[NEXUS_SUBPROCESS_EXTRA_ENV];\n if (raw === undefined || raw.trim() === '') return [];\n return raw\n .split(/[,\\s]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n}\n\n/**\n * Pattern matching secret or credential environment variable names that must\n * NEVER be implicitly forwarded to spawned CLI subprocesses by prefix match,\n * even when matching `NEXUS_` or another infrastructure prefix.\n *\n * Specific vendor keys in `CLI_VENDOR_KEYS` or operator-explicit extra variables\n * configured via {@link NEXUS_SUBPROCESS_EXTRA_ENV} are still honored.\n */\nconst BLOCKED_SECRET_PATTERN =\n /(?:^NEXUS_SECRET_)|(?:(?:^|_|[a-z])(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS)$)/i;\n\n/** True if `key` matches patterns designated for secrets/credentials. */\nfunction isBlockedSecretVar(key: string): boolean {\n return BLOCKED_SECRET_PATTERN.test(key);\n}\n\n/**\n * True if `key` is permitted for a CLI whose vendor keys are `vendorKeys`, plus\n * any operator-allowlisted `extraEnv` names (#4037).\n */\nfunction isAllowed(\n key: string,\n vendorKeys: readonly string[],\n extraEnv: readonly string[]\n): boolean {\n if (BASE_ENV_EXACT.includes(key)) return true;\n if (vendorKeys.includes(key)) return true;\n if (extraEnv.includes(key)) return true;\n if (isBlockedSecretVar(key)) return false;\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 * Granular extension: {@link NEXUS_SUBPROCESS_EXTRA_ENV} forwards named extra\n * vars (e.g. a custom gateway key) while keeping cross-vendor isolation — prefer\n * it over the blunt `=false` hatch (#4037).\n *\n * Escape hatch: the boolean `NEXUS_SUBPROCESS_ENV_ALLOWLIST` (default on)\n * set to `false`/`0` restores the pre-#2865 full-passthrough behavior (minus\n * `CLAUDECODE`) — a field un-break if the allowlist ever drops a var a CLI\n * needs. Parsed with the shared `parseBoolValue` accept-set (#5155).\n */\nexport function buildChildEnv(cliName: CliName): NodeJS.ProcessEnv {\n const source = process.env;\n const childEnv: NodeJS.ProcessEnv = {};\n // Stamp the incremented nesting depth (#4033) LAST in both branches so it\n // overrides any inherited value rather than copying the parent's depth.\n const nextDepth = String(readSubprocessDepth(source) + 1);\n\n if (!parseBoolValue(source['NEXUS_SUBPROCESS_ENV_ALLOWLIST'], true)) {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined && key !== 'CLAUDECODE') childEnv[key] = value;\n }\n childEnv[NEXUS_SUBPROCESS_DEPTH_ENV] = nextDepth;\n stampNoRelaunch(cliName, childEnv);\n return childEnv;\n }\n\n const vendorKeys = CLI_VENDOR_KEYS[cliName];\n const extraEnv = readExtraEnvNames(source);\n for (const [key, value] of Object.entries(source)) {\n if (value === undefined) continue;\n if (key === 'CLAUDECODE') continue;\n if (isAllowed(key, vendorKeys, extraEnv)) childEnv[key] = value;\n }\n childEnv[NEXUS_SUBPROCESS_DEPTH_ENV] = nextDepth;\n stampNoRelaunch(cliName, childEnv);\n return childEnv;\n}\n\n/**\n * gemini-cli relaunches itself as a child process unless told not to, and the\n * relaunching parent does not stop its worker on SIGTERM (#6680). The adapter\n * kills the child's tracked descendant tree anyway (#6703); this keeps the\n * worker the process the adapter spawned. Harmless for a binary that does not\n * read it.\n */\nfunction stampNoRelaunch(cliName: CliName, childEnv: NodeJS.ProcessEnv): void {\n if (cliName === 'gemini') childEnv['GEMINI_CLI_NO_RELAUNCH'] = 'true';\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 * Signal a CLI subprocess together with the processes it spawned (#6680).\n *\n * A CLI can relaunch itself as a child (gemini-cli does unless\n * `GEMINI_CLI_NO_RELAUNCH` is set), so signalling only the spawned PID left\n * the real worker running as an orphan after a cancel or a timeout. These\n * helpers collect the child's descendant PIDs first, then signal the child\n * and exactly those PIDs, never a process group. The CLI stays in the\n * server's process group, so a harness that kills that group, even with\n * SIGKILL, still reaches every CLI process as it did before.\n *\n * Descendants are read from `/proc/<pid>/task/<tid>/children` on Linux and\n * from `ps -A -o pid=,ppid=` on other POSIX systems. Where neither works\n * (Windows) only the direct child is signalled.\n *\n * Off Linux, `ps` runs asynchronously (#6718), so a signal pass does not block\n * the event loop for up to the `ps` timeout. The descendants are still\n * collected before anything is signalled: the async paths await the `ps`\n * result, then signal. The one synchronous `ps` left is the `exit` hook's,\n * because a `process.on('exit')` handler cannot await. On Linux the `/proc`\n * walk is synchronous everywhere; it reads small files and spawns nothing.\n *\n * PID reuse (#6714): a PID is only a name, and the kernel hands it out again\n * once its process is reaped. So the fresh walk is skipped once the child has\n * exited (Node reaps it at once, freeing its PID), and on Linux each\n * descendant is recorded with its start time (`/proc/<pid>/stat` field 22)\n * and re-verified before every later signal or liveness check; a mismatch or\n * an unreadable stat means the process is gone and the PID is skipped. Other\n * platforms expose no start time cheaply, so there a descendant is recorded\n * without one and signalled by PID alone, as before.\n *\n * Known gap (#6718): a descendant that double-forked and was reparented to\n * init, or to another subreaper, before the signal is no longer in the tree,\n * so it is neither signalled nor escalated. The alternatives were weighed and\n * not adopted. A process-group or session kill cannot be used: the CLIs share\n * the server's group (#6703), and a daemon that double-forks usually calls\n * `setsid` as well. `PR_SET_CHILD_SUBREAPER` needs a `prctl` call Node does\n * not expose, so it would take a native addon or a wrapper binary. A cgroup\n * needs a delegated, writable cgroup v2 subtree, which a plain server does not\n * have. And a daemon that detached itself on purpose may be meant to outlive\n * the CLI. If a real CLI is seen leaking one, the cheapest dependency-free\n * option on Linux is to tag each spawn's environment with a unique marker and\n * match it in `/proc/<pid>/environ`, which a double fork inherits.\n *\n * @module cli-adapters/process-tree-kill\n */\n\nimport { execFile, execFileSync } from 'node:child_process';\nimport { readdirSync, readFileSync } from 'node:fs';\nimport type { ChildProcess } from 'node:child_process';\nimport { readProcStartTime } from './proc-start-time.js';\n\n/** Upper bound on descendants collected, so a fork bomb cannot stall the walk. */\nconst MAX_DESCENDANTS = 1_000;\n\n/** `ps` arguments listing every process with its parent. */\nconst PS_ARGS = ['-A', '-o', 'pid=,ppid='];\n\n/** Bound on one `ps` run, synchronous or not. */\nconst PS_TIMEOUT_MS = 2_000;\n\n/**\n * True for a child `spawn` actually started. Duck-typed on the fields only a\n * real spawn sets: a test double lacks them, so its made-up PID is never\n * walked or signalled.\n */\nfunction isSpawnedProcess(child: ChildProcess): boolean {\n return (\n typeof child.pid === 'number' &&\n typeof child.spawnfile === 'string' &&\n Array.isArray(child.spawnargs)\n );\n}\n\n/** Direct children of `pid` from `/proc` (Linux), or undefined when unreadable. */\nfunction procChildren(pid: number): number[] | undefined {\n try {\n const tasks = readdirSync(`/proc/${String(pid)}/task`);\n const kids: number[] = [];\n for (const tid of tasks) {\n const raw = readFileSync(`/proc/${String(pid)}/task/${tid}/children`, 'utf8');\n for (const token of raw.split(/\\s+/)) {\n const kid = Number(token);\n if (token !== '' && Number.isInteger(kid)) kids.push(kid);\n }\n }\n return kids;\n } catch {\n return undefined;\n }\n}\n\n/** Parse `ps -o pid=,ppid=` output into a `ppid → children` map. */\nfunction parsePsChildMap(out: string): Map<number, number[]> {\n const map = new Map<number, number[]>();\n for (const line of out.split('\\n')) {\n const [pidText, ppidText] = line.trim().split(/\\s+/);\n const pid = Number(pidText);\n const ppid = Number(ppidText);\n if (!Number.isInteger(pid) || !Number.isInteger(ppid)) continue;\n map.set(ppid, [...(map.get(ppid) ?? []), pid]);\n }\n return map;\n}\n\n/**\n * A `ppid → children` map from a SYNCHRONOUS `ps` (non-Linux POSIX), or\n * undefined when unavailable. It blocks the event loop for up to\n * {@link PS_TIMEOUT_MS}, so only the synchronous paths use it (#6718).\n */\nfunction psChildMapSync(): Map<number, number[]> | undefined {\n if (process.platform === 'win32') return undefined;\n try {\n return parsePsChildMap(\n execFileSync('ps', PS_ARGS, { encoding: 'utf8', timeout: PS_TIMEOUT_MS })\n );\n } catch {\n return undefined;\n }\n}\n\n/** The same map from an asynchronous `ps`; resolves undefined when unavailable. */\nfunction psChildMapAsync(): Promise<Map<number, number[]> | undefined> {\n if (process.platform === 'win32') return Promise.resolve(undefined);\n return new Promise((resolve) => {\n execFile('ps', PS_ARGS, { encoding: 'utf8', timeout: PS_TIMEOUT_MS }, (error, stdout) => {\n resolve(error === null ? parsePsChildMap(stdout) : undefined);\n });\n });\n}\n\n/** Every descendant PID of `root`, breadth-first, capped at {@link MAX_DESCENDANTS}. */\nfunction walkDescendants(root: number, childrenOf: (pid: number) => number[]): number[] {\n const seen = new Set<number>([root]);\n const out: number[] = [];\n const queue = [root];\n while (queue.length > 0 && out.length < MAX_DESCENDANTS) {\n const pid = queue.shift() as number;\n for (const kid of childrenOf(pid)) {\n if (seen.has(kid)) continue;\n seen.add(kid);\n out.push(kid);\n queue.push(kid);\n }\n }\n return out;\n}\n\n/**\n * Every descendant PID of `root`, synchronously. Empty when the platform\n * offers no way to list them.\n */\nfunction collectDescendants(root: number): number[] {\n const useProc = process.platform === 'linux' && procChildren(root) !== undefined;\n const psMap = useProc ? undefined : psChildMapSync();\n return walkDescendants(root, (pid) => (useProc ? procChildren(pid) : psMap?.get(pid)) ?? []);\n}\n\n/** Every descendant PID of `root` from an asynchronous `ps` (#6718). */\nasync function collectDescendantsAsync(root: number): Promise<number[]> {\n const psMap = await psChildMapAsync();\n return walkDescendants(root, (pid) => psMap?.get(pid) ?? []);\n}\n\n/** Only ESRCH proves a process is gone; EPERM means it exists but is not ours. */\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error: unknown) {\n return (error as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n}\n\n/**\n * A descendant as it was when collected. `startTime` is REQUIRED so every\n * producer has to decide it: the `/proc/<pid>/stat` start time on Linux, or\n * `undefined` where the platform offers none, which means \"signal by PID\n * alone\" (#6714).\n */\ninterface KnownProcess {\n readonly pid: number;\n readonly startTime: string | undefined;\n}\n\n/** The OS operations the tree kill performs; a seam so tests can stage PID reuse. */\ninterface ProcessTreeOps {\n /** Every descendant PID of `root`, or empty when they cannot be listed. Synchronous. */\n readonly collectDescendants: (root: number) => number[];\n /**\n * The same without blocking the event loop, or undefined where the\n * synchronous walk does not block (Linux `/proc`). REQUIRED so every\n * producer decides; every path but the `exit` hook uses it when set (#6718).\n */\n readonly collectDescendantsAsync: ((root: number) => Promise<number[]>) | undefined;\n /** True when start times are available at all (Linux). */\n readonly hasStartTimes: boolean;\n /** The start time of `pid` now, or undefined when it cannot be read (gone). */\n readonly readStartTime: (pid: number) => string | undefined;\n readonly isPidAlive: (pid: number) => boolean;\n readonly kill: (pid: number, signal: NodeJS.Signals) => void;\n}\n\nconst defaultOps: ProcessTreeOps = {\n collectDescendants,\n collectDescendantsAsync: process.platform === 'linux' ? undefined : collectDescendantsAsync,\n hasStartTimes: process.platform === 'linux',\n readStartTime: readProcStartTime,\n isPidAlive,\n kill: (pid, signal) => {\n process.kill(pid, signal);\n },\n};\n\n/**\n * Record each PID with its start time. On Linux a PID whose stat cannot be\n * read has already exited and is dropped; elsewhere none has a start time.\n */\nfunction identify(pids: readonly number[], ops: ProcessTreeOps): KnownProcess[] {\n if (!ops.hasStartTimes) return pids.map((pid) => ({ pid, startTime: undefined }));\n const out: KnownProcess[] = [];\n for (const pid of pids) {\n const startTime = ops.readStartTime(pid);\n if (startTime !== undefined) out.push({ pid, startTime });\n }\n return out;\n}\n\n/**\n * True while `known` is still the process that was collected. A recorded\n * start time must read back identically; without one (non-Linux) only\n * whether the PID exists can be checked.\n */\nfunction isSameProcess(known: KnownProcess, ops: ProcessTreeOps): boolean {\n if (known.startTime === undefined) return ops.isPidAlive(known.pid);\n return ops.readStartTime(known.pid) === known.startTime;\n}\n\n/** The first entry recorded for each PID, in order. */\nfunction uniqueByPid(entries: readonly KnownProcess[]): KnownProcess[] {\n const byPid = new Map<number, KnownProcess>();\n for (const entry of entries) {\n if (!byPid.has(entry.pid)) byPid.set(entry.pid, entry);\n }\n return [...byPid.values()];\n}\n\nfunction hasExited(child: ChildProcess): boolean {\n return child.exitCode !== null || child.signalCode !== null;\n}\n\n/**\n * CLI process trees still running, so server shutdown can end them (#6680).\n *\n * The CLIs share the server's process group, so a signal to the whole group\n * reaches them directly. A signal to the server's PID alone does not: the\n * shutdown path SIGTERMs these trees instead, and a synchronous `exit` hook\n * SIGKILLs whatever is left.\n */\nconst liveTrees = new Map<ChildProcess, KnownProcess[]>();\nlet exitHookInstalled = false;\n\n/**\n * The PID to walk for fresh descendants, or undefined when no walk may be\n * made: a test double, or a child that has exited and whose PID may already\n * name another process (#6714).\n */\nfunction walkablePid(child: ChildProcess): number | undefined {\n return isSpawnedProcess(child) && !hasExited(child) ? child.pid : undefined;\n}\n\n/**\n * Signal the child, then `fresh` merged with `known` and the tracked set, each\n * re-verified first and skipped if its PID now names a different process\n * (#6714). ESRCH (already gone) is ignored. Returns the descendants signalled.\n */\nfunction signalCollected(\n child: ChildProcess,\n signal: NodeJS.Signals,\n known: readonly KnownProcess[],\n fresh: readonly KnownProcess[],\n ops: ProcessTreeOps\n): KnownProcess[] {\n // A tracked tree may hold descendants an earlier signal collected (the shutdown path).\n const candidates = uniqueByPid([...known, ...(liveTrees.get(child) ?? []), ...fresh]);\n child.kill(signal);\n const tree = candidates.filter((entry) => isSameProcess(entry, ops));\n for (const entry of tree) {\n try {\n ops.kill(entry.pid, signal);\n } catch {\n // ESRCH: already gone.\n }\n }\n if (liveTrees.has(child)) liveTrees.set(child, tree);\n return tree;\n}\n\n/**\n * Signal the child and its descendants, synchronously. The descendants are\n * collected before anything is signalled — once a parent dies its children\n * are reparented and can no longer be found through it — and merged with\n * `known`, the set an earlier call collected, so a SIGKILL escalation still\n * reaches a grandchild whose parent exited on the SIGTERM.\n *\n * Once the child has exited no fresh walk is made and only `known` is\n * signalled (#6714). Returns the descendants still tracked: those signalled,\n * besides the child.\n *\n * Off Linux the walk is a synchronous `ps` that blocks the event loop, so in\n * production only the `exit` hook reaches this; every other path goes through\n * {@link terminateProcessTree} or {@link signalTrackedProcessTreesAsync} (#6718).\n */\nexport function signalProcessTree(\n child: ChildProcess,\n signal: NodeJS.Signals,\n known: readonly KnownProcess[],\n ops: ProcessTreeOps = defaultOps\n): KnownProcess[] {\n const pid = walkablePid(child);\n const fresh = pid === undefined ? [] : identify(ops.collectDescendants(pid), ops);\n return signalCollected(child, signal, known, fresh, ops);\n}\n\n/**\n * Signal without blocking the event loop (#6718). When no asynchronous walk is\n * needed (`ops.collectDescendantsAsync` unset, or no walk at all) the signals\n * are sent before this returns and the tree comes back as an array, exactly as\n * {@link signalProcessTree}. Otherwise the returned promise collects FIRST and\n * signals once the collection resolves.\n */\nfunction signalProcessTreeSoon(\n child: ChildProcess,\n signal: NodeJS.Signals,\n known: readonly KnownProcess[],\n ops: ProcessTreeOps\n): KnownProcess[] | Promise<KnownProcess[]> {\n const pid = walkablePid(child);\n const collectAsync = ops.collectDescendantsAsync;\n if (pid === undefined || collectAsync === undefined) {\n return signalProcessTree(child, signal, known, ops);\n }\n return collectAsync(pid).then(\n (pids) => {\n // The child may have exited, and its PID been reused, while `ps` ran (#6714).\n const fresh = hasExited(child) ? [] : identify(pids, ops);\n return signalCollected(child, signal, known, fresh, ops);\n },\n // A failed walk must not leave the child unsignalled or reject into a `void`.\n () => signalCollected(child, signal, known, [], ops)\n );\n}\n\n/**\n * True while the child, or any collected descendant that is still the same\n * process (#6714), is running.\n */\nexport function isProcessTreeAlive(\n child: ChildProcess,\n tree: readonly KnownProcess[],\n ops: ProcessTreeOps = defaultOps\n): boolean {\n if (!hasExited(child)) return true;\n return tree.some((entry) => isSameProcess(entry, ops));\n}\n\n/**\n * True once a tracked tree can be forgotten: its child has exited and no known\n * descendant is still the process that was collected. Without start times\n * (non-Linux) a live PID cannot be told from a reused one, so there a tree is\n * finished as soon as its child exits, as before #6714; retaining it could\n * leave a reused PID for the exit hook to SIGKILL.\n */\nfunction isFinishedTree(\n child: ChildProcess,\n known: readonly KnownProcess[],\n ops: ProcessTreeOps\n): boolean {\n if (!hasExited(child)) return false;\n return !ops.hasStartTimes || !isProcessTreeAlive(child, known, ops);\n}\n\n/** Forget every tracked tree that is finished. */\nfunction pruneFinishedTrees(ops: ProcessTreeOps): void {\n for (const [child, known] of liveTrees) {\n if (isFinishedTree(child, known, ops)) liveTrees.delete(child);\n }\n}\n\n/**\n * Track a spawned CLI, returning it. Only real spawns are tracked. On Linux\n * the tree stays tracked past the child's `close` while a descendant a signal\n * already collected is still the same running process, so a shutdown inside\n * the SIGKILL grace window still reaches a grandchild that ignored the\n * SIGTERM (#6714). Elsewhere it is forgotten on `close`, as before.\n */\nexport function trackProcessTree<T extends ChildProcess>(\n child: T,\n ops: ProcessTreeOps = defaultOps\n): T {\n if (!isSpawnedProcess(child)) return child;\n pruneFinishedTrees(ops);\n liveTrees.set(child, []);\n child.once('close', () => {\n if (isFinishedTree(child, liveTrees.get(child) ?? [], ops)) liveTrees.delete(child);\n });\n if (!exitHookInstalled) {\n exitHookInstalled = true;\n process.on('exit', () => {\n signalTrackedProcessTrees('SIGKILL');\n });\n }\n return child;\n}\n\n/**\n * Signal every tracked CLI tree; returns how many were signalled. SYNCHRONOUS\n * because the `exit` hook cannot await, so off Linux this is the one path that\n * still runs a blocking `ps` (#6718). Each tree's collected descendants are\n * remembered, so the exit hook's SIGKILL still reaches a grandchild whose\n * parent died on the shutdown SIGTERM.\n */\nexport function signalTrackedProcessTrees(\n signal: NodeJS.Signals,\n ops: ProcessTreeOps = defaultOps\n): number {\n pruneFinishedTrees(ops);\n let count = 0;\n for (const [child, known] of [...liveTrees]) {\n signalProcessTree(child, signal, known, ops);\n count++;\n }\n return count;\n}\n\n/**\n * {@link signalTrackedProcessTrees} for a caller that can await (the graceful\n * shutdown): off Linux each tree is collected by an asynchronous `ps` before\n * it is signalled (#6718). Resolves to how many trees were signalled.\n */\nexport async function signalTrackedProcessTreesAsync(\n signal: NodeJS.Signals,\n ops: ProcessTreeOps = defaultOps\n): Promise<number> {\n pruneFinishedTrees(ops);\n const trees = [...liveTrees];\n await Promise.all(\n trees.map(([child, known]) => Promise.resolve(signalProcessTreeSoon(child, signal, known, ops)))\n );\n return trees.length;\n}\n\n/**\n * Grace period before a SIGTERMed tree is SIGKILLed (#3026 finding 1). 5 s\n * gives a well-behaved child time to flush state and exit, and bounds how long\n * one that ignores SIGTERM keeps running.\n */\nexport const SIGKILL_GRACE_MS = 5_000;\n\n/**\n * SIGTERM the child and its descendants, then SIGKILL whatever of that tree is\n * still the same running process after `graceMs` (#6680, #6747). `onEscalate`\n * runs just before the SIGKILL, for the caller's log line. The escalation timer\n * is unref'd: a server exiting inside the grace window still reaches a tracked\n * tree through the exit hook.\n *\n * Where no asynchronous walk is needed (Linux) the SIGTERM is sent and the\n * timer armed before this returns. Off Linux the descendants are first\n * collected by an asynchronous `ps`, so the SIGTERM goes out, and the grace\n * period starts, once it resolves (#6718). Resolves to the descendants\n * signalled.\n */\nexport function terminateProcessTree(\n child: ChildProcess,\n graceMs: number = SIGKILL_GRACE_MS,\n onEscalate?: () => void,\n ops: ProcessTreeOps = defaultOps\n): Promise<KnownProcess[]> {\n const armEscalation = (tree: KnownProcess[]): KnownProcess[] => {\n const timer = setTimeout(() => {\n if (!isProcessTreeAlive(child, tree, ops)) return;\n onEscalate?.();\n void signalProcessTreeSoon(child, 'SIGKILL', tree, ops);\n }, graceMs);\n timer.unref();\n // A descendant can outlive the child's close, so only an empty tree cancels the check.\n if (tree.length === 0) {\n child.once('close', () => {\n clearTimeout(timer);\n });\n }\n return tree;\n };\n const signalled = signalProcessTreeSoon(child, 'SIGTERM', [], ops);\n if (Array.isArray(signalled)) return Promise.resolve(armEscalation(signalled));\n return signalled.then(armEscalation);\n}\n","/**\n * A process's start time from `/proc/<pid>/stat` (Linux), used to tell a\n * process from a later one that reused its PID (#6714). Together, a PID and\n * its start time name one process for as long as the kernel is up.\n *\n * @module cli-adapters/proc-start-time\n */\n\nimport { readFileSync } from 'node:fs';\n\n/** `/proc/<pid>/stat` field 22 is starttime; the split fields begin at field 3. */\nconst START_TIME_INDEX = 22 - 3;\n\n/**\n * Field 22 (starttime) of a `/proc/<pid>/stat` line, or undefined when it\n * does not parse. Field 2 (comm) is parenthesised and may itself contain\n * spaces and `)`, so the fields are split after the LAST `)`. A zombie\n * (state `Z`) has already died and only awaits its reaper, so it reads as\n * gone too: signalling it does nothing, and waiting on it would keep an\n * escalation armed where PID 1 never reaps orphans.\n */\nexport function parseProcStatStartTime(stat: string): string | undefined {\n const close = stat.lastIndexOf(')');\n if (close === -1) return undefined;\n const fields = stat\n .slice(close + 1)\n .trim()\n .split(/\\s+/);\n if (fields[0] === 'Z') return undefined;\n const startTime = fields[START_TIME_INDEX];\n return startTime !== undefined && /^\\d+$/.test(startTime) ? startTime : undefined;\n}\n\n/** The start time of `pid`, or undefined when its stat cannot be read (it is gone). */\nexport function readProcStartTime(pid: number): string | undefined {\n try {\n return parseProcStatStartTime(readFileSync(`/proc/${String(pid)}/stat`, 'utf8'));\n } catch {\n // ENOENT/ESRCH: the process is gone.\n return undefined;\n }\n}\n","/**\n * Private call-scoped stdout evidence for late-settlement measurement (#6851).\n * The shared deadline reason survives AbortSignal.any; weak keys retain no calls\n * beyond their lifetimes. An absent observation means stdout was not measured.\n */\ninterface AbortObservation {\n readonly stdoutBytes: number;\n readonly sawFirstByte: boolean;\n}\n\nconst observations = new WeakMap<object, AbortObservation>();\n\n/** Preserve subprocess evidence only for a deadline; operator cancels are unrelated. */\nexport function recordAbortObservation(reason: unknown, observation: AbortObservation): void {\n if (!(reason instanceof DOMException) || reason.name !== 'TimeoutError') return;\n observations.set(reason, observation);\n}\n\n/** Missing reason or snapshot stays absent, including a subprocess that never started. */\nexport function getAbortObservation(reason: unknown): AbortObservation | undefined {\n if (!(reason instanceof DOMException) || reason.name !== 'TimeoutError') return undefined;\n return observations.get(reason);\n}\n"],"mappings":"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","names":["estimateTaskComplexity","readFileSync","readFileSync","msg","snippet"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-ZO6ZKR7L.js";
|
|
4
4
|
import {
|
|
5
5
|
SessionMemory
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-YI6DZGN6.js";
|
|
7
7
|
import {
|
|
8
8
|
TRUST_TIER_NUMERIC,
|
|
9
9
|
TrustTierSchema
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from "./chunk-ROYGBFVE.js";
|
|
18
18
|
import {
|
|
19
19
|
generateId
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-INVGMQKJ.js";
|
|
21
21
|
import {
|
|
22
22
|
ErrorCode,
|
|
23
23
|
NexusError,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
stringifyValue,
|
|
33
33
|
tokenize,
|
|
34
34
|
tokenizeFiltered
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-OMWOFIK5.js";
|
|
36
36
|
import {
|
|
37
37
|
createLogger,
|
|
38
38
|
getTimeProvider
|
|
@@ -5844,4 +5844,4 @@ export {
|
|
|
5844
5844
|
shutdownToolMemory,
|
|
5845
5845
|
ToolMemoryManager
|
|
5846
5846
|
};
|
|
5847
|
-
//# sourceMappingURL=chunk-
|
|
5847
|
+
//# sourceMappingURL=chunk-4HOSKAB3.js.map
|
|
@@ -729,13 +729,13 @@ var DEFAULT_MODEL_CAPABILITIES = {
|
|
|
729
729
|
]
|
|
730
730
|
};
|
|
731
731
|
var DEFAULT_MODEL_PER_CLI = {
|
|
732
|
-
// #4176: fable/gpt-5.5 were strongest per CLI; gemini-3.5-flash is flash-tier, not default.
|
|
733
732
|
// #6842: option A; revert this default to gpt-5.6-sol in one line if needed.
|
|
734
733
|
claude: "claude-fable-5",
|
|
735
|
-
gemini: "gemini-3-
|
|
734
|
+
gemini: "gemini-3.8-flash",
|
|
736
735
|
codex: "gpt-6.1-sol",
|
|
737
736
|
opencode: "opencode-default"
|
|
738
737
|
};
|
|
738
|
+
var DEFAULT_GOOGLE_API_MODEL = "gemini-3-pro";
|
|
739
739
|
var STATIC_CLI_COST_PER_1M = {
|
|
740
740
|
claude: { input: 3, output: 15 },
|
|
741
741
|
gemini: { input: 0.075, output: 0.3 },
|
|
@@ -1838,7 +1838,7 @@ function setDefaultRegistry(registry) {
|
|
|
1838
1838
|
}
|
|
1839
1839
|
async function reloadDefaultRegistry() {
|
|
1840
1840
|
globalRegistry = buildDefaultRegistry();
|
|
1841
|
-
const { resetGlobalRegistry } = await import("./unified-registry-
|
|
1841
|
+
const { resetGlobalRegistry } = await import("./unified-registry-MIANRTCJ.js");
|
|
1842
1842
|
resetGlobalRegistry();
|
|
1843
1843
|
return globalRegistry;
|
|
1844
1844
|
}
|
|
@@ -1846,6 +1846,7 @@ async function reloadDefaultRegistry() {
|
|
|
1846
1846
|
export {
|
|
1847
1847
|
DEFAULT_MODEL_CAPABILITIES,
|
|
1848
1848
|
DEFAULT_MODEL_PER_CLI,
|
|
1849
|
+
DEFAULT_GOOGLE_API_MODEL,
|
|
1849
1850
|
unpricedCliCostPer1M,
|
|
1850
1851
|
DEFAULT_ENTRY,
|
|
1851
1852
|
deriveEntry,
|
|
@@ -1867,4 +1868,4 @@ export {
|
|
|
1867
1868
|
setDefaultRegistry,
|
|
1868
1869
|
reloadDefaultRegistry
|
|
1869
1870
|
};
|
|
1870
|
-
//# sourceMappingURL=chunk-
|
|
1871
|
+
//# sourceMappingURL=chunk-4MKZAA6W.js.map
|