nexus-agents 2.149.1 → 2.150.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.
Files changed (123) hide show
  1. package/dist/{child-mcp-config-YTJSYSDO.js → child-mcp-config-EXXD4NVX.js} +2 -2
  2. package/dist/{chunk-4FT35FDA.js → chunk-27JU5EIO.js} +8 -8
  3. package/dist/{chunk-OSYZ7FT7.js → chunk-2Y5UAHBN.js} +4 -4
  4. package/dist/{chunk-ZGY3V7RD.js → chunk-4EDNTMRD.js} +2 -2
  5. package/dist/{chunk-ZZKZ4UHC.js → chunk-5AWBRS3R.js} +4 -4
  6. package/dist/{chunk-S75CT7MY.js → chunk-6D7NYWDW.js} +2 -2
  7. package/dist/{chunk-BYMPT7NU.js → chunk-76BPE6FB.js} +2 -2
  8. package/dist/{chunk-UXEARNIP.js → chunk-AFNO7KMH.js} +2 -2
  9. package/dist/{chunk-XWPTHKA2.js → chunk-BOJOJQLH.js} +5 -5
  10. package/dist/{chunk-PX634ZOU.js → chunk-BX5CYNHE.js} +7 -7
  11. package/dist/{chunk-ZIN26XX5.js → chunk-FR2YSJC7.js} +4 -4
  12. package/dist/{chunk-CPCRNL36.js → chunk-FWEYQX4N.js} +26 -18
  13. package/dist/chunk-FWEYQX4N.js.map +1 -0
  14. package/dist/{chunk-7H3Z5Q2X.js → chunk-GTEGNTFD.js} +2 -2
  15. package/dist/{chunk-ZHT4TFFA.js → chunk-GUAG2ADJ.js} +3 -3
  16. package/dist/{chunk-TCI7DNWK.js → chunk-HQL7TF57.js} +129 -86
  17. package/dist/chunk-HQL7TF57.js.map +1 -0
  18. package/dist/{chunk-OJI53VOI.js → chunk-HZXJ3JAZ.js} +2 -2
  19. package/dist/{chunk-QWEKW6FF.js → chunk-IJ5JFATI.js} +7 -7
  20. package/dist/{chunk-Z7TY67AH.js → chunk-J3QSLEHM.js} +2 -2
  21. package/dist/{chunk-FEB4O6BV.js → chunk-KIDH3EWN.js} +2 -2
  22. package/dist/{chunk-MLAD6ZTK.js → chunk-LGSU5C46.js} +34 -34
  23. package/dist/{chunk-GC3BEJNL.js → chunk-MDCSXJWB.js} +2 -2
  24. package/dist/{chunk-6KVJKH7P.js → chunk-OECO3UIW.js} +3 -3
  25. package/dist/{chunk-O7KV4UGP.js → chunk-PBNYJR7F.js} +2 -2
  26. package/dist/{chunk-HH7IATAZ.js → chunk-Q42KWK42.js} +3 -3
  27. package/dist/{chunk-K4B5N5QH.js → chunk-RKQQEJEU.js} +3 -3
  28. package/dist/{chunk-5I4LPOKG.js → chunk-RLBYREDT.js} +2 -2
  29. package/dist/{chunk-IMLHCK4P.js → chunk-V25VUUPP.js} +5 -5
  30. package/dist/{chunk-367EP2C7.js → chunk-V2PQVMGE.js} +2 -2
  31. package/dist/{chunk-3DL4MAGN.js → chunk-VGINLUME.js} +12 -3
  32. package/dist/{chunk-3DL4MAGN.js.map → chunk-VGINLUME.js.map} +1 -1
  33. package/dist/{chunk-L3F27J72.js → chunk-VPFK7LIK.js} +2 -2
  34. package/dist/{chunk-2UU5ZXTW.js → chunk-WO4MB65I.js} +3 -3
  35. package/dist/{chunk-77GBDHVF.js → chunk-WUYXJJTL.js} +19 -13
  36. package/dist/chunk-WUYXJJTL.js.map +1 -0
  37. package/dist/{chunk-KNTNSBHK.js → chunk-XA3PKYBR.js} +4 -4
  38. package/dist/{chunk-2AJDFDMI.js → chunk-ZGYLWKAZ.js} +2 -2
  39. package/dist/{chunk-XYOST7XP.js → chunk-ZO2FWH6W.js} +5 -5
  40. package/dist/{cli-circuit-breaker-7XBDSYYS.js → cli-circuit-breaker-CLQKA7NG.js} +4 -4
  41. package/dist/cli.js +41 -41
  42. package/dist/{composite-router-CS6YW7FL.js → composite-router-ZIIMWIPS.js} +2 -2
  43. package/dist/{consensus-vote-FQ7DMGQ5.js → consensus-vote-PGPDRVWI.js} +15 -15
  44. package/dist/{context-retriever-RJ6D67WW.js → context-retriever-EMVN6NNW.js} +8 -8
  45. package/dist/{doctor-deep-HFJGB7HZ.js → doctor-deep-4VYC4ZFD.js} +3 -3
  46. package/dist/{expert-bridge-BSEUAG5B.js → expert-bridge-D53IE52J.js} +4 -4
  47. package/dist/{factory-GXAOB66V.js → factory-JAVXQI2M.js} +5 -5
  48. package/dist/{factory-SJF3GF6T.js → factory-R6WV357Q.js} +8 -8
  49. package/dist/{improvement-review-GCIDNUGA.js → improvement-review-MJ6A6HFV.js} +5 -5
  50. package/dist/index.d.ts +34 -0
  51. package/dist/index.js +30 -30
  52. package/dist/{init-opencode-QKPN4FQ6.js → init-opencode-JAFMTL6D.js} +6 -6
  53. package/dist/{issue-triage-VSLGCWHP.js → issue-triage-WJFYACOD.js} +6 -6
  54. package/dist/{pr-reviewer-helpers-X7MU2OUO.js → pr-reviewer-helpers-LX46ZNDN.js} +4 -4
  55. package/dist/{registry-command-AQOQHU6R.js → registry-command-STRBISOJ.js} +2 -2
  56. package/dist/{repo-security-plan-23K6ZLFD.js → repo-security-plan-BAQRQDVT.js} +3 -3
  57. package/dist/{research-helpers-synthesize-OOQHAUON.js → research-helpers-synthesize-I7CCPVI5.js} +4 -4
  58. package/dist/{routing-memory-KNXPI7HA.js → routing-memory-GASTCLCD.js} +2 -2
  59. package/dist/{session-memory-GVEMAPT3.js → session-memory-DMD4LWZF.js} +3 -3
  60. package/dist/{setup-command-ICXDEARW.js → setup-command-XBER4WR2.js} +11 -11
  61. package/dist/{setup-config-PYE3DHHH.js → setup-config-AVMV3GTY.js} +3 -3
  62. package/dist/{setup-custom-api-Y2MTGAS7.js → setup-custom-api-3WRO27ZG.js} +3 -3
  63. package/dist/{tool-memory-PE7RNTVL.js → tool-memory-734GCMZM.js} +5 -5
  64. package/dist/{unified-registry-PGK7BFEQ.js → unified-registry-STRPR5KB.js} +9 -9
  65. package/dist/{weather-report-KDNG2TKZ.js → weather-report-3LMA4ZVW.js} +2 -2
  66. package/package.json +1 -1
  67. package/dist/chunk-77GBDHVF.js.map +0 -1
  68. package/dist/chunk-CPCRNL36.js.map +0 -1
  69. package/dist/chunk-TCI7DNWK.js.map +0 -1
  70. /package/dist/{child-mcp-config-YTJSYSDO.js.map → child-mcp-config-EXXD4NVX.js.map} +0 -0
  71. /package/dist/{chunk-4FT35FDA.js.map → chunk-27JU5EIO.js.map} +0 -0
  72. /package/dist/{chunk-OSYZ7FT7.js.map → chunk-2Y5UAHBN.js.map} +0 -0
  73. /package/dist/{chunk-ZGY3V7RD.js.map → chunk-4EDNTMRD.js.map} +0 -0
  74. /package/dist/{chunk-ZZKZ4UHC.js.map → chunk-5AWBRS3R.js.map} +0 -0
  75. /package/dist/{chunk-S75CT7MY.js.map → chunk-6D7NYWDW.js.map} +0 -0
  76. /package/dist/{chunk-BYMPT7NU.js.map → chunk-76BPE6FB.js.map} +0 -0
  77. /package/dist/{chunk-UXEARNIP.js.map → chunk-AFNO7KMH.js.map} +0 -0
  78. /package/dist/{chunk-XWPTHKA2.js.map → chunk-BOJOJQLH.js.map} +0 -0
  79. /package/dist/{chunk-PX634ZOU.js.map → chunk-BX5CYNHE.js.map} +0 -0
  80. /package/dist/{chunk-ZIN26XX5.js.map → chunk-FR2YSJC7.js.map} +0 -0
  81. /package/dist/{chunk-7H3Z5Q2X.js.map → chunk-GTEGNTFD.js.map} +0 -0
  82. /package/dist/{chunk-ZHT4TFFA.js.map → chunk-GUAG2ADJ.js.map} +0 -0
  83. /package/dist/{chunk-OJI53VOI.js.map → chunk-HZXJ3JAZ.js.map} +0 -0
  84. /package/dist/{chunk-QWEKW6FF.js.map → chunk-IJ5JFATI.js.map} +0 -0
  85. /package/dist/{chunk-Z7TY67AH.js.map → chunk-J3QSLEHM.js.map} +0 -0
  86. /package/dist/{chunk-FEB4O6BV.js.map → chunk-KIDH3EWN.js.map} +0 -0
  87. /package/dist/{chunk-MLAD6ZTK.js.map → chunk-LGSU5C46.js.map} +0 -0
  88. /package/dist/{chunk-GC3BEJNL.js.map → chunk-MDCSXJWB.js.map} +0 -0
  89. /package/dist/{chunk-6KVJKH7P.js.map → chunk-OECO3UIW.js.map} +0 -0
  90. /package/dist/{chunk-O7KV4UGP.js.map → chunk-PBNYJR7F.js.map} +0 -0
  91. /package/dist/{chunk-HH7IATAZ.js.map → chunk-Q42KWK42.js.map} +0 -0
  92. /package/dist/{chunk-K4B5N5QH.js.map → chunk-RKQQEJEU.js.map} +0 -0
  93. /package/dist/{chunk-5I4LPOKG.js.map → chunk-RLBYREDT.js.map} +0 -0
  94. /package/dist/{chunk-IMLHCK4P.js.map → chunk-V25VUUPP.js.map} +0 -0
  95. /package/dist/{chunk-367EP2C7.js.map → chunk-V2PQVMGE.js.map} +0 -0
  96. /package/dist/{chunk-L3F27J72.js.map → chunk-VPFK7LIK.js.map} +0 -0
  97. /package/dist/{chunk-2UU5ZXTW.js.map → chunk-WO4MB65I.js.map} +0 -0
  98. /package/dist/{chunk-KNTNSBHK.js.map → chunk-XA3PKYBR.js.map} +0 -0
  99. /package/dist/{chunk-2AJDFDMI.js.map → chunk-ZGYLWKAZ.js.map} +0 -0
  100. /package/dist/{chunk-XYOST7XP.js.map → chunk-ZO2FWH6W.js.map} +0 -0
  101. /package/dist/{cli-circuit-breaker-7XBDSYYS.js.map → cli-circuit-breaker-CLQKA7NG.js.map} +0 -0
  102. /package/dist/{composite-router-CS6YW7FL.js.map → composite-router-ZIIMWIPS.js.map} +0 -0
  103. /package/dist/{consensus-vote-FQ7DMGQ5.js.map → consensus-vote-PGPDRVWI.js.map} +0 -0
  104. /package/dist/{context-retriever-RJ6D67WW.js.map → context-retriever-EMVN6NNW.js.map} +0 -0
  105. /package/dist/{doctor-deep-HFJGB7HZ.js.map → doctor-deep-4VYC4ZFD.js.map} +0 -0
  106. /package/dist/{expert-bridge-BSEUAG5B.js.map → expert-bridge-D53IE52J.js.map} +0 -0
  107. /package/dist/{factory-GXAOB66V.js.map → factory-JAVXQI2M.js.map} +0 -0
  108. /package/dist/{factory-SJF3GF6T.js.map → factory-R6WV357Q.js.map} +0 -0
  109. /package/dist/{improvement-review-GCIDNUGA.js.map → improvement-review-MJ6A6HFV.js.map} +0 -0
  110. /package/dist/{init-opencode-QKPN4FQ6.js.map → init-opencode-JAFMTL6D.js.map} +0 -0
  111. /package/dist/{issue-triage-VSLGCWHP.js.map → issue-triage-WJFYACOD.js.map} +0 -0
  112. /package/dist/{pr-reviewer-helpers-X7MU2OUO.js.map → pr-reviewer-helpers-LX46ZNDN.js.map} +0 -0
  113. /package/dist/{registry-command-AQOQHU6R.js.map → registry-command-STRBISOJ.js.map} +0 -0
  114. /package/dist/{repo-security-plan-23K6ZLFD.js.map → repo-security-plan-BAQRQDVT.js.map} +0 -0
  115. /package/dist/{research-helpers-synthesize-OOQHAUON.js.map → research-helpers-synthesize-I7CCPVI5.js.map} +0 -0
  116. /package/dist/{routing-memory-KNXPI7HA.js.map → routing-memory-GASTCLCD.js.map} +0 -0
  117. /package/dist/{session-memory-GVEMAPT3.js.map → session-memory-DMD4LWZF.js.map} +0 -0
  118. /package/dist/{setup-command-ICXDEARW.js.map → setup-command-XBER4WR2.js.map} +0 -0
  119. /package/dist/{setup-config-PYE3DHHH.js.map → setup-config-AVMV3GTY.js.map} +0 -0
  120. /package/dist/{setup-custom-api-Y2MTGAS7.js.map → setup-custom-api-3WRO27ZG.js.map} +0 -0
  121. /package/dist/{tool-memory-PE7RNTVL.js.map → tool-memory-734GCMZM.js.map} +0 -0
  122. /package/dist/{unified-registry-PGK7BFEQ.js.map → unified-registry-STRPR5KB.js.map} +0 -0
  123. /package/dist/{weather-report-KDNG2TKZ.js.map → weather-report-3LMA4ZVW.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli-adapters/cli-to-model-adapter.ts","../src/cli-adapters/model-to-cli-adapter.ts","../src/adapters/claude-adapter.ts","../src/adapters/claude-adapter-types.ts","../src/adapters/claude-adapter-helpers.ts","../src/context/token-counter-helpers.ts","../src/adapters/prompt-utils.ts","../src/security/output-sanitizer.ts","../src/adapters/sdk/sdk-adapter.ts","../src/cli-adapters/cli-detection-cache.ts","../src/adapters/auto-adapter.ts","../src/cli-adapters/subprocess-adapter.ts","../src/cli-adapters/base-adapter.ts","../src/cli-adapters/cli-timeout-helpers.ts","../src/cli-adapters/cli-timeout-profiles.ts","../src/cli-adapters/capacity-tracker.ts","../src/utils/async-utils.ts","../src/cli-adapters/cli-error-helpers.ts","../src/cli-adapters/cli-retry-loop.ts","../src/cli-adapters/subprocess-env.ts","../src/cli-adapters/cli-error-envelope.ts","../src/utils/type-coercion.ts","../src/cli-adapters/parsers/claude-parser.ts","../src/config/models-dev-by-vendor.ts","../src/cli-adapters/adapters/claude-adapter.ts","../src/cli-adapters/adapters/gemini-adapter.ts","../src/cli-adapters/parsers/gemini-parser-resilient-helpers.ts","../src/cli-adapters/parsers/gemini-parser-resilient.ts","../src/cli-adapters/adapters/gemini-adapter-helpers.ts","../src/cli-adapters/adapters/codex-adapter.ts","../src/cli-adapters/parsers/codex-parser.ts","../src/cli-adapters/adapters/codex-adapter-helpers.ts","../src/cli-adapters/adapters/codex-mcp-adapter.ts","../src/cli-adapters/adapters/codex-mcp-adapter-helpers.ts","../src/cli-adapters/adapters/opencode-adapter.ts","../src/cli-adapters/parsers/opencode-parser.ts","../src/config/resolve-live-model.ts","../src/cli/cli-auth-probe.ts","../src/cli-adapters/factory.ts"],"sourcesContent":["/**\n * CLI-to-Model Adapter Bridge\n *\n * Wraps an ICliAdapter to implement IModelAdapter, enabling CLI tools\n * (claude, gemini, codex) to be used where model adapters are expected.\n *\n * @module cli-adapters/cli-to-model-adapter\n */\n\nimport type {\n Result,\n IModelAdapter,\n CompletionRequest,\n CompletionResponse,\n ModelCapability,\n} from '../core/index.js';\nimport { ModelCapability as MC, ok, err, ModelError, ConfigError } from '../core/index.js';\nimport { estimateTokens } from '../core/token-estimator.js';\nimport type { ICliAdapter, CliTask, CliResponse, CliError, ExecutionOptions } from './types.js';\nimport type { StreamChunk } from '../core/types/model.js';\n\n/** Configuration for CliToModelAdapter. */\nexport interface CliToModelAdapterConfig {\n /** Default timeout for CLI calls (ms). Overrides auto-detection. */\n readonly defaultTimeoutMs?: number;\n}\n\n/**\n * Bridge adapter that wraps ICliAdapter to implement IModelAdapter.\n *\n * This enables using CLI tools (claude, gemini, codex) in contexts\n * that expect IModelAdapter.\n *\n * @example\n * ```typescript\n * const cliAdapter = createCliAdapter({ cli: 'claude' });\n * const modelAdapter = new CliToModelAdapter(cliAdapter);\n *\n * // Now use modelAdapter where IModelAdapter is expected\n * const result = await modelAdapter.complete({\n * messages: [{ role: 'user', content: 'Hello!' }],\n * });\n * ```\n */\nexport class CliToModelAdapter implements IModelAdapter {\n readonly providerId: string;\n readonly modelId: string;\n readonly capabilities: readonly ModelCapability[];\n\n private readonly cliAdapter: ICliAdapter;\n private readonly defaultTimeoutMs: number | undefined;\n\n /**\n * Creates a bridge from CLI adapter to model adapter.\n *\n * @param cliAdapter - The CLI adapter to wrap\n * @param config - Optional configuration (e.g. timeout override)\n */\n constructor(cliAdapter: ICliAdapter, config?: CliToModelAdapterConfig) {\n this.cliAdapter = cliAdapter;\n this.defaultTimeoutMs = config?.defaultTimeoutMs;\n this.providerId = `cli-${cliAdapter.name}`;\n this.modelId = cliAdapter.getModelInfo().id;\n this.capabilities = this.deriveCapabilities();\n }\n\n /**\n * Derives ModelCapability from CLI capabilities.\n */\n private deriveCapabilities(): readonly ModelCapability[] {\n const caps: ModelCapability[] = [MC.COMPLETION, MC.TOOL_USE];\n\n // Claude CLI has extended thinking capability\n if (this.cliAdapter.name === 'claude') {\n caps.push(MC.EXTENDED_THINKING);\n }\n\n return caps;\n }\n\n /**\n * Converts CompletionRequest to CliTask.\n */\n private toCliTask(request: CompletionRequest): CliTask {\n // Build content from messages\n const content = request.messages\n .map((msg) => {\n const text =\n typeof msg.content === 'string'\n ? msg.content\n : msg.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('\\n');\n return `[${msg.role}]: ${text}`;\n })\n .join('\\n\\n');\n\n // Build task with conditional optional properties\n const task: CliTask = { content };\n\n if (request.systemPrompt !== undefined) {\n (task as { systemPrompt: string }).systemPrompt = request.systemPrompt;\n }\n if (request.maxTokens !== undefined) {\n (task as { maxTokens: number }).maxTokens = request.maxTokens;\n }\n\n return task;\n }\n\n /**\n * Converts CliResponse to CompletionResponse.\n */\n private toCompletionResponse(response: CliResponse): CompletionResponse {\n return {\n content: [{ type: 'text', text: response.text }],\n usage: {\n inputTokens: response.usage?.inputTokens ?? 0,\n outputTokens: response.usage?.outputTokens ?? 0,\n totalTokens: response.usage?.totalTokens ?? 0,\n },\n stopReason: 'end_turn',\n model: response.model ?? this.modelId,\n };\n }\n\n /**\n * Converts CliError to ModelError.\n */\n private toModelError(cliError: CliError): ModelError {\n const options = cliError.cause !== undefined ? { cause: cliError.cause } : {};\n return new ModelError(cliError.message, options);\n }\n\n /**\n * Send a completion request via CLI.\n */\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n const task = this.toCliTask(request);\n // Per-request timeout (#3304) takes precedence over the construction-time\n // default, so a long-budget caller (e.g. a consensus vote) isn't cut off by\n // the adapter's shorter standard CLI timeout.\n const effectiveTimeoutMs = request.timeoutMs ?? this.defaultTimeoutMs;\n const opts: ExecutionOptions | undefined =\n effectiveTimeoutMs !== undefined ? { timeoutMs: effectiveTimeoutMs } : undefined;\n const result = await this.cliAdapter.execute(task, opts);\n\n if (!result.ok) {\n return err(this.toModelError(result.error));\n }\n\n return ok(this.toCompletionResponse(result.value));\n }\n\n /**\n * Streaming is not supported via CLI adapters.\n * Falls back to non-streaming and yields single chunk.\n */\n async *stream(request: CompletionRequest): AsyncIterable<StreamChunk> {\n const result = await this.complete(request);\n\n if (!result.ok) {\n throw result.error;\n }\n\n const response = result.value;\n\n yield { type: 'message_start', message: { model: response.model } };\n\n yield {\n type: 'content_block_start',\n index: 0,\n contentBlock: response.content[0] ?? { type: 'text', text: '' },\n };\n\n const firstBlock = response.content[0];\n const text = firstBlock?.type === 'text' ? firstBlock.text : '';\n yield { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text } };\n\n yield { type: 'content_block_stop', index: 0 };\n\n yield {\n type: 'message_delta',\n delta: { stop_reason: response.stopReason },\n usage: response.usage,\n };\n\n yield { type: 'message_stop' };\n }\n\n /**\n * Token count via canonical estimator (DRY consolidation Issue #1596).\n */\n countTokens(text: string): Promise<number> {\n return Promise.resolve(estimateTokens(text));\n }\n\n /**\n * Validate configuration by running health check.\n */\n validateConfig(): Result<void, ConfigError> {\n // CLI adapters validate via health check\n return ok(undefined);\n }\n\n /**\n * Initialize the underlying CLI adapter.\n */\n async initialize(): Promise<void> {\n await this.cliAdapter.initialize();\n }\n\n /**\n * Dispose the underlying CLI adapter.\n */\n async dispose(): Promise<void> {\n await this.cliAdapter.dispose();\n }\n}\n\n/**\n * Creates a model adapter from a CLI adapter.\n *\n * @param cliAdapter - The CLI adapter to wrap\n * @returns IModelAdapter implementation\n */\nexport function createCliToModelAdapter(\n cliAdapter: ICliAdapter,\n config?: CliToModelAdapterConfig\n): CliToModelAdapter {\n return new CliToModelAdapter(cliAdapter, config);\n}\n","/**\n * Model-to-CLI Adapter Bridge (#3422)\n *\n * The inverse of {@link createCliToModelAdapter}: wraps an `IModelAdapter`\n * (direct-API adapter — Anthropic/OpenAI/Google/custom-OpenAI) to implement\n * `ICliAdapter`, so a CompositeRouter — which operates on `Map<_, ICliAdapter>`\n * — can route to API adapters and record their bandit outcomes on a *distinct*\n * arm (epic #3317 step 1, Option C). The routing arm id is the Map key\n * (`api:<vendor>`), kept separate from this adapter's display `name` (a CLI\n * slot), so CLI and API telemetry are never merged.\n *\n * @module cli-adapters/model-to-cli-adapter\n */\n\nimport type {\n Result,\n IModelAdapter,\n CompletionRequest,\n CompletionResponse,\n} from '../core/index.js';\nimport { ok, err, ModelError } from '../core/index.js';\nimport { FALLBACK_CONTEXT_WINDOW } from '../config/model-config-helpers.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport type {\n ICliAdapter,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n CliModelInfo,\n CliName,\n CliTransport,\n CapabilityProfile,\n ExecutionOptions,\n ModelInfo,\n HealthStatus,\n CapacityStatus,\n} from './types.js';\n\n/** Configuration for {@link ModelToCliAdapter}. */\nexport interface ModelToCliAdapterConfig {\n /**\n * Display CLI slot for attribution/`getModelInfo` (e.g. `claude` for the\n * Anthropic API). This is NOT the routing arm id — the router indexes arms by\n * the adapter Map key (`api:<vendor>`), so the display name can be the slot\n * without merging CLI and API telemetry.\n */\n readonly name: CliName;\n /**\n * Routing capability profile (TOPSIS/preference scoring). Supply the\n * display slot's registry profile; falls back to a neutral mid profile.\n */\n readonly capabilities?: CapabilityProfile;\n}\n\n/** Default context window when the model adapter exposes no capability hint. */\nconst DEFAULT_CONTEXT_WINDOW = FALLBACK_CONTEXT_WINDOW;\n\n/** Neutral mid capability profile used when the caller supplies none. */\nconst NEUTRAL_CAPABILITIES: CapabilityProfile = {\n reasoning: 7,\n contextWindow: DEFAULT_CONTEXT_WINDOW,\n codeGeneration: 7,\n speed: 7,\n cost: 5,\n};\n\n/** Direct-API calls are outbound requests; tag them as the subprocess-style transport. */\nconst API_TRANSPORT: CliTransport = 'subprocess';\n\n/**\n * Bridge adapter that wraps `IModelAdapter` to implement `ICliAdapter`.\n */\nexport class ModelToCliAdapter implements ICliAdapter {\n readonly name: CliName;\n readonly transport: CliTransport = API_TRANSPORT;\n readonly capabilities: CapabilityProfile;\n\n private readonly modelAdapter: IModelAdapter;\n\n constructor(modelAdapter: IModelAdapter, config: ModelToCliAdapterConfig) {\n this.modelAdapter = modelAdapter;\n this.name = config.name;\n this.capabilities = config.capabilities ?? NEUTRAL_CAPABILITIES;\n }\n\n /** Build a single-turn CompletionRequest from a CliTask. */\n private toCompletionRequest(task: CliTask, options?: ExecutionOptions): CompletionRequest {\n const request: CompletionRequest = {\n messages: [{ role: 'user', content: task.content }],\n };\n if (task.systemPrompt !== undefined) {\n (request as { systemPrompt: string }).systemPrompt = task.systemPrompt;\n }\n if (task.maxTokens !== undefined) {\n (request as { maxTokens: number }).maxTokens = task.maxTokens;\n }\n if (options?.timeoutMs !== undefined) {\n (request as { timeoutMs: number }).timeoutMs = options.timeoutMs;\n }\n return request;\n }\n\n /** Flatten a CompletionResponse's content blocks to plain text. */\n private toText(response: CompletionResponse): string {\n return response.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('\\n');\n }\n\n /** Convert a CompletionResponse to a CliResponse. */\n private toCliResponse(response: CompletionResponse): CliResponse {\n return {\n text: this.toText(response),\n usage: {\n inputTokens: response.usage.inputTokens,\n outputTokens: response.usage.outputTokens,\n totalTokens: response.usage.totalTokens,\n },\n model: response.model,\n };\n }\n\n /**\n * Convert a ModelError to a CliError. Rate-limit text → RATE_LIMITED\n * (retryable); everything else → EXECUTION_ERROR (non-retryable) so the\n * routing/circuit layers see a real, typed failure.\n */\n private toCliError(error: ModelError): CliError {\n const rateLimited = isRateLimitText(error.message);\n const code: CliErrorCode = rateLimited ? 'RATE_LIMITED' : 'EXECUTION_ERROR';\n const base: CliError = {\n code,\n message: error.message,\n cli: this.name,\n retryable: rateLimited,\n };\n return error.cause instanceof Error ? { ...base, cause: error.cause } : base;\n }\n\n async execute(task: CliTask, options?: ExecutionOptions): Promise<Result<CliResponse, CliError>> {\n const result = await this.modelAdapter.complete(this.toCompletionRequest(task, options));\n if (!result.ok) {\n return err(this.toCliError(result.error));\n }\n return ok(this.toCliResponse(result.value));\n }\n\n /** Health is derived from the model adapter's config validation. */\n async healthCheck(): Promise<HealthStatus> {\n const valid = this.modelAdapter.validateConfig();\n return Promise.resolve({\n healthy: valid.ok,\n version: 'api',\n versionStatus: 'supported',\n lastChecked: new Date(0),\n ...(valid.ok ? {} : { message: valid.error.message }),\n });\n }\n\n /**\n * API adapters don't expose subprocess-style rate windows; report\n * non-exhausted capacity. Real rate-limit signals surface via execute()'s\n * RATE_LIMITED error, which the resilience layer acts on.\n */\n getCapacity(): Promise<CapacityStatus> {\n return Promise.resolve({\n remainingTokens: Number.POSITIVE_INFINITY,\n remainingRequests: Number.POSITIVE_INFINITY,\n resetTime: new Date(0),\n utilizationPercent: 0,\n exhausted: false,\n });\n }\n\n getVersion(): Promise<string> {\n return Promise.resolve('api');\n }\n\n getModelInfo(): ModelInfo {\n return {\n id: this.modelAdapter.modelId,\n name: this.modelAdapter.modelId,\n contextWindow: DEFAULT_CONTEXT_WINDOW,\n };\n }\n\n /** Delegate to the model adapter's listModels surface when present (#2529). */\n async listModels(): Promise<readonly CliModelInfo[]> {\n if (this.modelAdapter.listModels === undefined) return [];\n const models = await this.modelAdapter.listModels();\n return models.map((m) => ({\n id: m.id,\n ...(m.ownedBy !== undefined ? { provider: m.ownedBy } : {}),\n }));\n }\n\n initialize(): Promise<void> {\n return Promise.resolve();\n }\n\n dispose(): Promise<void> {\n return Promise.resolve();\n }\n}\n\n/** Creates an ICliAdapter from an IModelAdapter (direct-API adapter). */\nexport function createModelToCliAdapter(\n modelAdapter: IModelAdapter,\n config: ModelToCliAdapterConfig\n): ModelToCliAdapter {\n return new ModelToCliAdapter(modelAdapter, config);\n}\n","/**\n * nexus-agents/adapters - Claude/Anthropic Model Adapter\n *\n * Adapter for Anthropic's Claude models (claude-opus-4, claude-sonnet-4, claude-haiku-3).\n * Implements the IModelAdapter interface with streaming support, rate limiting,\n * and proper error handling.\n *\n * Verified 2026-01-03: @anthropic-ai/sdk@0.71.2 is current stable\n * (Source: npm registry)\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport type { MessageStreamEvent } from '@anthropic-ai/sdk/resources/messages';\nimport type {\n Result,\n CompletionRequest,\n CompletionResponse,\n ModelMetadata,\n StreamChunk,\n ContentBlock,\n TokenUsage,\n} from '../core/index.js';\nimport { ok, err, ModelError, ConfigError, getTokenEstimator } from '../core/index.js';\nimport {\n BaseAdapter,\n type BaseAdapterConfig,\n requireApiKey,\n validateApiKeyPresence,\n} from './base-adapter.js';\nimport { createStream } from './streaming.js';\nimport type { ClaudeAdapterConfig } from './claude-adapter-types.js';\nimport { DEFAULT_MAX_TOKENS } from './claude-adapter-types.js';\nimport {\n mapStopReason,\n mapContentBlock,\n mapMessage,\n mapTool,\n resolveModelId,\n getModelCapabilities,\n forcesResponseTool,\n buildRespondTool,\n mapResponseWithRespondTool,\n RESPOND_TOOL_NAME,\n} from './claude-adapter-helpers.js';\nimport { extractRequestSystemPrompt } from './prompt-utils.js';\nimport { planOptionalParams, type DroppedParam } from './optional-params.js';\n\n// Re-export types and constants for backward compatibility\nexport type { ClaudeAdapterConfig } from './claude-adapter-types.js';\nexport { CLAUDE_MODELS, CLAUDE_MODEL_ALIASES } from './claude-adapter-types.js';\n\n/**\n * Claude/Anthropic model adapter.\n *\n * Provides a unified interface for interacting with Anthropic's Claude models.\n * Supports completion, streaming, tool use, and vision capabilities.\n *\n * @example\n * ```typescript\n * const adapter = new ClaudeAdapter({\n * modelId: 'claude-sonnet-4',\n * apiKey: process.env.ANTHROPIC_API_KEY,\n * });\n *\n * const result = await adapter.complete({\n * messages: [{ role: 'user', content: 'Hello!' }],\n * maxTokens: 1024,\n * });\n *\n * if (result.ok) {\n * console.log(result.value.content);\n * }\n * ```\n */\nexport class ClaudeAdapter extends BaseAdapter {\n private readonly client: Anthropic;\n private readonly resolvedModelId: string;\n\n /**\n * Creates a new ClaudeAdapter instance.\n *\n * @param config - Claude adapter configuration\n * @throws {ConfigError} If API key is missing\n */\n constructor(config: ClaudeAdapterConfig) {\n const resolvedModelId = resolveModelId(config.modelId);\n\n // Build baseConfig conditionally to satisfy exactOptionalPropertyTypes\n const baseConfig: BaseAdapterConfig = {\n providerId: 'anthropic',\n modelId: resolvedModelId,\n capabilities: getModelCapabilities(config.modelId),\n apiKey: config.apiKey,\n };\n\n // Only set optional properties if defined\n if (config.baseUrl !== undefined) {\n baseConfig.baseUrl = config.baseUrl;\n }\n if (config.timeout !== undefined) {\n baseConfig.timeout = config.timeout;\n }\n if (config.maxRetries !== undefined) {\n baseConfig.maxRetries = config.maxRetries;\n }\n\n super(baseConfig);\n\n this.resolvedModelId = resolvedModelId;\n\n // Validate API key presence\n requireApiKey(config.apiKey, 'Anthropic', config.modelId);\n\n // Create Anthropic client\n this.client = new Anthropic({\n apiKey: config.apiKey,\n baseURL: config.baseUrl,\n timeout: config.timeout,\n maxRetries: config.maxRetries ?? 2,\n });\n }\n\n /**\n * Validates adapter configuration.\n * Extends base validation with Claude-specific checks.\n */\n override validateConfig(): Result<void, ConfigError> {\n const baseResult = super.validateConfig();\n if (!baseResult.ok) {\n return baseResult;\n }\n\n // Validate API key is present\n const keyResult = validateApiKeyPresence(this.config.apiKey, this.providerId, this.modelId);\n if (!keyResult.ok) return keyResult;\n\n return ok(undefined);\n }\n\n /**\n * Send a completion request to Claude.\n *\n * @param request - The completion request\n * @returns Result with response or ModelError\n */\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n this.logRequest(request);\n\n try {\n const response = await this.executeCompletion(request);\n this.logResponse(response);\n return ok(response);\n } catch (error) {\n return err(this.transformError(error));\n }\n }\n\n /**\n * Stream a completion request from Claude.\n *\n * @param request - The completion request\n * @yields StreamChunk objects as they arrive\n */\n async *stream(request: CompletionRequest): AsyncIterable<StreamChunk> {\n this.logRequest(request);\n\n const [controller, iterable] = createStream<StreamChunk>();\n\n // Start streaming in the background\n this.executeStream(request, controller).catch((error: unknown) => {\n const modelError = this.transformError(error);\n controller.error(modelError);\n });\n\n yield* iterable;\n }\n\n /**\n * Count tokens in text using Claude-specific estimation.\n *\n * Claude uses a custom tokenizer. This provides a more accurate estimate\n * than the base adapter's generic calculation.\n *\n * @param text - Text to count tokens for\n * @returns Approximate token count\n */\n override countTokens(text: string): Promise<number> {\n // Use unified TokenEstimator with Claude-specific ratio (~3.5 chars/token)\n return Promise.resolve(getTokenEstimator().estimateText(text, 'claude'));\n }\n\n /**\n * Executes the completion request against the Anthropic API.\n */\n private async executeCompletion(request: CompletionRequest): Promise<CompletionResponse> {\n const { params, dropped } = this.buildRequestParams(request);\n // #3036: forward AbortSignal into the SDK so withWatchdog timeouts\n // actually cancel the in-flight HTTP request instead of leaking it\n // past the Promise.race boundary. Branch on signal presence — vitest\n // 4 `toHaveBeenCalledWith(params)` treats `(params, undefined)` as\n // a distinct call shape from `(params)`, so passing the second arg\n // unconditionally would break every callsite-shape assertion.\n const response =\n request.signal !== undefined\n ? await this.client.messages.create(params, { signal: request.signal })\n : await this.client.messages.create(params);\n\n // #3433: when we forced a `respond` tool to satisfy a non-text\n // responseFormat, surface its structured input as a text block so the\n // caller's JSON parser keeps working unchanged.\n // #4069: surface params dropped by the seam (e.g. temperature) as warnings.\n return this.mapResponse(response, forcesResponseTool(request), dropped);\n }\n\n /**\n * Executes streaming completion and pushes chunks to the controller.\n */\n private async executeStream(\n request: CompletionRequest,\n controller: {\n push: (chunk: StreamChunk) => Result<void, Error>;\n complete: () => void;\n error: (error: Error) => void;\n }\n ): Promise<void> {\n try {\n const { params } = this.buildRequestParams(request);\n const stream = this.client.messages.stream(params);\n\n for await (const event of stream) {\n const chunk = this.mapStreamEvent(event);\n if (chunk) {\n controller.push(chunk);\n }\n }\n\n controller.complete();\n } catch (error) {\n const modelError = this.transformError(error);\n controller.error(modelError);\n }\n }\n\n /**\n * Builds Anthropic API request parameters from our CompletionRequest.\n */\n private buildRequestParams(request: CompletionRequest): {\n params: Anthropic.MessageCreateParamsNonStreaming;\n dropped: readonly DroppedParam[];\n } {\n // Filter out system messages and map the rest\n const messages = request.messages.filter((m) => m.role !== 'system').map(mapMessage);\n\n const params: Anthropic.MessageCreateParamsNonStreaming = {\n model: this.resolvedModelId,\n messages,\n max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,\n };\n\n // Add system prompt if provided\n const systemPrompt = extractRequestSystemPrompt(request);\n if (systemPrompt !== undefined) {\n params.system = systemPrompt;\n }\n\n // Apply optional parameters; the seam reports any params it dropped (#4069).\n const dropped = this.applyOptionalParams(params, request);\n\n return { params, dropped };\n }\n\n /**\n * Applies optional parameters to the request params.\n *\n * @returns the params the seam dropped (#4069) — surfaced as response warnings.\n */\n private applyOptionalParams(\n params: Anthropic.MessageCreateParamsNonStreaming,\n request: CompletionRequest\n ): readonly DroppedParam[] {\n // #4068: the temperature drop-decision (#4061: Claude after Opus 4.6 rejects\n // any non-1.0 temperature with a 400; omit it — 1.0 is the API default, so\n // omitting is equivalent) is centralized in the shared planOptionalParams seam.\n const plan = planOptionalParams(request, this.resolvedModelId);\n if (plan.temperature !== undefined) {\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- still valid for older Anthropic models (≤ Opus 4.6) and value 1.0; the seam gates on temperatureUnsupportedForModel\n params.temperature = plan.temperature;\n }\n\n if (request.stop !== undefined && request.stop.length > 0) {\n params.stop_sequences = request.stop;\n }\n\n if (request.tools !== undefined && request.tools.length > 0) {\n params.tools = request.tools.map(mapTool);\n }\n\n // #3433: honor responseFormat via a forced `respond` tool_use. Anthropic\n // has no native JSON mode, so we register a synthetic tool whose\n // input_schema is the requested schema and force the model to call it.\n // The caller-supplied tools (above) are preserved — `respond` is merged\n // in, never clobbered. We only set tool_choice when the caller didn't\n // already specify their own tool usage intent.\n if (forcesResponseTool(request)) {\n const respondTool = buildRespondTool(request.responseFormat);\n params.tools = [...(params.tools ?? []), respondTool];\n params.tool_choice = { type: 'tool', name: RESPOND_TOOL_NAME };\n }\n\n return plan.dropped;\n }\n\n /**\n * Maps Anthropic API response to our CompletionResponse format.\n */\n private mapResponse(\n response: Anthropic.Message,\n surfaceRespondTool = false,\n dropped: readonly DroppedParam[] = []\n ): CompletionResponse {\n const content: ContentBlock[] = surfaceRespondTool\n ? mapResponseWithRespondTool(response.content)\n : response.content.map(mapContentBlock);\n\n const usage: TokenUsage = {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\n };\n\n return {\n content,\n usage,\n stopReason: mapStopReason(response.stop_reason),\n model: response.model,\n // #4069: surface dropped params (e.g. an omitted temperature) so the caller\n // can see a behavioral param had no effect. Omitted entirely when nothing\n // was dropped (exactOptionalPropertyTypes).\n ...(dropped.length > 0 ? { warnings: dropped } : {}),\n };\n }\n\n /**\n * Maps Anthropic stream events to our StreamChunk format.\n */\n private mapStreamEvent(event: MessageStreamEvent): StreamChunk | null {\n switch (event.type) {\n case 'message_start':\n return {\n type: 'message_start',\n message: { model: event.message.model },\n };\n\n case 'content_block_start':\n return {\n type: 'content_block_start',\n index: event.index,\n contentBlock: mapContentBlock(event.content_block),\n };\n\n case 'content_block_delta':\n if (event.delta.type === 'text_delta') {\n return {\n type: 'content_block_delta',\n index: event.index,\n delta: { type: 'text_delta', text: event.delta.text },\n };\n }\n return null;\n\n case 'content_block_stop':\n return {\n type: 'content_block_stop',\n index: event.index,\n };\n\n case 'message_delta':\n return {\n type: 'message_delta',\n delta: { stop_reason: mapStopReason(event.delta.stop_reason ?? null) },\n usage: {\n inputTokens: 0, // Not available in delta\n outputTokens: event.usage.output_tokens,\n totalTokens: event.usage.output_tokens,\n },\n };\n\n case 'message_stop':\n return { type: 'message_stop' };\n\n default:\n return null;\n }\n }\n\n /**\n * (#2540) List models the Anthropic API currently exposes.\n * Wraps `client.models.list()`. Cached for 5 min, in-flight promise\n * shared across concurrent callers, throws on non-2xx so the\n * harness-side identity resolver knows to fall back.\n */\n async listModels(): Promise<readonly ModelMetadata[]> {\n const now = Date.now();\n if (this.modelsCache !== null && now - this.modelsCache.fetchedAt < CLAUDE_LIST_MODELS_TTL_MS) {\n return this.modelsCache.value;\n }\n if (this.modelsInFlight !== null) return this.modelsInFlight;\n const inFlight = this.fetchModels();\n this.modelsInFlight = inFlight;\n try {\n const value = await inFlight;\n this.modelsCache = { value, fetchedAt: Date.now() };\n return value;\n } finally {\n this.modelsInFlight = null;\n }\n }\n\n private modelsCache: { value: readonly ModelMetadata[]; fetchedAt: number } | null = null;\n private modelsInFlight: Promise<readonly ModelMetadata[]> | null = null;\n\n private async fetchModels(): Promise<readonly ModelMetadata[]> {\n const list = await this.client.models.list();\n const out: ModelMetadata[] = [];\n for (const m of list.data) {\n const entry: ModelMetadata = { id: m.id };\n if (typeof m.created_at === 'string') {\n const ts = Date.parse(m.created_at);\n if (!Number.isNaN(ts)) {\n out.push({ ...entry, ownedBy: 'anthropic', createdAt: Math.floor(ts / 1000) });\n continue;\n }\n }\n out.push({ ...entry, ownedBy: 'anthropic' });\n }\n return out;\n }\n}\n\nconst CLAUDE_LIST_MODELS_TTL_MS = 5 * 60 * 1000;\n\n/**\n * Creates a ClaudeAdapter with the specified configuration.\n * Factory function for cleaner API.\n *\n * @param config - Claude adapter configuration\n * @returns A configured ClaudeAdapter instance\n *\n * @example\n * ```typescript\n * const adapter = createClaudeAdapter({\n * modelId: 'claude-sonnet-4',\n * apiKey: process.env.ANTHROPIC_API_KEY!,\n * });\n * ```\n */\nexport function createClaudeAdapter(config: ClaudeAdapterConfig): ClaudeAdapter {\n return new ClaudeAdapter(config);\n}\n","/**\n * nexus-agents/adapters - Claude Adapter Types\n *\n * Type definitions and constants for the Claude/Anthropic adapter.\n *\n * @module adapters/claude-adapter-types\n */\n\nimport { getCliModelName } from '../config/model-config-helpers.js';\n\n/**\n * Supported Claude model identifiers.\n *\n * Derived from `config/in-tree-data.ts` via `getCliModelName()` (which reads\n * the ModelRegistry — see `config/model-registry.ts`). Do not hardcode\n * model-version strings here; update the registry.\n */\nexport const CLAUDE_MODELS = {\n OPUS_4: getCliModelName('claude-opus'),\n SONNET_4: getCliModelName('claude-sonnet'),\n HAIKU_4: getCliModelName('claude-haiku'),\n} as const;\n\n/**\n * Legacy version-suffix aliases mapped to the current registry cliModelName.\n *\n * Values come from `CLAUDE_MODELS` so they stay in sync with the canonical\n * registry. Add legacy entries here, never the version strings themselves.\n */\nexport const CLAUDE_MODEL_ALIASES: Record<string, string> = {\n 'claude-opus-4': CLAUDE_MODELS.OPUS_4,\n 'claude-sonnet-4': CLAUDE_MODELS.SONNET_4,\n 'claude-haiku-4': CLAUDE_MODELS.HAIKU_4,\n // Legacy alias — pre-4.x users routed to the current haiku.\n 'claude-haiku-3': CLAUDE_MODELS.HAIKU_4,\n} as const;\n\n/**\n * Configuration specific to ClaudeAdapter.\n */\nexport interface ClaudeAdapterConfig {\n /** Model ID (e.g., 'claude-sonnet-4' or full model identifier) */\n modelId: string;\n /** API key for Anthropic API (required) */\n apiKey: string;\n /** Base URL for API (optional, defaults to Anthropic's API) */\n baseUrl?: string;\n /** Request timeout in milliseconds (optional) */\n timeout?: number;\n /** Maximum retries for failed requests (optional) */\n maxRetries?: number;\n}\n\n// Note: Token estimation moved to core/token-estimator.ts (unified TokenEstimator)\n\n/**\n * Default maximum tokens for Claude models.\n */\nexport const DEFAULT_MAX_TOKENS = 4096;\n","/**\n * nexus-agents/adapters - Claude Adapter Helpers\n *\n * Helper functions for mapping between nexus-agents types and Anthropic SDK types.\n *\n * @module adapters/claude-adapter-helpers\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport type {\n MessageParam,\n ContentBlock as AnthropicContentBlock,\n} from '@anthropic-ai/sdk/resources/messages';\nimport type {\n ContentBlock,\n Message,\n ToolDefinition,\n StopReason,\n CompletionRequest,\n ResponseFormat,\n} from '../core/index.js';\nimport { ModelCapability } from '../core/index.js';\nimport { getCliModelName, resolveCliAlias } from '../config/model-config-helpers.js';\n\n/**\n * Name of the synthetic tool the adapter forces when a caller requests a\n * structured `responseFormat` (#3433). Anthropic has no native JSON mode, so\n * we model structured output as a forced `tool_use`.\n */\nexport const RESPOND_TOOL_NAME = 'respond';\n\n/**\n * Maps Anthropic stop reasons to our StopReason type.\n */\nexport function mapStopReason(anthropicReason: string | null): StopReason {\n switch (anthropicReason) {\n case 'end_turn':\n return 'end_turn';\n case 'max_tokens':\n return 'max_tokens';\n case 'stop_sequence':\n return 'stop_sequence';\n case 'tool_use':\n return 'tool_use';\n default:\n return 'end_turn';\n }\n}\n\n/**\n * Maps Anthropic content blocks to our ContentBlock type.\n */\nexport function mapContentBlock(block: AnthropicContentBlock): ContentBlock {\n if (block.type === 'text') {\n return { type: 'text', text: block.text };\n }\n if (block.type === 'tool_use') {\n const toolBlock = block;\n return {\n type: 'tool_use',\n id: toolBlock.id,\n name: toolBlock.name,\n input: toolBlock.input,\n };\n }\n // Handle unexpected block types gracefully\n return { type: 'text', text: '' };\n}\n\n/**\n * Maps our Message format to Anthropic's MessageParam format.\n */\nexport function mapMessage(message: Message): MessageParam {\n const role = message.role === 'user' ? 'user' : 'assistant';\n\n if (typeof message.content === 'string') {\n return { role, content: message.content };\n }\n\n // Map content blocks\n const content = message.content.map((block) => {\n if (block.type === 'text') {\n return { type: 'text' as const, text: block.text };\n }\n if (block.type === 'tool_use') {\n return {\n type: 'tool_use' as const,\n id: block.id,\n name: block.name,\n input: block.input,\n };\n }\n if (block.type === 'tool_result') {\n const toolResult: {\n type: 'tool_result';\n tool_use_id: string;\n content: string;\n is_error?: boolean;\n } = {\n type: 'tool_result' as const,\n tool_use_id: block.tool_use_id,\n content: block.content,\n };\n // Only set is_error if explicitly defined (exactOptionalPropertyTypes)\n if (block.is_error !== undefined) {\n toolResult.is_error = block.is_error;\n }\n return toolResult;\n }\n // Image type is the remaining possibility\n // Cast source to match Anthropic's expected type\n return {\n type: 'image' as const,\n source: block.source as Anthropic.ImageBlockParam['source'],\n };\n });\n\n return { role, content };\n}\n\n/**\n * Maps our ToolDefinition to Anthropic's tool format.\n */\nexport function mapTool(tool: ToolDefinition): Anthropic.Tool {\n return {\n name: tool.name,\n description: tool.description,\n input_schema: tool.inputSchema as Anthropic.Tool.InputSchema,\n };\n}\n\n/**\n * Whether this request asks the Claude adapter to produce structured output\n * via a forced `respond` tool_use (#3433). True only when `responseFormat` is\n * present and not the plain `text` form.\n */\nexport function forcesResponseTool(request: CompletionRequest): boolean {\n return request.responseFormat !== undefined && request.responseFormat.type !== 'text';\n}\n\n/**\n * Builds the synthetic `respond` tool for a non-text responseFormat (#3433).\n * For `json_schema` the caller's schema becomes the tool `input_schema`; for\n * `json_object` we use a permissive `{ type: 'object' }` schema.\n */\nexport function buildRespondTool(format: ResponseFormat | undefined): Anthropic.Tool {\n const inputSchema: Record<string, unknown> =\n format?.type === 'json_schema' ? format.schema : { type: 'object' };\n return mapTool({\n name: RESPOND_TOOL_NAME,\n description:\n 'Return the structured response for this request. Call this tool exactly once with the full answer as its arguments.',\n inputSchema,\n });\n}\n\n/**\n * Maps an Anthropic response body when a forced `respond` tool was requested\n * (#3433). If the model emitted a `respond` tool_use block, its `.input` is\n * surfaced as a single JSON `text` block so existing text/JSON parsers keep\n * working unchanged. Otherwise falls back to the standard block mapping.\n */\nexport function mapResponseWithRespondTool(\n blocks: readonly AnthropicContentBlock[]\n): ContentBlock[] {\n const respondBlock = blocks.find(\n (block) => block.type === 'tool_use' && block.name === RESPOND_TOOL_NAME\n );\n if (respondBlock?.type === 'tool_use') {\n return [{ type: 'text', text: JSON.stringify(respondBlock.input) }];\n }\n return blocks.map(mapContentBlock);\n}\n\n/**\n * Resolves a Claude model alias to the full identifier the SDK expects.\n *\n * `resolveCliAlias` consults the canonical registry — both the cliAlias /\n * id columns AND the `aliases` array (#2199 Child 5 migration). Unknown\n * ids pass through (e.g., custom Bedrock identifiers).\n *\n * The canonical model strings live in `config/in-tree-data.ts` and are\n * resolved through the ModelRegistry; this function never holds them\n * directly (issue #2186 Child 1).\n */\nexport function resolveModelId(modelId: string): string {\n const registryId = resolveCliAlias(modelId);\n if (registryId !== undefined) return getCliModelName(registryId);\n return modelId;\n}\n\n/**\n * Determines capabilities based on model ID.\n */\nexport function getModelCapabilities(modelId: string): readonly ModelCapability[] {\n const capabilities: ModelCapability[] = [\n ModelCapability.COMPLETION,\n ModelCapability.STREAMING,\n ModelCapability.TOOL_USE,\n ModelCapability.VISION,\n ];\n\n // Extended thinking is available on Opus and Sonnet 4\n const resolvedId = resolveModelId(modelId);\n if (resolvedId.includes('opus') || resolvedId.includes('sonnet-4')) {\n capabilities.push(ModelCapability.EXTENDED_THINKING);\n }\n\n return capabilities;\n}\n","/**\n * nexus-agents/context - Token Counter Helpers\n *\n * Internal helper functions for token counting.\n *\n * @module context/token-counter-helpers\n */\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport type { Message } from '../core/index.js';\nimport type { TokenCounterProvider } from './token-counter-types.js';\n\n/**\n * Generates a cache key from content.\n */\nexport function generateCacheKey(\n content: string | Message[],\n provider: TokenCounterProvider | 'estimate',\n model?: string\n): string {\n const contentStr = typeof content === 'string' ? content : JSON.stringify(content);\n return `${provider}:${model ?? 'default'}:${contentStr}`;\n}\n\n/**\n * Converts Message[] to Anthropic MessageParam[] format.\n */\nexport function messagesToAnthropicFormat(messages: Message[]): Anthropic.MessageParam[] {\n return messages\n .filter((m) => m.role !== 'system')\n .map((m) => {\n const role = m.role === 'user' ? 'user' : 'assistant';\n if (typeof m.content === 'string') {\n return { role, content: m.content };\n }\n // Map content blocks\n const content = m.content.map((block) => {\n if (block.type === 'text') {\n return { type: 'text' as const, text: block.text };\n }\n if (block.type === 'tool_use') {\n return {\n type: 'tool_use' as const,\n id: block.id,\n name: block.name,\n input: block.input,\n };\n }\n if (block.type === 'tool_result') {\n return {\n type: 'tool_result' as const,\n tool_use_id: block.tool_use_id,\n content: block.content,\n };\n }\n // Image type - handle source type properly\n return {\n type: 'image' as const,\n source: block.source as Anthropic.ImageBlockParam['source'],\n };\n });\n return { role, content };\n });\n}\n\n/**\n * Extracts system prompt from messages if present.\n */\nexport function extractSystemPrompt(messages: Message[]): string | undefined {\n const systemMsg = messages.find((m) => m.role === 'system');\n if (systemMsg === undefined) {\n return undefined;\n }\n if (typeof systemMsg.content === 'string') {\n return systemMsg.content;\n }\n return systemMsg.content\n .filter((b): b is { type: 'text'; text: string } => b.type === 'text')\n .map((b) => b.text)\n .join('\\n');\n}\n","/**\n * Shared prompt extraction utilities for model adapters.\n *\n * Consolidates the duplicated extractSystemPrompt logic from\n * claude-adapter, gemini-adapter, and ollama-adapter into a single\n * implementation.\n *\n * @module adapters/prompt-utils\n * (Source: Issue #1596 — DRY adapter standardization)\n */\n\nimport type { CompletionRequest } from '../core/index.js';\nimport { extractSystemPrompt } from '../context/token-counter-helpers.js';\n\n/**\n * Extracts the system prompt from a CompletionRequest.\n *\n * Checks the explicit `systemPrompt` field first, then falls back to\n * searching the messages array for a system-role message.\n */\nexport function extractRequestSystemPrompt(request: CompletionRequest): string | undefined {\n if (request.systemPrompt !== undefined && request.systemPrompt !== '') {\n return request.systemPrompt;\n }\n return extractSystemPrompt(request.messages);\n}\n","/**\n * nexus-agents/security - Output Sanitizer\n *\n * Redacts API keys and tokens from CLI subprocess stdout/stderr\n * before the output is returned, logged, or traced.\n *\n * @module security/output-sanitizer\n * (Source: Issue #1597 — subprocess output scrubbing gap)\n */\n\n/** Placeholder text that replaces redacted keys. */\nexport const REDACTED_KEY_PLACEHOLDER = '[REDACTED_KEY]';\n\n/**\n * Patterns matching known API key formats.\n *\n * Order matters: more-specific prefixes (sk-ant-, sk-proj-) come before\n * the generic sk-* pattern so they match first.\n *\n * Each pattern requires a minimum token length after the prefix to avoid\n * false positives on short strings like \"sk-ab\".\n */\nconst KEY_PATTERNS: readonly RegExp[] = [\n // Anthropic: sk-ant-api03-... (at least 20 chars after prefix)\n /sk-ant-[A-Za-z0-9_-]{20,}/g,\n // OpenAI project: sk-proj-... (at least 20 chars after prefix)\n /sk-proj-[A-Za-z0-9_-]{20,}/g,\n // Generic OpenAI: sk-... (at least 20 chars after prefix)\n /sk-[A-Za-z0-9_-]{20,}/g,\n // Google AI / Gemini: AIzaSy... (at least 30 chars total)\n /AIzaSy[A-Za-z0-9_-]{24,}/g,\n // GitHub PAT: ghp_...\n /ghp_[A-Za-z0-9]{20,}/g,\n // GitHub OAuth: gho_...\n /gho_[A-Za-z0-9]{20,}/g,\n // GitLab PAT: glpat-...\n /glpat-[A-Za-z0-9_-]{10,}/g,\n // npm token: npm_...\n /npm_[A-Za-z0-9]{20,}/g,\n // PyPI token: pypi-...\n /pypi-[A-Za-z0-9_-]{20,}/g,\n];\n\n/**\n * Redacts known API key patterns from a string.\n *\n * Designed to be called on subprocess stdout/stderr before the output\n * is returned to callers, written to logs, or included in trace data.\n *\n * @param text - Raw subprocess output\n * @returns The same text with API keys replaced by [REDACTED_KEY]\n */\nexport function sanitizeOutput(text: string): string {\n if (text === '') return text;\n\n let result = text;\n for (const pattern of KEY_PATTERNS) {\n // Reset lastIndex for global regex reuse\n pattern.lastIndex = 0;\n result = result.replace(pattern, REDACTED_KEY_PLACEHOLDER);\n }\n return result;\n}\n","/**\n * nexus-agents/adapters/sdk - Base SDK Adapter\n *\n * Implements IModelAdapter using the Vercel AI SDK's generateText/streamText\n * APIs. Provides a unified adapter for any AI SDK-supported provider.\n *\n * @module adapters/sdk/sdk-adapter\n * (Source: Issue #1123 — AI SDK provider layer)\n */\n\nimport type {\n CompletionRequest,\n CompletionResponse,\n ContentBlock,\n ResponseFormat,\n StreamChunk,\n Result,\n ILogger,\n} from '../../core/index.js';\nimport {\n ok,\n ModelError,\n ModelCapability,\n createLogger,\n getErrorMessage,\n} from '../../core/index.js';\nimport { BaseAdapter, AdapterModelError } from '../base-adapter.js';\nimport { ErrorCode } from '../../core/index.js';\nimport { isRateLimitLikeError } from '../rate-limit-detector.js';\nimport { sanitizeOutput } from '../../security/output-sanitizer.js';\nimport type { SdkAdapterConfig, SdkProviderId } from './types.js';\nimport { PROVIDER_ENV_KEYS, CUSTOM_API_BASE_URL_ENV } from './types.js';\nimport { planOptionalParams, type DroppedParam } from '../optional-params.js';\nimport {\n validateCustomApiBaseUrl,\n assertCustomApiHostResolvesPublic,\n} from './custom-api-validation.js';\n\n/** Minimal AI SDK model interface (duck-typed for optional dependency). */\ninterface AiSdkModel {\n readonly modelId: string;\n}\n\n/** AI SDK generateText result shape (duck-typed). */\ninterface GenerateTextResult {\n text: string;\n finishReason: string;\n usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n totalTokens: number | undefined;\n };\n response: { modelId: string };\n}\n\n/** AI SDK streamText result shape (duck-typed). */\ninterface StreamTextResult {\n textStream: AsyncIterable<string>;\n}\n\n/** AI SDK generateObject result shape (duck-typed). */\ninterface GenerateObjectResult {\n object: unknown;\n finishReason: string;\n usage: {\n inputTokens: number | undefined;\n outputTokens: number | undefined;\n totalTokens: number | undefined;\n };\n response: { modelId: string };\n}\n\n/** Opaque schema handle returned by the AI SDK `jsonSchema` helper. */\ntype AiSdkSchema = unknown;\n\n/** Function signatures for AI SDK entry points (loaded dynamically). */\ninterface AiSdkFunctions {\n generateText: (options: Record<string, unknown>) => Promise<GenerateTextResult>;\n streamText: (options: Record<string, unknown>) => StreamTextResult;\n generateObject: (options: Record<string, unknown>) => Promise<GenerateObjectResult>;\n jsonSchema: (schema: Record<string, unknown>) => AiSdkSchema;\n}\n\n/** AI SDK provider factory: creates a provider instance that is callable as a model factory. */\ntype ProviderFactory = (opts: Record<string, unknown>) => ProviderInstance;\n\n/** AI SDK provider instance: callable to create a model. */\ntype ProviderInstance = (id: string) => AiSdkModel;\n\n/**\n * Extracts a named provider factory from a dynamically-imported AI SDK module.\n *\n * AI SDK provider modules export factory functions (e.g., createAnthropic, createOpenAI)\n * that return callable provider instances. Since these are optional peer dependencies\n * loaded via dynamic import, we validate the shape at runtime rather than relying on\n * compile-time types.\n */\nfunction extractProviderFactory(\n mod: Record<string, unknown>,\n factoryName: string\n): ProviderFactory {\n const factory = mod[factoryName];\n if (typeof factory !== 'function') {\n throw new Error(`AI SDK module missing expected export: ${factoryName}`);\n }\n return factory as ProviderFactory;\n}\n\n/**\n * Validates a dynamically-imported AI SDK module has the expected generateText/streamText exports.\n *\n * The 'ai' package is an optional peer dependency loaded via dynamic import.\n * We validate the shape at runtime to avoid unsafe casts.\n */\n/**\n * Validate that a dynamically-imported `ai` module exposes the functions this\n * adapter needs; throw a clear, per-export error otherwise. Exported for direct\n * unit testing (#3449) so the \"missing export\" cases don't need a global module\n * mock (`vi.doMock`/`resetModules`), whose state leaked across parallel tests.\n */\nexport function extractAiSdkFunctions(mod: Record<string, unknown>): AiSdkFunctions {\n const generateText = mod['generateText'];\n const streamText = mod['streamText'];\n const generateObject = mod['generateObject'];\n const jsonSchema = mod['jsonSchema'];\n if (typeof generateText !== 'function') {\n throw new Error(\"AI SDK module missing expected export: 'generateText'\");\n }\n if (typeof streamText !== 'function') {\n throw new Error(\"AI SDK module missing expected export: 'streamText'\");\n }\n // #3433: structured output routes through generateObject + jsonSchema.\n if (typeof generateObject !== 'function') {\n throw new Error(\"AI SDK module missing expected export: 'generateObject'\");\n }\n if (typeof jsonSchema !== 'function') {\n throw new Error(\"AI SDK module missing expected export: 'jsonSchema'\");\n }\n return {\n generateText: generateText as AiSdkFunctions['generateText'],\n streamText: streamText as AiSdkFunctions['streamText'],\n generateObject: generateObject as AiSdkFunctions['generateObject'],\n jsonSchema: jsonSchema as AiSdkFunctions['jsonSchema'],\n };\n}\n\n/**\n * Runtime-validates the duck-typed `generateObject` result shape (#3433).\n *\n * `generateObject` comes from the optional `ai` peer dependency, so its\n * result is `unknown` to us. We narrow it here rather than casting, so a\n * shape change in the SDK surfaces as a clear error instead of a silent\n * `undefined` downstream.\n */\nfunction isGenerateObjectResult(value: unknown): value is GenerateObjectResult {\n if (typeof value !== 'object' || value === null) return false;\n const record = value as Record<string, unknown>;\n if (!('object' in record)) return false;\n if (typeof record['finishReason'] !== 'string') return false;\n const usage = record['usage'];\n if (typeof usage !== 'object' || usage === null) return false;\n const response = record['response'];\n if (typeof response !== 'object' || response === null) return false;\n if (typeof (response as Record<string, unknown>)['modelId'] !== 'string') return false;\n return true;\n}\n\n/**\n * Resolves the API key for a given provider.\n * Priority: explicit config > environment variable.\n */\nfunction resolveApiKey(providerId: SdkProviderId, configKey?: string): string | undefined {\n if (configKey !== undefined) return configKey;\n const envVar = PROVIDER_ENV_KEYS[providerId];\n return process.env[envVar];\n}\n\n/**\n * For the `custom-openai` provider only: resolve the base URL (config >\n * env) and run it through the SSRF guard. Returns `undefined` for every\n * other provider (the AI SDK's built-in factories handle their own\n * endpoints). Throws `ConfigError` at construction time for invalid\n * custom-openai setups — catching misconfiguration immediately rather\n * than on the first request.\n */\nfunction resolveAndValidateCustomBaseUrl(config: SdkAdapterConfig): string | undefined {\n if (config.providerId !== 'custom-openai') return undefined;\n const raw = config.baseUrl ?? process.env[CUSTOM_API_BASE_URL_ENV];\n const validated = validateCustomApiBaseUrl(raw);\n if (!validated.ok) throw validated.error;\n return validated.value.toString();\n}\n\n/**\n * Maps AI SDK finish reasons to our StopReason type.\n */\nfunction mapFinishReason(reason: string): CompletionResponse['stopReason'] {\n switch (reason) {\n case 'stop':\n case 'end-turn':\n return 'end_turn';\n case 'length':\n return 'max_tokens';\n case 'tool-calls':\n return 'tool_use';\n default:\n return 'end_turn';\n }\n}\n\n/**\n * Categorizes an error into an ErrorCode for the circuit breaker.\n */\nfunction categorizeError(error: unknown): ErrorCode {\n if (isRateLimitLikeError(error)) {\n return ErrorCode.MODEL_RATE_LIMITED;\n }\n const message = getErrorMessage(error).toLowerCase();\n if (message.includes('timeout') || message.includes('timed out')) {\n return ErrorCode.MODEL_TIMEOUT;\n }\n if (message.includes('401') || message.includes('unauthorized') || message.includes('api key')) {\n return ErrorCode.CONFIG_INVALID;\n }\n return ErrorCode.MODEL_ERROR;\n}\n\n/**\n * AI SDK adapter implementing IModelAdapter.\n *\n * Uses Vercel AI SDK (npm: ai) for model interaction instead of\n * CLI subprocess spawning. Supports any provider that has an\n * `@ai-sdk/*` package.\n */\nexport class SdkAdapter extends BaseAdapter {\n private readonly sdkProviderId: SdkProviderId;\n private model: AiSdkModel | undefined;\n private sdkFunctions: AiSdkFunctions | undefined;\n private readonly sdkConfig: SdkAdapterConfig;\n /** Validated base URL for custom-openai provider; undefined for built-ins. */\n private readonly customBaseUrl: string | undefined;\n /** Inflight init promise for coalescing concurrent calls (Issue #1438). */\n private initPromise: Promise<void> | undefined;\n /**\n * Cached result of the DNS-resolve-time SSRF check for custom-openai\n * (#3426). Resolved once on first init so we don't re-resolve the gateway\n * hostname on every request. `undefined` until the check has run.\n */\n private resolveSsrfChecked = false;\n\n constructor(config: SdkAdapterConfig, logger?: ILogger) {\n const apiKey = resolveApiKey(config.providerId, config.apiKey);\n super({\n providerId: `sdk-${config.providerId}`,\n modelId: config.modelId,\n capabilities: [ModelCapability.COMPLETION, ModelCapability.STREAMING],\n logger: logger ?? createLogger({ adapter: `sdk-${config.providerId}` }),\n ...(apiKey !== undefined ? { apiKey } : {}),\n ...(config.timeout !== undefined ? { timeout: config.timeout } : {}),\n ...(config.maxRetries !== undefined ? { maxRetries: config.maxRetries } : {}),\n });\n this.sdkProviderId = config.providerId;\n this.sdkConfig = config;\n this.customBaseUrl = resolveAndValidateCustomBaseUrl(config);\n }\n\n /**\n * Lazily initialize the AI SDK model and functions.\n * This allows the adapter to be created without the AI SDK installed,\n * failing only when actually used.\n */\n private async ensureInitialized(): Promise<void> {\n if (this.model !== undefined) return;\n // Coalesce concurrent init calls into a single load (Issue #1438)\n if (this.initPromise !== undefined) {\n await this.initPromise;\n return;\n }\n this.initPromise = this.doInitialize();\n try {\n await this.initPromise;\n } finally {\n this.initPromise = undefined;\n }\n }\n\n private async doInitialize(): Promise<void> {\n const apiKey = resolveApiKey(this.sdkProviderId, this.sdkConfig.apiKey);\n if (apiKey === undefined) {\n throw new AdapterModelError(`No API key for ${this.sdkProviderId}`, {\n code: ErrorCode.CONFIG_INVALID,\n });\n }\n\n // DNS-resolve-time SSRF guard for custom-openai gateways (#3426). The\n // construction-time guard is string-level only; this resolves the gateway\n // hostname and rejects if it points at a private/loopback/link-local IP.\n // Run BEFORE any model state is set so a rejection leaves the adapter\n // uninitialized — a retry re-runs the guard rather than skipping it via the\n // `this.model !== undefined` short-circuit in ensureInitialized().\n await this.ensureCustomHostResolvesPublic();\n\n // Dynamic import — AI SDK is an optional peer dependency\n const providerModule = await this.loadProvider(apiKey);\n this.model = providerModule.model;\n\n // AI SDK is an optional peer dependency — validate shape at runtime\n const aiModule = await import('ai');\n this.sdkFunctions = extractAiSdkFunctions(aiModule);\n }\n\n /**\n * For custom-openai only: run the DNS-resolve-time SSRF check exactly once\n * and throw if the gateway hostname resolves to a private address (#3426).\n * Cached via `resolveSsrfChecked` so the hostname is not re-resolved on\n * every request. No-op for non-custom providers (built-in endpoints are\n * trusted) and when no custom base URL is configured.\n */\n private async ensureCustomHostResolvesPublic(): Promise<void> {\n if (this.resolveSsrfChecked) return;\n if (this.sdkProviderId !== 'custom-openai' || this.customBaseUrl === undefined) {\n this.resolveSsrfChecked = true;\n return;\n }\n const hostname = new URL(this.customBaseUrl).hostname;\n const result = await assertCustomApiHostResolvesPublic(hostname);\n if (!result.ok) {\n // Do NOT cache a rejection (#3426 QA): leaving the flag false means a\n // retry re-runs the guard rather than silently skipping it via the\n // early-return above. The guard itself fails OPEN on transient resolver\n // errors, so a flaky-DNS host still proceeds; only a confirmed private\n // resolution throws here.\n throw result.error;\n }\n this.resolveSsrfChecked = true;\n }\n\n /**\n * Loads the provider-specific AI SDK module.\n *\n * Each @ai-sdk/* package exports a factory function (e.g., createAnthropic)\n * that returns a callable provider instance. We use extractProviderFactory()\n * to validate the export exists at runtime, since these are optional peer deps.\n */\n private async loadProvider(apiKey: string): Promise<{ model: AiSdkModel }> {\n switch (this.sdkProviderId) {\n case 'anthropic': {\n const mod = await import('@ai-sdk/anthropic');\n const factory = extractProviderFactory(mod, 'createAnthropic');\n const provider = factory({ apiKey });\n return { model: provider(this.modelId) };\n }\n case 'openai': {\n const mod = await import('@ai-sdk/openai');\n const factory = extractProviderFactory(mod, 'createOpenAI');\n const provider = factory({ apiKey });\n return { model: provider(this.modelId) };\n }\n case 'google': {\n const mod = await import('@ai-sdk/google');\n const factory = extractProviderFactory(mod, 'createGoogleGenerativeAI');\n const provider = factory({ apiKey });\n return { model: provider(this.modelId) };\n }\n case 'custom-openai': {\n // OpenAI-compatible gateway (multi-vendor proxies, self-hosted servers,\n // corporate LLM gateways). Reuses @ai-sdk/openai with a configurable\n // baseURL. See custom-api-validation.ts for the SSRF guard; the\n // adapter constructor validates before this method is reached.\n const mod = await import('@ai-sdk/openai');\n const factory = extractProviderFactory(mod, 'createOpenAI');\n const opts: Record<string, unknown> = { apiKey };\n if (this.customBaseUrl !== undefined) opts['baseURL'] = this.customBaseUrl;\n const provider = factory(opts);\n return { model: provider(this.modelId) };\n }\n }\n }\n\n /**\n * Maps our CompletionRequest to AI SDK generateText options.\n */\n private buildSdkOptions(request: CompletionRequest): {\n options: Record<string, unknown>;\n dropped: readonly DroppedParam[];\n } {\n const options: Record<string, unknown> = {\n model: this.model,\n messages: request.messages.map((m) => ({\n role: m.role === 'system' ? 'system' : m.role,\n content:\n typeof m.content === 'string'\n ? m.content\n : m.content.map((c: ContentBlock) => {\n if (c.type === 'text') return { type: 'text' as const, text: c.text };\n return c;\n }),\n })),\n };\n\n if (request.systemPrompt !== undefined) {\n options['system'] = request.systemPrompt;\n }\n // #4068: the temperature drop-decision (#4061/#4062: Claude after Opus 4.6 and\n // OpenAI reasoning models reject a non-1.0 temperature with a 400; the AI-SDK\n // path routes to both, so omit the param for those models — 1.0 is the API\n // default, equivalent) is centralized in the shared planOptionalParams seam.\n const plan = planOptionalParams(request, this.modelId);\n if (plan.temperature !== undefined) {\n options['temperature'] = plan.temperature;\n }\n if (request.maxTokens !== undefined) {\n options['maxTokens'] = request.maxTokens;\n }\n if (request.stop !== undefined) {\n options['stopSequences'] = request.stop;\n }\n\n // #4069: report dropped params so complete() can surface them as warnings.\n return { options, dropped: plan.dropped };\n }\n\n /**\n * generateText path (text / absent responseFormat) — unchanged behavior.\n */\n private async completeText(\n sdk: AiSdkFunctions,\n options: Record<string, unknown>\n ): Promise<CompletionResponse> {\n const result = await sdk.generateText(options);\n return {\n content: [{ type: 'text', text: result.text }],\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: result.usage.totalTokens ?? 0,\n },\n stopReason: mapFinishReason(result.finishReason),\n model: result.response.modelId,\n };\n }\n\n /**\n * generateObject path (#3433) — json_object / json_schema responseFormat.\n *\n * Uses the AI SDK `jsonSchema` helper to build the schema handle\n * (permissive `{ type: 'object' }` for json_object), then stringifies the\n * returned object into a text content block so downstream parsers /\n * extractTextFromResponse keep working unchanged.\n */\n private async completeStructured(\n sdk: AiSdkFunctions,\n options: Record<string, unknown>,\n responseFormat: Exclude<ResponseFormat, { type: 'text' }>\n ): Promise<CompletionResponse> {\n const rawSchema: Record<string, unknown> =\n responseFormat.type === 'json_schema' ? responseFormat.schema : { type: 'object' };\n const schema = sdk.jsonSchema(rawSchema);\n const result: unknown = await sdk.generateObject({ ...options, schema });\n if (!isGenerateObjectResult(result)) {\n throw new Error(\n 'AI SDK generateObject returned an unexpected result shape ' +\n '(missing object/usage/finishReason/response.modelId)'\n );\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(result.object) }],\n usage: {\n inputTokens: result.usage.inputTokens ?? 0,\n outputTokens: result.usage.outputTokens ?? 0,\n totalTokens: result.usage.totalTokens ?? 0,\n },\n stopReason: mapFinishReason(result.finishReason),\n model: result.response.modelId,\n };\n }\n\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n try {\n await this.ensureInitialized();\n this.logRequest(request);\n\n const sdk = this.sdkFunctions;\n if (sdk === undefined) {\n throw new Error(\n `SDK not initialized for model '${this.sdkConfig.modelId}' (provider: ${this.sdkProviderId}). ` +\n 'Ensure ensureInitialized() completes before calling complete().'\n );\n }\n const { options, dropped } = this.buildSdkOptions(request);\n\n // #3433: native structured output. json_object/json_schema route\n // through generateObject; everything else keeps the generateText path\n // unchanged.\n const responseFormat = request.responseFormat;\n const base =\n responseFormat !== undefined && responseFormat.type !== 'text'\n ? await this.completeStructured(sdk, options, responseFormat)\n : await this.completeText(sdk, options);\n\n // #4069: surface params dropped by the seam (e.g. temperature) as warnings.\n // Omitted entirely when nothing was dropped (exactOptionalPropertyTypes).\n const response: CompletionResponse =\n dropped.length > 0 ? { ...base, warnings: dropped } : base;\n\n this.logResponse(response);\n return ok(response);\n } catch (error: unknown) {\n const code = categorizeError(error);\n return this.toErrorResult(error, code);\n }\n }\n\n async *stream(request: CompletionRequest): AsyncIterable<StreamChunk> {\n // Ensure initialization and SDK readiness before entering the generator body.\n // Errors thrown before the first yield in an async generator bypass for-await-of\n // try/catch in callers, so we validate eagerly and wrap the body in try/catch.\n await this.ensureInitialized();\n this.logRequest(request);\n\n const sdk = this.sdkFunctions;\n if (sdk === undefined) {\n throw new AdapterModelError('SDK not initialized after ensureInitialized()', {\n code: ErrorCode.CONFIG_INVALID,\n });\n }\n\n const { options } = this.buildSdkOptions(request);\n\n // First yield establishes the generator — errors after this point are\n // properly caught by callers using for-await-of with try/catch.\n yield { type: 'message_start', message: { model: this.modelId } };\n\n const result = sdk.streamText(options);\n let index = 0;\n yield { type: 'content_block_start', index, contentBlock: { type: 'text', text: '' } };\n\n for await (const text of result.textStream) {\n // #3317 finding #8: skip empty-string deltas — the SDK can emit zero-length\n // chunks (keepalives/segment boundaries); a `text_delta` with `text: ''` is\n // noise that downstream re-assemblers must otherwise special-case.\n if (text === '') continue;\n yield {\n type: 'content_block_delta',\n index,\n delta: { type: 'text_delta', text },\n };\n }\n\n yield { type: 'content_block_stop', index };\n index++;\n yield {\n type: 'message_delta',\n delta: { stop_reason: 'end_turn' },\n usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n };\n yield { type: 'message_stop' };\n }\n\n /**\n * Converts a caught error into a Result error with categorized ErrorCode.\n */\n private toErrorResult(error: unknown, code: ErrorCode): Result<CompletionResponse, ModelError> {\n const message = getErrorMessage(error);\n // Scrub API keys + bearer tokens out of upstream SDK error messages\n // before they hit logs or the surfaced ModelError. Parity with the\n // subprocess-adapter path. Audit #2824.\n const safeMessage = sanitizeOutput(message);\n const errorObj = error instanceof Error ? error : new Error(safeMessage);\n this.logger.error(`SDK adapter error (${this.sdkProviderId})`, errorObj);\n // AdapterModelError extends ModelError — no cast needed\n const modelError = new AdapterModelError(`${this.sdkProviderId} SDK error: ${safeMessage}`, {\n code,\n });\n return { ok: false, error: modelError };\n }\n}\n","/**\n * nexus-agents/cli-adapters - CLI Detection Cache\n *\n * Caches CLI health check results to avoid repeated subprocess calls.\n * Invalidates on circuit breaker trips or manual invalidation.\n *\n * @module cli-adapters/cli-detection-cache\n * (Source: Issue #165, Proposal adapter-architecture-review.md)\n */\n\nimport { z } from 'zod';\nimport { createLogger } from '../core/logger.js';\nimport type { ILogger } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { CliName, HealthStatus, VersionStatus } from './types.js';\n\n/**\n * Cached health result for a CLI.\n */\nexport interface CliHealthResult {\n /** Whether the CLI is healthy and available */\n readonly healthy: boolean;\n /** CLI version detected */\n readonly version: string;\n /** Version compatibility status */\n readonly versionStatus: VersionStatus;\n /** When this result was captured */\n readonly checkedAt: Date;\n /** Optional status message */\n readonly message?: string | undefined;\n}\n\n/**\n * Configuration for the CLI detection cache.\n */\nexport interface CliDetectionCacheConfig {\n /** Base time-to-live in milliseconds (default: 5 minutes) */\n readonly ttlMs: number;\n /** Enable adaptive TTL based on health history (default: true) */\n readonly adaptiveTtl?: boolean | undefined;\n /** Logger instance */\n readonly logger?: ILogger | undefined;\n}\n\n/**\n * Zod schema for cache configuration validation.\n */\nexport const CliDetectionCacheConfigSchema = z.object({\n ttlMs: z.number().min(1000).max(3600_000).default(300_000),\n});\n\n/**\n * Default cache configuration.\n */\nexport const DEFAULT_CACHE_CONFIG: CliDetectionCacheConfig = {\n ttlMs: 300_000, // 5 minutes\n adaptiveTtl: true,\n};\n\n/** Adaptive TTL multipliers. Healthy CLIs are polled less often; unhealthy more often. */\nconst ADAPTIVE_MULTIPLIER_HEALTHY = 2.0;\nconst ADAPTIVE_MULTIPLIER_UNHEALTHY = 0.25;\n/** Number of consecutive same-status results before the multiplier kicks in. */\nconst ADAPTIVE_STREAK_THRESHOLD = 2;\n\n/**\n * Interface for CLI detection cache.\n * Allows dependency injection for testing.\n */\nexport interface ICliDetectionCache {\n /** Get cached health result for a CLI */\n get(cli: CliName): CliHealthResult | undefined;\n\n /** Set health result for a CLI */\n set(cli: CliName, result: CliHealthResult): void;\n\n /** Check if cache entry is stale */\n isStale(cli: CliName): boolean;\n\n /** Invalidate cache for a specific CLI or all CLIs */\n invalidate(cli?: CliName): void;\n\n /** Get all cached results */\n getAll(): ReadonlyMap<CliName, CliHealthResult>;\n\n /** Get cache statistics */\n getStats(): CacheStats;\n\n /** Get effective TTL for a CLI (accounts for adaptive adjustments) */\n getEffectiveTtl(cli: CliName): number;\n}\n\n/**\n * Cache statistics for observability.\n */\nexport interface CacheStats {\n /** Number of cached entries */\n readonly size: number;\n /** Cache hits since last reset */\n readonly hits: number;\n /** Cache misses since last reset */\n readonly misses: number;\n /** Hit rate (0-1) */\n readonly hitRate: number;\n /** When stats were last reset */\n readonly lastReset: Date;\n}\n\n/**\n * CLI detection cache implementation.\n * Thread-safe for Node.js single-threaded execution.\n */\nexport class CliDetectionCache implements ICliDetectionCache {\n private readonly config: CliDetectionCacheConfig;\n private readonly logger: ILogger;\n private readonly cache: Map<CliName, CliHealthResult> = new Map();\n /** Consecutive same-health-status count per CLI (for adaptive TTL). */\n private readonly streaks: Map<CliName, { healthy: boolean; count: number }> = new Map();\n private hits = 0;\n private misses = 0;\n private lastReset: Date = new Date(getTimeProvider().now());\n\n constructor(config?: Partial<CliDetectionCacheConfig>) {\n const validated = CliDetectionCacheConfigSchema.parse({\n ttlMs: config?.ttlMs ?? DEFAULT_CACHE_CONFIG.ttlMs,\n });\n this.config = {\n ...validated,\n adaptiveTtl: config?.adaptiveTtl ?? DEFAULT_CACHE_CONFIG.adaptiveTtl,\n logger: config?.logger,\n };\n this.logger = config?.logger ?? createLogger({ component: 'CliDetectionCache' });\n\n this.logger.debug('CliDetectionCache initialized', { ttlMs: this.config.ttlMs });\n }\n\n get(cli: CliName): CliHealthResult | undefined {\n const result = this.cache.get(cli);\n\n if (result === undefined) {\n this.misses++;\n this.logger.debug('Cache miss', { cli });\n return undefined;\n }\n\n if (this.isStale(cli)) {\n this.misses++;\n this.logger.debug('Cache stale', { cli, checkedAt: result.checkedAt });\n return undefined;\n }\n\n this.hits++;\n this.logger.debug('Cache hit', { cli, healthy: result.healthy });\n return result;\n }\n\n set(cli: CliName, result: CliHealthResult): void {\n this.cache.set(cli, result);\n this.updateStreak(cli, result.healthy);\n this.logger.debug('Cache updated', {\n cli,\n healthy: result.healthy,\n version: result.version,\n });\n }\n\n isStale(cli: CliName): boolean {\n const result = this.cache.get(cli);\n if (result === undefined) return true;\n\n const age = getTimeProvider().now() - result.checkedAt.getTime();\n return age > this.getEffectiveTtl(cli);\n }\n\n /** Returns the effective TTL for a CLI, applying adaptive multiplier if enabled. */\n getEffectiveTtl(cli: CliName): number {\n if (this.config.adaptiveTtl === false) return this.config.ttlMs;\n const streak = this.streaks.get(cli);\n if (streak === undefined || streak.count < ADAPTIVE_STREAK_THRESHOLD) {\n return this.config.ttlMs;\n }\n const multiplier = streak.healthy ? ADAPTIVE_MULTIPLIER_HEALTHY : ADAPTIVE_MULTIPLIER_UNHEALTHY;\n return this.config.ttlMs * multiplier;\n }\n\n private updateStreak(cli: CliName, healthy: boolean): void {\n const prev = this.streaks.get(cli);\n if (prev?.healthy === healthy) {\n this.streaks.set(cli, { healthy, count: prev.count + 1 });\n } else {\n this.streaks.set(cli, { healthy, count: 1 });\n }\n }\n\n invalidate(cli?: CliName): void {\n if (cli !== undefined) {\n this.cache.delete(cli);\n this.streaks.delete(cli);\n this.logger.info('Cache invalidated', { cli });\n } else {\n this.cache.clear();\n this.streaks.clear();\n this.logger.info('Cache cleared');\n }\n }\n\n getAll(): ReadonlyMap<CliName, CliHealthResult> {\n return this.cache;\n }\n\n getStats(): CacheStats {\n const total = this.hits + this.misses;\n return {\n size: this.cache.size,\n hits: this.hits,\n misses: this.misses,\n hitRate: total > 0 ? this.hits / total : 0,\n lastReset: this.lastReset,\n };\n }\n\n /**\n * Resets cache statistics.\n */\n resetStats(): void {\n this.hits = 0;\n this.misses = 0;\n this.lastReset = new Date(getTimeProvider().now());\n this.logger.debug('Cache stats reset');\n }\n\n /**\n * Converts HealthStatus to CliHealthResult for caching.\n */\n static fromHealthStatus(status: HealthStatus): CliHealthResult {\n return {\n healthy: status.healthy,\n version: status.version,\n versionStatus: status.versionStatus,\n checkedAt: status.lastChecked,\n message: status.message,\n };\n }\n}\n\n/**\n * Creates a CLI detection cache instance.\n *\n * @param config - Optional cache configuration\n * @returns CLI detection cache\n *\n * @example\n * ```typescript\n * const cache = createCliDetectionCache({ ttlMs: 60_000 }); // 1 minute TTL\n * const result = cache.get('claude');\n * if (!result) {\n * const health = await adapter.healthCheck();\n * cache.set('claude', CliDetectionCache.fromHealthStatus(health));\n * }\n * ```\n */\nexport function createCliDetectionCache(\n config?: Partial<CliDetectionCacheConfig>\n): ICliDetectionCache {\n return new CliDetectionCache(config);\n}\n","/**\n * Auto-Selecting Model Adapter Factory\n *\n * Automatically selects the best available adapter:\n * 1. CLI adapters (claude/gemini/codex) - OAuth, no API keys needed\n * The CLIs handle model selection internally.\n * 2. API adapters (Anthropic/OpenAI) - requires API keys (fallback)\n *\n * Supports optional caching to avoid repeated CLI health checks.\n *\n * @module adapters/auto-adapter\n * (Source: Issue #165 - CLI detection cache)\n */\n\nimport type { IModelAdapter, ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\nimport { createCliAdapter, isCliAvailable, getAvailableClis } from '../cli-adapters/factory.js';\nimport { createCliToModelAdapter } from '../cli-adapters/cli-to-model-adapter.js';\nimport { createModelToCliAdapter } from '../cli-adapters/model-to-cli-adapter.js';\nimport { createClaudeAdapter } from './claude-adapter.js';\nimport { SdkAdapter } from './sdk/index.js';\nimport type { CliName, ICliAdapter, ApiVendor, ApiArmId } from '../cli-adapters/types.js';\nimport { apiArmId } from '../cli-adapters/types.js';\nimport { buildCliCapabilityProfiles } from '../config/model-config-helpers.js';\nimport type { ICliDetectionCache } from '../cli-adapters/cli-detection-cache.js';\nimport { createCliDetectionCache } from '../cli-adapters/cli-detection-cache.js';\nimport { CUSTOM_API_DEFAULT_MODEL } from '../config/defaults.js';\nimport { getCliModelName, getDefaultModelForCli } from '../config/model-config-helpers.js';\n\n/**\n * Adapter selection priority.\n */\nexport type AdapterPriority = 'cli-first' | 'api-first' | 'cli-only' | 'api-only';\n\n/**\n * Configuration for auto-selecting adapters.\n */\nexport interface AutoAdapterConfig {\n /** Selection priority (default: 'cli-first') */\n readonly priority?: AdapterPriority;\n /** Preferred CLI if multiple available (optional) */\n readonly preferredCli?: CliName;\n /** API key for Anthropic (optional, for fallback) */\n readonly anthropicApiKey?: string;\n /** API key for OpenAI (optional, for fallback via AI SDK) */\n readonly openaiApiKey?: string;\n /** API key for Google AI (optional, for fallback via AI SDK) */\n readonly googleApiKey?: string;\n /** Logger instance */\n readonly logger?: ILogger;\n /** CLI detection cache (optional, creates new if not provided) */\n readonly cache?: ICliDetectionCache;\n /** Whether to create and use cache if not provided (default: true) */\n readonly enableCache?: boolean;\n /** Default timeout for CLI subprocess calls (ms). Overrides auto-detection. */\n readonly defaultCliTimeoutMs?: number;\n}\n\n/**\n * Result of adapter selection.\n */\nexport interface AdapterSelection {\n /** The selected adapter */\n readonly adapter: IModelAdapter;\n /** Source of the adapter */\n readonly source: 'cli' | 'api';\n /** Which CLI or API was selected */\n readonly name: string;\n /** Why this adapter was selected */\n readonly reason: string;\n /** The cache used for CLI detection (for reuse) */\n readonly cache?: ICliDetectionCache | undefined;\n}\n\nconst defaultLogger = createLogger({ component: 'auto-adapter' });\n\n/**\n * Resolves the cache to use based on configuration.\n */\nfunction resolveCache(config: AutoAdapterConfig, logger: ILogger): ICliDetectionCache | undefined {\n if (config.cache !== undefined) {\n return config.cache;\n }\n const enableCache = config.enableCache ?? true;\n return enableCache ? createCliDetectionCache({ logger }) : undefined;\n}\n\n/**\n * Attempts to create a CLI-based model adapter.\n * The CLI tools (claude, gemini, codex) handle their own model selection.\n * Uses cache to avoid repeated health checks.\n */\nasync function tryCliAdapter(\n config: AutoAdapterConfig,\n logger: ILogger,\n cache?: ICliDetectionCache\n): Promise<AdapterSelection | null> {\n const preferredCli = config.preferredCli;\n\n const bridgeConfig =\n config.defaultCliTimeoutMs !== undefined\n ? { defaultTimeoutMs: config.defaultCliTimeoutMs }\n : undefined;\n\n // If preferred CLI specified, try that first\n if (preferredCli !== undefined && (await isCliAvailable(preferredCli, cache))) {\n logger.info('Using preferred CLI', { cli: preferredCli });\n const cliAdapter = createCliAdapter({ cli: preferredCli, logger });\n await cliAdapter.initialize();\n return {\n adapter: createCliToModelAdapter(cliAdapter, bridgeConfig),\n source: 'cli',\n name: preferredCli,\n reason: `Preferred CLI '${preferredCli}' is available (model selection handled by CLI)`,\n cache,\n };\n }\n\n // Otherwise, get all available CLIs and use the first one found\n const availableClis = await getAvailableClis(cache);\n\n if (availableClis.length === 0) {\n logger.info('No CLI adapters available');\n return null;\n }\n\n // Use first available CLI - each CLI handles its own model selection\n const selectedCli = availableClis[0];\n\n if (selectedCli === undefined) {\n return null;\n }\n\n logger.info('Auto-selected CLI', { cli: selectedCli, available: availableClis });\n const cliAdapter = createCliAdapter({ cli: selectedCli, logger });\n await cliAdapter.initialize();\n\n return {\n adapter: createCliToModelAdapter(cliAdapter, bridgeConfig),\n source: 'cli',\n name: selectedCli,\n reason: `Using '${selectedCli}' CLI (model selection handled by CLI)`,\n cache,\n };\n}\n\n/**\n * Resolves an API key from config or environment variable.\n */\nfunction resolveApiKeyFromEnv(configKey: string | undefined, envVar: string): string | undefined {\n const key = configKey ?? process.env[envVar];\n return key !== undefined && key.length > 0 ? key : undefined;\n}\n\n/**\n * Attempts to create an API-based model adapter.\n * Tries providers in order: Anthropic (native), OpenAI (SDK), Google (SDK).\n * This is a fallback when no CLIs are available.\n */\nfunction tryApiAdapter(config: AutoAdapterConfig, logger: ILogger): AdapterSelection | null {\n // Derive default model IDs from canonical registry instead of hardcoding\n const claudeModelId = getCliModelName(getDefaultModelForCli('claude'));\n const codexModelId = getCliModelName(getDefaultModelForCli('codex'));\n const geminiModelId = getCliModelName(getDefaultModelForCli('gemini'));\n\n // 1. Anthropic — use native ClaudeAdapter (battle-tested)\n const anthropicKey = resolveApiKeyFromEnv(config.anthropicApiKey, 'ANTHROPIC_API_KEY');\n if (anthropicKey !== undefined) {\n logger.info('Using Anthropic API adapter', { model: claudeModelId });\n return {\n adapter: createClaudeAdapter({ modelId: claudeModelId, apiKey: anthropicKey }),\n source: 'api',\n name: 'anthropic',\n reason: `Using Anthropic API (native adapter, model: ${claudeModelId})`,\n };\n }\n\n // 2. OpenAI — use AI SDK adapter\n const openaiKey = resolveApiKeyFromEnv(config.openaiApiKey, 'OPENAI_API_KEY');\n if (openaiKey !== undefined) {\n logger.info('Using OpenAI API adapter (AI SDK)', { model: codexModelId });\n return {\n adapter: new SdkAdapter({ providerId: 'openai', modelId: codexModelId, apiKey: openaiKey }),\n source: 'api',\n name: 'openai',\n reason: `Using OpenAI API via AI SDK (model: ${codexModelId})`,\n };\n }\n\n // 3. Google — use AI SDK adapter\n const googleKey = resolveApiKeyFromEnv(config.googleApiKey, 'GOOGLE_AI_API_KEY');\n if (googleKey !== undefined) {\n logger.info('Using Google AI API adapter (AI SDK)', { model: geminiModelId });\n return {\n adapter: new SdkAdapter({\n providerId: 'google',\n modelId: geminiModelId,\n apiKey: googleKey,\n }),\n source: 'api',\n name: 'google',\n reason: `Using Google AI API via AI SDK (model: ${geminiModelId})`,\n };\n }\n\n // 4. Custom OpenAI-compatible gateway (multi-vendor proxies, self-hosted\n // LLM servers, corporate gateways). Extracted for line limit.\n const custom = tryCustomOpenAiAdapter(logger);\n if (custom !== null) return custom;\n\n logger.info('No API keys available for any provider');\n return null;\n}\n\n/**\n * Tries the custom-openai SDK adapter if `NEXUS_CUSTOM_API_KEY` and\n * `NEXUS_CUSTOM_API_BASE_URL` are both set. The adapter constructor\n * runs the base URL through an SSRF guard (see\n * adapters/sdk/custom-api-validation.ts). Epic #2119.\n */\nfunction tryCustomOpenAiAdapter(logger: ILogger): AdapterSelection | null {\n const customKey = resolveApiKeyFromEnv(undefined, 'NEXUS_CUSTOM_API_KEY');\n const customBaseUrl = process.env['NEXUS_CUSTOM_API_BASE_URL'];\n if (customKey === undefined || customBaseUrl === undefined || customBaseUrl === '') {\n return null;\n }\n const customModelId = process.env['NEXUS_CUSTOM_MODEL'] ?? CUSTOM_API_DEFAULT_MODEL;\n logger.info('Using custom-openai SDK adapter', {\n model: customModelId,\n baseUrl: customBaseUrl,\n });\n return {\n adapter: new SdkAdapter({\n providerId: 'custom-openai',\n modelId: customModelId,\n apiKey: customKey,\n baseUrl: customBaseUrl,\n }),\n source: 'api',\n name: 'custom-openai',\n reason: `Using custom OpenAI-compatible gateway at ${customBaseUrl} (model: ${customModelId})`,\n };\n}\n\n/**\n * Resolve an API-vendor name to its `{vendor, slot}` pair (#3422). `slot` is the\n * *attribution* CLI slot (`getModelInfo`, capability profile) — NOT the routing\n * arm id, which stays distinct (`api:<vendor>`) so CLI and API telemetry never\n * merge. Exhaustive switch (concrete literals, no index-access undefined).\n */\nfunction resolveApiVendor(name: string): { vendor: ApiVendor; slot: CliName } | undefined {\n switch (name) {\n case 'anthropic':\n return { vendor: 'anthropic', slot: 'claude' };\n case 'openai':\n return { vendor: 'openai', slot: 'codex' };\n case 'google':\n return { vendor: 'google', slot: 'gemini' };\n case 'custom-openai':\n return { vendor: 'custom-openai', slot: 'opencode' };\n default:\n return undefined;\n }\n}\n\n/**\n * Wrap an `AdapterSelection{source:'api'}` for insertion into a CompositeRouter's\n * `Map<RoutingArmId, ICliAdapter>` (#3317 step 1 / #3422). Returns the distinct\n * routing arm id (`api:<vendor>`) and an `ICliAdapter` view of the IModelAdapter\n * (via {@link createModelToCliAdapter}). Returns null for CLI selections (the\n * router already gets those from `createAllAdapters` under their slot key) or an\n * unrecognized vendor.\n */\nexport function wrapApiSelectionForRouter(\n selection: AdapterSelection\n): { armId: ApiArmId; adapter: ICliAdapter } | null {\n if (selection.source !== 'api') return null;\n const resolved = resolveApiVendor(selection.name);\n if (resolved === undefined) return null;\n const adapter = createModelToCliAdapter(selection.adapter, {\n name: resolved.slot,\n capabilities: buildCliCapabilityProfiles()[resolved.slot],\n });\n return { armId: apiArmId(resolved.vendor), adapter };\n}\n\n/**\n * Build an `AdapterSelection{source:'api'}` for a single vendor when its key(s)\n * are present, else null. Reuses the same adapter constructors as\n * {@link tryApiAdapter} but is key-presence-only and never calls out (#3422).\n */\nfunction buildApiSelectionForVendor(vendor: ApiVendor, logger: ILogger): AdapterSelection | null {\n switch (vendor) {\n case 'anthropic': {\n const key = resolveApiKeyFromEnv(undefined, 'ANTHROPIC_API_KEY');\n if (key === undefined) return null;\n const modelId = getCliModelName(getDefaultModelForCli('claude'));\n return {\n adapter: createClaudeAdapter({ modelId, apiKey: key }),\n source: 'api',\n name: 'anthropic',\n reason: `Using Anthropic API (native adapter, model: ${modelId})`,\n };\n }\n case 'openai': {\n const key = resolveApiKeyFromEnv(undefined, 'OPENAI_API_KEY');\n if (key === undefined) return null;\n const modelId = getCliModelName(getDefaultModelForCli('codex'));\n return {\n adapter: new SdkAdapter({ providerId: 'openai', modelId, apiKey: key }),\n source: 'api',\n name: 'openai',\n reason: `Using OpenAI API via AI SDK (model: ${modelId})`,\n };\n }\n case 'google': {\n const key = resolveApiKeyFromEnv(undefined, 'GOOGLE_AI_API_KEY');\n if (key === undefined) return null;\n const modelId = getCliModelName(getDefaultModelForCli('gemini'));\n return {\n adapter: new SdkAdapter({ providerId: 'google', modelId, apiKey: key }),\n source: 'api',\n name: 'google',\n reason: `Using Google AI API via AI SDK (model: ${modelId})`,\n };\n }\n case 'custom-openai':\n return tryCustomOpenAiAdapter(logger);\n default: {\n const exhaustive: never = vendor;\n throw new Error(`Unknown API vendor: ${String(exhaustive)}`);\n }\n }\n}\n\n/** API vendors enumerated in routing-arm order (#3422). */\nconst API_ROUTING_VENDORS: readonly ApiVendor[] = [\n 'anthropic',\n 'openai',\n 'google',\n 'custom-openai',\n];\n\n/**\n * Enumerate the direct-API routing arms whose keys are present in the\n * environment, each wrapped as an `ICliAdapter` keyed by its distinct\n * `api:<vendor>` arm id (#3422). Key-presence-only and deterministic: a vendor\n * is included iff its required env var(s) are set; keys are never validated by\n * calling out. Used by `createAllAdapters` under `NEXUS_BILLING_MODE=api`.\n */\nexport function collectApiRoutingArms(\n logger: ILogger = defaultLogger\n): Array<{ armId: ApiArmId; adapter: ICliAdapter }> {\n const arms: Array<{ armId: ApiArmId; adapter: ICliAdapter }> = [];\n for (const vendor of API_ROUTING_VENDORS) {\n const selection = buildApiSelectionForVendor(vendor, logger);\n if (selection === null) continue;\n const wrapped = wrapApiSelectionForRouter(selection);\n if (wrapped !== null) arms.push(wrapped);\n }\n return arms;\n}\n\n/** Try CLI first, then API as fallback. */\nasync function selectCliFirst(\n config: AutoAdapterConfig,\n logger: ILogger,\n cache?: ICliDetectionCache\n): Promise<AdapterSelection> {\n const cliResult = await tryCliAdapter(config, logger, cache);\n if (cliResult !== null) return cliResult;\n const apiResult = tryApiAdapter(config, logger);\n if (apiResult !== null) return apiResult;\n throw new Error(\n 'No adapters available. Install a CLI (claude/gemini/codex) or set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_AI_API_KEY.'\n );\n}\n\n/** Try API first, then CLI as fallback. */\nasync function selectApiFirst(\n config: AutoAdapterConfig,\n logger: ILogger,\n cache?: ICliDetectionCache\n): Promise<AdapterSelection> {\n const apiResult = tryApiAdapter(config, logger);\n if (apiResult !== null) return apiResult;\n const cliResult = await tryCliAdapter(config, logger, cache);\n if (cliResult !== null) return cliResult;\n throw new Error(\n 'No adapters available. Set ANTHROPIC_API_KEY/OPENAI_API_KEY/GOOGLE_AI_API_KEY or install a CLI (claude/gemini/codex).'\n );\n}\n\n/** CLI only - no API fallback. */\nasync function selectCliOnly(\n config: AutoAdapterConfig,\n logger: ILogger,\n cache?: ICliDetectionCache\n): Promise<AdapterSelection> {\n const cliResult = await tryCliAdapter(config, logger, cache);\n if (cliResult !== null) return cliResult;\n throw new Error(\n 'No CLI adapters available. Install and authenticate claude, gemini, or codex CLI.'\n );\n}\n\n/** API only - no CLI fallback. */\nfunction selectApiOnly(config: AutoAdapterConfig, logger: ILogger): AdapterSelection {\n const apiResult = tryApiAdapter(config, logger);\n if (apiResult !== null) return apiResult;\n throw new Error(\n 'No API key available. Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_AI_API_KEY.'\n );\n}\n\n/**\n * Auto-selects the best available model adapter.\n * Uses caching to avoid repeated CLI health checks.\n *\n * @param config - Configuration options\n * @returns Selected adapter or throws if none available\n *\n * @example\n * ```typescript\n * // Use CLI if available, fall back to API\n * const { adapter, source, reason, cache } = await createAutoAdapter();\n * console.log(`Using ${source} adapter: ${reason}`);\n *\n * // Reuse cache for subsequent selections\n * const { adapter: adapter2 } = await createAutoAdapter({ cache });\n *\n * // Force CLI only\n * const { adapter } = await createAutoAdapter({ priority: 'cli-only' });\n * ```\n */\nexport async function createAutoAdapter(config: AutoAdapterConfig = {}): Promise<AdapterSelection> {\n const logger = config.logger ?? defaultLogger;\n const priority = config.priority ?? 'cli-first';\n const cache = resolveCache(config, logger);\n\n logger.info('Auto-selecting adapter', { priority, cacheEnabled: cache !== undefined });\n\n switch (priority) {\n case 'cli-first':\n return selectCliFirst(config, logger, cache);\n case 'api-first':\n return selectApiFirst(config, logger, cache);\n case 'cli-only':\n return selectCliOnly(config, logger, cache);\n case 'api-only':\n return selectApiOnly(config, logger);\n default: {\n const exhaustive: never = priority;\n throw new Error(`Unknown priority: ${String(exhaustive)}`);\n }\n }\n}\n\n/**\n * Checks which adapters are available without creating them.\n * Uses caching to avoid repeated CLI health checks.\n *\n * @param cache - Optional cache to use\n * @returns Available CLIs and which API keys are set\n */\nexport async function getAvailableAdapters(cache?: ICliDetectionCache): Promise<{\n clis: CliName[];\n hasAnthropicKey: boolean;\n hasOpenaiKey: boolean;\n hasGoogleKey: boolean;\n cache?: ICliDetectionCache;\n}> {\n const effectiveCache = cache ?? createCliDetectionCache();\n const clis = await getAvailableClis(effectiveCache);\n\n return {\n clis,\n hasAnthropicKey: resolveApiKeyFromEnv(undefined, 'ANTHROPIC_API_KEY') !== undefined,\n hasOpenaiKey: resolveApiKeyFromEnv(undefined, 'OPENAI_API_KEY') !== undefined,\n hasGoogleKey: resolveApiKeyFromEnv(undefined, 'GOOGLE_AI_API_KEY') !== undefined,\n cache: effectiveCache,\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 } from 'node:child_process';\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, getTimeProvider, createLogger } from '../core/index.js';\n\nimport type {\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n ResolvedExecutionOptions,\n ICliResponseParser,\n} from './types.js';\nimport { BaseCliAdapter } from './base-adapter.js';\nimport { buildChildEnv } from './subprocess-env.js';\nimport { sanitizeOutput } from '../security/output-sanitizer.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\nimport { parseCliErrorEnvelope, classifyExtractedError } from './cli-error-envelope.js';\nimport { generateHyphenId } from '../utils/id-utils.js';\n\n/** Minimum length for plaintext fallback to kick in.\n * Lowered from 100→30 to recover short but valid CLI responses (#1401). */\nconst PLAINTEXT_FALLBACK_MIN_LENGTH = 30;\n\n/**\n * Attempts to extract a usable response from raw stdout when the structured\n * parser fails. Returns the trimmed text if it looks like natural language\n * (not JSON/NDJSON) and exceeds the minimum length threshold.\n *\n * Recovers responses from CLIs that output plaintext instead of their\n * expected structured format. (#1401)\n */\nfunction tryPlaintextFallback(stdout: string): string | null {\n const trimmed = stdout.trim();\n if (trimmed.length < PLAINTEXT_FALLBACK_MIN_LENGTH) return null;\n // Skip if it looks like structured output the parser should handle\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) return null;\n return trimmed;\n}\n\n/** Error patterns in stderr that indicate a real failure, not debug output (#1402). */\nconst STDERR_ERROR_PATTERNS = [\n 'error:',\n 'fatal:',\n 'panic:',\n 'unhandled',\n 'not found',\n 'invalid model',\n 'authentication',\n 'unauthorized',\n 'permission denied',\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'timeout',\n 'failed to connect',\n 'invalid api key',\n 'rate limit',\n 'quota exceeded',\n 'service unavailable',\n];\n\n/** Checks if stderr looks like a real error (not just debug/progress output). */\nfunction looksLikeErrorStderr(stderr: string): boolean {\n const lower = stderr.toLowerCase();\n return STDERR_ERROR_PATTERNS.some((pattern) => lower.includes(pattern));\n}\n\n/** Stderr patterns indicating transient connection failures (retryable). */\nconst STDERR_CONNECTION_PATTERNS = [\n 'connection refused',\n 'econnrefused',\n 'enotfound',\n 'econnreset',\n 'failed to connect',\n 'service unavailable',\n 'eaddrinuse',\n 'address already in use',\n];\n\n/** Stderr patterns indicating timeout (retryable). */\nconst STDERR_TIMEOUT_PATTERNS = ['timeout', 'timed out', 'etimedout'];\n\n/**\n * Classifies a stderr error message into the most specific CliErrorCode.\n * Checks for transient patterns (connection, rate-limit, timeout) before\n * falling back to EXECUTION_ERROR. This ensures transient failures in\n * stderr are retried instead of treated as terminal. (#1401)\n *\n * Rate-limit detection uses shared patterns from rate-limit-detector. (#1596)\n */\nfunction classifyStderrError(stderr: string): CliErrorCode {\n const lower = stderr.toLowerCase();\n if (STDERR_CONNECTION_PATTERNS.some((p) => lower.includes(p))) return 'CONNECTION_ERROR';\n if (isRateLimitText(stderr)) return 'RATE_LIMITED';\n if (STDERR_TIMEOUT_PATTERNS.some((p) => lower.includes(p))) return 'TIMEOUT';\n return 'EXECUTION_ERROR';\n}\n\nconst subprocessLogger = createLogger({ component: 'subprocess-adapter' });\n\n/** Maximum buffer size for stdout/stderr (10 MB). */\nconst MAX_BUFFER_BYTES = 10 * 1024 * 1024;\n\n/** CliErrorCodes that represent transient failures safe to retry. */\nconst TRANSIENT_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n 'PARSE_ERROR',\n]);\n\n/** Delay schedule for transient-error retries (ms per attempt index). */\nconst TRANSIENT_RETRY_DELAYS_MS = [500, 1000] as const;\n\n/** Maximum number of transient-error retries. */\nconst MAX_TRANSIENT_RETRIES = TRANSIENT_RETRY_DELAYS_MS.length;\n\n/**\n * Maximum retries for PARSE_ERROR specifically (#1533).\n * Parse errors are less likely to self-heal than timeouts/connection errors,\n * so we cap at 1 retry instead of 2.\n */\nexport const MAX_PARSE_RETRIES = 1;\n\n/** Timeout extension multiplier when retrying a TIMEOUT error. (#1401) */\nexport const TIMEOUT_RETRY_MULTIPLIER = 1.5;\n\n/**\n * Grace period before escalating SIGTERM to SIGKILL on timeout (#3026\n * finding 1). 5s gives well-behaved children time to flush state and\n * exit cleanly while bounding zombie-process accumulation when a child\n * ignores SIGTERM. Exported so tests can assert against the threshold.\n */\nexport const SIGKILL_GRACE_MS = 5_000;\n\n/**\n * Checks whether a CliErrorCode represents a transient failure.\n * Timeout, rate_limit, connection, and parse errors are transient.\n * Parse errors get fewer retries (MAX_PARSE_RETRIES) than others (#1533).\n */\nexport function isTransientError(code: CliErrorCode): boolean {\n return TRANSIENT_ERROR_CODES.has(code);\n}\n\n/**\n * Exit codes that indicate transient process termination (retryable).\n * - 137 = 128 + SIGKILL (9): OOM killer, system resource limits\n * - 143 = 128 + SIGTERM (15): external termination (our timeout SIGTERM\n * is already caught by the timeout handler before close fires)\n */\nconst TRANSIENT_EXIT_CODES = new Set([137, 143]);\n\n/** Human-readable signal names for exit codes (128 + signal number). */\nconst EXIT_CODE_SIGNAL_NAMES: Record<number, string> = {\n 137: 'SIGKILL (OOM or killed)',\n 143: 'SIGTERM (terminated)',\n};\n\n/** Builds an error message for signal exit codes that includes identifiable keywords. */\nfunction buildSignalExitMessage(code: number): string {\n const signalName = EXIT_CODE_SIGNAL_NAMES[code];\n if (signalName !== undefined) return `Process killed by ${signalName}, exit code ${String(code)}`;\n return `Process exited with code ${String(code)}`;\n}\n\n/**\n * Checks whether a process exit code indicates a transient failure\n * that is safe to retry (e.g., OOM kill, external SIGTERM).\n */\nexport function isTransientExitCode(code: number | null): boolean {\n return code !== null && TRANSIENT_EXIT_CODES.has(code);\n}\n\n/** Internal state for buffered stream collection. */\ninterface BufferState {\n stdout: string;\n stderr: string;\n stdoutBytes: number;\n stderrBytes: number;\n stdoutTruncated: boolean;\n stderrTruncated: boolean;\n resolved: boolean;\n /**\n * Wall-clock at first stdout byte (or null if none yet). Used by #2472 to\n * split total subprocess time into spawn-latency (spawn→first byte) and\n * streaming (first byte→close), which is the cheapest way to identify\n * which stage causes stochastic timeouts.\n */\n firstByteTime: number | null;\n}\n\n/** Append data to a buffered stream, respecting the 10 MB cap. */\nfunction appendBuffered(state: BufferState, stream: 'stdout' | 'stderr', data: Buffer): void {\n const bytesKey = stream === 'stdout' ? 'stdoutBytes' : 'stderrBytes';\n const truncKey = stream === 'stdout' ? 'stdoutTruncated' : 'stderrTruncated';\n if (state[bytesKey] < MAX_BUFFER_BYTES) {\n state[stream] += data.toString();\n state[bytesKey] += data.length;\n } else if (!state[truncKey]) {\n state[truncKey] = true;\n subprocessLogger.warn(`${stream} buffer exceeded 10 MB, truncating`);\n }\n}\n\n/**\n * Command configuration returned by getCommand.\n */\nexport interface CommandConfig {\n command: string;\n args: string[];\n /** Optional stdin content (prompt passed via stdin instead of args) */\n stdin?: string;\n /**\n * Optional cleanup callback invoked after the subprocess resolves\n * (success, error, or timeout). Used by adapters that materialize\n * temp files for the subprocess (e.g. codex `model_instructions_file`).\n * Errors thrown by cleanup are logged but do not affect the request result.\n */\n cleanup?: () => void | Promise<void>;\n}\n\n/**\n * Configuration for transient-error retry behaviour.\n */\nexport interface TransientRetryConfig {\n /** Whether transient-error retry is enabled (default: false). */\n enabled: boolean;\n}\n\n/**\n * Base class for subprocess-based CLI adapters.\n * Used by ClaudeCliAdapter and GeminiCliAdapter.\n */\nexport abstract class SubprocessCliAdapter extends BaseCliAdapter {\n readonly transport: CliTransport = 'subprocess';\n\n protected abstract readonly parser: ICliResponseParser;\n\n /** Transient-error retry config. Override in subclass to enable. */\n protected readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n /**\n * The inner {@link retryTransient} layer is the single retry authority\n * for subprocess CLIs. When it is enabled (the default), the shared\n * outer retry loop must not also retry: nesting both meant up to 6\n * subprocess spawns and ~10-minute hangs on a persistent TIMEOUT, since\n * the inner layer's timeout extension compounds on every outer attempt\n * (#2824). The outer loop still runs once, so circuit-breaker failure\n * recording is unaffected.\n */\n protected override shouldOuterRetry(opts: 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 ): void {\n const onAbort = (): void => {\n if (child.exitCode === null && child.signalCode === null) {\n child.kill('SIGTERM');\n }\n resolve(err(this.createError('TIMEOUT', 'Aborted by caller signal')));\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) return result;\n if (!isTransientError(result.error.code)) 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 (!isTransientError(result.error.code)) 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 private spawnSubprocess(\n task: CliTask,\n options: ResolvedExecutionOptions,\n requestId: string\n ): Promise<Result<CliResponse, CliError>> {\n const cmdConfig = this.getCommand(task);\n const startTime = getTimeProvider().now();\n\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.\n const signal = options.signal;\n if (signal?.aborted === true) {\n return Promise.resolve(err(this.createError('TIMEOUT', 'Aborted before spawn')));\n }\n\n return new Promise((resolveOuter) => {\n const resolve = (result: Result<CliResponse, CliError>): void => {\n this.runSubprocessCleanup(cmdConfig.cleanup);\n resolveOuter(result);\n };\n // Curated child env: base infrastructure vars + only this CLI's\n // own vendor credentials, so cross-vendor API keys don't leak\n // into the spawned CLI (#2865). Also drops CLAUDECODE — a nested\n // CLI must not believe it's already inside Claude Code.\n const childEnv = buildChildEnv(this.name);\n\n const child = spawn(cmdConfig.command, cmdConfig.args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n env: childEnv,\n });\n\n const onProgress = options.onProgress;\n const state = this.setupChildProcessHandlers({\n child,\n startTime,\n timeoutMs: options.timeoutMs,\n resolve,\n requestId,\n ...(onProgress !== undefined ? { onProgress } : {}),\n });\n\n if (signal !== undefined) {\n this.attachAbortSignal(child, signal, resolve);\n }\n\n // Write stdin content if provided and close stdin\n if (cmdConfig.stdin !== undefined) {\n child.stdin.write(cmdConfig.stdin);\n }\n child.stdin.end();\n\n // Reference state to prevent unused variable warning\n void state;\n });\n }\n\n /**\n * Sets up child process event handlers for output collection and error handling.\n */\n private setupChildProcessHandlers(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 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 timers = this.scheduleTimeoutWithSigkillEscalation({\n child,\n timeoutMs,\n requestId,\n resolveOnce,\n });\n\n child.on('close', (code: number | null) => {\n clearTimeout(timers.timeoutId);\n if (timers.sigkillTimerId !== undefined) clearTimeout(timers.sigkillTimerId);\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 primary timer fires SIGTERM and resolves the caller's promise\n * immediately so it doesn't wait on a hung child. The escalation\n * timer (`SIGKILL_GRACE_MS` later) checks whether the child actually\n * exited and force-reaps it with SIGKILL if not — preventing\n * zombie accumulation when a child ignores SIGTERM (Node CLIs that\n * install graceful-shutdown handlers can hang on a broken stream).\n * Both timers are cleared from the `'close'` handler so a child\n * that exits within the grace window doesn't see the second signal.\n */\n private scheduleTimeoutWithSigkillEscalation(opts: {\n child: ReturnType<typeof spawn>;\n timeoutMs: number;\n requestId: string;\n resolveOnce: (result: Result<CliResponse, CliError>) => void;\n }): { timeoutId: NodeJS.Timeout; sigkillTimerId: NodeJS.Timeout | undefined } {\n const { child, timeoutMs, requestId, resolveOnce } = opts;\n const timers: { timeoutId: NodeJS.Timeout; sigkillTimerId: NodeJS.Timeout | undefined } = {\n timeoutId: setTimeout(() => {\n child.kill('SIGTERM');\n resolveOnce(err(this.createError('TIMEOUT', 'Execution timed out')));\n timers.sigkillTimerId = setTimeout(() => {\n if (child.exitCode === null && child.signalCode === null) {\n this.logger.warn('Child ignored SIGTERM, escalating to SIGKILL', {\n cli: this.name,\n requestId,\n sigkillGraceMs: SIGKILL_GRACE_MS,\n });\n child.kill('SIGKILL');\n }\n }, SIGKILL_GRACE_MS);\n timers.sigkillTimerId.unref();\n }, timeoutMs),\n sigkillTimerId: undefined,\n };\n return timers;\n }\n\n /** Attach stdout/stderr data handlers + capture first-byte time (#2472). */\n private attachStdoutHandlers(\n child: ReturnType<typeof spawn>,\n state: BufferState,\n onProgress?: () => void\n ): void {\n // stdio: ['pipe', 'pipe', 'pipe'] guarantees non-null streams\n if (child.stdout !== null) {\n child.stdout.on('data', (data: Buffer) => {\n if (state.firstByteTime === null && data.length > 0) {\n state.firstByteTime = getTimeProvider().now();\n }\n appendBuffered(state, 'stdout', data);\n onProgress?.();\n });\n }\n if (child.stderr !== null) {\n child.stderr.on('data', (data: Buffer) => {\n appendBuffered(state, 'stderr', data);\n });\n }\n }\n\n /**\n * Log spawn-latency vs streaming breakdown at info level (#2472). Emits\n * one structured event per subprocess invocation, queryable via the\n * existing trace JSONL infrastructure. The breakdown lets operators\n * identify whether a slow run was caused by:\n * - High spawn-latency: model gateway took its time before producing\n * the first token (cold-start, queueing, network jitter).\n * - High streaming-time: response body was large or generation slow.\n * - Total approaches the timeout cap with no first-byte: hung process.\n *\n * Structured fields chosen so existing query_trace tooling can group by\n * cli + provider + model and surface tail-latency outliers.\n */\n private logTimingBreakdown(\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 private handleSubprocessOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (stderr !== '' && stdout === '') {\n return err(this.createError('EXECUTION_ERROR', stderr));\n }\n\n const text = this.parser.extractResponse(stdout);\n if (text === null) {\n // Error-only stream (e.g. OpenCode NDJSON `{\"type\":\"error\"}`): the parser\n // surfaced an `errorMessage` but no usable content. Classify it before\n // the generic PARSE_ERROR path, which would mask the real cause.\n const errorOnly = this.classifyErrorOnlyStream(stdout);\n if (errorOnly !== null) return errorOnly;\n return this.handleUnparseableOutput(stdout, stderr, startTime);\n }\n\n const usage = this.parser.extractUsage(stdout);\n const sessionId = this.parser.extractSessionId(stdout);\n\n return ok(\n this.normalizeResponse(text, usage ?? undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n ...(sessionId !== null && { sessionId }),\n })\n );\n }\n\n /**\n * 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. Plaintext fallback for natural-language output (#1401)\n * 4. Generic PARSE_ERROR with truncated snippet\n */\n private handleUnparseableOutput(\n stdout: string,\n stderr: string,\n startTime: number\n ): Result<CliResponse, CliError> {\n if (isRateLimitText(stdout)) {\n const snippet = stdout.slice(0, 500).trim();\n return err(this.createError('RATE_LIMITED', snippet));\n }\n const envelope = parseCliErrorEnvelope(stdout, this.name);\n if (envelope !== null) {\n const msg =\n envelope.hint !== undefined\n ? `${envelope.message}\\n → ${envelope.hint}`\n : envelope.message;\n // #2455 ask 3: at debug level, dump the full sanitized envelope so\n // operators can recover context without re-running. Sanitized via\n // output-sanitizer.ts so leaked tokens (some upstreams echo back the\n // bad token in error responses) don't reach logs.\n subprocessLogger.debug('CLI error envelope unwrapped', {\n cli: this.name,\n code: envelope.code,\n rawSanitized: sanitizeOutput(stdout),\n });\n return err(this.createError(envelope.code, msg));\n }\n const plaintext = tryPlaintextFallback(stdout);\n if (plaintext !== null) {\n subprocessLogger.debug('Using plaintext fallback for unparseable output', {\n rawSanitized: sanitizeOutput(stdout),\n });\n return ok(\n this.normalizeResponse(plaintext, undefined, {\n durationMs: getTimeProvider().now() - startTime,\n raw: stdout,\n })\n );\n }\n const snippet = stdout.slice(0, 500).trim();\n const stderrHint = stderr !== '' ? ` [stderr: ${stderr.slice(0, 300).trim()}]` : '';\n return err(\n this.createError('PARSE_ERROR', `Failed to parse response: ${snippet}${stderrHint}`)\n );\n }\n\n /**\n * Handles subprocess execution errors.\n */\n private handleSubprocessError(error: unknown): Result<CliResponse, CliError> {\n if (!(error instanceof Error)) {\n return err(this.createError('EXECUTION_ERROR', 'Unknown error'));\n }\n\n if (error.message.includes('ETIMEDOUT') || error.message.includes('timeout')) {\n return err(this.createError('TIMEOUT', 'Execution timed out', error));\n }\n\n if (error.message.includes('ENOENT')) {\n return err(this.createError('NOT_FOUND', `${this.name} CLI not found`, error));\n }\n\n return err(this.createError('EXECUTION_ERROR', sanitizeOutput(error.message), error));\n }\n\n /**\n * Initializes the adapter and capacity tracker.\n */\n initialize(): Promise<void> {\n this.initCapacityTracker();\n this.initialized = true;\n return Promise.resolve();\n }\n\n /**\n * Disposes the adapter (no-op for subprocess).\n */\n dispose(): Promise<void> {\n this.initialized = false;\n return Promise.resolve();\n }\n}\n","/**\n * nexus-agents/cli-adapters - Base Adapter\n *\n * Abstract base class for CLI adapters with common functionality.\n * Provides version checking, health checks, and error handling.\n *\n * SubprocessCliAdapter extracted to subprocess-adapter.ts per Issue #272.\n *\n * (Source: cli-project_plan.md v2.1.0)\n */\n\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport semver from 'semver';\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\n\nimport type { Result } from '../core/index.js';\nimport { getTimeProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\n\nimport type {\n ICliAdapter,\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n CliErrorCode,\n HealthStatus,\n CapacityStatus,\n ModelInfo,\n CapabilityProfile,\n ExecutionOptions,\n 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';\n\nconst execAsync = promisify(exec);\n\n/**\n * Fallback capacity (in tokens) when capacity tracker is uninitialized.\n * Uses a realistic 100k token budget instead of MAX_SAFE_INTEGER to prevent\n * downstream consumers from treating the adapter as having unlimited capacity.\n * Issue #1463.\n */\nexport const DEFAULT_CAPACITY_FALLBACK = 100_000;\n\n/**\n * Default execution options.\n *\n * Timeout reduced from 120s to 60s per Issue #280 to prevent\n * cascading timeouts in multi-agent voting scenarios.\n */\nconst DEFAULT_OPTIONS: 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 protected readonly logger: ILogger;\n protected capacityTracker: CapacityTracker | null = null;\n protected initialized = false;\n protected lastHealthCheck?: HealthStatus;\n protected cachedVersion?: string;\n\n constructor(logger?: ILogger) {\n this.logger = logger ?? createLogger({ component: 'cli-adapter' });\n }\n\n /**\n * Initializes the capacity tracker.\n * Called by subclasses after name is set.\n */\n protected initCapacityTracker(): void {\n this.capacityTracker = createCapacityTracker(this.name);\n }\n\n /**\n * Gets the capability profile for this CLI.\n */\n get capabilities(): CapabilityProfile {\n return DEFAULT_CAPABILITIES[this.name];\n }\n\n /**\n * Abstract method for executing a task.\n * Implemented by concrete adapters.\n */\n abstract executeTask(\n task: CliTask,\n options: 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 const effectiveTimeout = this.computeTimeout(task, options);\n const opts = { ...DEFAULT_OPTIONS, ...options, timeoutMs: effectiveTimeout };\n\n if (!this.initialized) {\n await this.initialize();\n }\n\n this.logger.debug('Executing task', {\n cli: this.name,\n contentLength: task.content.length,\n model: task.model,\n timeoutMs: effectiveTimeout,\n });\n\n return this.executeWithRetry(task, opts);\n }\n\n /**\n * Computes effective timeout for a task.\n */\n private computeTimeout(task: CliTask, options?: ExecutionOptions): number {\n if (options?.timeoutMs !== undefined) return options.timeoutMs;\n if (task.timeoutMs !== undefined) return task.timeoutMs;\n return getTimeoutForTaskAuto(this.name, task.content);\n }\n\n /**\n * Whether the shared outer retry loop ({@link executeCliRetryLoop}) is\n * allowed to retry this adapter's failures. The base adapter honors the\n * caller's `allowRetry`. Subprocess adapters override this to suppress\n * the outer loop when their own transient-retry layer is active, so the\n * two layers do not nest into multiplied spawns (#2824).\n */\n protected shouldOuterRetry(opts: 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 const result = await executeCliRetryLoop(() => this.executeTask(task, opts), {\n maxRetries: opts.maxRetries,\n allowRetry: this.shouldOuterRetry(opts),\n baseDelayMs: 1_000,\n maxDelayMs: 16_000,\n cli: this.name,\n logger: this.logger,\n });\n\n if (result.ok) {\n this.recordUsage(result.value.response);\n this.logger.info('Task executed successfully', {\n cli: this.name,\n attempt: result.value.retryCount + 1,\n durationMs: result.value.response.durationMs,\n tokensUsed: result.value.response.usage?.totalTokens,\n });\n return { ok: true, value: result.value.response };\n }\n\n this.logger.warn('Task execution failed', {\n cli: this.name,\n error: result.error.message,\n retryable: result.error.retryable,\n });\n return result;\n }\n\n /**\n * Performs a health check.\n */\n async healthCheck(): Promise<HealthStatus> {\n try {\n const version = await this.getVersion();\n const versionStatus = this.checkVersionCompatibility(version);\n\n const message = this.getVersionMessage(versionStatus, version);\n const status: HealthStatus = {\n healthy: versionStatus !== 'unsupported' && versionStatus !== 'breaking',\n version,\n versionStatus,\n lastChecked: new Date(getTimeProvider().now()),\n ...(message !== undefined && { message }),\n };\n\n this.lastHealthCheck = status;\n return status;\n } catch (error) {\n return {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n message: error instanceof Error ? error.message : 'Health check failed',\n lastChecked: new Date(getTimeProvider().now()),\n };\n }\n }\n\n /**\n * Gets CLI version.\n */\n async getVersion(): Promise<string> {\n if (this.cachedVersion !== undefined && this.cachedVersion !== '') {\n return this.cachedVersion;\n }\n\n try {\n const { stdout } = await execAsync(`${this.name} --version`, {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n\n // Extract version number from output\n const version = this.parseVersion(stdout.trim());\n this.cachedVersion = version;\n return version;\n } catch (cause: unknown) {\n throw new Error(`Failed to get ${this.name} version`, { cause });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n * Uses usage-based tracking since CLI subprocess execution\n * doesn't expose HTTP rate limit headers.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n getCapacity(): Promise<CapacityStatus> {\n // Lazy-init the tracker if no caller has run initialize() yet (#2714).\n // Pre-fix every doctor invocation tripped this path: doctor calls\n // adapter.getCapacity() WITHOUT first calling adapter.initialize(),\n // so each of the four adapters logged a \"Capacity tracker uninitialized\"\n // WARN and returned a hardcoded 100k-token fallback. The fallback\n // surfaced in doctor's output as \"Capacity: 100% remaining\" — a\n // fictional reading, not a real one. The tracker is per-process and\n // idempotent under createCapacityTracker, so initializing on first\n // read is safe.\n if (this.capacityTracker === null) {\n this.initCapacityTracker();\n }\n const tracker = this.capacityTracker;\n if (tracker === null) {\n // Unreachable in practice — initCapacityTracker assigns the field —\n // but keep the type-safe path for the impossible case.\n throw new Error(`Capacity tracker initialization failed for ${this.name}`);\n }\n return Promise.resolve(tracker.getCapacity());\n }\n\n /**\n * Records usage from a response for capacity tracking.\n */\n protected recordUsage(response: CliResponse): void {\n if (this.capacityTracker !== null) {\n this.capacityTracker.recordUsage(response.usage);\n }\n }\n\n /**\n * Parses version from CLI output.\n */\n protected parseVersion(output: string): string {\n // Handle common version formats:\n // \"2.0.76 (Claude Code)\"\n // \"0.22.5\"\n // \"codex-cli 0.77.0\"\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output);\n return match?.[1] ?? '0.0.0';\n }\n\n /**\n * Checks version compatibility.\n */\n protected checkVersionCompatibility(version: string): VersionStatus {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n const validVersion = semver.valid(version);\n if (validVersion === null) {\n return 'unsupported';\n }\n\n const isLtMinimum = semver.lt(validVersion, requirements.minimum);\n if (isLtMinimum) {\n return 'unsupported';\n }\n\n const hasBreaking = requirements.breaking.some((v) => semver.gte(validVersion, v));\n if (hasBreaking) {\n return 'breaking';\n }\n\n const isLtRecommended = semver.lt(validVersion, requirements.recommended);\n if (isLtRecommended) {\n return 'outdated';\n }\n\n return 'supported';\n }\n\n /**\n * Gets version status message.\n */\n protected getVersionMessage(status: VersionStatus, version: string): string | undefined {\n const requirements = CLI_VERSION_REQUIREMENTS[this.name];\n\n switch (status) {\n case 'unsupported':\n return `Version ${version} is not supported. Minimum: ${requirements.minimum}`;\n case 'breaking':\n return `Version ${version} has known compatibility issues`;\n case 'outdated':\n return `Consider upgrading to ${requirements.recommended}`;\n case 'supported':\n return undefined;\n }\n }\n\n /**\n * Creates a CLI error.\n */\n protected createError(code: CliErrorCode, message: string, cause?: Error): CliError {\n const retryable = ['RATE_LIMITED', 'TIMEOUT', 'CONNECTION_ERROR'].includes(code);\n\n return {\n code,\n message,\n cli: this.name,\n retryable,\n ...(cause !== undefined && { cause }),\n };\n }\n\n /**\n * Normalizes CLI response to common format.\n */\n protected normalizeResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n ): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n }\n\n /**\n * Delays for the specified milliseconds.\n */\n protected delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * CLI Timeout Helpers\n *\n * Task complexity estimation for timeout selection.\n * Separated from timeout values (which live in config/timeouts.ts).\n *\n * @module cli-adapters/cli-timeout-helpers\n * (Source: Issue #984 — Centralize timeout configuration)\n */\n\nimport type { TaskComplexity } from '../config/timeouts.js';\nimport { getCliTimeout } from '../config/timeouts.js';\nimport { detectTaskCategory } from '../config/task-specialization.js';\nimport { getOutcomeStore } from '../orchestration/outcomes/outcome-store.js';\nimport type { CliNameLiteral } from '../config/model-capabilities-types.js';\n\n/**\n * Estimate task complexity from task description.\n *\n * Heuristics based on testing:\n * - Simple: Single function, quick query, < 5 files\n * - Standard: Multi-file changes, moderate analysis\n * - Complex: Codebase-wide, deep analysis, architecture\n *\n * @param taskDescription - Description of the task\n * @returns Estimated complexity\n */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n const lower = taskDescription.toLowerCase();\n\n // Complex indicators\n const complexIndicators = [\n 'codebase',\n 'architecture',\n 'refactor',\n 'all files',\n 'entire',\n 'comprehensive',\n 'deep analysis',\n 'system-wide',\n 'security',\n 'audit',\n 'vulnerability',\n ];\n if (complexIndicators.some((indicator) => lower.includes(indicator))) {\n return 'complex';\n }\n\n // Simple indicators\n // Testing and exploration demoted to simple per weather data (99%+ success) (#1401)\n const simpleIndicators = [\n 'single',\n 'quick',\n 'one function',\n 'simple',\n 'small',\n 'brief',\n 'short',\n 'run tests',\n 'test suite',\n 'exploration',\n 'explore',\n ];\n if (simpleIndicators.some((indicator) => lower.includes(indicator))) {\n return 'simple';\n }\n\n // Default to standard\n return 'standard';\n}\n\n// ============================================================================\n// Adaptive Timeout (#1534)\n// ============================================================================\n\n/** Minimum successful outcomes required before adaptive timeout kicks in. */\nexport const ADAPTIVE_TIMEOUT_MIN_SAMPLES = 10;\n\n/** Safety margin applied to p95 duration (p95 * margin = adaptive timeout). */\nexport const ADAPTIVE_TIMEOUT_MARGIN = 1.2;\n\n/**\n * Compute p95 of a sorted array of numbers.\n * Returns the value at the 95th percentile index.\n */\nfunction computeP95(sorted: readonly number[]): number {\n if (sorted.length === 0) return 0;\n const idx = Math.ceil(sorted.length * 0.95) - 1;\n return sorted[Math.min(idx, sorted.length - 1)] as number;\n}\n\n/** Options for adaptive timeout computation. */\nexport interface AdaptiveTimeoutOptions {\n /** Override the outcome store (for testing). */\n readonly store?: import('../orchestration/outcomes/outcome-store.js').OutcomeStore;\n}\n\n/**\n * Get adaptive timeout for a CLI + task description pair.\n *\n * Uses historical outcome data to compute p95 execution duration.\n * When sufficient samples exist, returns max(static_timeout, p95 * 1.2).\n * Falls back to static keyword-based timeout when data is sparse.\n *\n * @param cli - CLI name\n * @param taskDescription - Task description for complexity + category detection\n * @param options - Optional overrides (e.g., custom store for testing)\n * @returns Timeout in milliseconds (never less than static timeout)\n */\nexport function getAdaptiveTimeout(\n cli: string,\n taskDescription: string,\n options?: AdaptiveTimeoutOptions\n): number {\n const complexity = estimateTaskComplexity(taskDescription);\n const staticTimeout = getCliTimeout(cli, complexity);\n\n const match = detectTaskCategory(taskDescription);\n if (match === null) return staticTimeout;\n\n const store = options?.store ?? getOutcomeStore();\n const outcomes = store.query({\n cli: cli as CliNameLiteral,\n category: match.category,\n success: true,\n });\n\n if (outcomes.length < ADAPTIVE_TIMEOUT_MIN_SAMPLES) return staticTimeout;\n\n const durations = outcomes.map((o) => o.durationMs).sort((a, b) => a - b);\n const p95 = computeP95(durations);\n const adaptiveTimeout = Math.round(p95 * ADAPTIVE_TIMEOUT_MARGIN);\n\n return Math.max(staticTimeout, adaptiveTimeout);\n}\n","/**\n * CLI Timeout Profiles - Configurable timeouts per CLI tool.\n *\n * Delegates to `config/timeouts.ts` (canonical source, Issue #984).\n * This file provides backward-compatible re-exports.\n *\n * @module cli-adapters/cli-timeout-profiles\n * (Source: Issue #357, CLI delegation testing 2026-01-18)\n */\n\nimport {\n CLI_TIMEOUTS,\n getCliTimeout,\n type TaskComplexity,\n type TimeoutProfile,\n} from '../config/timeouts.js';\nimport {\n estimateTaskComplexity as _estimateTaskComplexity,\n getAdaptiveTimeout,\n} from './cli-timeout-helpers.js';\n\n// Re-export types for backward compatibility\nexport type { TimeoutProfile, TaskComplexity };\n\n/** Per-CLI timeout profiles. Canonical source: `config/timeouts.ts`. */\nexport const CLI_TIMEOUT_PROFILES: Record<string, TimeoutProfile> = {\n claude: CLI_TIMEOUTS.claude,\n gemini: CLI_TIMEOUTS.gemini,\n codex: CLI_TIMEOUTS.codex,\n};\n\n/** Default timeout profile. Canonical source: `config/timeouts.ts`. */\nexport const DEFAULT_TIMEOUT_PROFILE: TimeoutProfile = CLI_TIMEOUTS.default;\n\n/** Get timeout for a task. Canonical source: `config/timeouts.ts`. */\nexport function getTimeoutForTask(cli: string, complexity: TaskComplexity): number {\n return getCliTimeout(cli, complexity);\n}\n\n/** Estimate task complexity from description. Canonical: `cli-timeout-helpers.ts`. */\nexport function estimateTaskComplexity(taskDescription: string): TaskComplexity {\n return _estimateTaskComplexity(taskDescription);\n}\n\n/**\n * Get timeout with automatic complexity estimation.\n * Uses adaptive timeout from outcome history when sufficient data exists (#1534).\n */\nexport function getTimeoutForTaskAuto(cli: string, taskDescription: string): number {\n return getAdaptiveTimeout(cli, taskDescription);\n}\n","/**\n * nexus-agents/cli-adapters - Capacity Tracker\n *\n * Usage-based capacity tracking for CLI adapters.\n * Tracks cumulative token/request usage to estimate remaining capacity.\n *\n * Since CLI subprocess execution doesn't expose HTTP rate limit headers,\n * this tracker estimates capacity based on usage patterns.\n *\n * @see Issue #456 - Real API rate limit tracking\n */\n\nimport type { CliName, TokenUsage, CapacityStatus } from './types-core.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { clampPercent } from '../utils/math-utils.js';\n\n/**\n * Default rate limits per CLI provider (tokens per minute).\n * These are conservative estimates based on typical API tiers.\n * Override via environment variables: NEXUS_<CLI>_TOKEN_LIMIT\n */\nexport const DEFAULT_TOKEN_LIMITS: Record<CliName, number> = {\n claude: 100_000, // Claude API Build tier\n gemini: 1_000_000, // Gemini Pro generous limits\n codex: 500_000, // OpenAI tier 1\n opencode: 500_000, // Multi-provider proxy\n};\n\n/**\n * Default request limits per CLI provider (requests per minute).\n * Override via environment variables: NEXUS_<CLI>_REQUEST_LIMIT\n */\nexport const DEFAULT_REQUEST_LIMITS: Record<CliName, number> = {\n claude: 50, // Claude API Build tier\n gemini: 60, // Gemini Pro\n codex: 500, // OpenAI tier 1\n opencode: 300, // Multi-provider proxy\n};\n\n/**\n * Rate limit window in milliseconds (1 minute).\n */\nexport const RATE_LIMIT_WINDOW_MS = 60_000;\n\n/**\n * Configuration for capacity tracker.\n */\nexport interface CapacityTrackerConfig {\n /** Maximum tokens per window */\n readonly tokenLimit: number;\n /** Maximum requests per window */\n readonly requestLimit: number;\n /** Window duration in milliseconds */\n readonly windowMs: number;\n}\n\n/**\n * Tracked usage entry with timestamp.\n */\ninterface UsageEntry {\n readonly timestamp: number;\n readonly tokens: number;\n}\n\n/**\n * Creates default configuration for a CLI from environment or defaults.\n */\nexport function getDefaultConfig(cli: CliName): CapacityTrackerConfig {\n const envPrefix = `NEXUS_${cli.toUpperCase()}`;\n const tokenEnv = process.env[`${envPrefix}_TOKEN_LIMIT`];\n const requestEnv = process.env[`${envPrefix}_REQUEST_LIMIT`];\n\n return {\n tokenLimit:\n tokenEnv !== undefined && tokenEnv !== ''\n ? parseInt(tokenEnv, 10)\n : DEFAULT_TOKEN_LIMITS[cli],\n requestLimit:\n requestEnv !== undefined && requestEnv !== ''\n ? parseInt(requestEnv, 10)\n : DEFAULT_REQUEST_LIMITS[cli],\n windowMs: RATE_LIMIT_WINDOW_MS,\n };\n}\n\n/**\n * Capacity tracker for CLI adapters.\n *\n * Tracks cumulative usage within a sliding window to estimate\n * remaining capacity when HTTP headers are not available.\n *\n * @example\n * ```typescript\n * const tracker = new CapacityTracker(getDefaultConfig('claude'));\n *\n * // Record usage after each request\n * tracker.recordUsage({ inputTokens: 1000, outputTokens: 500 });\n *\n * // Get current capacity status\n * const status = tracker.getCapacity();\n * if (status.exhausted) {\n * // Wait before next request\n * }\n * ```\n */\nexport class CapacityTracker {\n private readonly config: CapacityTrackerConfig;\n private readonly usageHistory: UsageEntry[];\n private requestCount: number;\n private windowStart: number;\n\n /**\n * Timestamps of every recorded request (#3026 finding 4).\n *\n * Pre-fix, `requestCount` was a plain counter reset only by the\n * tumbling-window branch of `pruneOldEntries`. Under continuous\n * traffic across a window boundary, that branch drops requests that\n * are still inside the *sliding* window — e.g. with windowMs=60s, a\n * request at t=59s followed by one at t=61s would tumbling-reset\n * the counter to 1 even though the t=59s request is still inside\n * the [1s, 61s] window. The downstream `remainingRequests === 0`\n * exhaustion check fired prematurely (or too late) depending on\n * burst patterns.\n *\n * Counting via a per-request timestamp array that's pruned the same\n * way as `usageHistory` keeps the two views consistent. Every\n * `recordUsage` pushes here; `requestCount` is derived from\n * `.length` after pruning.\n */\n private requestTimestamps: number[];\n\n constructor(config: CapacityTrackerConfig) {\n this.config = config;\n this.usageHistory = [];\n this.requestCount = 0;\n this.requestTimestamps = [];\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Records token usage from a completed request.\n */\n recordUsage(usage: TokenUsage | undefined): void {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n this.requestTimestamps.push(now);\n this.requestCount = this.requestTimestamps.length;\n\n if (usage !== undefined) {\n const tokens = usage.totalTokens ?? usage.inputTokens + usage.outputTokens;\n this.usageHistory.push({\n timestamp: now,\n tokens,\n });\n }\n }\n\n /**\n * Gets current capacity status based on tracked usage.\n */\n getCapacity(): CapacityStatus {\n const now = getTimeProvider().now();\n this.pruneOldEntries(now);\n\n const usedTokens = this.usageHistory.reduce((sum, entry) => sum + entry.tokens, 0);\n const remainingTokens = Math.max(0, this.config.tokenLimit - usedTokens);\n const remainingRequests = Math.max(0, this.config.requestLimit - this.requestCount);\n\n const tokenUtilization = (usedTokens / this.config.tokenLimit) * 100;\n const requestUtilization = (this.requestCount / this.config.requestLimit) * 100;\n const utilizationPercent = clampPercent(Math.max(tokenUtilization, requestUtilization));\n\n const exhausted = remainingTokens === 0 || remainingRequests === 0;\n const resetTime = new Date(this.windowStart + this.config.windowMs);\n\n return {\n remainingTokens,\n remainingRequests,\n resetTime,\n utilizationPercent: Math.round(utilizationPercent * 100) / 100,\n exhausted,\n };\n }\n\n /**\n * Gets time until the rate limit window resets.\n */\n getTimeUntilReset(): number {\n const now = getTimeProvider().now();\n const resetTime = this.windowStart + this.config.windowMs;\n return Math.max(0, resetTime - now);\n }\n\n /**\n * Resets all tracked usage (for testing or manual reset).\n */\n reset(): void {\n this.usageHistory.length = 0;\n this.requestTimestamps.length = 0;\n this.requestCount = 0;\n this.windowStart = getTimeProvider().now();\n }\n\n /**\n * Updates configuration (e.g., after receiving actual rate limit info).\n */\n updateConfig(partial: Partial<CapacityTrackerConfig>): void {\n Object.assign(this.config, partial);\n }\n\n /**\n * Gets current configuration.\n */\n getConfig(): Readonly<CapacityTrackerConfig> {\n return { ...this.config };\n }\n\n /**\n * Removes entries older than the window duration.\n */\n private pruneOldEntries(now: number): void {\n const cutoff = now - this.config.windowMs;\n\n // Sliding-window prune (#3026 finding 4):\n // Pre-fix, this used a \"tumbling reset\" branch — when `windowStart`\n // (the time of the FIRST request) was older than the cutoff, the\n // whole structure was zeroed. Under continuous traffic, that condition\n // fires whenever the earliest tracked request is older than windowMs\n // ago — even though more recent requests are still inside the\n // sliding window. The result was a periodic mass-prune that incorrectly\n // dropped current-window requests, making `remainingRequests === 0`\n // fire prematurely (or too late) depending on burst pattern.\n //\n // Now both arrays are slide-pruned individually: drop entries with\n // `timestamp < cutoff`, leave the rest. `windowStart` is rebased to\n // the earliest remaining entry (used by `resetTime` reporting),\n // falling back to `now` when both arrays are empty.\n while (this.usageHistory[0] !== undefined && this.usageHistory[0].timestamp < cutoff) {\n this.usageHistory.shift();\n }\n while (this.requestTimestamps[0] !== undefined && this.requestTimestamps[0] < cutoff) {\n this.requestTimestamps.shift();\n }\n this.requestCount = this.requestTimestamps.length;\n\n const earliestRequest = this.requestTimestamps[0];\n const earliestUsage = this.usageHistory[0]?.timestamp;\n if (earliestRequest === undefined && earliestUsage === undefined) {\n this.windowStart = now;\n } else {\n this.windowStart = Math.min(earliestRequest ?? Infinity, earliestUsage ?? Infinity);\n }\n }\n}\n\n/**\n * Creates a capacity tracker for a specific CLI.\n */\nexport function createCapacityTracker(cli: CliName): CapacityTracker {\n return new CapacityTracker(getDefaultConfig(cli));\n}\n","import { getErrorMessage } from '../core/index.js';\n\n/**\n * Async Utilities\n *\n * Centralized async helper functions for delay, timeout, and promise utilities.\n * Consolidates 9+ duplicate sleep/delay implementations across the codebase.\n *\n * @module utils/async-utils\n * (Source: LOOP H-K consolidation)\n */\n\n// ============================================================================\n// Delay / Sleep\n// ============================================================================\n\n/**\n * Creates a promise that resolves after the specified delay.\n * Alias: `delay` (both names are exported for compatibility)\n *\n * @param ms - Delay in milliseconds\n * @returns Promise that resolves after the delay\n *\n * @example\n * ```typescript\n * await sleep(1000); // Wait 1 second\n * await delay(500); // Wait 500ms (alias)\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Alias for `sleep()` - provided for compatibility with existing code.\n */\nexport const delay = sleep;\n\n// ============================================================================\n// Timeout Wrapper\n// ============================================================================\n\n/**\n * Result type for withTimeout operations.\n */\nexport type TimeoutResult<T> =\n | { readonly ok: true; readonly value: T }\n | { readonly ok: false; readonly error: string };\n\n/**\n * Wraps a promise with a timeout.\n * Returns an error result if the timeout is exceeded.\n *\n * @param promise - The promise to wrap\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Error message if timeout is exceeded\n * @returns A result object with either the value or an error\n *\n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Request timed out after 5s'\n * );\n *\n * if (result.ok) {\n * console.log(result.value);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage: string\n): Promise<TimeoutResult<T>> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: true, value: result };\n } catch (error) {\n if (timeoutId !== undefined) clearTimeout(timeoutId);\n return { ok: false, error: getErrorMessage(error) };\n }\n}\n\n// ============================================================================\n// Promise Utilities\n// ============================================================================\n\n/**\n * Executes promises in sequence, one at a time.\n *\n * @param tasks - Array of functions that return promises\n * @returns Array of results in order\n *\n * @example\n * ```typescript\n * const results = await sequence([\n * () => fetch('/api/1'),\n * () => fetch('/api/2'),\n * ]);\n * ```\n */\nexport async function sequence<T>(tasks: ReadonlyArray<() => Promise<T>>): Promise<T[]> {\n const results: T[] = [];\n for (const task of tasks) {\n results.push(await task());\n }\n return results;\n}\n","/**\n * Canonical helpers for constructing CliError values with the correct\n * `retryable` flag.\n *\n * Consolidates three previously-duplicated copies:\n * - `cli-retry-loop.ts` (as a module-local set + `isRetryableError`)\n * - `adapters/codex-adapter-helpers.ts` (as `createCodexError`)\n * - `adapters/codex-mcp-adapter-helpers.ts` (as `createCliError`)\n * - `testing/adapters/mock-adapter-helpers.ts` (as `createCliError`)\n *\n * Every call path that classifies retryable CLI errors should now flow\n * through here. Adding a new retryable code is a one-line change in one\n * place instead of four.\n *\n * (Issue #2181 — adapter harness consolidation)\n *\n * @module cli-adapters/cli-error-helpers\n */\n\nimport type { CliError, CliErrorCode, CliName } from './types.js';\n\n/** Error codes the retry machinery treats as transient. */\nexport const RETRYABLE_ERROR_CODES: ReadonlySet<CliErrorCode> = new Set<CliErrorCode>([\n 'TIMEOUT',\n 'RATE_LIMITED',\n 'CONNECTION_ERROR',\n]);\n\n/** Whether a given CLI error code should be retried. */\nexport function isRetryableErrorCode(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Constructs a CliError with `retryable` auto-derived from the code.\n * Every adapter that needs to surface a CliError should prefer this\n * helper (or the `createError` method on `BaseCliAdapter`, which calls\n * into the same logic) rather than building the shape inline.\n */\nexport function createCliError(\n code: CliErrorCode,\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return {\n code,\n message,\n cli,\n retryable: isRetryableErrorCode(code),\n ...(cause !== undefined && { cause }),\n };\n}\n","/**\n * nexus-agents/cli-adapters - Unified CLI Retry Loop\n *\n * CLI-specific retry loop used by all CLI adapters (base + Gemini).\n * Supports optional circuit-breaker integration, returns CliResponse\n * with retryCount, and maps to FailureCategory for breaker tracking.\n *\n * Sibling implementation (see #2230): adapters/retry.ts holds the\n * generic, type-parameterized `withRetry<T>` for non-CLI use. Don't\n * reach for that one when you need circuit-breaker coupling; don't\n * reach for this one from non-CLI code. Math primitives differ\n * deliberately:\n * - this file: 1-indexed attempt, +0..30% jitter, cap-after\n * - adapters/retry.ts: 0-indexed attempt, ±jitterFactor, cap-before-jitter\n *\n * If you find yourself writing a third retry loop: stop, run\n * `consensus_vote` with scope_steward in the panel, and pick whichever\n * of these two fits — don't add a third.\n *\n * (Source: Issue #1596 — Extract shared prompt utils and rate-limit patterns)\n */\n\nimport type { Result } from '../core/index.js';\nimport { err, ok, getRandomProvider } from '../core/index.js';\nimport type { ILogger } from '../core/index.js';\nimport type { CliResponse, CliError, CliErrorCode, CliName } from './types.js';\nimport type { ICircuitBreaker, FailureCategory } from './circuit-breaker-types.js';\nimport { delay } from '../utils/async-utils.js';\nimport { RETRYABLE_ERROR_CODES } from './cli-error-helpers.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface CliRetryLoopConfig {\n readonly maxRetries: number;\n readonly allowRetry: boolean;\n readonly baseDelayMs: number;\n readonly maxDelayMs: number;\n readonly circuitBreaker?: ICircuitBreaker | null;\n readonly cli: CliName;\n readonly logger: ILogger;\n}\n\nexport interface CliRetryResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n}\n\n// ============================================================================\n// Retry Logic (moved from gemini-adapter-helpers.ts)\n// ============================================================================\n\n/**\n * Calculates exponential backoff delay with jitter.\n *\n * @param attempt - Current attempt number (1-indexed)\n * @param baseDelayMs - Base delay in milliseconds\n * @param maxDelayMs - Maximum delay cap in milliseconds\n * @returns Delay in milliseconds with jitter applied\n */\nexport function calculateBackoffDelay(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number\n): number {\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);\n const jitter = getRandomProvider().random() * 0.3 * exponentialDelay;\n const delayMs = exponentialDelay + jitter;\n return Math.min(delayMs, maxDelayMs);\n}\n\n/** Determines if an error code is retryable. */\nexport function isRetryableError(code: CliErrorCode): boolean {\n return RETRYABLE_ERROR_CODES.has(code);\n}\n\n/**\n * Categorizes a CLI error for circuit breaker tracking.\n * Returns a FailureCategory compatible with the circuit breaker.\n */\nexport function categorizeError(error: CliError): FailureCategory {\n switch (error.code) {\n case 'TIMEOUT':\n return 'timeout';\n case 'RATE_LIMITED':\n return 'rate_limit';\n case 'NOT_AUTHENTICATED':\n return 'authentication';\n case 'CONNECTION_ERROR':\n return 'connection';\n default:\n return 'unknown';\n }\n}\n\n// ============================================================================\n// Unified Retry Loop\n// ============================================================================\n\n/**\n * Executes a CLI operation with retry logic and optional circuit breaker.\n *\n * Used by both BaseCliAdapter (no circuit breaker) and GeminiCliAdapter\n * (with circuit breaker) to eliminate duplicate retry implementations.\n */\nexport async function executeCliRetryLoop(\n executeFn: () => Promise<Result<CliResponse, CliError>>,\n config: CliRetryLoopConfig\n): Promise<Result<CliRetryResult, CliError>> {\n const maxAttempts = config.allowRetry ? config.maxRetries + 1 : 1;\n let lastError: CliError | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const result = await executeFn();\n\n if (result.ok) {\n return ok({ response: result.value, retryCount: attempt - 1 });\n }\n\n lastError = result.error;\n\n // Record failure with circuit breaker if present\n if (config.circuitBreaker !== undefined && config.circuitBreaker !== null) {\n config.circuitBreaker.recordFailure(categorizeError(lastError));\n }\n\n // Check if we should retry\n if (!shouldRetry(lastError, attempt, maxAttempts, config.circuitBreaker)) {\n return err(lastError);\n }\n\n const delayMs = calculateBackoffDelay(attempt, config.baseDelayMs, config.maxDelayMs);\n config.logger.debug('Retrying CLI execution', {\n cli: config.cli,\n attempt,\n nextAttempt: attempt + 1,\n delayMs: Math.round(delayMs),\n });\n\n await delay(delayMs);\n }\n\n return err(\n lastError ?? {\n code: 'UNKNOWN',\n message: 'Max retries exceeded',\n cli: config.cli,\n retryable: false,\n }\n );\n}\n\nfunction shouldRetry(\n error: CliError,\n attempt: number,\n maxAttempts: number,\n circuitBreaker?: ICircuitBreaker | null\n): boolean {\n if (attempt >= maxAttempts) return false;\n if (!error.retryable) return false;\n if (!isRetryableError(error.code)) return false;\n if (circuitBreaker?.getState() === 'open') return false;\n return true;\n}\n","/**\n * Environment-variable allowlist for spawned CLI subprocesses (#2865).\n *\n * `spawnSubprocess` previously passed the entire `process.env` to every\n * spawned CLI (claude / gemini / codex / opencode) — only `CLAUDECODE`\n * was stripped. That leaked cross-vendor API keys: the gemini CLI\n * received `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`, the codex CLI\n * received `GOOGLE_AI_API_KEY`, and so on. A buggy or malicious CLI\n * could exfiltrate keys it has no business seeing.\n *\n * `buildChildEnv()` constructs a curated child environment instead:\n * base infrastructure vars that every CLI needs, plus ONLY the spawned\n * CLI's own vendor credential(s).\n *\n * @module cli-adapters/subprocess-env\n */\n\nimport type { CliName } from './types.js';\n\n/**\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 '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=0` 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 * 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 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 `=0` hatch (#4037).\n *\n * Escape hatch: `NEXUS_SUBPROCESS_ENV_ALLOWLIST=0` restores the\n * pre-#2865 full-passthrough behavior (minus `CLAUDECODE`) — a\n * field un-break if the allowlist ever drops a var a CLI needs.\n */\nexport function buildChildEnv(cliName: CliName): NodeJS.ProcessEnv {\n const source = process.env;\n const childEnv: NodeJS.ProcessEnv = {};\n // 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 (source['NEXUS_SUBPROCESS_ENV_ALLOWLIST'] === '0') {\n for (const [key, value] of Object.entries(source)) {\n if (value !== undefined && key !== 'CLAUDECODE') childEnv[key] = value;\n }\n childEnv[NEXUS_SUBPROCESS_DEPTH_ENV] = nextDepth;\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 return childEnv;\n}\n\n/** Test/introspection accessor for the per-CLI vendor-key map. */\nexport function getCliVendorKeys(): Readonly<Record<CliName, readonly string[]>> {\n return CLI_VENDOR_KEYS;\n}\n","/**\n * cli-error-envelope — extract the actionable message from a CLI's\n * structured error envelope.\n *\n * When `claude`, `codex`, etc. return a JSON envelope with `is_error: true`,\n * the response parser correctly fails to find a usable assistant message\n * and falls through to the generic PARSE_ERROR path in `subprocess-adapter`.\n * That path stuffs the first 500 chars of the envelope into the error\n * message, producing the unreadable wall of escaped JSON described in #2440.\n *\n * This module unwraps known envelope shapes so the operator sees:\n *\n * ✗ Claude CLI: Not logged in\n * → claude /login, then retry\n *\n * instead of 600 characters of `{\"timestamp\":\"...\",\"level\":\"warn\",...}`.\n *\n * Source: Issue #2440 (round-14 onboarding audit, ask 1 + ask 2).\n */\n\nimport type { CliErrorCode, CliName } from './types.js';\nimport { isRateLimitText } from '../adapters/rate-limit-detector.js';\n\n/**\n * Result of unwrapping a CLI's structured error envelope. `null` when the\n * stdout doesn't match a known shape — caller falls back to the existing\n * snippet behavior.\n */\nexport interface ParsedCliError {\n /** Short, user-facing message — the unwrapped CLI error string. */\n readonly message: string;\n /** Classified code so the retry/fail-closed logic can do the right thing. */\n readonly code: CliErrorCode;\n /** Optional one-line hint with the canonical fix for this CLI. */\n readonly hint?: string;\n}\n\n/**\n * Claude CLI structured envelope shape:\n * {\"type\":\"result\",\"is_error\":true,\"result\":\"<reason>\",\"session_id\":\"...\",...}\n *\n * Use a structural type guard rather than parsing into a strict schema —\n * upstream may add fields and we only care about three of them.\n */\ninterface ClaudeErrorEnvelope {\n readonly type: 'result';\n readonly is_error: true;\n readonly result?: string;\n}\n\nfunction isClaudeErrorEnvelope(v: unknown): v is ClaudeErrorEnvelope {\n if (typeof v !== 'object' || v === null) return false;\n const obj = v as { type?: unknown; is_error?: unknown };\n return obj.type === 'result' && obj.is_error === true;\n}\n\n/**\n * Codex CLI envelope shape (best-effort — codex CLI's error shape is\n * less stable than Claude's):\n * {\"error\":\"<reason>\"} or {\"is_error\":true,\"message\":\"<reason>\"}\n */\nfunction unwrapCodexEnvelope(parsed: unknown): string | null {\n if (typeof parsed !== 'object' || parsed === null) return null;\n const obj = parsed as { error?: unknown; message?: unknown; is_error?: unknown };\n if (typeof obj.error === 'string' && obj.error !== '') return obj.error;\n if (obj.is_error === true && typeof obj.message === 'string' && obj.message !== '') {\n return obj.message;\n }\n return null;\n}\n\n/** Login hint matched against the parsed message text, per CLI. */\nconst LOGIN_HINTS: Record<CliName, string> = {\n claude: 'claude /login',\n codex: 'codex login',\n gemini: 'gemini',\n opencode: 'opencode auth login',\n};\n\nconst NOT_AUTH_PATTERNS: readonly RegExp[] = [\n /not logged in/i,\n /please run \\/?login/i,\n /authentication (?:required|expired|failed)/i,\n /invalid (?:api ?key|credentials)/i,\n /unauthorized/i,\n // #2455 ask 1: catch \"API key expired\" / \"API key revoked\" / \"API key\n // missing\" — the bare /invalid api key/ pattern misses these. Architects\n // explicitly ruled OUT `permission denied` (that's authz, not authn —\n // routing to /login is the wrong fix).\n /api[- ]?key (?:expired|revoked|missing)/i,\n // Token expiry/revocation as a standalone signal, not co-occurring with\n // \"unauthorized\" — some upstreams emit \"Token expired. Please re-auth.\"\n // without the unauthorized keyword.\n /token (?:expired|revoked)/i,\n // #3350: OAuth refresh-token rotation. The codex CLI emits \"Your access\n // token could not be refreshed because your refresh token was already used.\n // Please log out and sign in again.\" This previously fell through to a raw\n // fail-closed voter error with no `<cli> login` signal for the operator.\n /refresh token .*already used/i,\n /could not be refreshed/i,\n /log ?out and sign in/i,\n /sign in again/i,\n];\n\nfunction classifyMessage(message: string): { code: CliErrorCode; auth: boolean } {\n for (const re of NOT_AUTH_PATTERNS) {\n if (re.test(message)) return { code: 'NOT_AUTHENTICATED', auth: true };\n }\n return { code: 'EXECUTION_ERROR', auth: false };\n}\n\n/**\n * Resolve a bare CLI name from a possibly-prefixed identifier. `IModelAdapter`\n * exposes `providerId` as `cli-codex`/`cli-claude` (see `CliToModelAdapter`),\n * so callers can pass either form. Returns `null` when the name is not a known\n * CLI — the remediation map can't produce a hint we'd vouch for.\n */\nfunction resolveCliName(cliName: string): CliName | null {\n const bare = cliName.startsWith('cli-') ? cliName.slice('cli-'.length) : cliName;\n return bare in LOGIN_HINTS ? (bare as CliName) : null;\n}\n\n/**\n * #3350: one-line operator remediation for a stale-auth voter failure.\n *\n * Returns `null` when `message` is not an authentication error (callers leave\n * the error text untouched), or when `cliName` is not a recognized CLI.\n * Otherwise returns a single line reusing {@link LOGIN_HINTS}, e.g.\n *\n * Re-authenticate: run `codex login` (the codex CLI's stored OAuth token is stale).\n *\n * Reuses {@link classifyMessage} + {@link LOGIN_HINTS} — does not duplicate the\n * pattern list or the per-CLI command map (DRY).\n */\nexport function authRemediation(message: string, cliName: string): string | null {\n if (!classifyMessage(message).auth) return null;\n const cli = resolveCliName(cliName);\n if (cli === null) return null;\n return `Re-authenticate: run \\`${LOGIN_HINTS[cli]}\\` (the ${cli} CLI's stored OAuth token is stale).`;\n}\n\n/**\n * Classify an error message a CLI's response parser already extracted from an\n * error-only stream (e.g. OpenCode's NDJSON `{\"type\":\"error\",...}` event,\n * surfaced via `ICliResponseParser.extractErrorMessage`). Unlike\n * {@link parseCliErrorEnvelope} this takes the *already-unwrapped* message — the\n * parser did the format-specific extraction — and only classifies it, mirroring\n * the recovery order in `subprocess-adapter.handleUnparseableOutput`:\n * rate-limit → auth → generic execution error. `cliName` may be prefixed\n * (`cli-opencode`) — resolved internally for the remediation hint.\n */\nexport function classifyExtractedError(message: string, cliName: string): ParsedCliError {\n const trimmed = message.trim();\n if (isRateLimitText(trimmed)) {\n return { message: trimmed, code: 'RATE_LIMITED' };\n }\n const { code, auth } = classifyMessage(trimmed);\n if (auth) {\n const hint = authRemediation(trimmed, cliName);\n return hint !== null ? { message: trimmed, code, hint } : { message: trimmed, code };\n }\n return { message: trimmed, code };\n}\n\n/**\n * Try to find the actionable error string inside a CLI's stdout. Returns\n * `null` if the stdout doesn't look like a structured error envelope (the\n * caller then falls back to the existing snippet truncation).\n */\nexport function parseCliErrorEnvelope(stdout: string, cliName: CliName): ParsedCliError | null {\n const trimmed = stdout.trim();\n if (trimmed === '' || (!trimmed.startsWith('{') && !trimmed.startsWith('['))) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n // Whole-blob parse failed — could be NDJSON (one JSON object per line).\n // Try the last line, which is where Claude/Codex emit the terminal\n // envelope.\n return tryLastLine(trimmed, cliName);\n }\n\n let message: string | undefined;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n message = parsed.result;\n } else {\n const codex = unwrapCodexEnvelope(parsed);\n if (codex !== null) message = codex;\n }\n\n if (message === undefined || message === '') return null;\n\n return buildParsedError(message, cliName);\n}\n\nfunction tryLastLine(stdout: string, cliName: CliName): ParsedCliError | null {\n const lines = stdout.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length < 2) return null;\n const last = lines.at(-1);\n if (last === undefined) return null;\n if (!last.startsWith('{')) return null;\n try {\n const parsed = JSON.parse(last) as unknown;\n if (isClaudeErrorEnvelope(parsed) && typeof parsed.result === 'string') {\n return buildParsedError(parsed.result, cliName);\n }\n } catch {\n /* ignore — fall through to null */\n }\n return null;\n}\n\nfunction buildParsedError(message: string, cliName: CliName): ParsedCliError {\n // Trim to first line + cap length — operators don't need 500 chars of envelope.\n const firstLine = (message.split('\\n')[0] ?? message).trim().slice(0, 240);\n const { code, auth } = classifyMessage(firstLine);\n if (auth) {\n return {\n message: firstLine,\n code,\n hint: `Run \\`${LOGIN_HINTS[cliName]}\\` to authenticate, then retry.`,\n };\n }\n return { message: firstLine, code };\n}\n","/**\n * nexus-agents/utils - Type Coercion Utilities\n *\n * Safe type coercion helpers for parsing and validating unknown values.\n * Consolidates patterns used across parsers, validators, and adapters.\n *\n * @module utils/type-coercion\n */\n\n/**\n * Safely casts value to Record if it's a non-null, non-array object.\n *\n * @param value - Value to check\n * @returns Record if valid object, null otherwise\n *\n * @example\n * const data = asRecord(parsed);\n * if (data !== null) {\n * const name = asString(data.name);\n * }\n */\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return null;\n}\n\n/**\n * Type guard version of asRecord for use in conditionals.\n *\n * @param value - Value to check\n * @returns True if value is a non-null, non-array object\n *\n * @example\n * if (isRecord(data)) {\n * console.log(data.field);\n * }\n */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Safely extracts a string value.\n *\n * @param value - Value to check\n * @returns String if valid, null otherwise\n */\nexport function asString(value: unknown): string | null {\n return typeof value === 'string' ? value : null;\n}\n\n/**\n * Safely extracts a number value.\n *\n * @param value - Value to check\n * @returns Number if valid (not NaN, not Infinity), null otherwise\n */\nexport function asNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) {\n return value;\n }\n return null;\n}\n\n/**\n * Safely extracts a boolean value.\n *\n * @param value - Value to check\n * @returns Boolean if valid, null otherwise\n */\nexport function asBoolean(value: unknown): boolean | null {\n return typeof value === 'boolean' ? value : null;\n}\n\n/**\n * Safely extracts an array value.\n *\n * @param value - Value to check\n * @returns Array if valid, null otherwise\n */\nexport function asArray(value: unknown): unknown[] | null {\n return Array.isArray(value) ? value : null;\n}\n\n/**\n * Extracts a string field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns String value or undefined if not found/invalid\n */\nexport function extractStringField(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n const value = record[key];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Extracts a number field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Number value or null if not found/invalid\n */\nexport function extractNumberField(record: Record<string, unknown>, key: string): number | null {\n const value = record[key];\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\n/**\n * Extracts a boolean field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Boolean value or undefined if not found/invalid\n */\nexport function extractBooleanField(\n record: Record<string, unknown>,\n key: string\n): boolean | undefined {\n const value = record[key];\n return typeof value === 'boolean' ? value : undefined;\n}\n\n/**\n * Extracts a nested record field from a record.\n *\n * @param record - Record to extract from\n * @param key - Field key\n * @returns Nested record or null if not found/invalid\n */\nexport function extractRecordField(\n record: Record<string, unknown>,\n key: string\n): Record<string, unknown> | null {\n return asRecord(record[key]);\n}\n\n/**\n * Safely parses JSON with fallback to null.\n *\n * @param raw - Raw JSON string\n * @returns Parsed value or null if invalid\n */\nexport function safeJsonParse(raw: string): unknown {\n try {\n return JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n}\n\n/**\n * Safely parses JSON and returns as Record.\n *\n * @param raw - Raw JSON string\n * @returns Parsed record or null if invalid\n */\nexport function safeJsonParseRecord(raw: string): Record<string, unknown> | null {\n const parsed = safeJsonParse(raw);\n return asRecord(parsed);\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Response Parser\n *\n * Defensive parser for Claude CLI JSON output.\n * Handles version 2.0.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'claude-parser' });\n\n/**\n * Claude CLI response structure.\n * (Source: CLI testing 2026-01-04)\n */\nexport interface ClaudeCliResponse {\n readonly type: 'result';\n readonly subtype?: 'success' | 'error';\n readonly is_error: boolean;\n readonly duration_ms?: number;\n readonly result: string;\n readonly session_id?: string;\n readonly total_cost_usd?: number;\n readonly usage?: {\n readonly input_tokens: number;\n readonly output_tokens: number;\n readonly cache_creation_input_tokens?: number;\n readonly cache_read_input_tokens?: number;\n };\n readonly modelUsage?: Record<\n string,\n {\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly cacheReadInputTokens?: number;\n readonly cacheCreationInputTokens?: number;\n readonly costUSD?: number;\n readonly contextWindow?: number;\n }\n >;\n}\n\n/**\n * Parser for Claude CLI JSON output.\n * Implements defensive parsing - only requires essential fields.\n */\nexport class ClaudeResponseParser implements ICliResponseParser<ClaudeCliResponse> {\n readonly name = 'claude-parser';\n readonly supportedVersionRange = '>=2.0.0 <3.0.0';\n\n /**\n * Parses complete Claude CLI response.\n */\n parse(raw: string): ClaudeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n\n if (!this.isValidResponse(data)) {\n return null;\n }\n\n return data;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Returns null if the response contains an error.\n */\n extractResponse(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n // Check for API errors (is_error: true indicates an error occurred)\n if (record.is_error === true) {\n return null;\n }\n\n const result = record.result;\n if (typeof result === 'string') {\n return result;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const usageRecord = asRecord(record.usage);\n if (usageRecord === null) return null;\n\n const inputTokens = extractNumberField(usageRecord, 'input_tokens');\n const outputTokens = extractNumberField(usageRecord, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usageRecord, 'cache_read_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const sessionId = record.session_id;\n if (typeof sessionId === 'string') {\n return sessionId;\n }\n\n return null;\n } catch {\n logger.debug('Skipped malformed output line', { snippet: raw.slice(0, 100) });\n return null;\n }\n }\n\n /**\n * Type guard for valid response structure.\n */\n private isValidResponse(data: unknown): data is ClaudeCliResponse {\n const record = asRecord(data);\n if (record === null) return false;\n\n // Only require the essential field\n return typeof record.result === 'string';\n }\n}\n","/**\n * Key-free model enumeration for CLI-subprocess adapters via models.dev (#3405).\n *\n * claude/codex/gemini CLIs have no `list-models` command, and their OAuth tokens\n * can't call the vendor `/v1/models` REST endpoints (inference-only). So we\n * enumerate from the committed, CI-refreshed **models.dev snapshot** filtered by\n * vendor — a current, comprehensive, *key-free* catalog. This is EXISTENCE only\n * (liveness is handled reactively by the 404 fallback); the in-tree registry\n * stays authoritative for pricing/capability.\n *\n * Fail-OPEN: a missing/malformed snapshot yields `[]`, never throws.\n *\n * @module config/models-dev-by-vendor\n */\nimport { createLogger } from '../core/index.js';\n\nimport { loadModelsDevSnapshot } from './models-dev-snapshot-loader.js';\n\nconst logger = createLogger({ component: 'models-dev-by-vendor' });\n\n/**\n * CLI name → models.dev vendor key. opencode is intentionally absent — it has a\n * native `opencode models` probe (wired separately).\n */\nexport const CLI_TO_MODELSDEV_VENDOR: Readonly<Record<string, string>> = {\n claude: 'anthropic',\n codex: 'openai',\n gemini: 'google',\n};\n\ninterface VendoredId {\n readonly id: string;\n readonly vendor: string;\n}\n\nlet cached: readonly VendoredId[] | null = null;\n\nfunction loadEntries(): readonly VendoredId[] {\n if (cached !== null) return cached;\n try {\n const { entries } = loadModelsDevSnapshot();\n // `vendor` is a required ModelEntry field; a non-matching/absent value simply\n // fails the equality filter below, so no defensive fallback is needed.\n cached = entries.map((e) => ({ id: e.id, vendor: e.vendor }));\n } catch (error: unknown) {\n logger.debug('models.dev snapshot load failed; enumeration empty', {\n error: error instanceof Error ? error.message : String(error),\n });\n cached = [];\n }\n return cached;\n}\n\n/** Reset the in-process snapshot cache (tests). */\nexport function resetModelsDevByVendorCache(): void {\n cached = null;\n}\n\n/** All model ids the models.dev snapshot lists for `vendor`. */\nexport function listModelsByVendor(vendor: string): readonly { id: string }[] {\n return loadEntries()\n .filter((e) => e.vendor === vendor)\n .map((e) => ({ id: e.id }));\n}\n\n/**\n * Model ids for a CLI, mapped via {@link CLI_TO_MODELSDEV_VENDOR}. Returns `[]`\n * for CLIs without a vendor mapping (e.g. opencode, which enumerates natively).\n */\nexport function listModelsForCli(cliName: string): readonly { id: string; provider: string }[] {\n const vendor = CLI_TO_MODELSDEV_VENDOR[cliName];\n if (vendor === undefined) return [];\n return listModelsByVendor(vendor).map((m) => ({ id: m.id, provider: vendor }));\n}\n","/**\n * nexus-agents/cli-adapters - Claude CLI Adapter\n *\n * Subprocess-based adapter for Claude CLI.\n * Uses JSON output format for stable parsing.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ClaudeResponseParser } from '../parsers/claude-parser.js';\nimport type { CliModelInfo } from '../types-capability.js';\nimport { listModelsForCli } from '../../config/models-dev-by-vendor.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n FALLBACK_CONTEXT_WINDOW,\n FALLBACK_MAX_OUTPUT,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Maps internal model names → Claude CLI aliases. Derived entirely from the\n * canonical registry: every claude entry contributes its `cliAlias` (passthrough),\n * its `cliModelName`, and every legacy-name in `aliases[]`. Migration of these\n * legacy strings into the registry happened in #2200 Child 1.\n */\nconst MODEL_TO_CLI_ALIAS: Record<string, string> = buildClaudeAliasMap();\n\nfunction buildClaudeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('claude')) {\n if (model.cliAlias === undefined) continue;\n const alias = model.cliAlias;\n map[alias] = alias;\n if (model.cliModelName !== undefined) map[model.cliModelName] = alias;\n for (const legacyName of model.aliases ?? []) {\n map[legacyName] = alias;\n }\n }\n return map;\n}\n\n/**\n * Default cost when an unrecognized model id is passed (pricing matches\n * current Opus, the strongest tier — conservative over-estimate). Per-model\n * legacy cost overrides were removed in #2200 Child 1; they're reachable\n * via the registry now.\n */\nconst UNKNOWN_MODEL_DEFAULT_INPUT_COST = 5.0;\nconst UNKNOWN_MODEL_DEFAULT_OUTPUT_COST = 25.0;\n\n/**\n * Claude CLI adapter using subprocess transport.\n * Executes: claude -p --output-format json \"<task>\"\n */\nexport class ClaudeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'claude';\n protected readonly parser: ICliResponseParser = new ClaudeResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('claude'));\n }\n\n /**\n * Key-free model enumeration (#3405): the claude CLI has no list-models\n * command and its OAuth token can't call /v1/models, so we enumerate the\n * vendor's models from the models.dev snapshot. Existence only.\n */\n listModels(): Promise<readonly CliModelInfo[]> {\n return Promise.resolve(listModelsForCli(this.name));\n }\n\n /**\n * Gets Claude model information.\n * `buildModelInfo` matches `cliModelName`, `cliAlias`, and `aliases[]` —\n * a single call handles 'opus', 'sonnet', 'haiku', current model names,\n * and the legacy `claude-opus-4` / `claude-haiku-3` / etc. entries that\n * live in the registry's aliases since #2200 Child 1.\n *\n * Truly unrecognized models fall through to conservative defaults\n * (current Opus pricing).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('claude', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: this.model,\n contextWindow: FALLBACK_CONTEXT_WINDOW,\n maxOutput: FALLBACK_MAX_OUTPUT,\n costPerMillionInput: UNKNOWN_MODEL_DEFAULT_INPUT_COST,\n costPerMillionOutput: UNKNOWN_MODEL_DEFAULT_OUTPUT_COST,\n };\n }\n\n /** Appends optional string-type task options to CLI args. */\n private appendTaskOptions(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--add-dir', workDir);\n }\n const mcpConfigPath = task.options?.['mcpConfigPath'];\n if (typeof mcpConfigPath === 'string' && mcpConfigPath.length > 0) {\n args.push('--mcp-config', mcpConfigPath);\n }\n // Allow full tool access in non-interactive mode (needed for SWE-bench)\n if (task.options?.['skipPermissions'] === true) {\n args.push('--dangerously-skip-permissions');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses stdin for the prompt to avoid argument escaping issues,\n * especially important when using --add-dir.\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['-p', '--output-format', 'json'];\n\n // Add model - convert internal names to CLI aliases\n const internalModel = task.model ?? this.model;\n const cliModel = MODEL_TO_CLI_ALIAS[internalModel] ?? internalModel;\n args.push('--model', cliModel);\n\n // Add system prompt if provided\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n args.push('--system-prompt', task.systemPrompt);\n }\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n this.appendTaskOptions(args, task);\n\n // Note: maxTokens is intentionally not passed to Claude CLI.\n // The Claude CLI does not support --max-tokens. Use --max-budget-usd instead.\n // The CLI handles token limits internally based on model configuration.\n\n // Pass prompt via stdin to avoid argument escaping issues\n return { command: 'claude', args, stdin: task.content };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter\n *\n * Subprocess-based adapter for Gemini CLI with:\n * - Tiered timeout profiles based on task complexity\n * - Resilient JSON parsing with fallback strategies\n * - Exponential backoff retry logic\n * - Circuit breaker integration for sustained failures\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n * (Source: Issue #389 - Merged enhanced adapter back to canonical)\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { Result, ILogger } from '../../core/index.js';\nimport { ok, err, createLogger, getTimeProvider } from '../../core/index.js';\nimport type {\n ICliResponseParser,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n CliName,\n ExecutionOptions,\n ResolvedExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { ResilientGeminiParser } from '../parsers/gemini-parser-resilient.js';\nimport type { CliModelInfo } from '../types-capability.js';\nimport { listModelsForCli } from '../../config/models-dev-by-vendor.js';\nimport {\n getTimeoutForTask,\n estimateTaskComplexity,\n type TaskComplexity,\n} from '../cli-timeout-profiles.js';\nimport {\n CliCircuitBreaker,\n DEFAULT_CIRCUIT_BREAKER_CONFIG,\n type CircuitBreakerConfig,\n type CircuitBreakerSnapshot,\n} from '../circuit-breaker.js';\nimport { GEMINI_LEGACY_DEFAULTS, createCircuitOpenError } from './gemini-adapter-helpers.js';\nimport { executeCliRetryLoop } from '../cli-retry-loop.js';\nimport {\n buildModelInfo,\n getCliModelName,\n getDefaultModelForCli,\n} from '../../config/model-config-helpers.js';\n\n/** Derive the CLI model name for the default Gemini model from the canonical registry. */\nconst DEFAULT_GEMINI_CLI_MODEL: string = getCliModelName(getDefaultModelForCli('gemini'));\n\n/** Configuration for Gemini adapter. Extends BaseAdapterOptions with retry/circuit breaker. */\nexport interface GeminiConfig extends BaseAdapterOptions {\n /** Maximum retry attempts (default: 3) */\n readonly maxRetries?: number;\n /** Base delay for exponential backoff in ms (default: 1000) */\n readonly baseDelayMs?: number;\n /** Maximum delay for backoff in ms (default: 30000) */\n readonly maxDelayMs?: number;\n /** Circuit breaker configuration */\n readonly circuitBreakerConfig?: Partial<CircuitBreakerConfig>;\n /** Enable circuit breaker (default: true) */\n readonly enableCircuitBreaker?: boolean;\n}\n\n/** Execution result with metadata. */\nexport interface GeminiExecutionResult {\n readonly response: CliResponse;\n readonly retryCount: number;\n readonly totalDurationMs: number;\n readonly complexity: TaskComplexity;\n readonly circuitState: 'closed' | 'open' | 'half-open';\n}\n\nconst DEFAULT_CONFIG: Required<Omit<GeminiConfig, 'logger' | 'circuitBreakerConfig'>> = {\n model: DEFAULT_GEMINI_CLI_MODEL,\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30_000,\n enableCircuitBreaker: true,\n};\n\n/**\n * Gemini CLI adapter with reliability features.\n *\n * Includes tiered timeouts, resilient parsing, retry logic, and circuit breaker.\n */\nexport class GeminiCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'gemini';\n protected readonly parser: ICliResponseParser;\n\n private readonly model: string;\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n private readonly circuitBreaker: CliCircuitBreaker | null;\n private readonly adapterLogger: ILogger;\n\n constructor(options?: GeminiConfig) {\n const mergedConfig = { ...DEFAULT_CONFIG, ...options };\n super(options?.logger);\n\n this.model = mergedConfig.model;\n this.maxRetries = mergedConfig.maxRetries;\n this.baseDelayMs = mergedConfig.baseDelayMs;\n this.maxDelayMs = mergedConfig.maxDelayMs;\n this.parser = new ResilientGeminiParser();\n this.adapterLogger = options?.logger ?? createLogger({ component: 'gemini-adapter' });\n\n // Initialize circuit breaker if enabled\n if (mergedConfig.enableCircuitBreaker) {\n const cbConfig: CircuitBreakerConfig = {\n ...DEFAULT_CIRCUIT_BREAKER_CONFIG,\n ...options?.circuitBreakerConfig,\n };\n this.circuitBreaker = new CliCircuitBreaker('gemini', cbConfig);\n } else {\n this.circuitBreaker = null;\n }\n }\n\n /** Key-free model enumeration via the models.dev snapshot (#3405). */\n listModels(): Promise<readonly CliModelInfo[]> {\n return Promise.resolve(listModelsForCli(this.name));\n }\n\n /**\n * Gets Gemini model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n * Note: maxOutput is capped at 8_192 (Gemini CLI constraint).\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('gemini', this.model);\n if (fromRegistry !== undefined) {\n return { ...fromRegistry, maxOutput: 8_192 };\n }\n return {\n id: this.model,\n name: GEMINI_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow:\n GEMINI_LEGACY_DEFAULTS.contextWindows[this.model] ?? GEMINI_LEGACY_DEFAULTS.contextWindow,\n maxOutput: 8_192,\n costPerMillionInput:\n GEMINI_LEGACY_DEFAULTS.inputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n GEMINI_LEGACY_DEFAULTS.outputCosts[this.model] ?? GEMINI_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Executes a task with reliability features.\n */\n override async execute(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n const result = await this.executeWithMetadata(task, options);\n\n if (result.ok) {\n return ok(result.value.response);\n }\n\n return err(result.error);\n }\n\n /**\n * Executes with full metadata about retry attempts and circuit state.\n */\n async executeWithMetadata(\n task: CliTask,\n options?: ExecutionOptions\n ): Promise<Result<GeminiExecutionResult, CliError>> {\n const circuitCheckResult = this.checkCircuitBreaker();\n if (circuitCheckResult !== null) {\n return err(circuitCheckResult);\n }\n\n const startTime = getTimeProvider().now();\n const complexity = estimateTaskComplexity(task.content);\n const effectiveOptions = this.buildExecutionOptions(task.content, options);\n\n const result = await this.executeWithRetryTracking(task, effectiveOptions);\n\n return this.buildExecutionResult(result, startTime, complexity);\n }\n\n /**\n * Gets current circuit breaker snapshot.\n */\n getCircuitBreakerSnapshot(): CircuitBreakerSnapshot | null {\n return this.circuitBreaker?.getSnapshot() ?? null;\n }\n\n /**\n * Resets the circuit breaker to closed state.\n */\n resetCircuitBreaker(): void {\n this.circuitBreaker?.reset();\n }\n\n /**\n * Gets CLI command and arguments for execution.\n */\n protected override getCommand(task: CliTask): CommandConfig {\n const args: string[] = [];\n\n // Add the task content as positional argument\n args.push(task.content);\n\n // Add output format\n args.push('-o', 'json');\n\n // Add model (always present due to default)\n const model = task.model ?? this.model;\n args.push('-m', model);\n\n // Add session for continuation\n if (task.sessionId !== undefined && task.sessionId !== '') {\n args.push('--resume', task.sessionId);\n }\n\n // Note: Sandbox mode (-s) removed - causes npm permission issues\n // and \"rebuilt dependencies successfully\" contamination\n\n // Honor systemPrompt via gemini's --policy flag (#1886).\n // Gemini treats policy files as system-level instructions, preserving\n // the system-role framing (unlike prepending to user content).\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-gemini-sysprompt-'));\n const file = join(dir, 'policy.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('--policy', file);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every gemini call with a systemPrompt leaked\n // one empty `/tmp/nexus-gemini-sysprompt-XXXXXX` dir until the OS\n // reaper ran.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n return cleanup === undefined\n ? { command: 'gemini', args }\n : { command: 'gemini', args, cleanup };\n }\n\n private checkCircuitBreaker(): CliError | null {\n if (this.circuitBreaker === null) {\n return null;\n }\n if (this.circuitBreaker.getState() === 'open') {\n return createCircuitOpenError('gemini');\n }\n return null;\n }\n\n private buildExecutionOptions(\n taskContent: string,\n options?: ExecutionOptions\n ): ResolvedExecutionOptions {\n const complexity = estimateTaskComplexity(taskContent);\n const timeoutMs = options?.timeoutMs ?? getTimeoutForTask(this.name, complexity);\n\n return {\n timeoutMs,\n allowRetry: options?.allowRetry ?? true,\n maxRetries: options?.maxRetries ?? this.maxRetries,\n trackUsage: options?.trackUsage ?? true,\n onProgress: options?.onProgress,\n };\n }\n\n private buildExecutionResult(\n result: Result<{ response: CliResponse; retryCount: number }, CliError>,\n startTime: number,\n complexity: TaskComplexity\n ): Result<GeminiExecutionResult, CliError> {\n const totalDurationMs = getTimeProvider().now() - startTime;\n const circuitState = this.circuitBreaker?.getState() ?? 'closed';\n\n if (result.ok) {\n this.circuitBreaker?.recordSuccess();\n return ok({\n response: result.value.response,\n retryCount: result.value.retryCount,\n totalDurationMs,\n complexity,\n circuitState,\n });\n }\n\n return err(result.error);\n }\n\n private async executeWithRetryTracking(\n task: CliTask,\n options: ResolvedExecutionOptions\n ): Promise<Result<{ response: CliResponse; retryCount: number }, CliError>> {\n return executeCliRetryLoop(() => this.executeTask(task, options), {\n maxRetries: options.maxRetries,\n allowRetry: this.shouldOuterRetry(options),\n baseDelayMs: this.baseDelayMs,\n maxDelayMs: this.maxDelayMs,\n circuitBreaker: this.circuitBreaker,\n cli: this.name,\n logger: this.adapterLogger,\n });\n }\n}\n\n/** Creates a Gemini CLI adapter with reliability features. */\nexport function createGeminiAdapter(options?: GeminiConfig): GeminiCliAdapter {\n return new GeminiCliAdapter(options);\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini Parser Helpers\n *\n * Utility functions for parsing Gemini CLI output.\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { TokenUsage } from '../types.js';\nimport type { TokenTotals } from './gemini-parser-resilient-types.js';\nimport { asRecord, extractStringField, extractNumberField } from '../../utils/type-coercion.js';\n\n// Re-export for backward compatibility\nexport { asRecord, extractStringField };\n\n/**\n * Aggregates token counts from model stats.\n */\nexport function aggregateModelTokens(models: Record<string, unknown>): TokenTotals {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCached = 0;\n\n for (const modelStats of Object.values(models)) {\n const modelRecord = asRecord(modelStats);\n if (modelRecord === null) continue;\n\n const tokens = asRecord(modelRecord.tokens);\n if (tokens === null) continue;\n\n const input = extractNumberField(tokens, 'input');\n const candidates = extractNumberField(tokens, 'candidates');\n const cached = extractNumberField(tokens, 'cached');\n\n if (input !== null) totalInput += input;\n if (candidates !== null) totalOutput += candidates;\n if (cached !== null) totalCached += cached;\n }\n\n return { input: totalInput, output: totalOutput, cached: totalCached };\n}\n\n/**\n * Extracts token usage from a parsed record.\n */\nexport function extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | undefined {\n const stats = asRecord(record.stats);\n if (stats === null) return undefined;\n\n const models = asRecord(stats.models);\n if (models === null) return undefined;\n\n const totals = aggregateModelTokens(models);\n if (totals.input === 0 && totals.output === 0) return undefined;\n\n return {\n inputTokens: totals.input,\n outputTokens: totals.output,\n totalTokens: totals.input + totals.output,\n ...(totals.cached > 0 && { cachedInputTokens: totals.cached }),\n };\n}\n\n/**\n * Extracts session ID from text patterns.\n */\nexport function extractSessionIdFromText(raw: string): string | null {\n const patterns = [/session[_-]?id[:\\s]+[\"']?([a-zA-Z0-9_-]+)[\"']?/i, /gem_([a-zA-Z0-9]+)/];\n\n for (const pattern of patterns) {\n const match = pattern.exec(raw);\n const captured = match?.[1];\n if (captured !== undefined) {\n return captured.startsWith('gem_') ? captured : `gem_${captured}`;\n }\n }\n\n return null;\n}\n\n/**\n * Extracts text content from markdown, removing code blocks and formatting.\n */\nexport function extractTextFromMarkdown(raw: string): string {\n let content = raw;\n\n // Remove code blocks\n content = content.replace(/```[\\s\\S]*?```/g, '');\n\n // Remove markdown formatting\n content = content.replace(/#{1,6}\\s+/g, '');\n content = content.replace(/\\*{1,2}([^*]+)\\*{1,2}/g, '$1');\n content = content.replace(/_([^_]+)_/g, '$1');\n\n return content.trim();\n}\n\n/**\n * Extracts a clean error message from raw output.\n */\nexport function extractErrorMessage(raw: string): string {\n const lines = raw.split('\\n').filter((line) => line.trim().length > 0);\n\n // Look for error: prefix\n for (const line of lines) {\n const lower = line.toLowerCase();\n if (lower.includes('error:')) {\n return line.replace(/.*error:\\s*/i, '').trim();\n }\n }\n\n // Return first non-empty line as fallback\n return lines[0]?.trim() ?? 'Unknown error';\n}\n\n/**\n * Checks if output appears to be an error message.\n */\nexport function isLikelyErrorOutput(raw: string): boolean {\n const lower = raw.toLowerCase();\n const errorIndicators = ['error:', 'exception:', 'traceback', 'stack trace', 'fatal:', 'panic:'];\n\n // Check if output starts with error indicators\n for (const indicator of errorIndicators) {\n if (lower.startsWith(indicator)) return true;\n }\n\n // Check if it's a short error message\n if (raw.length < 200) {\n const errorKeywords = ['failed', 'error', 'cannot', 'unable to'];\n const hasErrorKeyword = errorKeywords.some((kw) => lower.includes(kw));\n const hasNoContent = !lower.includes('the ') && !lower.includes('this ');\n if (hasErrorKeyword && hasNoContent) return true;\n }\n\n return false;\n}\n","/**\n * nexus-agents/cli-adapters - Resilient Gemini CLI Response Parser\n *\n * Enhanced parser with multiple fallback strategies for handling\n * various Gemini CLI output formats including:\n * - Standard JSON output\n * - Plain text responses\n * - Multi-line outputs with markdown\n * - Error messages and exit codes\n *\n * (Source: Issue #366 - Gemini CLI timeout and parser improvements)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport type { GeminiCliResponse } from './gemini-parser.js';\nimport type { ResilientParseResult, GeminiErrorInfo } from './gemini-parser-resilient-types.js';\nimport { extractJsonObject } from '../../core/index.js';\nimport {\n asRecord,\n extractStringField,\n extractUsageFromRecord,\n extractSessionIdFromText,\n extractTextFromMarkdown,\n extractErrorMessage,\n isLikelyErrorOutput,\n} from './gemini-parser-resilient-helpers.js';\n\n// Re-export types for backward compatibility\nexport type {\n ResilientParseResult,\n ParseStrategy,\n GeminiErrorInfo,\n} from './gemini-parser-resilient-types.js';\n\n/**\n * Resilient parser for Gemini CLI output.\n * Implements multiple fallback strategies for robust parsing.\n */\nexport class ResilientGeminiParser implements ICliResponseParser<GeminiCliResponse> {\n readonly name = 'gemini-resilient-parser';\n readonly supportedVersionRange = '>=0.20.0 <1.0.0';\n\n /**\n * Parses Gemini CLI output using multiple strategies.\n * Tries JSON first, then falls back to text extraction.\n */\n parse(raw: string): GeminiCliResponse | null {\n const result = this.parseResilient(raw);\n if (result === null) return null;\n\n // Build the response object, only including optional fields when present\n const response: GeminiCliResponse = {\n response: result.response,\n };\n\n // Add stats if usage info is available\n if (result.usage !== undefined) {\n return {\n ...response,\n ...(result.sessionId !== undefined && { session_id: result.sessionId }),\n stats: {\n models: {\n 'gemini-unknown': {\n tokens: {\n input: result.usage.inputTokens,\n candidates: result.usage.outputTokens,\n },\n },\n },\n },\n };\n }\n\n // No usage - just add session_id if it exists\n if (result.sessionId !== undefined) {\n return { ...response, session_id: result.sessionId };\n }\n\n return response;\n }\n\n /**\n * Parses with full metadata about parsing strategy.\n */\n parseResilient(raw: string): ResilientParseResult | null {\n // Strategy 1: Standard JSON parsing\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult !== null) return jsonResult;\n\n // Strategy 2: Extract JSON from mixed output\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson !== null) return extractedJson;\n\n // Strategy 3: Extract from markdown code blocks\n const markdownResult = this.tryExtractFromMarkdown(raw);\n if (markdownResult !== null) return markdownResult;\n\n // Strategy 4: Plain text fallback\n const plainTextResult = this.tryPlainText(raw);\n if (plainTextResult !== null) return plainTextResult;\n\n return null;\n }\n\n /**\n * Extracts just the response text with fallback strategies.\n */\n extractResponse(raw: string): string | null {\n const result = this.parseResilient(raw);\n return result?.response ?? null;\n }\n\n /**\n * Extracts token usage if available.\n */\n extractUsage(raw: string): TokenUsage | null {\n // Try JSON parsing first for structured usage data\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.usage) return jsonResult.usage;\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.usage) return extractedJson.usage;\n\n return null;\n }\n\n /**\n * Extracts session ID if present.\n */\n extractSessionId(raw: string): string | null {\n // Try JSON parsing first\n const jsonResult = this.tryParseJson(raw);\n if (jsonResult?.sessionId !== undefined && jsonResult.sessionId !== '') {\n return jsonResult.sessionId;\n }\n\n const extractedJson = this.tryExtractJson(raw);\n if (extractedJson?.sessionId !== undefined && extractedJson.sessionId !== '') {\n return extractedJson.sessionId;\n }\n\n // Try to extract session ID from text patterns\n return extractSessionIdFromText(raw);\n }\n\n /**\n * Detects and extracts error information from output.\n */\n extractError(raw: string): GeminiErrorInfo | null {\n const lower = raw.toLowerCase();\n\n if (lower.includes('timeout') || lower.includes('timed out')) {\n return { type: 'timeout', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('authentication') || lower.includes('unauthorized')) {\n return { type: 'auth', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('rate limit') || lower.includes('quota exceeded')) {\n return { type: 'rate-limit', message: extractErrorMessage(raw) };\n }\n\n if (lower.includes('error') || lower.includes('failed')) {\n return { type: 'api-error', message: extractErrorMessage(raw) };\n }\n\n return null;\n }\n\n // -------------------------------------------------------------------------\n // Private Strategy Methods\n // -------------------------------------------------------------------------\n\n private tryParseJson(raw: string): ResilientParseResult | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return null;\n\n const response = record.response;\n if (typeof response !== 'string') return null;\n\n const sessionId = extractStringField(record, 'session_id');\n const usage = extractUsageFromRecord(record);\n\n const result: ResilientParseResult = {\n response,\n parseStrategy: 'json',\n raw,\n };\n\n if (sessionId !== undefined) {\n (result as { sessionId?: string }).sessionId = sessionId;\n }\n if (usage !== undefined) {\n (result as { usage?: TokenUsage }).usage = usage;\n }\n\n return result;\n } catch {\n return null;\n }\n }\n\n private tryExtractJson(raw: string): ResilientParseResult | null {\n // ReDoS-safe extraction (#1912): previously used compound patterns like\n // `/\\{[\\s\\S]*\"response\"\\s*:\\s*\"[\\s\\S]*\"\\s*[\\s\\S]*\\}/` which have THREE\n // `[\\s\\S]*` groups — catastrophic backtracking on large non-matching\n // input. Now we extract the JSON object via indexOf/lastIndexOf (O(n))\n // and let tryParseJson validate the \"response\" field structurally.\n const candidate = extractJsonObject(raw);\n if (candidate === undefined) return null;\n const result = this.tryParseJson(candidate);\n if (result !== null) {\n return { ...result, parseStrategy: 'json-extracted', raw };\n }\n return null;\n }\n\n private tryExtractFromMarkdown(raw: string): ResilientParseResult | null {\n // Extract content from markdown code blocks\n const codeBlockPattern = /```(?:json)?\\s*([\\s\\S]*?)```/g;\n let match: RegExpExecArray | null = codeBlockPattern.exec(raw);\n\n while (match !== null) {\n const captured = match[1];\n if (captured !== undefined) {\n const content = captured.trim();\n\n // Try to parse as JSON\n const jsonResult = this.tryParseJson(content);\n if (jsonResult !== null) {\n return { ...jsonResult, parseStrategy: 'markdown-code-block', raw };\n }\n }\n\n match = codeBlockPattern.exec(raw);\n }\n\n // If no JSON found in code blocks, treat entire content as response\n // but only if it looks like substantive output\n if (raw.includes('```')) {\n const cleanedContent = extractTextFromMarkdown(raw);\n if (cleanedContent.length > 0) {\n return {\n response: cleanedContent,\n parseStrategy: 'markdown-code-block',\n raw,\n };\n }\n }\n\n return null;\n }\n\n private tryPlainText(raw: string): ResilientParseResult | null {\n const trimmed = raw.trim();\n\n // Skip if empty or looks like an error\n if (trimmed.length === 0) return null;\n\n // Skip if it looks like just error output\n if (isLikelyErrorOutput(trimmed)) return null;\n\n // Accept as plain text response\n return {\n response: trimmed,\n parseStrategy: 'plain-text',\n raw,\n };\n }\n}\n\n/**\n * Creates a resilient Gemini parser instance.\n */\nexport function createResilientGeminiParser(): ResilientGeminiParser {\n return new ResilientGeminiParser();\n}\n","/**\n * nexus-agents/cli-adapters - Gemini CLI Adapter Helpers\n *\n * CLI-specific helper functions for retry logic and error handling.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName } from '../types.js';\n\n// -----------------------------------------------------------------------------\n// Fallback Defaults (for unknown models not in canonical registry)\n// -----------------------------------------------------------------------------\n\n/**\n * Fallback defaults for Gemini models not in the canonical registry.\n * All current models are in config/in-tree-data.ts and served by\n * buildModelInfo('gemini', model). This provides sensible defaults\n * when an unknown model name is encountered at runtime.\n *\n * @see config/in-tree-data.ts — single source of truth for current models\n */\nexport const GEMINI_LEGACY_DEFAULTS = {\n displayNames: {} as Readonly<Record<string, string>>,\n contextWindows: {} as Readonly<Record<string, number>>,\n inputCosts: {} as Readonly<Record<string, number>>,\n outputCosts: {} as Readonly<Record<string, number>>,\n contextWindow: 1_000_000,\n inputCost: 0.15,\n outputCost: 0.6,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Re-exports from canonical cli-retry-loop.ts (Issue #1596)\n// -----------------------------------------------------------------------------\n\nexport { calculateBackoffDelay, isRetryableError, categorizeError } from '../cli-retry-loop.js';\n\n// -----------------------------------------------------------------------------\n// Error Factory\n// -----------------------------------------------------------------------------\n\n/** Creates a circuit breaker open error. */\nexport function createCircuitOpenError(cli: CliName): CliError {\n return {\n code: 'EXECUTION_ERROR',\n message: `Circuit breaker is open - ${cli} CLI temporarily unavailable`,\n cli,\n retryable: false,\n };\n}\n\n// -----------------------------------------------------------------------------\n// Utility Functions\n// -----------------------------------------------------------------------------\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter\n *\n * Subprocess-based adapter for Codex CLI.\n * Extends SubprocessCliAdapter to reuse retry logic, health checks,\n * version detection, and capacity tracking.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #1140 — Migrated to SubprocessCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell: true.\n * User task content is passed as a single argv element (no shell interpolation).\n */\n\nimport { writeFileSync, rmSync, mkdtempSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type {\n ICliResponseParser,\n CliTask,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport { SubprocessCliAdapter, type CommandConfig } from '../subprocess-adapter.js';\nimport { CodexResponseParser } from '../parsers/codex-parser.js';\nimport type { CliModelInfo } from '../types-capability.js';\nimport { listModelsForCli } from '../../config/models-dev-by-vendor.js';\nimport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n// Re-export CLI-specific helpers for backward compatibility\nexport { createCodexError, normalizeCodexResponse, delay } from './codex-adapter-helpers.js';\n\n/**\n * Codex CLI adapter using subprocess transport.\n *\n * Extends SubprocessCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Subprocess spawn with timeout handling\n */\nexport class CodexCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'codex';\n protected readonly parser: ICliResponseParser = new CodexResponseParser();\n\n private readonly model: string;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /** Key-free model enumeration via the models.dev snapshot (#3405). */\n listModels(): Promise<readonly CliModelInfo[]> {\n return Promise.resolve(listModelsForCli(this.name));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Task content is passed as a positional argument (not via stdin).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['exec'];\n\n // Add JSON output\n args.push('--json');\n\n // Add model only if specified (use CLI default otherwise)\n const model = task.model ?? this.model;\n if (model !== '') {\n args.push('-m', model);\n }\n\n // Add sandbox mode for safety (read-only by default)\n args.push('-s', 'read-only');\n\n // Skip git repo check for standalone prompts\n args.push('--skip-git-repo-check');\n\n // Honor systemPrompt via codex's `model_instructions_file` config key\n // (per openai/codex#11588 — closed with this workaround). We materialize\n // the prompt into a tempfile, pass it via `-c`, and clean up on exit.\n let cleanup: (() => void) | undefined;\n if (task.systemPrompt !== undefined && task.systemPrompt !== '') {\n const dir = mkdtempSync(join(tmpdir(), 'nexus-codex-sysprompt-'));\n const file = join(dir, 'instructions.md');\n writeFileSync(file, task.systemPrompt, { encoding: 'utf8', mode: 0o600 });\n args.push('-c', `model_instructions_file=${file}`);\n cleanup = (): void => {\n // Recursive rm so we drop the parent tempdir, not just the file\n // inside it. Pre-fix every codex call with a systemPrompt leaked\n // one empty `/tmp/nexus-codex-sysprompt-XXXXXX` dir until the OS\n // reaper ran — exhausting inodes on long-running MCP daemons.\n try {\n rmSync(dir, { recursive: true, force: true });\n } catch {\n // best-effort; tempdir auto-cleanup will eventually reap it\n }\n };\n }\n\n // Add the task content (no JSON.stringify needed without shell: true)\n args.push(task.content);\n\n return cleanup === undefined ? { command: 'codex', args } : { command: 'codex', args, cleanup };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Response Parser\n *\n * Defensive parser for Codex CLI NDJSON output.\n * Handles version 0.7x.x output format.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: docs/research/cli-integration-architecture.md)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'codex-parser' });\n\n/**\n * Codex CLI NDJSON event types.\n */\nexport type CodexEventType =\n | 'thread.started'\n | 'turn.started'\n | 'item.completed'\n | 'turn.completed';\n\n/**\n * Base Codex event structure.\n */\nexport interface CodexEvent {\n readonly type: CodexEventType;\n}\n\n/**\n * Thread started event.\n */\nexport interface CodexThreadStarted extends CodexEvent {\n readonly type: 'thread.started';\n readonly thread_id: string;\n}\n\n/**\n * Item completed event (contains response or reasoning).\n */\nexport interface CodexItemCompleted extends CodexEvent {\n readonly type: 'item.completed';\n readonly item: {\n readonly id: string;\n readonly type: string;\n readonly text: string;\n };\n}\n\n/**\n * Turn completed event (contains usage).\n */\nexport interface CodexTurnCompleted extends CodexEvent {\n readonly type: 'turn.completed';\n readonly usage?: {\n readonly input_tokens: number;\n readonly cached_input_tokens?: number;\n readonly output_tokens: number;\n };\n}\n\n/**\n * Aggregated Codex response from NDJSON stream.\n */\nexport interface CodexCliResponse {\n readonly threadId?: string;\n readonly messages: readonly string[];\n readonly reasoning: readonly string[];\n readonly usage?: TokenUsage;\n}\n\n/**\n * Parser for Codex CLI NDJSON output.\n * Implements defensive parsing - processes stream of events.\n */\nexport class CodexResponseParser implements ICliResponseParser<CodexCliResponse> {\n readonly name = 'codex-parser';\n readonly supportedVersionRange = '>=0.70.0 <1.0.0';\n\n /**\n * Parses complete Codex CLI NDJSON stream.\n */\n parse(raw: string): CodexCliResponse | null {\n const lines = raw.trim().split('\\n');\n let threadId: string | undefined;\n const messages: string[] = [];\n const reasoning: string[] = [];\n let usage: TokenUsage | undefined;\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n this.processLine(\n line,\n messages,\n reasoning,\n (id) => (threadId = id),\n (u) => (usage = u)\n );\n }\n\n if (messages.length === 0 && reasoning.length === 0) {\n return null;\n }\n\n return {\n messages,\n reasoning,\n ...(threadId !== undefined && { threadId }),\n ...(usage !== undefined && { usage }),\n };\n }\n\n /**\n * Processes a single NDJSON line.\n */\n private processLine(\n line: string,\n messages: string[],\n reasoning: string[],\n setThreadId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) return;\n\n const eventType = record.type;\n\n if (eventType === 'thread.started') {\n const tid = record.thread_id;\n if (typeof tid === 'string') setThreadId(tid);\n } else if (eventType === 'item.completed') {\n this.processItemCompleted(record, messages, reasoning);\n } else if (eventType === 'turn.completed') {\n const usage = this.extractUsageFromEvent(record);\n if (usage !== null) setUsage(usage);\n }\n } catch {\n // Skip malformed NDJSON lines\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n }\n }\n\n /**\n * Extracts just the response text (most stable field).\n * Concatenates all agent_message items.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.messages.length === 0) {\n return null;\n }\n\n return parsed.messages.join('\\n');\n }\n\n /**\n * Extracts token usage from NDJSON stream.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'turn.completed') {\n return this.extractUsageFromEvent(record);\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID (thread_id) for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n if (record.type === 'thread.started') {\n const threadId = record.thread_id;\n if (typeof threadId === 'string') {\n return threadId;\n }\n }\n } catch {\n logger.debug('Skipped malformed NDJSON line', { snippet: line.slice(0, 100) });\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Processes an item.completed event.\n */\n private processItemCompleted(\n record: Record<string, unknown>,\n messages: string[],\n reasoning: string[]\n ): void {\n const item = asRecord(record.item);\n if (item === null) return;\n\n const itemType = item.type;\n const text = item.text;\n\n if (typeof text !== 'string') return;\n\n if (itemType === 'agent_message') {\n messages.push(text);\n } else if (itemType === 'reasoning') {\n reasoning.push(text);\n }\n }\n\n /**\n * Extracts usage from a turn.completed event.\n */\n private extractUsageFromEvent(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens = extractNumberField(usage, 'input_tokens');\n const outputTokens = extractNumberField(usage, 'output_tokens');\n\n if (inputTokens === null || outputTokens === null) {\n return null;\n }\n\n const cachedInputTokens = extractNumberField(usage, 'cached_input_tokens');\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n ...(cachedInputTokens !== null && { cachedInputTokens }),\n };\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex CLI Adapter Helpers\n *\n * CLI-specific helper functions for Codex subprocess adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n */\n\nimport type { CliError, CliName, TokenUsage, CliResponse } from '../types.js';\nimport { createCliError as sharedCreateCliError } from '../cli-error-helpers.js';\n\n// -----------------------------------------------------------------------------\n// Legacy Fallback Defaults (for non-canonical models)\n// -----------------------------------------------------------------------------\n\n/** Legacy fallback values for Codex models not in the canonical registry. */\nexport const CODEX_LEGACY_DEFAULTS = {\n displayNames: {\n o3: 'O3',\n 'o3-mini': 'O3 Mini',\n 'o4-mini': 'O4 Mini',\n } as Readonly<Record<string, string>>,\n inputCosts: {\n o3: 10.0,\n 'o3-mini': 1.1,\n 'o4-mini': 1.1,\n } as Readonly<Record<string, number>>,\n outputCosts: {\n o3: 40.0,\n 'o3-mini': 4.4,\n 'o4-mini': 4.4,\n } as Readonly<Record<string, number>>,\n contextWindow: 400_000,\n maxOutput: 100_000,\n inputCost: 1.1,\n outputCost: 4.4,\n} as const;\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Creates a CLI error with the canonical retryable-flag logic.\n * Kept as an alias under this name for backward compatibility with callers\n * that imported `createCodexError` before the helper was consolidated in\n * `cli-error-helpers.ts` (#2181). Prefer `createCliError` from the shared\n * helper in new code.\n */\nexport function createCodexError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Response Normalization\n// -----------------------------------------------------------------------------\n\n/** Normalizes CLI response to common format. */\nexport function normalizeCodexResponse(\n text: string,\n usage?: TokenUsage,\n extra?: Partial<CliResponse>\n): CliResponse {\n return {\n text,\n ...(usage !== undefined && { usage }),\n ...extra,\n };\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter\n *\n * MCP-based adapter for Codex CLI. Preferred transport for Codex integration.\n * Extends BaseCliAdapter to reuse retry logic, health checks, version\n * detection, and capacity tracking.\n *\n * (Source: Issue #1140 — Migrated to BaseCliAdapter base class)\n *\n * SECURITY: All spawn() calls use array-based args without shell interpolation.\n */\n\nimport { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';\nimport type {\n CliName,\n CliTransport,\n CliTask,\n CliResponse,\n CliError,\n ModelInfo,\n ResolvedExecutionOptions,\n BaseAdapterOptions,\n} from '../types.js';\nimport type { Result } from '../../core/index.js';\nimport { getErrorMessage, ok, err, getTimeProvider, createLogger } from '../../core/index.js';\nimport { BaseCliAdapter } from '../base-adapter.js';\n\nimport {\n CODEX_LEGACY_DEFAULTS,\n type McpToolResult,\n extractTextFromContent,\n createTimeout,\n determineErrorCode,\n NEXUS_MCP_DEPTH_ENV,\n nextCodexMcpDepthOrThrow,\n} from './codex-mcp-adapter-helpers.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n} from '../../config/model-config-helpers.js';\n\n/**\n * Codex CLI adapter using MCP transport.\n *\n * Extends BaseCliAdapter which provides:\n * - Retry logic with exponential backoff\n * - Health checks with version compatibility\n * - Capacity tracking\n * - Error creation helpers\n */\nexport class CodexMcpAdapter extends BaseCliAdapter {\n readonly name: CliName = 'codex';\n readonly transport: CliTransport = 'mcp';\n\n private readonly model: string;\n private client: Client | undefined;\n private mcpTransport: StdioClientTransport | undefined;\n private connected = false;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger ?? createLogger({ component: 'codex-mcp-adapter' }));\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('codex'));\n }\n\n /**\n * Gets Codex model information.\n * Resolves from canonical registry when possible, falls back to legacy lookup.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('codex', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n return {\n id: this.model,\n name: CODEX_LEGACY_DEFAULTS.displayNames[this.model] ?? this.model,\n contextWindow: CODEX_LEGACY_DEFAULTS.contextWindow,\n maxOutput: CODEX_LEGACY_DEFAULTS.maxOutput,\n costPerMillionInput:\n CODEX_LEGACY_DEFAULTS.inputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.inputCost,\n costPerMillionOutput:\n CODEX_LEGACY_DEFAULTS.outputCosts[this.model] ?? CODEX_LEGACY_DEFAULTS.outputCost,\n };\n }\n\n /**\n * Initializes the MCP connection to Codex.\n */\n async initialize(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n this.initCapacityTracker();\n this.logger.debug('Initializing Codex MCP connection');\n\n // Recursion guard (#3350): refuse to spawn `codex mcp-server` if we're\n // already nested inside a nexus-spawned codex MCP context, and stamp the\n // child with the incremented depth so it (and anything it spawns) inherits\n // the marker. Throws before any spawn when nested — breaking the loop.\n const childDepth = nextCodexMcpDepthOrThrow();\n\n try {\n this.mcpTransport = new StdioClientTransport({\n command: 'codex',\n args: ['mcp-server'],\n stderr: 'pipe',\n env: { [NEXUS_MCP_DEPTH_ENV]: childDepth },\n });\n\n this.client = new Client({ name: 'nexus-agents', version: '2.0.0' }, { capabilities: {} });\n await this.client.connect(this.mcpTransport);\n this.connected = true;\n this.initialized = true;\n this.logger.info('Codex MCP connection established');\n } catch (error) {\n this.connected = false;\n const connectionError = error instanceof Error ? error : new Error('Connection failed');\n this.logger.error('Failed to initialize Codex MCP connection', connectionError);\n throw error;\n }\n }\n\n /**\n * Executes a task via MCP client.\n * Called by BaseCliAdapter.execute() with retry handling.\n */\n async executeTask(\n _task: CliTask,\n options: ResolvedExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n const startTime = getTimeProvider().now();\n\n if (this.client === undefined) {\n return err(this.createError('CONNECTION_ERROR', 'MCP client not initialized'));\n }\n\n try {\n const result = await Promise.race([\n this.callCodexTool(_task),\n createTimeout(options.timeoutMs),\n ]);\n\n if (result === null) {\n return err(this.createError('TIMEOUT', 'Execution timed out'));\n }\n\n return this.parseToolResult(result, startTime);\n } catch (error) {\n return this.handleExecutionError(error);\n }\n }\n\n /**\n * Calls the codex or codex-reply tool on Codex MCP server.\n * @see https://developers.openai.com/codex/mcp/\n */\n private async callCodexTool(task: CliTask): Promise<McpToolResult> {\n if (this.client === undefined) {\n throw new Error('Client not initialized');\n }\n\n const isReply = task.sessionId !== undefined && task.sessionId !== '';\n const toolName = isReply ? 'codex-reply' : 'codex';\n\n const baseArgs = {\n prompt: task.content,\n ...(task.model !== undefined && { model: task.model }),\n };\n\n const args = isReply\n ? { ...baseArgs, threadId: task.sessionId }\n : {\n ...baseArgs,\n sandbox: 'read-only' as const,\n 'approval-policy': 'on-failure' as const,\n };\n\n const result = await this.client.callTool({\n name: toolName,\n arguments: args,\n });\n\n return result as McpToolResult;\n }\n\n /**\n * Parses MCP tool result to CLI response.\n */\n private parseToolResult(result: McpToolResult, startTime: number): Result<CliResponse, CliError> {\n if (result.isError === true) {\n const errorText = extractTextFromContent(result.content);\n return err(this.createError('EXECUTION_ERROR', errorText ?? 'Tool execution failed'));\n }\n\n const text = extractTextFromContent(result.content);\n if (text === null) {\n return err(this.createError('PARSE_ERROR', 'No text content in response'));\n }\n\n return ok({\n text,\n durationMs: getTimeProvider().now() - startTime,\n raw: result,\n });\n }\n\n /**\n * Handles execution errors.\n */\n private handleExecutionError(error: unknown): Result<CliResponse, CliError> {\n const message = getErrorMessage(error);\n const errorCode = determineErrorCode(message);\n\n if (errorCode === 'CONNECTION_ERROR') {\n this.connected = false;\n }\n\n return err(this.createError(errorCode, message, error as Error));\n }\n\n /**\n * Disposes the adapter and closes MCP connection.\n */\n async dispose(): Promise<void> {\n if (this.mcpTransport !== undefined) {\n this.logger.debug('Closing Codex MCP connection');\n await this.mcpTransport.close();\n this.mcpTransport = undefined;\n }\n this.client = undefined;\n this.connected = false;\n this.initialized = false;\n }\n}\n","/**\n * nexus-agents/cli-adapters - Codex MCP Adapter Helpers\n *\n * CLI-specific helper functions for Codex MCP adapter.\n * Model info lookups consolidated into config/model-config-helpers.ts (#886).\n *\n * (Source: cli-project_plan.md v2.1.0, Issue #90)\n */\n\nimport type { ResolvedExecutionOptions, CliError, CliName } from '../types.js';\nimport { CODEX_MCP_TIMEOUTS } from '../../config/timeouts.js';\nimport {\n createCliError as sharedCreateCliError,\n isRetryableErrorCode as sharedIsRetryableErrorCode,\n} from '../cli-error-helpers.js';\n\n// Re-export legacy defaults from the subprocess helpers (DRY)\nexport { CODEX_LEGACY_DEFAULTS } from './codex-adapter-helpers.js';\n\n/**\n * Default execution options for Codex MCP.\n * Timeout and retry values derived from config/timeouts.ts (#1220).\n */\nexport const DEFAULT_CODEX_MCP_OPTIONS: ResolvedExecutionOptions = {\n timeoutMs: CODEX_MCP_TIMEOUTS.defaultMs,\n allowRetry: true,\n maxRetries: CODEX_MCP_TIMEOUTS.maxRetries,\n trackUsage: true,\n onProgress: undefined,\n};\n\n// ---------------------------------------------------------------------------\n// Recursion guard for `codex mcp-server` spawning (#3350)\n// ---------------------------------------------------------------------------\n\n/**\n * Env var stamped on the `codex mcp-server` child nexus spawns, marking how\n * deep we are in the nexus→codex-mcp spawn nesting. Inherited by anything the\n * codex MCP server itself spawns (including a nested `nexus-agents\n * --mode=server` if codex is misconfigured to launch one).\n */\nexport const NEXUS_MCP_DEPTH_ENV = 'NEXUS_MCP_DEPTH';\n\n/**\n * Highest nesting depth at which nexus will spawn `codex mcp-server`. `0`\n * means only the top-level nexus process spawns it; any deeper attempt is the\n * recursive codex↔nexus loop and is refused.\n */\nexport const MAX_CODEX_MCP_SPAWN_DEPTH = 0;\n\n/** Read the current nesting depth from an env bag; clamps missing/junk to 0. */\nexport function readMcpDepth(env: NodeJS.ProcessEnv = process.env): number {\n const raw = Number.parseInt(env[NEXUS_MCP_DEPTH_ENV] ?? '0', 10);\n return Number.isFinite(raw) && raw > 0 ? raw : 0;\n}\n\n/**\n * Recursion guard (#3350). Returns the depth string to stamp on the spawned\n * `codex mcp-server` child, or throws if we are already nested — which would\n * re-enter the codex↔nexus MCP spawn loop that corrupted the codex OAuth\n * token (dozens of leaked servers racing the shared refresh-token rotation).\n */\nexport function nextCodexMcpDepthOrThrow(env: NodeJS.ProcessEnv = process.env): string {\n const depth = readMcpDepth(env);\n if (depth > MAX_CODEX_MCP_SPAWN_DEPTH) {\n throw new Error(\n `Refusing to spawn 'codex mcp-server': already nested inside a ` +\n `nexus-spawned codex MCP context (${NEXUS_MCP_DEPTH_ENV}=${String(depth)}). ` +\n `This breaks the recursive codex↔nexus MCP spawn loop (#3350). If you ` +\n `intentionally configured codex to launch nexus-agents as an MCP ` +\n `server, remove that '[mcp_servers.nexus-agents]' entry from ~/.codex/config.toml.`\n );\n }\n return String(depth + 1);\n}\n\n/**\n * MCP tool call result structure.\n */\nexport interface McpToolResult {\n content?: Array<{ type: string; text?: string }>;\n isError?: boolean;\n}\n\n// -----------------------------------------------------------------------------\n// Error Handling\n// -----------------------------------------------------------------------------\n\n/**\n * Checks if an error code is retryable. Kept exported for backward\n * compatibility with callers that imported from this module; delegates\n * to the canonical helper (#2181).\n */\nexport function isRetryableErrorCode(code: CliError['code']): boolean {\n return sharedIsRetryableErrorCode(code);\n}\n\n/**\n * Creates a CLI error object with the canonical retryable-flag logic.\n * Kept exported for backward compatibility (#2181).\n */\nexport function createCliError(\n code: CliError['code'],\n message: string,\n cli: CliName,\n cause?: Error\n): CliError {\n return sharedCreateCliError(code, message, cli, cause);\n}\n\n// -----------------------------------------------------------------------------\n// Content Extraction\n// -----------------------------------------------------------------------------\n\n/** Extracts text from MCP content array. */\nexport function extractTextFromContent(\n content?: Array<{ type: string; text?: string }>\n): string | null {\n if (content === undefined || content.length === 0) {\n return null;\n }\n\n const textContents = content\n .filter((c): c is { type: string; text: string } => c.type === 'text' && c.text !== undefined)\n .map((c) => c.text);\n\n return textContents.length > 0 ? textContents.join('\\n') : null;\n}\n\n// Re-export from canonical source for backward compatibility\nexport { delay } from '../../utils/async-utils.js';\n\n/** Creates a timeout promise that resolves to null. */\nexport function createTimeout(ms: number): Promise<null> {\n return new Promise((resolve) => {\n setTimeout(() => {\n resolve(null);\n }, ms);\n });\n}\n\n/** Determines error code from error message. */\nexport function determineErrorCode(message: string): CliError['code'] {\n if (message.includes('ENOENT') || message.includes('not found')) {\n return 'NOT_FOUND';\n }\n\n if (message.includes('timeout') || message.includes('ETIMEDOUT')) {\n return 'TIMEOUT';\n }\n\n if (message.includes('connection') || message.includes('disconnect')) {\n return 'CONNECTION_ERROR';\n }\n\n return 'EXECUTION_ERROR';\n}\n\n/** Parses version string from codex --version output. */\nexport function parseVersionFromOutput(output: string): string {\n const match = /(\\d+\\.\\d+\\.\\d+)/.exec(output.trim());\n return match?.[1] ?? '0.0.0';\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Adapter\n *\n * Subprocess-based adapter for OpenCode CLI.\n * Uses `opencode run --format json` for stable parsing.\n *\n * (Source: Issue #1124, opencode.ai/docs/cli/)\n */\n\nimport { execFile } from 'node:child_process';\n\nimport type {\n ICliResponseParser,\n CliTask,\n CliModelInfo,\n ModelInfo,\n CliName,\n BaseAdapterOptions,\n} from '../types.js';\nimport {\n SubprocessCliAdapter,\n type CommandConfig,\n type TransientRetryConfig,\n} from '../subprocess-adapter.js';\nimport { OpenCodeResponseParser } from '../parsers/opencode-parser.js';\nimport { resolveLiveModelId } from '../../config/resolve-live-model.js';\nimport { isDynamicModelsEnabled } from '../../config/register-model-sources.js';\nimport { getAvailabilityCache } from '../../config/model-availability.js';\nimport type { ModelId } from '../../config/model-capabilities-types.js';\nimport type { Result } from '../../core/index.js';\nimport type { CliResponse, CliError } from '../types-core.js';\nimport type { ResolvedExecutionOptions } from '../types-capability.js';\nimport {\n getDefaultModelForCli,\n getCliModelName,\n buildModelInfo,\n findInTreeByCli,\n FALLBACK_CONTEXT_WINDOW,\n FALLBACK_MAX_OUTPUT,\n} from '../../config/model-config-helpers.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-adapter' });\n\n/** Strict allowlist for OpenCode --variant flag values. */\nconst ALLOWED_VARIANTS = ['high', 'max', 'minimal'];\n\n/**\n * Maps internal model names to OpenCode CLI --model values.\n * OpenCode uses `provider/model-name` format (e.g., `anthropic/claude-sonnet-4-6`).\n * Built from canonical registry + common alias fallbacks (#1402).\n */\nconst MODEL_TO_CLI_NAME: Record<string, string> = buildOpenCodeAliasMap();\n\nfunction buildOpenCodeAliasMap(): Record<string, string> {\n const map: Record<string, string> = {};\n for (const model of findInTreeByCli('opencode')) {\n if (model.cliModelName === undefined) continue;\n // Map internal ID → CLI model name\n map[model.id] = model.cliModelName;\n // Map CLI alias → CLI model name\n if (model.cliAlias !== undefined) {\n map[model.cliAlias] = model.cliModelName;\n }\n // Pass through cliModelName itself\n map[model.cliModelName] = model.cliModelName;\n }\n return map;\n}\n\n/** Resolves an internal model name to OpenCode CLI format. */\nfunction resolveOpenCodeModel(model: string): string {\n return MODEL_TO_CLI_NAME[model] ?? model;\n}\n\n/** Timeout for `opencode models` probe (ms). */\nconst PROBE_TIMEOUT_MS = 10_000;\n\n/**\n * Probes available models by running `opencode models`.\n * Returns a Set of model IDs (e.g., \"opencode/big-pickle\").\n * Caches result in a module-level variable for the process lifetime.\n */\nlet cachedModels: Set<string> | undefined;\n/** Inflight probe promise for coalescing concurrent calls (Issue #1438). */\nlet probePromise: Promise<Set<string>> | undefined;\n\nfunction probeAvailableModels(): Promise<Set<string>> {\n if (cachedModels !== undefined) return Promise.resolve(cachedModels);\n if (probePromise !== undefined) return probePromise;\n\n probePromise = new Promise<Set<string>>((resolve) => {\n execFile('opencode', ['models'], { timeout: PROBE_TIMEOUT_MS }, (error, stdout) => {\n if (error !== null || stdout.trim() === '') {\n logger.debug('Failed to probe OpenCode models, will omit --model flag', {\n error: error?.message,\n });\n cachedModels = new Set();\n resolve(cachedModels);\n return;\n }\n const models = new Set(\n stdout\n .trim()\n .split('\\n')\n .map((l) => l.trim())\n .filter((l) => l.length > 0)\n );\n logger.debug('Probed OpenCode models', { count: models.size });\n cachedModels = models;\n resolve(cachedModels);\n });\n }).finally(() => {\n probePromise = undefined;\n });\n\n return probePromise;\n}\n\n/** Patterns indicating an Anthropic provider in OpenCode models list. */\nconst ANTHROPIC_MODEL_PATTERNS = ['anthropic/', 'custom/claude'];\n\n/**\n * Logs a warning if OpenCode has an Anthropic provider configured (#1429).\n * Claude Code subscription API keys must NOT be used with third-party tools.\n */\nfunction warnIfAnthropicProvider(models: Set<string>): void {\n const anthropicModels = [...models].filter((m) =>\n ANTHROPIC_MODEL_PATTERNS.some((p) => m.toLowerCase().includes(p))\n );\n if (anthropicModels.length > 0) {\n logger.warn(\n 'OpenCode has Anthropic/Claude models configured. ' +\n 'Ensure these use a SEPARATE API key from console.anthropic.com, ' +\n 'NOT a Claude Code subscription key (which is restricted to Claude Code only).',\n { detectedModels: anthropicModels }\n );\n }\n}\n\n/**\n * OpenCode CLI adapter using subprocess transport.\n * Executes: opencode run --format json \"<task>\"\n *\n * Probes available models on first use and omits --model flag\n * when the requested model isn't available (#1402).\n */\nexport class OpenCodeCliAdapter extends SubprocessCliAdapter {\n readonly name: CliName = 'opencode';\n protected readonly parser: ICliResponseParser = new OpenCodeResponseParser();\n\n /** Enable transient-error retry for OpenCode (#1456). */\n protected override readonly transientRetry: TransientRetryConfig = { enabled: true };\n\n private readonly model: string;\n private availableModels: Set<string> | undefined;\n\n constructor(options?: BaseAdapterOptions) {\n super(options?.logger);\n this.model = options?.model ?? getCliModelName(getDefaultModelForCli('opencode'));\n }\n\n /**\n * Gets OpenCode model information from canonical registry.\n */\n getModelInfo(): ModelInfo {\n const fromRegistry = buildModelInfo('opencode', this.model);\n if (fromRegistry !== undefined) return fromRegistry;\n\n return {\n id: this.model,\n name: `OpenCode (${this.model})`,\n contextWindow: FALLBACK_CONTEXT_WINDOW,\n maxOutput: FALLBACK_MAX_OUTPUT,\n // OpenCode pricing fallback is adapter-specific (not the Claude 5/25).\n costPerMillionInput: 3.0,\n costPerMillionOutput: 15.0,\n };\n }\n\n /**\n * Initializes the adapter — probes available models.\n * Warns if Anthropic provider is configured (#1429 — API key boundaries).\n */\n override async initialize(): Promise<void> {\n this.availableModels = await probeAvailableModels();\n warnIfAnthropicProvider(this.availableModels);\n await super.initialize();\n }\n\n /** Returns true if the model is available in the OpenCode installation. */\n private isModelAvailable(cliModel: string): boolean {\n if (this.availableModels === undefined || this.availableModels.size === 0) return false;\n return this.availableModels.has(cliModel);\n }\n\n /** #3408: true if the model is in rate-limit cooldown (recent 429). Opt-in. */\n private isCooled(cliModel: string): boolean {\n return (\n isDynamicModelsEnabled() && getAvailabilityCache().isKnownUnavailable(cliModel as ModelId)\n );\n }\n\n /** Usable = offered by the OpenCode install AND not in rate-limit cooldown. */\n private isModelUsable(cliModel: string): boolean {\n return this.isModelAvailable(cliModel) && !this.isCooled(cliModel);\n }\n\n /** Appends --model if the resolved model is usable (#1402, #3407, #3408). */\n private appendModelArg(args: string[], task: CliTask): void {\n const internalModel = task.model ?? this.model;\n let cliModel = resolveOpenCodeModel(internalModel);\n\n // #3407/#3408: if the resolved model isn't usable — renamed away (#3407) or\n // in rate-limit cooldown (#3408) — resolve it to the closest USABLE live\n // model (excluding cooled ones from the candidate set). Opt-in\n // (NEXUS_DYNAMIC_MODELS) + fail-open: when discovery is off, isCooled is\n // always false and resolveLiveModelId returns the input unchanged, so\n // behavior is identical.\n if (\n !this.isModelUsable(cliModel) &&\n isDynamicModelsEnabled() &&\n this.availableModels !== undefined\n ) {\n const usable = new Set([...this.availableModels].filter((m) => !this.isCooled(m)));\n const resolved = resolveLiveModelId(cliModel, usable);\n if (resolved !== cliModel) {\n logger.debug('Resolved to live/non-cooled model (#3407/#3408)', {\n from: cliModel,\n to: resolved,\n });\n cliModel = resolved;\n }\n }\n\n if (this.isModelUsable(cliModel)) {\n args.push('--model', cliModel);\n } else {\n logger.debug('Model not usable (unavailable or cooled), using OpenCode default', {\n requested: cliModel,\n available: this.availableModels?.size ?? 0,\n });\n }\n }\n\n /**\n * #3408: mark a model in rate-limit cooldown when a call returns RATE_LIMITED,\n * so subsequent selections skip it until the AvailabilityCache TTL recovers.\n * Wraps the base executeTask; opt-in + fail-open (no-op when discovery is off).\n * Advisory: a cooled model is still usable via an explicit, available --model.\n */\n override async executeTask(\n task: CliTask,\n options: ResolvedExecutionOptions\n ): Promise<Result<CliResponse, CliError>> {\n const result = await super.executeTask(task, options);\n if (isDynamicModelsEnabled() && !result.ok && result.error.code === 'RATE_LIMITED') {\n const cliModel = resolveOpenCodeModel(task.model ?? this.model);\n getAvailabilityCache().markUnavailable(cliModel as ModelId, 'rate-limited (429)');\n logger.debug('Cooldown: marked model rate-limited (#3408)', { model: cliModel });\n }\n return result;\n }\n\n /** Appends optional task flags (workDir, variant, thinking). */\n private appendTaskFlags(args: string[], task: CliTask): void {\n const workDir = task.options?.['workDir'];\n if (typeof workDir === 'string' && workDir.length > 0) {\n args.push('--dir', workDir);\n }\n const variant = task.options?.['variant'];\n if (typeof variant === 'string' && ALLOWED_VARIANTS.includes(variant)) {\n args.push('--variant', variant);\n }\n if (task.options?.['thinking'] === true) {\n args.push('--thinking');\n }\n }\n\n /**\n * Gets CLI command and arguments for execution.\n * Uses `opencode run` with JSON format for stable parsing.\n * Omits --model when the requested model isn't available (#1402).\n */\n protected getCommand(task: CliTask): CommandConfig {\n const args: string[] = ['run', '--format', 'json'];\n this.appendModelArg(args, task);\n this.appendTaskFlags(args, task);\n\n // Honor systemPrompt by prepending to stdin content (#1886).\n // OpenCode CLI has no --system-prompt or --policy equivalent, so\n // prepend is the only option. This loses the formal system-role\n // distinction, but satisfies the contract that systemPrompt\n // influences the call (far better than silently dropping it).\n const content =\n task.systemPrompt !== undefined && task.systemPrompt !== ''\n ? `${task.systemPrompt}\\n\\n---\\n\\n${task.content}`\n : task.content;\n\n return { command: 'opencode', args, stdin: content };\n }\n\n /**\n * (#2540) Lists models the local OpenCode installation can route to.\n * Wraps the existing `probeAvailableModels()` (cached for the process\n * lifetime — see `cachedModels` at the top of this file) and reshapes\n * the result into the CliModelInfo schema. Splits `provider/model` ids\n * when present.\n */\n async listModels(): Promise<readonly CliModelInfo[]> {\n const ids = await probeAvailableModels();\n const out: CliModelInfo[] = [];\n for (const raw of ids) {\n const slash = raw.indexOf('/');\n if (slash > 0 && slash < raw.length - 1) {\n out.push({ id: raw, provider: raw.slice(0, slash) });\n } else {\n out.push({ id: raw });\n }\n }\n return out;\n }\n}\n\n/**\n * Factory function for creating OpenCode adapter.\n */\nexport function createOpenCodeAdapter(options?: BaseAdapterOptions): OpenCodeCliAdapter {\n return new OpenCodeCliAdapter(options);\n}\n\n/** Resets model probe cache (for testing). */\nexport function resetOpenCodeModelCache(): void {\n cachedModels = undefined;\n}\n","/**\n * nexus-agents/cli-adapters - OpenCode CLI Response Parser\n *\n * Defensive parser for OpenCode CLI JSON output.\n * Handles `opencode run --format json` NDJSON event stream.\n *\n * Real opencode v1.2.x NDJSON format (verified via E2E testing):\n * {\"type\":\"step_start\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-start\",...}}\n * {\"type\":\"text\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"text\",\"text\":\"Hello!\",...}}\n * {\"type\":\"step_finish\",\"sessionID\":\"ses_...\",\"part\":{\"type\":\"step-finish\",\"tokens\":{...},...}}\n *\n * (Source: Issue #1124, #1244, opencode.ai/docs/cli/)\n */\n\nimport type { ICliResponseParser, TokenUsage } from '../types.js';\nimport { asRecord, extractNumberField } from '../../utils/type-coercion.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'opencode-parser' });\n\n/** Minimum raw text length for plaintext fallback (#1402). */\nconst PLAINTEXT_MIN_LENGTH = 10;\n\n/** Returns true if text looks like NDJSON (most non-empty lines start with '{' ). */\nfunction looksLikeNdjson(text: string): boolean {\n const lines = text.split('\\n').filter((l) => l.trim() !== '');\n if (lines.length === 0) return false;\n const jsonLineCount = lines.filter((l) => l.trimStart().startsWith('{')).length;\n return jsonLineCount > lines.length / 2;\n}\n\n/**\n * OpenCode CLI NDJSON event types.\n * Includes both real v1.2.x types and legacy assumed types for compatibility.\n */\nexport type OpenCodeEventType =\n // Real opencode v1.2.x event types\n | 'step_start'\n | 'text'\n | 'tool_use'\n | 'step_finish'\n | 'error'\n // Legacy assumed types (maintained for backward compatibility)\n | 'session.start'\n | 'message.start'\n | 'message.delta'\n | 'message.complete'\n | 'session.complete';\n\n/**\n * Aggregated OpenCode response from NDJSON stream.\n */\nexport interface OpenCodeCliResponse {\n readonly sessionId?: string;\n readonly content: string;\n readonly usage?: TokenUsage;\n /**\n * Concatenated error-event messages emitted during the NDJSON stream.\n * Set whenever `{\"type\":\"error\",...}` events appeared. Independent of\n * whether `content` is empty — if both are populated the model produced\n * text and then errored, callers can decide what to do.\n * #2821: previously error events were folded into `content` (making\n * failures look like successful responses to consensus voters/routers).\n */\n readonly errorMessage?: string;\n}\n\n/** Internal state from processing NDJSON lines. */\ninterface NdjsonParseState {\n readonly sessionId: string | undefined;\n readonly contentParts: string[];\n readonly errorMessages: string[];\n readonly usage: TokenUsage | undefined;\n readonly hasStepEvents: boolean;\n readonly hasAnyRecognizedEvent: boolean;\n}\n\n/**\n * Parser for OpenCode CLI JSON output.\n * Handles NDJSON event stream from `opencode run --format json`.\n *\n * Supports both real opencode v1.2.x format and legacy assumed format.\n */\nexport class OpenCodeResponseParser implements ICliResponseParser<OpenCodeCliResponse> {\n readonly name = 'opencode-parser';\n readonly supportedVersionRange = '>=1.0.0 <2.0.0';\n\n /**\n * Parses complete OpenCode CLI NDJSON stream.\n */\n parse(raw: string): OpenCodeCliResponse | null {\n const lines = raw.trim().split('\\n');\n const state = this.processAllLines(lines);\n\n const errorMessage =\n state.errorMessages.length > 0 ? state.errorMessages.join('; ') : undefined;\n\n if (state.contentParts.length === 0) {\n // #2821: error-only streams must surface as failure. Empty content +\n // errorMessage set causes extractResponse() to return null, which the\n // subprocess-adapter then classifies as EXECUTION_ERROR — instead of\n // wrapping `[OpenCode error: ...]` in ok() and feeding it to voters.\n if (errorMessage !== undefined) {\n return this.buildResponse('', state.sessionId, state.usage, errorMessage);\n }\n return this.handleEmptyContent(raw, lines.length, state);\n }\n\n return this.buildResponse(\n state.contentParts.join(''),\n state.sessionId,\n state.usage,\n errorMessage\n );\n }\n\n /** Processes all NDJSON lines and returns aggregated state. */\n private processAllLines(lines: readonly string[]): NdjsonParseState {\n let sessionId: string | undefined;\n const contentParts: string[] = [];\n const errorMessages: string[] = [];\n let usage: TokenUsage | undefined;\n let hasStepEvents = false;\n let hasAnyRecognizedEvent = false;\n\n for (let idx = 0; idx < lines.length; idx++) {\n const line = lines[idx];\n if (line === undefined || line.trim() === '') continue;\n const hadEvent = this.processLine(\n line,\n { contentParts, errorMessages },\n (id) => (sessionId = id),\n (u) => (usage = u),\n idx\n );\n if (hadEvent) hasStepEvents = true;\n if (hadEvent || this.isRecognizedLegacyEvent(line)) hasAnyRecognizedEvent = true;\n }\n\n return {\n sessionId,\n contentParts,\n errorMessages,\n usage,\n hasStepEvents,\n hasAnyRecognizedEvent,\n };\n }\n\n /** Handles the case where no text content was extracted from NDJSON. */\n private handleEmptyContent(\n raw: string,\n lineCount: number,\n state: NdjsonParseState\n ): OpenCodeCliResponse | null {\n // Tool-only responses have step_start/step_finish but no text events.\n if (state.hasStepEvents) {\n return this.buildResponse(\n '[Tool-only response — no text output]',\n state.sessionId,\n state.usage\n );\n }\n // Fallback: try parsing as plain JSON (non-streaming mode)\n logger.debug('No NDJSON content extracted, trying JSON fallback', {\n rawLength: raw.length,\n lineCount,\n hasStepEvents: state.hasStepEvents,\n hasAnyRecognizedEvent: state.hasAnyRecognizedEvent,\n });\n return this.parsePlainJson(raw, state.hasAnyRecognizedEvent);\n }\n\n /** Builds an OpenCodeCliResponse from parsed components. */\n private buildResponse(\n content: string,\n sessionId: string | undefined,\n usage: TokenUsage | undefined,\n errorMessage?: string\n ): OpenCodeCliResponse {\n return {\n content,\n ...(sessionId !== undefined && { sessionId }),\n ...(usage !== undefined && { usage }),\n ...(errorMessage !== undefined && { errorMessage }),\n };\n }\n\n /**\n * Extracts just the response text.\n */\n extractResponse(raw: string): string | null {\n const parsed = this.parse(raw);\n if (parsed === null || parsed.content === '') {\n logger.debug('extractResponse returned null', {\n rawLength: raw.length,\n snippet: raw.slice(0, 100),\n parsedNull: parsed === null,\n });\n return null;\n }\n return parsed.content;\n }\n\n /**\n * Surfaces the error message from an error-only NDJSON stream (a\n * `{\"type\":\"error\",...}` event with no text content). The subprocess adapter\n * consumes this when {@link extractResponse} returns `null`, so an upstream\n * 401 / rate-limit is classified by its message (NOT_AUTHENTICATED /\n * RATE_LIMITED with a remediation hint) instead of falling through to a\n * generic PARSE_ERROR.\n */\n extractErrorMessage(raw: string): string | null {\n return this.parse(raw)?.errorMessage ?? null;\n }\n\n /**\n * Extracts token usage from response.\n */\n extractUsage(raw: string): TokenUsage | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n try {\n const event: unknown = JSON.parse(line);\n const record = asRecord(event);\n if (record === null) continue;\n\n // Real format: step_finish with nested part.tokens\n if (record.type === 'step_finish') {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) return usage;\n }\n\n // Legacy format: session.complete or message.complete with usage field\n if (record.type === 'session.complete' || record.type === 'message.complete') {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) return usage;\n }\n } catch {\n continue;\n }\n }\n\n return null;\n }\n\n /**\n * Extracts session ID for resumption.\n */\n extractSessionId(raw: string): string | null {\n const lines = raw.trim().split('\\n');\n\n for (const line of lines) {\n if (line.trim() === '') continue;\n const sid = this.extractSessionIdFromLine(line);\n if (sid !== null) return sid;\n }\n\n return null;\n }\n\n /** Extracts session ID from a single NDJSON line. */\n private extractSessionIdFromLine(line: string): string | null {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return null;\n\n // Real format: sessionID at top level (step_start, text, step_finish)\n if (typeof record.sessionID === 'string') return record.sessionID;\n\n // Legacy format: session_id/sessionId in session events\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') return sid;\n\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * Processes a single NDJSON line.\n * Handles both real v1.2.x format and legacy assumed format.\n * Returns true if a real v1.2.x step event was processed (step_start/text/tool_use/step_finish).\n * Legacy events return false since they don't indicate tool-only responses.\n */\n private processLine(\n line: string,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void,\n lineIndex: number\n ): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n\n const isReal = this.processRealEvent(record, collectors, setSessionId, setUsage);\n if (isReal) return true;\n\n this.processLegacyEvent(record, collectors.contentParts, setSessionId, setUsage);\n return false;\n } catch {\n logger.debug('Skipped malformed NDJSON line', {\n lineNumber: lineIndex + 1,\n snippet: line.slice(0, 100),\n });\n return false;\n }\n }\n\n /** Processes real opencode v1.2.x event types. Returns true if handled. */\n private processRealEvent(\n record: Record<string, unknown>,\n collectors: { contentParts: string[]; errorMessages: string[] },\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): boolean {\n switch (record.type) {\n case 'step_start':\n case 'tool_use':\n this.handleRealSessionId(record, setSessionId);\n return true;\n case 'text':\n this.handleRealSessionId(record, setSessionId);\n this.pushRealTextContent(record, collectors.contentParts);\n return true;\n case 'step_finish':\n this.handleRealSessionId(record, setSessionId);\n this.emitRealUsage(record, setUsage);\n return true;\n case 'error':\n this.handleRealSessionId(record, setSessionId);\n this.captureErrorMessage(record, collectors.errorMessages);\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Captures an error-event message for the response's `errorMessage` field\n * (#2821). Previously this pushed `[OpenCode error: ...]` into `contentParts`,\n * which made error-only streams look like successful responses to consensus\n * voters and the routing learner.\n */\n private captureErrorMessage(record: Record<string, unknown>, errorMessages: string[]): void {\n const errorObj = asRecord(record.error);\n if (errorObj === null) return;\n\n const data = asRecord(errorObj.data);\n const message =\n data !== null && typeof data.message === 'string'\n ? data.message\n : typeof errorObj.name === 'string'\n ? errorObj.name\n : 'Unknown error';\n\n logger.warn('OpenCode returned error event', { message });\n errorMessages.push(message);\n }\n\n /** Processes legacy assumed event types. */\n private processLegacyEvent(\n record: Record<string, unknown>,\n contentParts: string[],\n setSessionId: (id: string) => void,\n setUsage: (usage: TokenUsage) => void\n ): void {\n switch (record.type) {\n case 'session.start':\n this.handleLegacySessionStart(record, setSessionId);\n break;\n case 'message.delta':\n this.pushLegacyTextContent(record, contentParts);\n break;\n case 'message.complete':\n this.pushLegacyTextContent(record, contentParts);\n this.emitLegacyUsage(record, setUsage);\n break;\n case 'session.complete':\n this.emitLegacyUsage(record, setUsage);\n break;\n }\n }\n\n // --- Real v1.2.x format handlers ---\n\n /** Extracts sessionID from top-level field (real format). */\n private handleRealSessionId(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n if (typeof record.sessionID === 'string') setSessionId(record.sessionID);\n }\n\n /** Extracts text from nested part.text field (real format). */\n private pushRealTextContent(record: Record<string, unknown>, parts: string[]): void {\n const part = asRecord(record.part);\n if (part === null) return;\n\n if (typeof part.text === 'string') parts.push(part.text);\n }\n\n /** Extracts usage from nested part.tokens field (real format). */\n private emitRealUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromPart(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Extracts usage from part.tokens (real opencode v1.2.x format). */\n private extractUsageFromPart(record: Record<string, unknown>): TokenUsage | null {\n const part = asRecord(record.part);\n if (part === null) return null;\n\n const tokens = asRecord(part.tokens);\n if (tokens === null) return null;\n\n const inputTokens = extractNumberField(tokens, 'input');\n const outputTokens = extractNumberField(tokens, 'output');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n\n // --- Legacy format handlers ---\n\n /** Extracts session ID from a session event record (legacy format). */\n private handleLegacySessionStart(\n record: Record<string, unknown>,\n setSessionId: (id: string) => void\n ): void {\n const sid = record.session_id ?? record.sessionId;\n if (typeof sid === 'string') setSessionId(sid);\n }\n\n /** Pushes text content from a message event (legacy format). */\n private pushLegacyTextContent(record: Record<string, unknown>, parts: string[]): void {\n const text = record.content ?? record.delta ?? record.text;\n if (typeof text === 'string') parts.push(text);\n }\n\n /** Emits usage from a record (legacy format). */\n private emitLegacyUsage(\n record: Record<string, unknown>,\n setUsage: (usage: TokenUsage) => void\n ): void {\n const usage = this.extractUsageFromRecord(record);\n if (usage !== null) setUsage(usage);\n }\n\n /** Checks if a line contains a recognized legacy event type (without full parsing). */\n private isRecognizedLegacyEvent(line: string): boolean {\n try {\n const record = asRecord(JSON.parse(line) as unknown);\n if (record === null) return false;\n const t = record.type;\n return (\n t === 'session.start' ||\n t === 'message.start' ||\n t === 'message.delta' ||\n t === 'message.complete' ||\n t === 'session.complete'\n );\n } catch {\n return false;\n }\n }\n\n /**\n * Fallback parser for plain JSON output (non-streaming).\n * Falls back to raw plaintext if JSON parsing fails and content is substantial (#1402).\n * When hasAnyRecognizedEvent is true, NDJSON-like plaintext is rejected (it was\n * recognized NDJSON that simply had no content — not malformed output).\n */\n private parsePlainJson(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n try {\n const data: unknown = JSON.parse(raw);\n const record = asRecord(data);\n if (record === null) return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n\n // Try common response field names\n const content = record.content ?? record.result ?? record.text ?? record.output;\n if (typeof content !== 'string') return null; // Valid JSON but no recognized fields\n\n const usage = this.extractUsageFromRecord(record);\n const sid = record.session_id ?? record.sessionId;\n\n return {\n content,\n ...(typeof sid === 'string' ? { sessionId: sid } : {}),\n ...(usage !== null ? { usage } : {}),\n };\n } catch {\n return this.parsePlaintext(raw, hasAnyRecognizedEvent);\n }\n }\n\n /**\n * Last-resort plaintext fallback for non-JSON CLI output (#1402).\n * Returns raw text as content when it has substantial length.\n * Accepts NDJSON-like content only when no recognized events were found\n * (meaning it's truly unrecognized/malformed output, not valid NDJSON with no text).\n */\n private parsePlaintext(raw: string, hasAnyRecognizedEvent: boolean): OpenCodeCliResponse | null {\n const trimmed = raw.trim();\n if (trimmed.length < PLAINTEXT_MIN_LENGTH) {\n logger.debug('Plaintext fallback rejected: too short', { length: trimmed.length });\n return null;\n }\n if (looksLikeNdjson(trimmed)) {\n if (hasAnyRecognizedEvent) {\n logger.debug('Plaintext fallback rejected: recognized NDJSON with no content', {\n length: trimmed.length,\n });\n return null;\n }\n logger.debug('Plaintext fallback: accepting malformed NDJSON as text', {\n length: trimmed.length,\n });\n }\n return { content: trimmed };\n }\n\n /**\n * Extracts usage from a record with usage/token fields (legacy format).\n */\n private extractUsageFromRecord(record: Record<string, unknown>): TokenUsage | null {\n const usage = asRecord(record.usage);\n if (usage === null) return null;\n\n const inputTokens =\n extractNumberField(usage, 'input_tokens') ?? extractNumberField(usage, 'inputTokens');\n const outputTokens =\n extractNumberField(usage, 'output_tokens') ?? extractNumberField(usage, 'outputTokens');\n\n if (inputTokens === null || outputTokens === null) return null;\n\n return {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n };\n }\n}\n","/**\n * Logical→live model-id resolution (#3407, epic #3403 Phase 2).\n *\n * When a configured model id has gone stale because the provider renamed it\n * (e.g. OpenRouter `qwen/qwen3-coder-480b-a35b:free` → `qwen/qwen3-coder:free`),\n * map it to the closest id that the transport actually offers right now — so a\n * rename is zero-touch instead of needing a registry edit.\n *\n * SAFE by design:\n * - **Deterministic** (pure function; same inputs → same output). No scoring\n * randomness, no network.\n * - **Conservative** — only substitutes within the SAME provider namespace and\n * only when the shared prefix is substantial (≥60% of the shorter id), so an\n * unrelated model is never chosen. Otherwise returns the input unchanged.\n * - **Fail-open** — an empty catalog (discovery disabled/cold) returns the\n * input unchanged, so routing behaves exactly as before.\n * - **Advisory** — an exact match always wins; this only kicks in when the id\n * is NOT offered.\n *\n * @module config/resolve-live-model\n */\n\n/** Split an id into its base and an optional `:tier` suffix (e.g. `:free`). */\nfunction splitTier(id: string): { base: string; tier: string } {\n const colon = id.indexOf(':');\n return colon >= 0 ? { base: id.slice(0, colon), tier: id.slice(colon) } : { base: id, tier: '' };\n}\n\n/**\n * True if `prefix` is a prefix of `full` ending at a TOKEN boundary — i.e. the\n * next char in `full` is a separator (`-`, `/`, end). This prevents matching a\n * partial token (`gpt-5` ⊄ `gpt-50`) while allowing `qwen3-coder` ⊂\n * `qwen3-coder-480b`.\n */\nfunction isTokenBoundaryPrefix(prefix: string, full: string): boolean {\n if (prefix.length > full.length || !full.startsWith(prefix)) return false;\n if (full.length === prefix.length) return true;\n const next = full[prefix.length];\n return next === '-' || next === '/';\n}\n\n/**\n * Resolve `configured` to the closest id present in `available`. Returns\n * `configured` unchanged when it's already offered, when `available` is empty,\n * or when nothing qualifies.\n *\n * A candidate qualifies ONLY when it is a **simplification** of the configured\n * id — its base is a token-boundary prefix of the configured base (the rename\n * pattern: `qwen3-coder-480b-a35b:free` → `qwen3-coder:free`). It will NOT\n * substitute a *more specific* sibling (`gpt-5` → `gpt-5-codex`), which would be\n * a different model and worse than falling back to the CLI default.\n */\nexport function resolveLiveModelId(configured: string, available: Iterable<string>): string {\n const set: ReadonlySet<string> =\n available instanceof Set ? (available as Set<string>) : new Set(available);\n if (set.size === 0 || set.has(configured)) return configured;\n\n const slash = configured.indexOf('/');\n const providerPrefix = slash > 0 ? configured.slice(0, slash + 1) : '';\n const cfg = splitTier(configured);\n\n const candidates = [...set]\n .filter((c) => providerPrefix === '' || c.startsWith(providerPrefix))\n .map((c) => splitTier(c))\n .filter((cand) => isTokenBoundaryPrefix(cand.base, cfg.base))\n .map((cand) => ({\n id: cand.base + cand.tier,\n baseLen: cand.base.length,\n tierMatch: cand.tier === cfg.tier,\n }));\n\n if (candidates.length === 0) return configured;\n\n candidates.sort(\n (a, b) =>\n b.baseLen - a.baseLen || // most-specific simplification (closest to configured)\n Number(b.tierMatch) - Number(a.tierMatch) || // matching :free / paid tier\n a.id.length - b.id.length || // shorter overall\n (a.id < b.id ? -1 : a.id > b.id ? 1 : 0) // lexicographic — fully deterministic\n );\n return candidates[0]?.id ?? configured;\n}\n","/**\n * cli-auth-probe — real authentication probes for the four AI CLIs.\n *\n * The existing `adapter.healthCheck()` only confirms the CLI binary exists +\n * the version is supported. It does NOT probe whether the CLI can actually\n * authenticate. Result: doctor reports \"✓ Auth: CLI auth\" for installed-but-\n * unauthed CLIs, then downstream commands fail with unreadable errors.\n *\n * This module fixes that. Per-CLI probes use the cheapest reliable signal:\n *\n * - claude → presence + non-expired `~/.claude/.credentials.json`\n * (or env: ANTHROPIC_API_KEY)\n * - codex → `codex login status` (returns auth state)\n * (or env: OPENAI_API_KEY)\n * - gemini → presence + non-expired `~/.gemini/oauth_creds.json`\n * (or env: GOOGLE_AI_API_KEY)\n * - opencode → `opencode auth list` (parses credential count)\n *\n * No live API calls. Tokens are not decoded or sent anywhere — only their\n * presence/expiry is read locally.\n *\n * Source: Issue #2447. Replaces the binary-detection-only path in doctor.ts\n * (Issue #2439 follow-up).\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\nimport type { CliName } from '../cli-adapters/types.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Result of probing a single CLI's authentication state. Discriminated so\n * callers can render auth | needs-login | not-installed | error states\n * without re-checking flags.\n */\nexport type AuthProbeResult =\n | {\n readonly cli: CliName;\n readonly state: 'authenticated';\n /** How auth was satisfied — informational, not load-bearing. */\n readonly via: 'env-var' | 'cli-credentials';\n /** Optional metadata (e.g. expiry timestamp) if cheap to extract. */\n readonly meta?: Readonly<Record<string, unknown>>;\n }\n | {\n readonly cli: CliName;\n readonly state: 'needs-login';\n /** Short, human-readable reason to surface to the operator. */\n readonly reason: string;\n /** Exact command the operator should run to fix this. */\n readonly fixCommand: string;\n /** Optional canonical URL for credentials/console. */\n readonly fixUrl?: string;\n /** Env-var alternative if applicable. */\n readonly envFallback?: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'not-installed';\n readonly reason: string;\n }\n | {\n readonly cli: CliName;\n readonly state: 'error';\n readonly reason: string;\n };\n\nconst HOME = homedir();\n\n// ============================================================================\n// Per-CLI probes\n// ============================================================================\n\nfunction claudeNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'claude',\n state: 'needs-login',\n reason,\n fixCommand: 'claude /login',\n envFallback: 'ANTHROPIC_API_KEY',\n fixUrl: 'https://console.anthropic.com/account/keys',\n };\n}\n\nfunction probeClaude(): AuthProbeResult {\n if (process.env['ANTHROPIC_API_KEY'] !== undefined && process.env['ANTHROPIC_API_KEY'] !== '') {\n return { cli: 'claude', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.claude', '.credentials.json');\n if (!existsSync(credPath)) {\n return claudeNeedsLogin(\n 'No credentials at ~/.claude/.credentials.json and ANTHROPIC_API_KEY is not set'\n );\n }\n try {\n const parsed: unknown = JSON.parse(readFileSync(credPath, 'utf-8'));\n if (!isClaudeCredsShape(parsed)) {\n return claudeNeedsLogin(\n 'Credentials file present but not in expected shape (missing claudeAiOauth.accessToken)'\n );\n }\n const expiresAt = parsed.claudeAiOauth.expiresAt;\n if (typeof expiresAt === 'number' && expiresAt < Date.now()) {\n return claudeNeedsLogin(`OAuth token expired ${new Date(expiresAt).toISOString()}`);\n }\n return {\n cli: 'claude',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof expiresAt === 'number' ? { meta: { expiresAt } } : {}),\n };\n } catch (e: unknown) {\n return {\n cli: 'claude',\n state: 'error',\n reason: `Failed to read claude credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nfunction codexNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'codex',\n state: 'needs-login',\n reason,\n fixCommand: 'codex login',\n envFallback: 'OPENAI_API_KEY',\n fixUrl: 'https://platform.openai.com/api-keys',\n };\n}\n\nfunction classifyCodexStdout(stdout: string): AuthProbeResult {\n // Check 'not logged in' BEFORE 'logged in' — substring shadowing.\n if (/not logged/i.test(stdout) || /no.*token/i.test(stdout)) {\n return codexNeedsLogin(stdout.trim().split('\\n')[0] ?? 'Not logged in');\n }\n // Probe succeeded; treat unrecognized output as authed (defensive default).\n return { cli: 'codex', state: 'authenticated', via: 'cli-credentials' };\n}\n\nasync function probeCodex(): Promise<AuthProbeResult> {\n if (process.env['OPENAI_API_KEY'] !== undefined && process.env['OPENAI_API_KEY'] !== '') {\n return { cli: 'codex', state: 'authenticated', via: 'env-var' };\n }\n try {\n const { stdout } = await execFileAsync('codex', ['login', 'status'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n return classifyCodexStdout(stdout);\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'codex', state: 'not-installed', reason: 'codex binary not on PATH' };\n }\n return codexNeedsLogin('Not logged in (codex login status returned non-zero)');\n }\n}\n\nfunction geminiNeedsLogin(reason: string): AuthProbeResult {\n return {\n cli: 'gemini',\n state: 'needs-login',\n reason,\n fixCommand: 'gemini',\n envFallback: 'GOOGLE_AI_API_KEY',\n fixUrl: 'https://aistudio.google.com/apikey',\n };\n}\n\nfunction classifyGeminiCreds(parsed: unknown): AuthProbeResult {\n if (!isGeminiCredsShape(parsed)) {\n return geminiNeedsLogin('OAuth credentials file present but not in expected shape');\n }\n if (typeof parsed.expiry_date === 'number' && parsed.expiry_date < Date.now()) {\n return geminiNeedsLogin(\n `OAuth access token expired ${new Date(parsed.expiry_date).toISOString()} (refresh may still work)`\n );\n }\n return {\n cli: 'gemini',\n state: 'authenticated',\n via: 'cli-credentials',\n ...(typeof parsed.expiry_date === 'number' ? { meta: { expiresAt: parsed.expiry_date } } : {}),\n };\n}\n\nfunction probeGemini(): AuthProbeResult {\n const env = process.env['GOOGLE_AI_API_KEY'] ?? process.env['GEMINI_API_KEY'];\n if (env !== undefined && env !== '') {\n return { cli: 'gemini', state: 'authenticated', via: 'env-var' };\n }\n const credPath = join(HOME, '.gemini', 'oauth_creds.json');\n if (!existsSync(credPath)) {\n return geminiNeedsLogin(\n 'No OAuth credentials at ~/.gemini/oauth_creds.json and GOOGLE_AI_API_KEY/GEMINI_API_KEY are not set'\n );\n }\n try {\n return classifyGeminiCreds(JSON.parse(readFileSync(credPath, 'utf-8')));\n } catch (e: unknown) {\n return {\n cli: 'gemini',\n state: 'error',\n reason: `Failed to read gemini credentials: ${e instanceof Error ? e.message : String(e)}`,\n };\n }\n}\n\nasync function probeOpencode(): Promise<AuthProbeResult> {\n // OpenCode's auth is per-provider (anthropic/openai/etc) configured in\n // ~/.config/opencode/opencode.json or via env. Probe by listing credentials.\n try {\n const { stdout } = await execFileAsync('opencode', ['auth', 'list'], {\n timeout: CLI_SUBPROCESS_TIMEOUTS.spawnMs,\n });\n if (/0 credentials/i.test(stdout)) {\n return {\n cli: 'opencode',\n state: 'needs-login',\n reason: 'No providers configured in opencode',\n fixCommand: 'opencode auth login',\n fixUrl: 'https://opencode.ai/docs/config',\n };\n }\n return { cli: 'opencode', state: 'authenticated', via: 'cli-credentials' };\n } catch (e: unknown) {\n const msg = e instanceof Error ? e.message : String(e);\n if (/ENOENT|not found/i.test(msg)) {\n return { cli: 'opencode', state: 'not-installed', reason: 'opencode binary not on PATH' };\n }\n return {\n cli: 'opencode',\n state: 'error',\n reason: msg.split('\\n')[0] ?? 'opencode auth list failed',\n };\n }\n}\n\n// ============================================================================\n// Type guards (no `any`, no untyped JSON)\n// ============================================================================\n\ninterface ClaudeCreds {\n readonly claudeAiOauth: {\n readonly accessToken: string;\n readonly expiresAt?: number;\n };\n}\n\nfunction isClaudeCredsShape(v: unknown): v is ClaudeCreds {\n if (typeof v !== 'object' || v === null) return false;\n const oauth = (v as { claudeAiOauth?: unknown }).claudeAiOauth;\n if (typeof oauth !== 'object' || oauth === null) return false;\n return typeof (oauth as { accessToken?: unknown }).accessToken === 'string';\n}\n\ninterface GeminiCreds {\n readonly access_token: string;\n readonly expiry_date?: number;\n}\n\nfunction isGeminiCredsShape(v: unknown): v is GeminiCreds {\n if (typeof v !== 'object' || v === null) return false;\n return typeof (v as { access_token?: unknown }).access_token === 'string';\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/** Probe a single CLI. */\nexport async function probeCli(cli: CliName): Promise<AuthProbeResult> {\n switch (cli) {\n case 'claude':\n return Promise.resolve(probeClaude());\n case 'codex':\n return probeCodex();\n case 'gemini':\n return Promise.resolve(probeGemini());\n case 'opencode':\n return probeOpencode();\n }\n}\n\n/** Probe all four CLIs in parallel. Order in returned array matches input. */\nexport async function probeAllClis(): Promise<readonly AuthProbeResult[]> {\n const clis: readonly CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n return Promise.all(clis.map((c) => probeCli(c)));\n}\n","/**\n * nexus-agents/cli-adapters - Adapter Factory\n *\n * Factory for creating CLI adapters based on configuration.\n * Supports optional caching of CLI health check results.\n *\n * (Source: cli-project_plan.md v2.1.0)\n * (Source: Issue #90 - Codex MCP adapter)\n * (Source: Issue #165 - CLI detection cache)\n */\n\nimport type { ICliAdapter, CliName, RoutingArmId, CliTransport } from './types.js';\nimport { getTimeProvider } from '../core/index.js';\nimport { collectApiRoutingArms } from '../adapters/auto-adapter.js';\nimport { ClaudeCliAdapter } from './adapters/claude-adapter.js';\nimport { GeminiCliAdapter } from './adapters/gemini-adapter.js';\nimport { CodexCliAdapter } from './adapters/codex-adapter.js';\nimport { CodexMcpAdapter } from './adapters/codex-mcp-adapter.js';\nimport { OpenCodeCliAdapter } from './adapters/opencode-adapter.js';\nimport type { ILogger } from '../core/index.js';\nimport type { ICliDetectionCache } from './cli-detection-cache.js';\nimport { CliDetectionCache } from './cli-detection-cache.js';\nimport { probeCli } from '../cli/cli-auth-probe.js';\n\n/**\n * Configuration for creating a CLI adapter.\n */\nexport interface CliAdapterConfig {\n /** Which CLI to use */\n readonly cli: CliName;\n /** Optional model override */\n readonly model?: string;\n /** Optional logger */\n readonly logger?: ILogger;\n /** Preferred transport (for Codex: 'mcp' or 'subprocess') */\n readonly transport?: CliTransport;\n}\n\n/**\n * Creates a CLI adapter based on configuration.\n *\n * @param config - Adapter configuration\n * @returns The configured CLI adapter\n * @throws Error if CLI name is not supported\n *\n * @example\n * ```typescript\n * const adapter = createCliAdapter({ cli: 'claude', model: 'claude-opus-4' });\n * const result = await adapter.execute({ content: 'Hello!' });\n * ```\n */\nexport function createCliAdapter(config: CliAdapterConfig): ICliAdapter {\n const options = {\n ...(config.model !== undefined && { model: config.model }),\n ...(config.logger !== undefined && { logger: config.logger }),\n };\n\n switch (config.cli) {\n case 'claude':\n return new ClaudeCliAdapter(options);\n\n case 'gemini':\n return new GeminiCliAdapter(options);\n\n case 'codex':\n return createCodexAdapter(config.transport, options);\n\n case 'opencode':\n return new OpenCodeCliAdapter(options);\n\n default: {\n const exhaustiveCheck: never = config.cli;\n throw new Error(`Unsupported CLI: ${String(exhaustiveCheck)}`);\n }\n }\n}\n\n/**\n * Creates a Codex adapter with preferred transport.\n * Defaults to MCP transport (most stable).\n *\n * @param transport - Preferred transport ('mcp' or 'subprocess')\n * @param options - Adapter options\n * @returns Codex CLI adapter\n */\nfunction createCodexAdapter(\n transport: CliTransport | undefined,\n options: { model?: string; logger?: ILogger }\n): ICliAdapter {\n // Default to MCP transport (preferred per Issue #90)\n if (transport === 'subprocess') {\n return new CodexCliAdapter(options);\n }\n return new CodexMcpAdapter(options);\n}\n\n/**\n * Creates all available routing-arm adapters.\n * Uses MCP transport for Codex by default (preferred).\n *\n * The four CLI slots are always registered under their slot key. When\n * `NEXUS_BILLING_MODE=api`, the direct-API adapters whose keys are present are\n * ALSO appended as distinct `api:<vendor>` routing arms (#3422) so the router /\n * bandit can score them separately from the CLI slots. DEFAULT (plan) mode\n * returns CLIs only — never surprise API spend. Key-presence-only and\n * deterministic; keys are never validated by calling out.\n *\n * @param logger - Optional shared logger\n * @param codexTransport - Transport for Codex (default: 'mcp')\n * @returns Map of routing arm id to adapter\n */\nexport function createAllAdapters(\n logger?: ILogger,\n codexTransport: CliTransport = 'mcp'\n): Map<RoutingArmId, ICliAdapter> {\n const adapters = new Map<RoutingArmId, ICliAdapter>();\n const options = logger !== undefined ? { logger } : undefined;\n\n adapters.set('claude', new ClaudeCliAdapter(options));\n adapters.set('gemini', new GeminiCliAdapter(options));\n adapters.set('codex', createCodexAdapter(codexTransport, options ?? {}));\n adapters.set('opencode', new OpenCodeCliAdapter(options));\n\n // API arms enter the router only in explicit api billing mode (#3422).\n if (process.env['NEXUS_BILLING_MODE'] === 'api') {\n for (const { armId, adapter } of collectApiRoutingArms(logger)) {\n adapters.set(armId, adapter);\n }\n }\n\n return adapters;\n}\n\n/**\n * Checks if a CLI is available by running a health check.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cli - CLI name to check\n * @param cache - Optional cache to use\n * @returns True if CLI is healthy\n */\nexport async function isCliAvailable(cli: CliName, cache?: ICliDetectionCache): Promise<boolean> {\n // Check cache first\n if (cache !== undefined) {\n const cached = cache.get(cli);\n if (cached !== undefined) {\n return cached.healthy;\n }\n }\n\n try {\n const adapter = createCliAdapter({ cli });\n // Pre-#2725 only ran healthCheck() — which confirms the binary exists\n // and runs but does NOT probe authentication. Result: orchestrate listed\n // opencode as \"Available\" when the user wasn't logged in, and the next\n // call failed with an opaque subprocess error. Auth must agree with the\n // probe doctor already uses (cli-auth-probe.ts, #2447).\n const [health, auth] = await Promise.all([adapter.healthCheck(), probeCli(cli)]);\n const available = health.healthy && auth.state === 'authenticated';\n\n // Store in cache if provided. Synthesize a degraded health record when\n // the binary is healthy but auth failed, so downstream consumers see\n // \"unavailable\" without losing the version string.\n if (cache !== undefined) {\n if (available) {\n cache.set(cli, CliDetectionCache.fromHealthStatus(health));\n } else {\n cache.set(cli, {\n healthy: false,\n version: health.version,\n versionStatus: health.versionStatus,\n checkedAt: new Date(),\n message:\n auth.state === 'authenticated'\n ? health.message\n : `auth: ${auth.state}` + ('reason' in auth ? ` (${auth.reason})` : ''),\n });\n }\n }\n\n return available;\n } catch (error: unknown) {\n // Closes #2952 (medium): pre-fix the bare `catch {}` dropped the error\n // entirely — operators saw `<cli>: unavailable` with no way to tell\n // whether the binary was missing, the probe timed out, or some other\n // failure occurred. Now include the message in the cached entry.\n cacheHealthCheckFailure(cache, cli, error);\n return false;\n }\n}\n\n/** Records a health-check exception in the cache with the error message preserved. */\nfunction cacheHealthCheckFailure(\n cache: ICliDetectionCache | undefined,\n cli: CliName,\n error: unknown\n): void {\n if (cache === undefined) return;\n const message = error instanceof Error ? error.message : String(error);\n cache.set(cli, {\n healthy: false,\n version: 'unknown',\n versionStatus: 'unsupported',\n checkedAt: new Date(getTimeProvider().now()),\n message: `Health check failed: ${message}`,\n });\n}\n\n/**\n * Gets all available CLIs by running health checks.\n * Uses cache if provided to avoid repeated subprocess calls.\n *\n * @param cache - Optional cache to use\n * @returns Array of available CLI names\n */\nexport async function getAvailableClis(cache?: ICliDetectionCache): Promise<CliName[]> {\n const clis: CliName[] = ['claude', 'gemini', 'codex', 'opencode'];\n\n // Check all CLIs in parallel to avoid sequential timeout penalties\n const results = await Promise.allSettled(\n clis.map(async (cli) => ({ cli, available: await isCliAvailable(cli, cache) }))\n );\n\n return results\n .filter(\n (r): r is PromiseFulfilledResult<{ cli: CliName; available: boolean }> =>\n r.status === 'fulfilled' && r.value.available\n )\n .map((r) => r.value.cli);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CO,IAAM,oBAAN,MAAiD;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EAEQ;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,YAAY,YAAyB,QAAkC;AACrE,SAAK,aAAa;AAClB,SAAK,mBAAmB,QAAQ;AAChC,SAAK,aAAa,OAAO,WAAW,IAAI;AACxC,SAAK,UAAU,WAAW,aAAa,EAAE;AACzC,SAAK,eAAe,KAAK,mBAAmB;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAiD;AACvD,UAAM,OAA0B,CAAC,gBAAG,YAAY,gBAAG,QAAQ;AAG3D,QAAI,KAAK,WAAW,SAAS,UAAU;AACrC,WAAK,KAAK,gBAAG,iBAAiB;AAAA,IAChC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,SAAqC;AAErD,UAAM,UAAU,QAAQ,SACrB,IAAI,CAAC,QAAQ;AACZ,YAAM,OACJ,OAAO,IAAI,YAAY,WACnB,IAAI,UACJ,IAAI,QACD,OAAO,CAAC,MAA2C,EAAE,SAAS,MAAM,EACpE,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI;AAClB,aAAO,IAAI,IAAI,IAAI,MAAM,IAAI;AAAA,IAC/B,CAAC,EACA,KAAK,MAAM;AAGd,UAAM,OAAgB,EAAE,QAAQ;AAEhC,QAAI,QAAQ,iBAAiB,QAAW;AACtC,MAAC,KAAkC,eAAe,QAAQ;AAAA,IAC5D;AACA,QAAI,QAAQ,cAAc,QAAW;AACnC,MAAC,KAA+B,YAAY,QAAQ;AAAA,IACtD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,UAA2C;AACtE,WAAO;AAAA,MACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,KAAK,CAAC;AAAA,MAC/C,OAAO;AAAA,QACL,aAAa,SAAS,OAAO,eAAe;AAAA,QAC5C,cAAc,SAAS,OAAO,gBAAgB;AAAA,QAC9C,aAAa,SAAS,OAAO,eAAe;AAAA,MAC9C;AAAA,MACA,YAAY;AAAA,MACZ,OAAO,SAAS,SAAS,KAAK;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,UAAgC;AACnD,UAAM,UAAU,SAAS,UAAU,SAAY,EAAE,OAAO,SAAS,MAAM,IAAI,CAAC;AAC5E,WAAO,IAAI,WAAW,SAAS,SAAS,OAAO;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,SAA6E;AAC1F,UAAM,OAAO,KAAK,UAAU,OAAO;AAInC,UAAM,qBAAqB,QAAQ,aAAa,KAAK;AACrD,UAAM,OACJ,uBAAuB,SAAY,EAAE,WAAW,mBAAmB,IAAI;AACzE,UAAM,SAAS,MAAM,KAAK,WAAW,QAAQ,MAAM,IAAI;AAEvD,QAAI,CAAC,OAAO,IAAI;AACd,aAAO,IAAI,KAAK,aAAa,OAAO,KAAK,CAAC;AAAA,IAC5C;AAEA,WAAO,GAAG,KAAK,qBAAqB,OAAO,KAAK,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,OAAO,SAAwD;AACpE,UAAM,SAAS,MAAM,KAAK,SAAS,OAAO;AAE1C,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,OAAO;AAAA,IACf;AAEA,UAAM,WAAW,OAAO;AAExB,UAAM,EAAE,MAAM,iBAAiB,SAAS,EAAE,OAAO,SAAS,MAAM,EAAE;AAElE,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,SAAS,QAAQ,CAAC,KAAK,EAAE,MAAM,QAAQ,MAAM,GAAG;AAAA,IAChE;AAEA,UAAM,aAAa,SAAS,QAAQ,CAAC;AACrC,UAAM,OAAO,YAAY,SAAS,SAAS,WAAW,OAAO;AAC7D,UAAM,EAAE,MAAM,uBAAuB,OAAO,GAAG,OAAO,EAAE,MAAM,cAAc,KAAK,EAAE;AAEnF,UAAM,EAAE,MAAM,sBAAsB,OAAO,EAAE;AAE7C,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO,EAAE,aAAa,SAAS,WAAW;AAAA,MAC1C,OAAO,SAAS;AAAA,IAClB;AAEA,UAAM,EAAE,MAAM,eAAe;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,MAA+B;AACzC,WAAO,QAAQ,QAAQ,eAAe,IAAI,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA4C;AAE1C,WAAO,GAAG,MAAS;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,UAAM,KAAK,WAAW,WAAW;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,UAAM,KAAK,WAAW,QAAQ;AAAA,EAChC;AACF;AAQO,SAAS,wBACd,YACA,QACmB;AACnB,SAAO,IAAI,kBAAkB,YAAY,MAAM;AACjD;;;AChLA,IAAM,yBAAyB;AAG/B,IAAM,uBAA0C;AAAA,EAC9C,WAAW;AAAA,EACX,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,OAAO;AAAA,EACP,MAAM;AACR;AAGA,IAAM,gBAA8B;AAK7B,IAAM,oBAAN,MAA+C;AAAA,EAC3C;AAAA,EACA,YAA0B;AAAA,EAC1B;AAAA,EAEQ;AAAA,EAEjB,YAAY,cAA6B,QAAiC;AACxE,SAAK,eAAe;AACpB,SAAK,OAAO,OAAO;AACnB,SAAK,eAAe,OAAO,gBAAgB;AAAA,EAC7C;AAAA;AAAA,EAGQ,oBAAoB,MAAe,SAA+C;AACxF,UAAM,UAA6B;AAAA,MACjC,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,KAAK,QAAQ,CAAC;AAAA,IACpD;AACA,QAAI,KAAK,iBAAiB,QAAW;AACnC,MAAC,QAAqC,eAAe,KAAK;AAAA,IAC5D;AACA,QAAI,KAAK,cAAc,QAAW;AAChC,MAAC,QAAkC,YAAY,KAAK;AAAA,IACtD;AACA,QAAI,SAAS,cAAc,QAAW;AACpC,MAAC,QAAkC,YAAY,QAAQ;AAAA,IACzD;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,OAAO,UAAsC;AACnD,WAAO,SAAS,QACb,OAAO,CAAC,MAA2C,EAAE,SAAS,MAAM,EACpE,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI;AAAA,EACd;AAAA;AAAA,EAGQ,cAAc,UAA2C;AAC/D,WAAO;AAAA,MACL,MAAM,KAAK,OAAO,QAAQ;AAAA,MAC1B,OAAO;AAAA,QACL,aAAa,SAAS,MAAM;AAAA,QAC5B,cAAc,SAAS,MAAM;AAAA,QAC7B,aAAa,SAAS,MAAM;AAAA,MAC9B;AAAA,MACA,OAAO,SAAS;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,WAAW,OAA6B;AAC9C,UAAM,cAAc,gBAAgB,MAAM,OAAO;AACjD,UAAM,OAAqB,cAAc,iBAAiB;AAC1D,UAAM,OAAiB;AAAA,MACrB;AAAA,MACA,SAAS,MAAM;AAAA,MACf,KAAK,KAAK;AAAA,MACV,WAAW;AAAA,IACb;AACA,WAAO,MAAM,iBAAiB,QAAQ,EAAE,GAAG,MAAM,OAAO,MAAM,MAAM,IAAI;AAAA,EAC1E;AAAA,EAEA,MAAM,QAAQ,MAAe,SAAoE;AAC/F,UAAM,SAAS,MAAM,KAAK,aAAa,SAAS,KAAK,oBAAoB,MAAM,OAAO,CAAC;AACvF,QAAI,CAAC,OAAO,IAAI;AACd,aAAO,IAAI,KAAK,WAAW,OAAO,KAAK,CAAC;AAAA,IAC1C;AACA,WAAO,GAAG,KAAK,cAAc,OAAO,KAAK,CAAC;AAAA,EAC5C;AAAA;AAAA,EAGA,MAAM,cAAqC;AACzC,UAAM,QAAQ,KAAK,aAAa,eAAe;AAC/C,WAAO,QAAQ,QAAQ;AAAA,MACrB,SAAS,MAAM;AAAA,MACf,SAAS;AAAA,MACT,eAAe;AAAA,MACf,aAAa,oBAAI,KAAK,CAAC;AAAA,MACvB,GAAI,MAAM,KAAK,CAAC,IAAI,EAAE,SAAS,MAAM,MAAM,QAAQ;AAAA,IACrD,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAuC;AACrC,WAAO,QAAQ,QAAQ;AAAA,MACrB,iBAAiB,OAAO;AAAA,MACxB,mBAAmB,OAAO;AAAA,MAC1B,WAAW,oBAAI,KAAK,CAAC;AAAA,MACrB,oBAAoB;AAAA,MACpB,WAAW;AAAA,IACb,CAAC;AAAA,EACH;AAAA,EAEA,aAA8B;AAC5B,WAAO,QAAQ,QAAQ,KAAK;AAAA,EAC9B;AAAA,EAEA,eAA0B;AACxB,WAAO;AAAA,MACL,IAAI,KAAK,aAAa;AAAA,MACtB,MAAM,KAAK,aAAa;AAAA,MACxB,eAAe;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aAA+C;AACnD,QAAI,KAAK,aAAa,eAAe,OAAW,QAAO,CAAC;AACxD,UAAM,SAAS,MAAM,KAAK,aAAa,WAAW;AAClD,WAAO,OAAO,IAAI,CAAC,OAAO;AAAA,MACxB,IAAI,EAAE;AAAA,MACN,GAAI,EAAE,YAAY,SAAY,EAAE,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC3D,EAAE;AAAA,EACJ;AAAA,EAEA,aAA4B;AAC1B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,UAAyB;AACvB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;AAGO,SAAS,wBACd,cACA,QACmB;AACnB,SAAO,IAAI,kBAAkB,cAAc,MAAM;AACnD;;;AC1MA,OAAOA,gBAAe;;;ACMf,IAAM,gBAAgB;AAAA,EAC3B,QAAQ,gBAAgB,aAAa;AAAA,EACrC,UAAU,gBAAgB,eAAe;AAAA,EACzC,SAAS,gBAAgB,cAAc;AACzC;AAQO,IAAM,uBAA+C;AAAA,EAC1D,iBAAiB,cAAc;AAAA,EAC/B,mBAAmB,cAAc;AAAA,EACjC,kBAAkB,cAAc;AAAA;AAAA,EAEhC,kBAAkB,cAAc;AAClC;AAuBO,IAAM,qBAAqB;;;AClDlC,OAAsB;AAqBf,IAAM,oBAAoB;AAK1B,SAAS,cAAc,iBAA4C;AACxE,UAAQ,iBAAiB;AAAA,IACvB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,gBAAgB,OAA4C;AAC1E,MAAI,MAAM,SAAS,QAAQ;AACzB,WAAO,EAAE,MAAM,QAAQ,MAAM,MAAM,KAAK;AAAA,EAC1C;AACA,MAAI,MAAM,SAAS,YAAY;AAC7B,UAAM,YAAY;AAClB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,IAAI,UAAU;AAAA,MACd,MAAM,UAAU;AAAA,MAChB,OAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,QAAQ,MAAM,GAAG;AAClC;AAKO,SAAS,WAAW,SAAgC;AACzD,QAAM,OAAO,QAAQ,SAAS,SAAS,SAAS;AAEhD,MAAI,OAAO,QAAQ,YAAY,UAAU;AACvC,WAAO,EAAE,MAAM,SAAS,QAAQ,QAAQ;AAAA,EAC1C;AAGA,QAAM,UAAU,QAAQ,QAAQ,IAAI,CAAC,UAAU;AAC7C,QAAI,MAAM,SAAS,QAAQ;AACzB,aAAO,EAAE,MAAM,QAAiB,MAAM,MAAM,KAAK;AAAA,IACnD;AACA,QAAI,MAAM,SAAS,YAAY;AAC7B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AACA,QAAI,MAAM,SAAS,eAAe;AAChC,YAAM,aAKF;AAAA,QACF,MAAM;AAAA,QACN,aAAa,MAAM;AAAA,QACnB,SAAS,MAAM;AAAA,MACjB;AAEA,UAAI,MAAM,aAAa,QAAW;AAChC,mBAAW,WAAW,MAAM;AAAA,MAC9B;AACA,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,MAAM;AAAA,IAChB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,MAAM,QAAQ;AACzB;AAKO,SAAS,QAAQ,MAAsC;AAC5D,SAAO;AAAA,IACL,MAAM,KAAK;AAAA,IACX,aAAa,KAAK;AAAA,IAClB,cAAc,KAAK;AAAA,EACrB;AACF;AAOO,SAAS,mBAAmB,SAAqC;AACtE,SAAO,QAAQ,mBAAmB,UAAa,QAAQ,eAAe,SAAS;AACjF;AAOO,SAAS,iBAAiB,QAAoD;AACnF,QAAM,cACJ,QAAQ,SAAS,gBAAgB,OAAO,SAAS,EAAE,MAAM,SAAS;AACpE,SAAO,QAAQ;AAAA,IACb,MAAM;AAAA,IACN,aACE;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAQO,SAAS,2BACd,QACgB;AAChB,QAAM,eAAe,OAAO;AAAA,IAC1B,CAAC,UAAU,MAAM,SAAS,cAAc,MAAM,SAAS;AAAA,EACzD;AACA,MAAI,cAAc,SAAS,YAAY;AACrC,WAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,aAAa,KAAK,EAAE,CAAC;AAAA,EACpE;AACA,SAAO,OAAO,IAAI,eAAe;AACnC;AAaO,SAAS,eAAe,SAAyB;AACtD,QAAM,aAAa,gBAAgB,OAAO;AAC1C,MAAI,eAAe,OAAW,QAAO,gBAAgB,UAAU;AAC/D,SAAO;AACT;AAKO,SAAS,qBAAqB,SAA6C;AAChF,QAAM,eAAkC;AAAA,IACtC,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB;AAGA,QAAM,aAAa,eAAe,OAAO;AACzC,MAAI,WAAW,SAAS,MAAM,KAAK,WAAW,SAAS,UAAU,GAAG;AAClE,iBAAa,KAAK,gBAAgB,iBAAiB;AAAA,EACrD;AAEA,SAAO;AACT;;;ACzMA,OAAsB;AAOf,SAAS,iBACd,SACA,UACA,OACQ;AACR,QAAM,aAAa,OAAO,YAAY,WAAW,UAAU,KAAK,UAAU,OAAO;AACjF,SAAO,GAAG,QAAQ,IAAI,SAAS,SAAS,IAAI,UAAU;AACxD;AAKO,SAAS,0BAA0B,UAA+C;AACvF,SAAO,SACJ,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,EACjC,IAAI,CAAC,MAAM;AACV,UAAM,OAAO,EAAE,SAAS,SAAS,SAAS;AAC1C,QAAI,OAAO,EAAE,YAAY,UAAU;AACjC,aAAO,EAAE,MAAM,SAAS,EAAE,QAAQ;AAAA,IACpC;AAEA,UAAM,UAAU,EAAE,QAAQ,IAAI,CAAC,UAAU;AACvC,UAAI,MAAM,SAAS,QAAQ;AACzB,eAAO,EAAE,MAAM,QAAiB,MAAM,MAAM,KAAK;AAAA,MACnD;AACA,UAAI,MAAM,SAAS,YAAY;AAC7B,eAAO;AAAA,UACL,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,OAAO,MAAM;AAAA,QACf;AAAA,MACF;AACA,UAAI,MAAM,SAAS,eAAe;AAChC,eAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa,MAAM;AAAA,UACnB,SAAS,MAAM;AAAA,QACjB;AAAA,MACF;AAEA,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ,MAAM;AAAA,MAChB;AAAA,IACF,CAAC;AACD,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB,CAAC;AACL;AAKO,SAAS,oBAAoB,UAAyC;AAC3E,QAAM,YAAY,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AAC1D,MAAI,cAAc,QAAW;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,UAAU;AACzC,WAAO,UAAU;AAAA,EACnB;AACA,SAAO,UAAU,QACd,OAAO,CAAC,MAA2C,EAAE,SAAS,MAAM,EACpE,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI;AACd;;;AC5DO,SAAS,2BAA2B,SAAgD;AACzF,MAAI,QAAQ,iBAAiB,UAAa,QAAQ,iBAAiB,IAAI;AACrE,WAAO,QAAQ;AAAA,EACjB;AACA,SAAO,oBAAoB,QAAQ,QAAQ;AAC7C;;;AJiDO,IAAM,gBAAN,cAA4B,YAAY;AAAA,EAC5B;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQjB,YAAY,QAA6B;AACvC,UAAM,kBAAkB,eAAe,OAAO,OAAO;AAGrD,UAAM,aAAgC;AAAA,MACpC,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,cAAc,qBAAqB,OAAO,OAAO;AAAA,MACjD,QAAQ,OAAO;AAAA,IACjB;AAGA,QAAI,OAAO,YAAY,QAAW;AAChC,iBAAW,UAAU,OAAO;AAAA,IAC9B;AACA,QAAI,OAAO,YAAY,QAAW;AAChC,iBAAW,UAAU,OAAO;AAAA,IAC9B;AACA,QAAI,OAAO,eAAe,QAAW;AACnC,iBAAW,aAAa,OAAO;AAAA,IACjC;AAEA,UAAM,UAAU;AAEhB,SAAK,kBAAkB;AAGvB,kBAAc,OAAO,QAAQ,aAAa,OAAO,OAAO;AAGxD,SAAK,SAAS,IAAIC,WAAU;AAAA,MAC1B,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,YAAY,OAAO,cAAc;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,iBAA4C;AACnD,UAAM,aAAa,MAAM,eAAe;AACxC,QAAI,CAAC,WAAW,IAAI;AAClB,aAAO;AAAA,IACT;AAGA,UAAM,YAAY,uBAAuB,KAAK,OAAO,QAAQ,KAAK,YAAY,KAAK,OAAO;AAC1F,QAAI,CAAC,UAAU,GAAI,QAAO;AAE1B,WAAO,GAAG,MAAS;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,SAA6E;AAC1F,SAAK,WAAW,OAAO;AAEvB,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,kBAAkB,OAAO;AACrD,WAAK,YAAY,QAAQ;AACzB,aAAO,GAAG,QAAQ;AAAA,IACpB,SAAS,OAAO;AACd,aAAO,IAAI,KAAK,eAAe,KAAK,CAAC;AAAA,IACvC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,OAAO,SAAwD;AACpE,SAAK,WAAW,OAAO;AAEvB,UAAM,CAAC,YAAY,QAAQ,IAAI,aAA0B;AAGzD,SAAK,cAAc,SAAS,UAAU,EAAE,MAAM,CAAC,UAAmB;AAChE,YAAM,aAAa,KAAK,eAAe,KAAK;AAC5C,iBAAW,MAAM,UAAU;AAAA,IAC7B,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWS,YAAY,MAA+B;AAElD,WAAO,QAAQ,QAAQ,kBAAkB,EAAE,aAAa,MAAM,QAAQ,CAAC;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,kBAAkB,SAAyD;AACvF,UAAM,EAAE,QAAQ,QAAQ,IAAI,KAAK,mBAAmB,OAAO;AAO3D,UAAM,WACJ,QAAQ,WAAW,SACf,MAAM,KAAK,OAAO,SAAS,OAAO,QAAQ,EAAE,QAAQ,QAAQ,OAAO,CAAC,IACpE,MAAM,KAAK,OAAO,SAAS,OAAO,MAAM;AAM9C,WAAO,KAAK,YAAY,UAAU,mBAAmB,OAAO,GAAG,OAAO;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,SACA,YAKe;AACf,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,KAAK,mBAAmB,OAAO;AAClD,YAAM,SAAS,KAAK,OAAO,SAAS,OAAO,MAAM;AAEjD,uBAAiB,SAAS,QAAQ;AAChC,cAAM,QAAQ,KAAK,eAAe,KAAK;AACvC,YAAI,OAAO;AACT,qBAAW,KAAK,KAAK;AAAA,QACvB;AAAA,MACF;AAEA,iBAAW,SAAS;AAAA,IACtB,SAAS,OAAO;AACd,YAAM,aAAa,KAAK,eAAe,KAAK;AAC5C,iBAAW,MAAM,UAAU;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,SAGzB;AAEA,UAAM,WAAW,QAAQ,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,IAAI,UAAU;AAEnF,UAAM,SAAoD;AAAA,MACxD,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,YAAY,QAAQ,aAAa;AAAA,IACnC;AAGA,UAAM,eAAe,2BAA2B,OAAO;AACvD,QAAI,iBAAiB,QAAW;AAC9B,aAAO,SAAS;AAAA,IAClB;AAGA,UAAM,UAAU,KAAK,oBAAoB,QAAQ,OAAO;AAExD,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBACN,QACA,SACyB;AAIzB,UAAM,OAAO,mBAAmB,SAAS,KAAK,eAAe;AAC7D,QAAI,KAAK,gBAAgB,QAAW;AAElC,aAAO,cAAc,KAAK;AAAA,IAC5B;AAEA,QAAI,QAAQ,SAAS,UAAa,QAAQ,KAAK,SAAS,GAAG;AACzD,aAAO,iBAAiB,QAAQ;AAAA,IAClC;AAEA,QAAI,QAAQ,UAAU,UAAa,QAAQ,MAAM,SAAS,GAAG;AAC3D,aAAO,QAAQ,QAAQ,MAAM,IAAI,OAAO;AAAA,IAC1C;AAQA,QAAI,mBAAmB,OAAO,GAAG;AAC/B,YAAM,cAAc,iBAAiB,QAAQ,cAAc;AAC3D,aAAO,QAAQ,CAAC,GAAI,OAAO,SAAS,CAAC,GAAI,WAAW;AACpD,aAAO,cAAc,EAAE,MAAM,QAAQ,MAAM,kBAAkB;AAAA,IAC/D;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,YACN,UACA,qBAAqB,OACrB,UAAmC,CAAC,GAChB;AACpB,UAAM,UAA0B,qBAC5B,2BAA2B,SAAS,OAAO,IAC3C,SAAS,QAAQ,IAAI,eAAe;AAExC,UAAM,QAAoB;AAAA,MACxB,aAAa,SAAS,MAAM;AAAA,MAC5B,cAAc,SAAS,MAAM;AAAA,MAC7B,aAAa,SAAS,MAAM,eAAe,SAAS,MAAM;AAAA,IAC5D;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,YAAY,cAAc,SAAS,WAAW;AAAA,MAC9C,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA,MAIhB,GAAI,QAAQ,SAAS,IAAI,EAAE,UAAU,QAAQ,IAAI,CAAC;AAAA,IACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAA+C;AACpE,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,SAAS,EAAE,OAAO,MAAM,QAAQ,MAAM;AAAA,QACxC;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,UACb,cAAc,gBAAgB,MAAM,aAAa;AAAA,QACnD;AAAA,MAEF,KAAK;AACH,YAAI,MAAM,MAAM,SAAS,cAAc;AACrC,iBAAO;AAAA,YACL,MAAM;AAAA,YACN,OAAO,MAAM;AAAA,YACb,OAAO,EAAE,MAAM,cAAc,MAAM,MAAM,MAAM,KAAK;AAAA,UACtD;AAAA,QACF;AACA,eAAO;AAAA,MAET,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,MAAM;AAAA,QACf;AAAA,MAEF,KAAK;AACH,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,EAAE,aAAa,cAAc,MAAM,MAAM,eAAe,IAAI,EAAE;AAAA,UACrE,OAAO;AAAA,YACL,aAAa;AAAA;AAAA,YACb,cAAc,MAAM,MAAM;AAAA,YAC1B,aAAa,MAAM,MAAM;AAAA,UAC3B;AAAA,QACF;AAAA,MAEF,KAAK;AACH,eAAO,EAAE,MAAM,eAAe;AAAA,MAEhC;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAgD;AACpD,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,KAAK,gBAAgB,QAAQ,MAAM,KAAK,YAAY,YAAY,2BAA2B;AAC7F,aAAO,KAAK,YAAY;AAAA,IAC1B;AACA,QAAI,KAAK,mBAAmB,KAAM,QAAO,KAAK;AAC9C,UAAM,WAAW,KAAK,YAAY;AAClC,SAAK,iBAAiB;AACtB,QAAI;AACF,YAAM,QAAQ,MAAM;AACpB,WAAK,cAAc,EAAE,OAAO,WAAW,KAAK,IAAI,EAAE;AAClD,aAAO;AAAA,IACT,UAAE;AACA,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,cAA6E;AAAA,EAC7E,iBAA2D;AAAA,EAEnE,MAAc,cAAiD;AAC7D,UAAM,OAAO,MAAM,KAAK,OAAO,OAAO,KAAK;AAC3C,UAAM,MAAuB,CAAC;AAC9B,eAAW,KAAK,KAAK,MAAM;AACzB,YAAM,QAAuB,EAAE,IAAI,EAAE,GAAG;AACxC,UAAI,OAAO,EAAE,eAAe,UAAU;AACpC,cAAM,KAAK,KAAK,MAAM,EAAE,UAAU;AAClC,YAAI,CAAC,OAAO,MAAM,EAAE,GAAG;AACrB,cAAI,KAAK,EAAE,GAAG,OAAO,SAAS,aAAa,WAAW,KAAK,MAAM,KAAK,GAAI,EAAE,CAAC;AAC7E;AAAA,QACF;AAAA,MACF;AACA,UAAI,KAAK,EAAE,GAAG,OAAO,SAAS,YAAY,CAAC;AAAA,IAC7C;AACA,WAAO;AAAA,EACT;AACF;AAEA,IAAM,4BAA4B,IAAI,KAAK;AAiBpC,SAAS,oBAAoB,QAA4C;AAC9E,SAAO,IAAI,cAAc,MAAM;AACjC;;;AK/bO,IAAM,2BAA2B;AAWxC,IAAM,eAAkC;AAAA;AAAA,EAEtC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AACF;AAWO,SAAS,eAAe,MAAsB;AACnD,MAAI,SAAS,GAAI,QAAO;AAExB,MAAI,SAAS;AACb,aAAW,WAAW,cAAc;AAElC,YAAQ,YAAY;AACpB,aAAS,OAAO,QAAQ,SAAS,wBAAwB;AAAA,EAC3D;AACA,SAAO;AACT;;;ACmCA,SAAS,uBACP,KACA,aACiB;AACjB,QAAM,UAAU,IAAI,WAAW;AAC/B,MAAI,OAAO,YAAY,YAAY;AACjC,UAAM,IAAI,MAAM,0CAA0C,WAAW,EAAE;AAAA,EACzE;AACA,SAAO;AACT;AAcO,SAAS,sBAAsB,KAA8C;AAClF,QAAM,eAAe,IAAI,cAAc;AACvC,QAAM,aAAa,IAAI,YAAY;AACnC,QAAM,iBAAiB,IAAI,gBAAgB;AAC3C,QAAM,aAAa,IAAI,YAAY;AACnC,MAAI,OAAO,iBAAiB,YAAY;AACtC,UAAM,IAAI,MAAM,uDAAuD;AAAA,EACzE;AACA,MAAI,OAAO,eAAe,YAAY;AACpC,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AAEA,MAAI,OAAO,mBAAmB,YAAY;AACxC,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,MAAI,OAAO,eAAe,YAAY;AACpC,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUA,SAAS,uBAAuB,OAA+C;AAC7E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,SAAS;AACf,MAAI,EAAE,YAAY,QAAS,QAAO;AAClC,MAAI,OAAO,OAAO,cAAc,MAAM,SAAU,QAAO;AACvD,QAAM,QAAQ,OAAO,OAAO;AAC5B,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,WAAW,OAAO,UAAU;AAClC,MAAI,OAAO,aAAa,YAAY,aAAa,KAAM,QAAO;AAC9D,MAAI,OAAQ,SAAqC,SAAS,MAAM,SAAU,QAAO;AACjF,SAAO;AACT;AAMA,SAAS,cAAc,YAA2B,WAAwC;AACxF,MAAI,cAAc,OAAW,QAAO;AACpC,QAAM,SAAS,kBAAkB,UAAU;AAC3C,SAAO,QAAQ,IAAI,MAAM;AAC3B;AAUA,SAAS,gCAAgC,QAA8C;AACrF,MAAI,OAAO,eAAe,gBAAiB,QAAO;AAClD,QAAM,MAAM,OAAO,WAAW,QAAQ,IAAI,uBAAuB;AACjE,QAAM,YAAY,yBAAyB,GAAG;AAC9C,MAAI,CAAC,UAAU,GAAI,OAAM,UAAU;AACnC,SAAO,UAAU,MAAM,SAAS;AAClC;AAKA,SAAS,gBAAgB,QAAkD;AACzE,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,gBAAgB,OAA2B;AAClD,MAAI,qBAAqB,KAAK,GAAG;AAC/B,WAAO,UAAU;AAAA,EACnB;AACA,QAAM,UAAU,gBAAgB,KAAK,EAAE,YAAY;AACnD,MAAI,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,WAAW,GAAG;AAChE,WAAO,UAAU;AAAA,EACnB;AACA,MAAI,QAAQ,SAAS,KAAK,KAAK,QAAQ,SAAS,cAAc,KAAK,QAAQ,SAAS,SAAS,GAAG;AAC9F,WAAO,UAAU;AAAA,EACnB;AACA,SAAO,UAAU;AACnB;AASO,IAAM,aAAN,cAAyB,YAAY;AAAA,EACzB;AAAA,EACT;AAAA,EACA;AAAA,EACS;AAAA;AAAA,EAEA;AAAA;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,qBAAqB;AAAA,EAE7B,YAAY,QAA0BC,SAAkB;AACtD,UAAM,SAAS,cAAc,OAAO,YAAY,OAAO,MAAM;AAC7D,UAAM;AAAA,MACJ,YAAY,OAAO,OAAO,UAAU;AAAA,MACpC,SAAS,OAAO;AAAA,MAChB,cAAc,CAAC,gBAAgB,YAAY,gBAAgB,SAAS;AAAA,MACpE,QAAQA,WAAU,aAAa,EAAE,SAAS,OAAO,OAAO,UAAU,GAAG,CAAC;AAAA,MACtE,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,MACzC,GAAI,OAAO,YAAY,SAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,MAClE,GAAI,OAAO,eAAe,SAAY,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;AAAA,IAC7E,CAAC;AACD,SAAK,gBAAgB,OAAO;AAC5B,SAAK,YAAY;AACjB,SAAK,gBAAgB,gCAAgC,MAAM;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,oBAAmC;AAC/C,QAAI,KAAK,UAAU,OAAW;AAE9B,QAAI,KAAK,gBAAgB,QAAW;AAClC,YAAM,KAAK;AACX;AAAA,IACF;AACA,SAAK,cAAc,KAAK,aAAa;AACrC,QAAI;AACF,YAAM,KAAK;AAAA,IACb,UAAE;AACA,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAc,eAA8B;AAC1C,UAAM,SAAS,cAAc,KAAK,eAAe,KAAK,UAAU,MAAM;AACtE,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,kBAAkB,kBAAkB,KAAK,aAAa,IAAI;AAAA,QAClE,MAAM,UAAU;AAAA,MAClB,CAAC;AAAA,IACH;AAQA,UAAM,KAAK,+BAA+B;AAG1C,UAAM,iBAAiB,MAAM,KAAK,aAAa,MAAM;AACrD,SAAK,QAAQ,eAAe;AAG5B,UAAM,WAAW,MAAM,OAAO,IAAI;AAClC,SAAK,eAAe,sBAAsB,QAAQ;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,iCAAgD;AAC5D,QAAI,KAAK,mBAAoB;AAC7B,QAAI,KAAK,kBAAkB,mBAAmB,KAAK,kBAAkB,QAAW;AAC9E,WAAK,qBAAqB;AAC1B;AAAA,IACF;AACA,UAAM,WAAW,IAAI,IAAI,KAAK,aAAa,EAAE;AAC7C,UAAM,SAAS,MAAM,kCAAkC,QAAQ;AAC/D,QAAI,CAAC,OAAO,IAAI;AAMd,YAAM,OAAO;AAAA,IACf;AACA,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,aAAa,QAAgD;AACzE,YAAQ,KAAK,eAAe;AAAA,MAC1B,KAAK,aAAa;AAChB,cAAM,MAAM,MAAM,OAAO,mBAAmB;AAC5C,cAAM,UAAU,uBAAuB,KAAK,iBAAiB;AAC7D,cAAM,WAAW,QAAQ,EAAE,OAAO,CAAC;AACnC,eAAO,EAAE,OAAO,SAAS,KAAK,OAAO,EAAE;AAAA,MACzC;AAAA,MACA,KAAK,UAAU;AACb,cAAM,MAAM,MAAM,OAAO,gBAAgB;AACzC,cAAM,UAAU,uBAAuB,KAAK,cAAc;AAC1D,cAAM,WAAW,QAAQ,EAAE,OAAO,CAAC;AACnC,eAAO,EAAE,OAAO,SAAS,KAAK,OAAO,EAAE;AAAA,MACzC;AAAA,MACA,KAAK,UAAU;AACb,cAAM,MAAM,MAAM,OAAO,gBAAgB;AACzC,cAAM,UAAU,uBAAuB,KAAK,0BAA0B;AACtE,cAAM,WAAW,QAAQ,EAAE,OAAO,CAAC;AACnC,eAAO,EAAE,OAAO,SAAS,KAAK,OAAO,EAAE;AAAA,MACzC;AAAA,MACA,KAAK,iBAAiB;AAKpB,cAAM,MAAM,MAAM,OAAO,gBAAgB;AACzC,cAAM,UAAU,uBAAuB,KAAK,cAAc;AAC1D,cAAM,OAAgC,EAAE,OAAO;AAC/C,YAAI,KAAK,kBAAkB,OAAW,MAAK,SAAS,IAAI,KAAK;AAC7D,cAAM,WAAW,QAAQ,IAAI;AAC7B,eAAO,EAAE,OAAO,SAAS,KAAK,OAAO,EAAE;AAAA,MACzC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,SAGtB;AACA,UAAM,UAAmC;AAAA,MACvC,OAAO,KAAK;AAAA,MACZ,UAAU,QAAQ,SAAS,IAAI,CAAC,OAAO;AAAA,QACrC,MAAM,EAAE,SAAS,WAAW,WAAW,EAAE;AAAA,QACzC,SACE,OAAO,EAAE,YAAY,WACjB,EAAE,UACF,EAAE,QAAQ,IAAI,CAAC,MAAoB;AACjC,cAAI,EAAE,SAAS,OAAQ,QAAO,EAAE,MAAM,QAAiB,MAAM,EAAE,KAAK;AACpE,iBAAO;AAAA,QACT,CAAC;AAAA,MACT,EAAE;AAAA,IACJ;AAEA,QAAI,QAAQ,iBAAiB,QAAW;AACtC,cAAQ,QAAQ,IAAI,QAAQ;AAAA,IAC9B;AAKA,UAAM,OAAO,mBAAmB,SAAS,KAAK,OAAO;AACrD,QAAI,KAAK,gBAAgB,QAAW;AAClC,cAAQ,aAAa,IAAI,KAAK;AAAA,IAChC;AACA,QAAI,QAAQ,cAAc,QAAW;AACnC,cAAQ,WAAW,IAAI,QAAQ;AAAA,IACjC;AACA,QAAI,QAAQ,SAAS,QAAW;AAC9B,cAAQ,eAAe,IAAI,QAAQ;AAAA,IACrC;AAGA,WAAO,EAAE,SAAS,SAAS,KAAK,QAAQ;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aACZ,KACA,SAC6B;AAC7B,UAAM,SAAS,MAAM,IAAI,aAAa,OAAO;AAC7C,WAAO;AAAA,MACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,MAC7C,OAAO;AAAA,QACL,aAAa,OAAO,MAAM,eAAe;AAAA,QACzC,cAAc,OAAO,MAAM,gBAAgB;AAAA,QAC3C,aAAa,OAAO,MAAM,eAAe;AAAA,MAC3C;AAAA,MACA,YAAY,gBAAgB,OAAO,YAAY;AAAA,MAC/C,OAAO,OAAO,SAAS;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,mBACZ,KACA,SACA,gBAC6B;AAC7B,UAAM,YACJ,eAAe,SAAS,gBAAgB,eAAe,SAAS,EAAE,MAAM,SAAS;AACnF,UAAM,SAAS,IAAI,WAAW,SAAS;AACvC,UAAM,SAAkB,MAAM,IAAI,eAAe,EAAE,GAAG,SAAS,OAAO,CAAC;AACvE,QAAI,CAAC,uBAAuB,MAAM,GAAG;AACnC,YAAM,IAAI;AAAA,QACR;AAAA,MAEF;AAAA,IACF;AACA,WAAO;AAAA,MACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;AAAA,MAC/D,OAAO;AAAA,QACL,aAAa,OAAO,MAAM,eAAe;AAAA,QACzC,cAAc,OAAO,MAAM,gBAAgB;AAAA,QAC3C,aAAa,OAAO,MAAM,eAAe;AAAA,MAC3C;AAAA,MACA,YAAY,gBAAgB,OAAO,YAAY;AAAA,MAC/C,OAAO,OAAO,SAAS;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAA6E;AAC1F,QAAI;AACF,YAAM,KAAK,kBAAkB;AAC7B,WAAK,WAAW,OAAO;AAEvB,YAAM,MAAM,KAAK;AACjB,UAAI,QAAQ,QAAW;AACrB,cAAM,IAAI;AAAA,UACR,kCAAkC,KAAK,UAAU,OAAO,gBAAgB,KAAK,aAAa;AAAA,QAE5F;AAAA,MACF;AACA,YAAM,EAAE,SAAS,QAAQ,IAAI,KAAK,gBAAgB,OAAO;AAKzD,YAAM,iBAAiB,QAAQ;AAC/B,YAAM,OACJ,mBAAmB,UAAa,eAAe,SAAS,SACpD,MAAM,KAAK,mBAAmB,KAAK,SAAS,cAAc,IAC1D,MAAM,KAAK,aAAa,KAAK,OAAO;AAI1C,YAAM,WACJ,QAAQ,SAAS,IAAI,EAAE,GAAG,MAAM,UAAU,QAAQ,IAAI;AAExD,WAAK,YAAY,QAAQ;AACzB,aAAO,GAAG,QAAQ;AAAA,IACpB,SAAS,OAAgB;AACvB,YAAM,OAAO,gBAAgB,KAAK;AAClC,aAAO,KAAK,cAAc,OAAO,IAAI;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,OAAO,OAAO,SAAwD;AAIpE,UAAM,KAAK,kBAAkB;AAC7B,SAAK,WAAW,OAAO;AAEvB,UAAM,MAAM,KAAK;AACjB,QAAI,QAAQ,QAAW;AACrB,YAAM,IAAI,kBAAkB,iDAAiD;AAAA,QAC3E,MAAM,UAAU;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,UAAM,EAAE,QAAQ,IAAI,KAAK,gBAAgB,OAAO;AAIhD,UAAM,EAAE,MAAM,iBAAiB,SAAS,EAAE,OAAO,KAAK,QAAQ,EAAE;AAEhE,UAAM,SAAS,IAAI,WAAW,OAAO;AACrC,QAAI,QAAQ;AACZ,UAAM,EAAE,MAAM,uBAAuB,OAAO,cAAc,EAAE,MAAM,QAAQ,MAAM,GAAG,EAAE;AAErF,qBAAiB,QAAQ,OAAO,YAAY;AAI1C,UAAI,SAAS,GAAI;AACjB,YAAM;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA,OAAO,EAAE,MAAM,cAAc,KAAK;AAAA,MACpC;AAAA,IACF;AAEA,UAAM,EAAE,MAAM,sBAAsB,MAAM;AAC1C;AACA,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO,EAAE,aAAa,WAAW;AAAA,MACjC,OAAO,EAAE,aAAa,GAAG,cAAc,GAAG,aAAa,EAAE;AAAA,IAC3D;AACA,UAAM,EAAE,MAAM,eAAe;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,OAAgB,MAAyD;AAC7F,UAAM,UAAU,gBAAgB,KAAK;AAIrC,UAAM,cAAc,eAAe,OAAO;AAC1C,UAAM,WAAW,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,WAAW;AACvE,SAAK,OAAO,MAAM,sBAAsB,KAAK,aAAa,KAAK,QAAQ;AAEvE,UAAM,aAAa,IAAI,kBAAkB,GAAG,KAAK,aAAa,eAAe,WAAW,IAAI;AAAA,MAC1F;AAAA,IACF,CAAC;AACD,WAAO,EAAE,IAAI,OAAO,OAAO,WAAW;AAAA,EACxC;AACF;;;ACtjBA,SAAS,SAAS;AAqCX,IAAM,gCAAgC,EAAE,OAAO;AAAA,EACpD,OAAO,EAAE,OAAO,EAAE,IAAI,GAAI,EAAE,IAAI,IAAQ,EAAE,QAAQ,GAAO;AAC3D,CAAC;AAKM,IAAM,uBAAgD;AAAA,EAC3D,OAAO;AAAA;AAAA,EACP,aAAa;AACf;AAGA,IAAM,8BAA8B;AACpC,IAAM,gCAAgC;AAEtC,IAAM,4BAA4B;AAiD3B,IAAM,oBAAN,MAAsD;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,QAAuC,oBAAI,IAAI;AAAA;AAAA,EAE/C,UAA6D,oBAAI,IAAI;AAAA,EAC9E,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAkB,IAAI,KAAK,gBAAgB,EAAE,IAAI,CAAC;AAAA,EAE1D,YAAY,QAA2C;AACrD,UAAM,YAAY,8BAA8B,MAAM;AAAA,MACpD,OAAO,QAAQ,SAAS,qBAAqB;AAAA,IAC/C,CAAC;AACD,SAAK,SAAS;AAAA,MACZ,GAAG;AAAA,MACH,aAAa,QAAQ,eAAe,qBAAqB;AAAA,MACzD,QAAQ,QAAQ;AAAA,IAClB;AACA,SAAK,SAAS,QAAQ,UAAU,aAAa,EAAE,WAAW,oBAAoB,CAAC;AAE/E,SAAK,OAAO,MAAM,iCAAiC,EAAE,OAAO,KAAK,OAAO,MAAM,CAAC;AAAA,EACjF;AAAA,EAEA,IAAI,KAA2C;AAC7C,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AAEjC,QAAI,WAAW,QAAW;AACxB,WAAK;AACL,WAAK,OAAO,MAAM,cAAc,EAAE,IAAI,CAAC;AACvC,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,QAAQ,GAAG,GAAG;AACrB,WAAK;AACL,WAAK,OAAO,MAAM,eAAe,EAAE,KAAK,WAAW,OAAO,UAAU,CAAC;AACrE,aAAO;AAAA,IACT;AAEA,SAAK;AACL,SAAK,OAAO,MAAM,aAAa,EAAE,KAAK,SAAS,OAAO,QAAQ,CAAC;AAC/D,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,KAAc,QAA+B;AAC/C,SAAK,MAAM,IAAI,KAAK,MAAM;AAC1B,SAAK,aAAa,KAAK,OAAO,OAAO;AACrC,SAAK,OAAO,MAAM,iBAAiB;AAAA,MACjC;AAAA,MACA,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,IAClB,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ,KAAuB;AAC7B,UAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,QAAI,WAAW,OAAW,QAAO;AAEjC,UAAM,MAAM,gBAAgB,EAAE,IAAI,IAAI,OAAO,UAAU,QAAQ;AAC/D,WAAO,MAAM,KAAK,gBAAgB,GAAG;AAAA,EACvC;AAAA;AAAA,EAGA,gBAAgB,KAAsB;AACpC,QAAI,KAAK,OAAO,gBAAgB,MAAO,QAAO,KAAK,OAAO;AAC1D,UAAM,SAAS,KAAK,QAAQ,IAAI,GAAG;AACnC,QAAI,WAAW,UAAa,OAAO,QAAQ,2BAA2B;AACpE,aAAO,KAAK,OAAO;AAAA,IACrB;AACA,UAAM,aAAa,OAAO,UAAU,8BAA8B;AAClE,WAAO,KAAK,OAAO,QAAQ;AAAA,EAC7B;AAAA,EAEQ,aAAa,KAAc,SAAwB;AACzD,UAAM,OAAO,KAAK,QAAQ,IAAI,GAAG;AACjC,QAAI,MAAM,YAAY,SAAS;AAC7B,WAAK,QAAQ,IAAI,KAAK,EAAE,SAAS,OAAO,KAAK,QAAQ,EAAE,CAAC;AAAA,IAC1D,OAAO;AACL,WAAK,QAAQ,IAAI,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,WAAW,KAAqB;AAC9B,QAAI,QAAQ,QAAW;AACrB,WAAK,MAAM,OAAO,GAAG;AACrB,WAAK,QAAQ,OAAO,GAAG;AACvB,WAAK,OAAO,KAAK,qBAAqB,EAAE,IAAI,CAAC;AAAA,IAC/C,OAAO;AACL,WAAK,MAAM,MAAM;AACjB,WAAK,QAAQ,MAAM;AACnB,WAAK,OAAO,KAAK,eAAe;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,SAAgD;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,WAAuB;AACrB,UAAM,QAAQ,KAAK,OAAO,KAAK;AAC/B,WAAO;AAAA,MACL,MAAM,KAAK,MAAM;AAAA,MACjB,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,SAAS,QAAQ,IAAI,KAAK,OAAO,QAAQ;AAAA,MACzC,WAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,YAAY,IAAI,KAAK,gBAAgB,EAAE,IAAI,CAAC;AACjD,SAAK,OAAO,MAAM,mBAAmB;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,iBAAiB,QAAuC;AAC7D,WAAO;AAAA,MACL,SAAS,OAAO;AAAA,MAChB,SAAS,OAAO;AAAA,MAChB,eAAe,OAAO;AAAA,MACtB,WAAW,OAAO;AAAA,MAClB,SAAS,OAAO;AAAA,IAClB;AAAA,EACF;AACF;AAkBO,SAAS,wBACd,QACoB;AACpB,SAAO,IAAI,kBAAkB,MAAM;AACrC;;;AC/LA,IAAM,gBAAgB,aAAa,EAAE,WAAW,eAAe,CAAC;AAKhE,SAAS,aAAa,QAA2BC,SAAiD;AAChG,MAAI,OAAO,UAAU,QAAW;AAC9B,WAAO,OAAO;AAAA,EAChB;AACA,QAAM,cAAc,OAAO,eAAe;AAC1C,SAAO,cAAc,wBAAwB,EAAE,QAAAA,QAAO,CAAC,IAAI;AAC7D;AAOA,eAAe,cACb,QACAA,SACA,OACkC;AAClC,QAAM,eAAe,OAAO;AAE5B,QAAM,eACJ,OAAO,wBAAwB,SAC3B,EAAE,kBAAkB,OAAO,oBAAoB,IAC/C;AAGN,MAAI,iBAAiB,UAAc,MAAM,eAAe,cAAc,KAAK,GAAI;AAC7E,IAAAA,QAAO,KAAK,uBAAuB,EAAE,KAAK,aAAa,CAAC;AACxD,UAAMC,cAAa,iBAAiB,EAAE,KAAK,cAAc,QAAAD,QAAO,CAAC;AACjE,UAAMC,YAAW,WAAW;AAC5B,WAAO;AAAA,MACL,SAAS,wBAAwBA,aAAY,YAAY;AAAA,MACzD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,kBAAkB,YAAY;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,gBAAgB,MAAM,iBAAiB,KAAK;AAElD,MAAI,cAAc,WAAW,GAAG;AAC9B,IAAAD,QAAO,KAAK,2BAA2B;AACvC,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,cAAc,CAAC;AAEnC,MAAI,gBAAgB,QAAW;AAC7B,WAAO;AAAA,EACT;AAEA,EAAAA,QAAO,KAAK,qBAAqB,EAAE,KAAK,aAAa,WAAW,cAAc,CAAC;AAC/E,QAAM,aAAa,iBAAiB,EAAE,KAAK,aAAa,QAAAA,QAAO,CAAC;AAChE,QAAM,WAAW,WAAW;AAE5B,SAAO;AAAA,IACL,SAAS,wBAAwB,YAAY,YAAY;AAAA,IACzD,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ,UAAU,WAAW;AAAA,IAC7B;AAAA,EACF;AACF;AAKA,SAAS,qBAAqB,WAA+B,QAAoC;AAC/F,QAAM,MAAM,aAAa,QAAQ,IAAI,MAAM;AAC3C,SAAO,QAAQ,UAAa,IAAI,SAAS,IAAI,MAAM;AACrD;AAOA,SAAS,cAAc,QAA2BA,SAA0C;AAE1F,QAAM,gBAAgB,gBAAgB,sBAAsB,QAAQ,CAAC;AACrE,QAAM,eAAe,gBAAgB,sBAAsB,OAAO,CAAC;AACnE,QAAM,gBAAgB,gBAAgB,sBAAsB,QAAQ,CAAC;AAGrE,QAAM,eAAe,qBAAqB,OAAO,iBAAiB,mBAAmB;AACrF,MAAI,iBAAiB,QAAW;AAC9B,IAAAA,QAAO,KAAK,+BAA+B,EAAE,OAAO,cAAc,CAAC;AACnE,WAAO;AAAA,MACL,SAAS,oBAAoB,EAAE,SAAS,eAAe,QAAQ,aAAa,CAAC;AAAA,MAC7E,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,+CAA+C,aAAa;AAAA,IACtE;AAAA,EACF;AAGA,QAAM,YAAY,qBAAqB,OAAO,cAAc,gBAAgB;AAC5E,MAAI,cAAc,QAAW;AAC3B,IAAAA,QAAO,KAAK,qCAAqC,EAAE,OAAO,aAAa,CAAC;AACxE,WAAO;AAAA,MACL,SAAS,IAAI,WAAW,EAAE,YAAY,UAAU,SAAS,cAAc,QAAQ,UAAU,CAAC;AAAA,MAC1F,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,uCAAuC,YAAY;AAAA,IAC7D;AAAA,EACF;AAGA,QAAM,YAAY,qBAAqB,OAAO,cAAc,mBAAmB;AAC/E,MAAI,cAAc,QAAW;AAC3B,IAAAA,QAAO,KAAK,wCAAwC,EAAE,OAAO,cAAc,CAAC;AAC5E,WAAO;AAAA,MACL,SAAS,IAAI,WAAW;AAAA,QACtB,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,QAAQ;AAAA,MACV,CAAC;AAAA,MACD,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,0CAA0C,aAAa;AAAA,IACjE;AAAA,EACF;AAIA,QAAM,SAAS,uBAAuBA,OAAM;AAC5C,MAAI,WAAW,KAAM,QAAO;AAE5B,EAAAA,QAAO,KAAK,wCAAwC;AACpD,SAAO;AACT;AAQA,SAAS,uBAAuBA,SAA0C;AACxE,QAAM,YAAY,qBAAqB,QAAW,sBAAsB;AACxE,QAAM,gBAAgB,QAAQ,IAAI,2BAA2B;AAC7D,MAAI,cAAc,UAAa,kBAAkB,UAAa,kBAAkB,IAAI;AAClF,WAAO;AAAA,EACT;AACA,QAAM,gBAAgB,QAAQ,IAAI,oBAAoB,KAAK;AAC3D,EAAAA,QAAO,KAAK,mCAAmC;AAAA,IAC7C,OAAO;AAAA,IACP,SAAS;AAAA,EACX,CAAC;AACD,SAAO;AAAA,IACL,SAAS,IAAI,WAAW;AAAA,MACtB,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,IACD,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ,6CAA6C,aAAa,YAAY,aAAa;AAAA,EAC7F;AACF;AAQA,SAAS,iBAAiB,MAAgE;AACxF,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,QAAQ,aAAa,MAAM,SAAS;AAAA,IAC/C,KAAK;AACH,aAAO,EAAE,QAAQ,UAAU,MAAM,QAAQ;AAAA,IAC3C,KAAK;AACH,aAAO,EAAE,QAAQ,UAAU,MAAM,SAAS;AAAA,IAC5C,KAAK;AACH,aAAO,EAAE,QAAQ,iBAAiB,MAAM,WAAW;AAAA,IACrD;AACE,aAAO;AAAA,EACX;AACF;AAUO,SAAS,0BACd,WACkD;AAClD,MAAI,UAAU,WAAW,MAAO,QAAO;AACvC,QAAM,WAAW,iBAAiB,UAAU,IAAI;AAChD,MAAI,aAAa,OAAW,QAAO;AACnC,QAAM,UAAU,wBAAwB,UAAU,SAAS;AAAA,IACzD,MAAM,SAAS;AAAA,IACf,cAAc,2BAA2B,EAAE,SAAS,IAAI;AAAA,EAC1D,CAAC;AACD,SAAO,EAAE,OAAO,SAAS,SAAS,MAAM,GAAG,QAAQ;AACrD;AAOA,SAAS,2BAA2B,QAAmBA,SAA0C;AAC/F,UAAQ,QAAQ;AAAA,IACd,KAAK,aAAa;AAChB,YAAM,MAAM,qBAAqB,QAAW,mBAAmB;AAC/D,UAAI,QAAQ,OAAW,QAAO;AAC9B,YAAM,UAAU,gBAAgB,sBAAsB,QAAQ,CAAC;AAC/D,aAAO;AAAA,QACL,SAAS,oBAAoB,EAAE,SAAS,QAAQ,IAAI,CAAC;AAAA,QACrD,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,+CAA+C,OAAO;AAAA,MAChE;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,YAAM,MAAM,qBAAqB,QAAW,gBAAgB;AAC5D,UAAI,QAAQ,OAAW,QAAO;AAC9B,YAAM,UAAU,gBAAgB,sBAAsB,OAAO,CAAC;AAC9D,aAAO;AAAA,QACL,SAAS,IAAI,WAAW,EAAE,YAAY,UAAU,SAAS,QAAQ,IAAI,CAAC;AAAA,QACtE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,uCAAuC,OAAO;AAAA,MACxD;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,YAAM,MAAM,qBAAqB,QAAW,mBAAmB;AAC/D,UAAI,QAAQ,OAAW,QAAO;AAC9B,YAAM,UAAU,gBAAgB,sBAAsB,QAAQ,CAAC;AAC/D,aAAO;AAAA,QACL,SAAS,IAAI,WAAW,EAAE,YAAY,UAAU,SAAS,QAAQ,IAAI,CAAC;AAAA,QACtE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,0CAA0C,OAAO;AAAA,MAC3D;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO,uBAAuBA,OAAM;AAAA,IACtC,SAAS;AACP,YAAM,aAAoB;AAC1B,YAAM,IAAI,MAAM,uBAAuB,OAAO,UAAU,CAAC,EAAE;AAAA,IAC7D;AAAA,EACF;AACF;AAGA,IAAM,sBAA4C;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AASO,SAAS,sBACdA,UAAkB,eACgC;AAClD,QAAM,OAAyD,CAAC;AAChE,aAAW,UAAU,qBAAqB;AACxC,UAAM,YAAY,2BAA2B,QAAQA,OAAM;AAC3D,QAAI,cAAc,KAAM;AACxB,UAAM,UAAU,0BAA0B,SAAS;AACnD,QAAI,YAAY,KAAM,MAAK,KAAK,OAAO;AAAA,EACzC;AACA,SAAO;AACT;AAGA,eAAe,eACb,QACAA,SACA,OAC2B;AAC3B,QAAM,YAAY,MAAM,cAAc,QAAQA,SAAQ,KAAK;AAC3D,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,YAAY,cAAc,QAAQA,OAAM;AAC9C,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAGA,eAAe,eACb,QACAA,SACA,OAC2B;AAC3B,QAAM,YAAY,cAAc,QAAQA,OAAM;AAC9C,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,YAAY,MAAM,cAAc,QAAQA,SAAQ,KAAK;AAC3D,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAGA,eAAe,cACb,QACAA,SACA,OAC2B;AAC3B,QAAM,YAAY,MAAM,cAAc,QAAQA,SAAQ,KAAK;AAC3D,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAGA,SAAS,cAAc,QAA2BA,SAAmC;AACnF,QAAM,YAAY,cAAc,QAAQA,OAAM;AAC9C,MAAI,cAAc,KAAM,QAAO;AAC/B,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAsBA,eAAsB,kBAAkB,SAA4B,CAAC,GAA8B;AACjG,QAAMA,UAAS,OAAO,UAAU;AAChC,QAAM,WAAW,OAAO,YAAY;AACpC,QAAM,QAAQ,aAAa,QAAQA,OAAM;AAEzC,EAAAA,QAAO,KAAK,0BAA0B,EAAE,UAAU,cAAc,UAAU,OAAU,CAAC;AAErF,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,eAAe,QAAQA,SAAQ,KAAK;AAAA,IAC7C,KAAK;AACH,aAAO,eAAe,QAAQA,SAAQ,KAAK;AAAA,IAC7C,KAAK;AACH,aAAO,cAAc,QAAQA,SAAQ,KAAK;AAAA,IAC5C,KAAK;AACH,aAAO,cAAc,QAAQA,OAAM;AAAA,IACrC,SAAS;AACP,YAAM,aAAoB;AAC1B,YAAM,IAAI,MAAM,qBAAqB,OAAO,UAAU,CAAC,EAAE;AAAA,IAC3D;AAAA,EACF;AACF;;;AC9bA,SAAS,aAAa;;;ACCtB,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B,OAAO,YAAY;;;ACcZ,SAAS,uBAAuB,iBAAyC;AAC9E,QAAM,QAAQ,gBAAgB,YAAY;AAG1C,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,kBAAkB,KAAK,CAAC,cAAc,MAAM,SAAS,SAAS,CAAC,GAAG;AACpE,WAAO;AAAA,EACT;AAIA,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB,KAAK,CAAC,cAAc,MAAM,SAAS,SAAS,CAAC,GAAG;AACnE,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAOO,IAAM,+BAA+B;AAGrC,IAAM,0BAA0B;AAMvC,SAAS,WAAW,QAAmC;AACrD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,KAAK,KAAK,OAAO,SAAS,IAAI,IAAI;AAC9C,SAAO,OAAO,KAAK,IAAI,KAAK,OAAO,SAAS,CAAC,CAAC;AAChD;AAoBO,SAAS,mBACd,KACA,iBACA,SACQ;AACR,QAAM,aAAa,uBAAuB,eAAe;AACzD,QAAM,gBAAgB,cAAc,KAAK,UAAU;AAEnD,QAAM,QAAQ,mBAAmB,eAAe;AAChD,MAAI,UAAU,KAAM,QAAO;AAE3B,QAAM,QAAQ,SAAS,SAAS,gBAAgB;AAChD,QAAM,WAAW,MAAM,MAAM;AAAA,IAC3B;AAAA,IACA,UAAU,MAAM;AAAA,IAChB,SAAS;AAAA,EACX,CAAC;AAED,MAAI,SAAS,SAAS,6BAA8B,QAAO;AAE3D,QAAM,YAAY,SAAS,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACxE,QAAM,MAAM,WAAW,SAAS;AAChC,QAAM,kBAAkB,KAAK,MAAM,MAAM,uBAAuB;AAEhE,SAAO,KAAK,IAAI,eAAe,eAAe;AAChD;;;AC7GO,IAAM,uBAAuD;AAAA,EAClE,QAAQ,aAAa;AAAA,EACrB,QAAQ,aAAa;AAAA,EACrB,OAAO,aAAa;AACtB;AAGO,IAAM,0BAA0C,aAAa;AAG7D,SAAS,kBAAkB,KAAa,YAAoC;AACjF,SAAO,cAAc,KAAK,UAAU;AACtC;AAGO,SAASE,wBAAuB,iBAAyC;AAC9E,SAAO,uBAAwB,eAAe;AAChD;AAMO,SAAS,sBAAsB,KAAa,iBAAiC;AAClF,SAAO,mBAAmB,KAAK,eAAe;AAChD;;;AC7BO,IAAM,uBAAgD;AAAA,EAC3D,QAAQ;AAAA;AAAA,EACR,QAAQ;AAAA;AAAA,EACR,OAAO;AAAA;AAAA,EACP,UAAU;AAAA;AACZ;AAMO,IAAM,yBAAkD;AAAA,EAC7D,QAAQ;AAAA;AAAA,EACR,QAAQ;AAAA;AAAA,EACR,OAAO;AAAA;AAAA,EACP,UAAU;AAAA;AACZ;AAKO,IAAM,uBAAuB;AAyB7B,SAAS,iBAAiB,KAAqC;AACpE,QAAM,YAAY,SAAS,IAAI,YAAY,CAAC;AAC5C,QAAM,WAAW,QAAQ,IAAI,GAAG,SAAS,cAAc;AACvD,QAAM,aAAa,QAAQ,IAAI,GAAG,SAAS,gBAAgB;AAE3D,SAAO;AAAA,IACL,YACE,aAAa,UAAa,aAAa,KACnC,SAAS,UAAU,EAAE,IACrB,qBAAqB,GAAG;AAAA,IAC9B,cACE,eAAe,UAAa,eAAe,KACvC,SAAS,YAAY,EAAE,IACvB,uBAAuB,GAAG;AAAA,IAChC,UAAU;AAAA,EACZ;AACF;AAsBO,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EACA;AAAA,EACT;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA;AAAA,EAER,YAAY,QAA+B;AACzC,SAAK,SAAS;AACd,SAAK,eAAe,CAAC;AACrB,SAAK,eAAe;AACpB,SAAK,oBAAoB,CAAC;AAC1B,SAAK,cAAc,gBAAgB,EAAE,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,OAAqC;AAC/C,UAAM,MAAM,gBAAgB,EAAE,IAAI;AAClC,SAAK,gBAAgB,GAAG;AAExB,SAAK,kBAAkB,KAAK,GAAG;AAC/B,SAAK,eAAe,KAAK,kBAAkB;AAE3C,QAAI,UAAU,QAAW;AACvB,YAAM,SAAS,MAAM,eAAe,MAAM,cAAc,MAAM;AAC9D,WAAK,aAAa,KAAK;AAAA,QACrB,WAAW;AAAA,QACX;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,cAA8B;AAC5B,UAAM,MAAM,gBAAgB,EAAE,IAAI;AAClC,SAAK,gBAAgB,GAAG;AAExB,UAAM,aAAa,KAAK,aAAa,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,QAAQ,CAAC;AACjF,UAAM,kBAAkB,KAAK,IAAI,GAAG,KAAK,OAAO,aAAa,UAAU;AACvE,UAAM,oBAAoB,KAAK,IAAI,GAAG,KAAK,OAAO,eAAe,KAAK,YAAY;AAElF,UAAM,mBAAoB,aAAa,KAAK,OAAO,aAAc;AACjE,UAAM,qBAAsB,KAAK,eAAe,KAAK,OAAO,eAAgB;AAC5E,UAAM,qBAAqB,aAAa,KAAK,IAAI,kBAAkB,kBAAkB,CAAC;AAEtF,UAAM,YAAY,oBAAoB,KAAK,sBAAsB;AACjE,UAAM,YAAY,IAAI,KAAK,KAAK,cAAc,KAAK,OAAO,QAAQ;AAElE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,oBAAoB,KAAK,MAAM,qBAAqB,GAAG,IAAI;AAAA,MAC3D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA4B;AAC1B,UAAM,MAAM,gBAAgB,EAAE,IAAI;AAClC,UAAM,YAAY,KAAK,cAAc,KAAK,OAAO;AACjD,WAAO,KAAK,IAAI,GAAG,YAAY,GAAG;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,aAAa,SAAS;AAC3B,SAAK,kBAAkB,SAAS;AAChC,SAAK,eAAe;AACpB,SAAK,cAAc,gBAAgB,EAAE,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAA+C;AAC1D,WAAO,OAAO,KAAK,QAAQ,OAAO;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAKA,YAA6C;AAC3C,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,KAAmB;AACzC,UAAM,SAAS,MAAM,KAAK,OAAO;AAgBjC,WAAO,KAAK,aAAa,CAAC,MAAM,UAAa,KAAK,aAAa,CAAC,EAAE,YAAY,QAAQ;AACpF,WAAK,aAAa,MAAM;AAAA,IAC1B;AACA,WAAO,KAAK,kBAAkB,CAAC,MAAM,UAAa,KAAK,kBAAkB,CAAC,IAAI,QAAQ;AACpF,WAAK,kBAAkB,MAAM;AAAA,IAC/B;AACA,SAAK,eAAe,KAAK,kBAAkB;AAE3C,UAAM,kBAAkB,KAAK,kBAAkB,CAAC;AAChD,UAAM,gBAAgB,KAAK,aAAa,CAAC,GAAG;AAC5C,QAAI,oBAAoB,UAAa,kBAAkB,QAAW;AAChE,WAAK,cAAc;AAAA,IACrB,OAAO;AACL,WAAK,cAAc,KAAK,IAAI,mBAAmB,UAAU,iBAAiB,QAAQ;AAAA,IACpF;AAAA,EACF;AACF;AAKO,SAAS,sBAAsB,KAA+B;AACnE,SAAO,IAAI,gBAAgB,iBAAiB,GAAG,CAAC;AAClD;;;ACxOO,SAAS,MAAM,IAA2B;AAC/C,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAKO,IAAM,QAAQ;AAqCrB,eAAsB,YACpB,SACA,WACA,cAC2B;AAC3B,MAAI;AAEJ,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,gBAAY,WAAW,MAAM;AAC3B,aAAO,IAAI,MAAM,YAAY,CAAC;AAAA,IAChC,GAAG,SAAS;AAAA,EACd,CAAC;AAED,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAC3D,QAAI,cAAc,OAAW,cAAa,SAAS;AACnD,WAAO,EAAE,IAAI,MAAM,OAAO,OAAO;AAAA,EACnC,SAAS,OAAO;AACd,QAAI,cAAc,OAAW,cAAa,SAAS;AACnD,WAAO,EAAE,IAAI,OAAO,OAAO,gBAAgB,KAAK,EAAE;AAAA,EACpD;AACF;;;ACxEO,IAAM,wBAAmD,oBAAI,IAAkB;AAAA,EACpF;AAAA,EACA;AAAA,EACA;AACF,CAAC;;;ACmCM,SAAS,sBACd,SACA,aACA,YACQ;AACR,QAAM,mBAAmB,cAAc,KAAK,IAAI,GAAG,UAAU,CAAC;AAC9D,QAAM,SAAS,kBAAkB,EAAE,OAAO,IAAI,MAAM;AACpD,QAAM,UAAU,mBAAmB;AACnC,SAAO,KAAK,IAAI,SAAS,UAAU;AACrC;AAGO,SAAS,iBAAiB,MAA6B;AAC5D,SAAO,sBAAsB,IAAI,IAAI;AACvC;AAMO,SAASC,iBAAgB,OAAkC;AAChE,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAYA,eAAsB,oBACpB,WACA,QAC2C;AAC3C,QAAM,cAAc,OAAO,aAAa,OAAO,aAAa,IAAI;AAChE,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,UAAM,SAAS,MAAM,UAAU;AAE/B,QAAI,OAAO,IAAI;AACb,aAAO,GAAG,EAAE,UAAU,OAAO,OAAO,YAAY,UAAU,EAAE,CAAC;AAAA,IAC/D;AAEA,gBAAY,OAAO;AAGnB,QAAI,OAAO,mBAAmB,UAAa,OAAO,mBAAmB,MAAM;AACzE,aAAO,eAAe,cAAcA,iBAAgB,SAAS,CAAC;AAAA,IAChE;AAGA,QAAI,CAAC,YAAY,WAAW,SAAS,aAAa,OAAO,cAAc,GAAG;AACxE,aAAO,IAAI,SAAS;AAAA,IACtB;AAEA,UAAM,UAAU,sBAAsB,SAAS,OAAO,aAAa,OAAO,UAAU;AACpF,WAAO,OAAO,MAAM,0BAA0B;AAAA,MAC5C,KAAK,OAAO;AAAA,MACZ;AAAA,MACA,aAAa,UAAU;AAAA,MACvB,SAAS,KAAK,MAAM,OAAO;AAAA,IAC7B,CAAC;AAED,UAAM,MAAM,OAAO;AAAA,EACrB;AAEA,SAAO;AAAA,IACL,aAAa;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,KAAK,OAAO;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAEA,SAAS,YACP,OACA,SACA,aACA,gBACS;AACT,MAAI,WAAW,YAAa,QAAO;AACnC,MAAI,CAAC,MAAM,UAAW,QAAO;AAC7B,MAAI,CAAC,iBAAiB,MAAM,IAAI,EAAG,QAAO;AAC1C,MAAI,gBAAgB,SAAS,MAAM,OAAQ,QAAO;AAClD,SAAO;AACT;;;ANzHA,IAAM,YAAY,UAAU,IAAI;AAgBhC,IAAM,kBAA4C;AAAA,EAChD,WAAW;AAAA;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AACd;AAMO,IAAe,iBAAf,MAAqD;AAAA,EAIvC;AAAA,EACT,kBAA0C;AAAA,EAC1C,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EAEV,YAAYC,SAAkB;AAC5B,SAAK,SAASA,WAAU,aAAa,EAAE,WAAW,cAAc,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,sBAA4B;AACpC,SAAK,kBAAkB,sBAAsB,KAAK,IAAI;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,eAAkC;AACpC,WAAO,qBAAqB,KAAK,IAAI;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqCA,MAAM,QAAQ,MAAe,SAAoE;AAC/F,UAAM,mBAAmB,KAAK,eAAe,MAAM,OAAO;AAC1D,UAAM,OAAO,EAAE,GAAG,iBAAiB,GAAG,SAAS,WAAW,iBAAiB;AAE3E,QAAI,CAAC,KAAK,aAAa;AACrB,YAAM,KAAK,WAAW;AAAA,IACxB;AAEA,SAAK,OAAO,MAAM,kBAAkB;AAAA,MAClC,KAAK,KAAK;AAAA,MACV,eAAe,KAAK,QAAQ;AAAA,MAC5B,OAAO,KAAK;AAAA,MACZ,WAAW;AAAA,IACb,CAAC;AAED,WAAO,KAAK,iBAAiB,MAAM,IAAI;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,MAAe,SAAoC;AACxE,QAAI,SAAS,cAAc,OAAW,QAAO,QAAQ;AACrD,QAAI,KAAK,cAAc,OAAW,QAAO,KAAK;AAC9C,WAAO,sBAAsB,KAAK,MAAM,KAAK,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASU,iBAAiB,MAAyC;AAClE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBACZ,MACA,MACwC;AACxC,UAAM,SAAS,MAAM,oBAAoB,MAAM,KAAK,YAAY,MAAM,IAAI,GAAG;AAAA,MAC3E,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK,iBAAiB,IAAI;AAAA,MACtC,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK;AAAA,IACf,CAAC;AAED,QAAI,OAAO,IAAI;AACb,WAAK,YAAY,OAAO,MAAM,QAAQ;AACtC,WAAK,OAAO,KAAK,8BAA8B;AAAA,QAC7C,KAAK,KAAK;AAAA,QACV,SAAS,OAAO,MAAM,aAAa;AAAA,QACnC,YAAY,OAAO,MAAM,SAAS;AAAA,QAClC,YAAY,OAAO,MAAM,SAAS,OAAO;AAAA,MAC3C,CAAC;AACD,aAAO,EAAE,IAAI,MAAM,OAAO,OAAO,MAAM,SAAS;AAAA,IAClD;AAEA,SAAK,OAAO,KAAK,yBAAyB;AAAA,MACxC,KAAK,KAAK;AAAA,MACV,OAAO,OAAO,MAAM;AAAA,MACpB,WAAW,OAAO,MAAM;AAAA,IAC1B,CAAC;AACD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAqC;AACzC,QAAI;AACF,YAAM,UAAU,MAAM,KAAK,WAAW;AACtC,YAAM,gBAAgB,KAAK,0BAA0B,OAAO;AAE5D,YAAM,UAAU,KAAK,kBAAkB,eAAe,OAAO;AAC7D,YAAM,SAAuB;AAAA,QAC3B,SAAS,kBAAkB,iBAAiB,kBAAkB;AAAA,QAC9D;AAAA,QACA;AAAA,QACA,aAAa,IAAI,KAAK,gBAAgB,EAAE,IAAI,CAAC;AAAA,QAC7C,GAAI,YAAY,UAAa,EAAE,QAAQ;AAAA,MACzC;AAEA,WAAK,kBAAkB;AACvB,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,eAAe;AAAA,QACf,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD,aAAa,IAAI,KAAK,gBAAgB,EAAE,IAAI,CAAC;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA8B;AAClC,QAAI,KAAK,kBAAkB,UAAa,KAAK,kBAAkB,IAAI;AACjE,aAAO,KAAK;AAAA,IACd;AAEA,QAAI;AACF,YAAM,EAAE,OAAO,IAAI,MAAM,UAAU,GAAG,KAAK,IAAI,cAAc;AAAA,QAC3D,SAAS,wBAAwB;AAAA,MACnC,CAAC;AAGD,YAAM,UAAU,KAAK,aAAa,OAAO,KAAK,CAAC;AAC/C,WAAK,gBAAgB;AACrB,aAAO;AAAA,IACT,SAAS,OAAgB;AACvB,YAAM,IAAI,MAAM,iBAAiB,KAAK,IAAI,YAAY,EAAE,MAAM,CAAC;AAAA,IACjE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,cAAuC;AAUrC,QAAI,KAAK,oBAAoB,MAAM;AACjC,WAAK,oBAAoB;AAAA,IAC3B;AACA,UAAM,UAAU,KAAK;AACrB,QAAI,YAAY,MAAM;AAGpB,YAAM,IAAI,MAAM,8CAA8C,KAAK,IAAI,EAAE;AAAA,IAC3E;AACA,WAAO,QAAQ,QAAQ,QAAQ,YAAY,CAAC;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKU,YAAY,UAA6B;AACjD,QAAI,KAAK,oBAAoB,MAAM;AACjC,WAAK,gBAAgB,YAAY,SAAS,KAAK;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,aAAa,QAAwB;AAK7C,UAAM,QAAQ,kBAAkB,KAAK,MAAM;AAC3C,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKU,0BAA0B,SAAgC;AAClE,UAAM,eAAe,yBAAyB,KAAK,IAAI;AAEvD,UAAM,eAAe,OAAO,MAAM,OAAO;AACzC,QAAI,iBAAiB,MAAM;AACzB,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,OAAO,GAAG,cAAc,aAAa,OAAO;AAChE,QAAI,aAAa;AACf,aAAO;AAAA,IACT;AAEA,UAAM,cAAc,aAAa,SAAS,KAAK,CAAC,MAAM,OAAO,IAAI,cAAc,CAAC,CAAC;AACjF,QAAI,aAAa;AACf,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,OAAO,GAAG,cAAc,aAAa,WAAW;AACxE,QAAI,iBAAiB;AACnB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKU,kBAAkB,QAAuB,SAAqC;AACtF,UAAM,eAAe,yBAAyB,KAAK,IAAI;AAEvD,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO,WAAW,OAAO,+BAA+B,aAAa,OAAO;AAAA,MAC9E,KAAK;AACH,eAAO,WAAW,OAAO;AAAA,MAC3B,KAAK;AACH,eAAO,yBAAyB,aAAa,WAAW;AAAA,MAC1D,KAAK;AACH,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,YAAY,MAAoB,SAAiB,OAAyB;AAClF,UAAM,YAAY,CAAC,gBAAgB,WAAW,kBAAkB,EAAE,SAAS,IAAI;AAE/E,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,KAAK,KAAK;AAAA,MACV;AAAA,MACA,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,kBACR,MACA,OACA,OACa;AACb,WAAO;AAAA,MACL;AAAA,MACA,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,MACnC,GAAG;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKU,MAAM,IAA2B;AACzC,WAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,EACzD;AACF;;;AO3WO,IAAM,6BAA6B;AAGnC,SAAS,oBAAoB,MAAyB,QAAQ,KAAa;AAChF,QAAM,MAAM,OAAO,SAAS,IAAI,0BAA0B,KAAK,KAAK,EAAE;AACtE,SAAO,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;AACjD;AAGA,IAAM,iBAAoC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,oBAAuC;AAAA,EAC3C;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AACF;AAOA,IAAM,kBAAsD;AAAA,EAC1D,QAAQ,CAAC,mBAAmB;AAAA,EAC5B,QAAQ,CAAC,qBAAqB,kBAAkB,gBAAgB;AAAA,EAChE,OAAO,CAAC,gBAAgB;AAAA,EACxB,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUO,IAAM,6BAA6B;AAG1C,SAAS,kBAAkB,KAA2C;AACpE,QAAM,MAAM,IAAI,0BAA0B;AAC1C,MAAI,QAAQ,UAAa,IAAI,KAAK,MAAM,GAAI,QAAO,CAAC;AACpD,SAAO,IACJ,MAAM,QAAQ,EACd,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC/B;AAMA,SAAS,UACP,KACA,YACA,UACS;AACT,MAAI,eAAe,SAAS,GAAG,EAAG,QAAO;AACzC,MAAI,WAAW,SAAS,GAAG,EAAG,QAAO;AACrC,MAAI,SAAS,SAAS,GAAG,EAAG,QAAO;AACnC,SAAO,kBAAkB,KAAK,CAAC,WAAW,IAAI,WAAW,MAAM,CAAC;AAClE;AAmBO,SAAS,cAAc,SAAqC;AACjE,QAAM,SAAS,QAAQ;AACvB,QAAM,WAA8B,CAAC;AAGrC,QAAM,YAAY,OAAO,oBAAoB,MAAM,IAAI,CAAC;AAExD,MAAI,OAAO,gCAAgC,MAAM,KAAK;AACpD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,UAAI,UAAU,UAAa,QAAQ,aAAc,UAAS,GAAG,IAAI;AAAA,IACnE;AACA,aAAS,0BAA0B,IAAI;AACvC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,gBAAgB,OAAO;AAC1C,QAAM,WAAW,kBAAkB,MAAM;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,UAAU,OAAW;AACzB,QAAI,QAAQ,aAAc;AAC1B,QAAI,UAAU,KAAK,YAAY,QAAQ,EAAG,UAAS,GAAG,IAAI;AAAA,EAC5D;AACA,WAAS,0BAA0B,IAAI;AACvC,SAAO;AACT;;;ACvHA,SAAS,sBAAsB,GAAsC;AACnE,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,QAAM,MAAM;AACZ,SAAO,IAAI,SAAS,YAAY,IAAI,aAAa;AACnD;AAOA,SAAS,oBAAoB,QAAgC;AAC3D,MAAI,OAAO,WAAW,YAAY,WAAW,KAAM,QAAO;AAC1D,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,UAAU,YAAY,IAAI,UAAU,GAAI,QAAO,IAAI;AAClE,MAAI,IAAI,aAAa,QAAQ,OAAO,IAAI,YAAY,YAAY,IAAI,YAAY,IAAI;AAClF,WAAO,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAGA,IAAM,cAAuC;AAAA,EAC3C,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AACZ;AAEA,IAAM,oBAAuC;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,gBAAgB,SAAwD;AAC/E,aAAW,MAAM,mBAAmB;AAClC,QAAI,GAAG,KAAK,OAAO,EAAG,QAAO,EAAE,MAAM,qBAAqB,MAAM,KAAK;AAAA,EACvE;AACA,SAAO,EAAE,MAAM,mBAAmB,MAAM,MAAM;AAChD;AAQA,SAAS,eAAe,SAAiC;AACvD,QAAM,OAAO,QAAQ,WAAW,MAAM,IAAI,QAAQ,MAAM,OAAO,MAAM,IAAI;AACzE,SAAO,QAAQ,cAAe,OAAmB;AACnD;AAcO,SAAS,gBAAgB,SAAiB,SAAgC;AAC/E,MAAI,CAAC,gBAAgB,OAAO,EAAE,KAAM,QAAO;AAC3C,QAAM,MAAM,eAAe,OAAO;AAClC,MAAI,QAAQ,KAAM,QAAO;AACzB,SAAO,0BAA0B,YAAY,GAAG,CAAC,WAAW,GAAG;AACjE;AAYO,SAAS,uBAAuB,SAAiB,SAAiC;AACvF,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,gBAAgB,OAAO,GAAG;AAC5B,WAAO,EAAE,SAAS,SAAS,MAAM,eAAe;AAAA,EAClD;AACA,QAAM,EAAE,MAAM,KAAK,IAAI,gBAAgB,OAAO;AAC9C,MAAI,MAAM;AACR,UAAM,OAAO,gBAAgB,SAAS,OAAO;AAC7C,WAAO,SAAS,OAAO,EAAE,SAAS,SAAS,MAAM,KAAK,IAAI,EAAE,SAAS,SAAS,KAAK;AAAA,EACrF;AACA,SAAO,EAAE,SAAS,SAAS,KAAK;AAClC;AAOO,SAAS,sBAAsB,QAAgB,SAAyC;AAC7F,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,YAAY,MAAO,CAAC,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,WAAW,GAAG,EAAI,QAAO;AAErF,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;AAAA,EAC7B,QAAQ;AAIN,WAAO,YAAY,SAAS,OAAO;AAAA,EACrC;AAEA,MAAI;AACJ,MAAI,sBAAsB,MAAM,KAAK,OAAO,OAAO,WAAW,UAAU;AACtE,cAAU,OAAO;AAAA,EACnB,OAAO;AACL,UAAM,QAAQ,oBAAoB,MAAM;AACxC,QAAI,UAAU,KAAM,WAAU;AAAA,EAChC;AAEA,MAAI,YAAY,UAAa,YAAY,GAAI,QAAO;AAEpD,SAAO,iBAAiB,SAAS,OAAO;AAC1C;AAEA,SAAS,YAAY,QAAgB,SAAyC;AAC5E,QAAM,QAAQ,OAAO,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE;AAC9D,MAAI,MAAM,SAAS,EAAG,QAAO;AAC7B,QAAM,OAAO,MAAM,GAAG,EAAE;AACxB,MAAI,SAAS,OAAW,QAAO;AAC/B,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,sBAAsB,MAAM,KAAK,OAAO,OAAO,WAAW,UAAU;AACtE,aAAO,iBAAiB,OAAO,QAAQ,OAAO;AAAA,IAChD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,SAAiB,SAAkC;AAE3E,QAAM,aAAa,QAAQ,MAAM,IAAI,EAAE,CAAC,KAAK,SAAS,KAAK,EAAE,MAAM,GAAG,GAAG;AACzE,QAAM,EAAE,MAAM,KAAK,IAAI,gBAAgB,SAAS;AAChD,MAAI,MAAM;AACR,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,MAAM,SAAS,YAAY,OAAO,CAAC;AAAA,IACrC;AAAA,EACF;AACA,SAAO,EAAE,SAAS,WAAW,KAAK;AACpC;;;AT/LA,IAAM,gCAAgC;AAUtC,SAAS,qBAAqB,QAA+B;AAC3D,QAAM,UAAU,OAAO,KAAK;AAC5B,MAAI,QAAQ,SAAS,8BAA+B,QAAO;AAE3D,MAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG,EAAG,QAAO;AAC/D,SAAO;AACT;AAGA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,SAAS,qBAAqB,QAAyB;AACrD,QAAM,QAAQ,OAAO,YAAY;AACjC,SAAO,sBAAsB,KAAK,CAAC,YAAY,MAAM,SAAS,OAAO,CAAC;AACxE;AAGA,IAAM,6BAA6B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,0BAA0B,CAAC,WAAW,aAAa,WAAW;AAUpE,SAAS,oBAAoB,QAA8B;AACzD,QAAM,QAAQ,OAAO,YAAY;AACjC,MAAI,2BAA2B,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC,EAAG,QAAO;AACtE,MAAI,gBAAgB,MAAM,EAAG,QAAO;AACpC,MAAI,wBAAwB,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC,EAAG,QAAO;AACnE,SAAO;AACT;AAEA,IAAM,mBAAmB,aAAa,EAAE,WAAW,qBAAqB,CAAC;AAGzE,IAAM,mBAAmB,KAAK,OAAO;AAGrC,IAAM,wBAAmD,oBAAI,IAAI;AAAA,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,IAAM,4BAA4B,CAAC,KAAK,GAAI;AAG5C,IAAM,wBAAwB,0BAA0B;AAOjD,IAAM,oBAAoB;AAG1B,IAAM,2BAA2B;AAQjC,IAAM,mBAAmB;AAOzB,SAAS,iBAAiB,MAA6B;AAC5D,SAAO,sBAAsB,IAAI,IAAI;AACvC;AAQA,IAAM,uBAAuB,oBAAI,IAAI,CAAC,KAAK,GAAG,CAAC;AAG/C,IAAM,yBAAiD;AAAA,EACrD,KAAK;AAAA,EACL,KAAK;AACP;AAGA,SAAS,uBAAuB,MAAsB;AACpD,QAAM,aAAa,uBAAuB,IAAI;AAC9C,MAAI,eAAe,OAAW,QAAO,qBAAqB,UAAU,eAAe,OAAO,IAAI,CAAC;AAC/F,SAAO,4BAA4B,OAAO,IAAI,CAAC;AACjD;AAMO,SAAS,oBAAoB,MAA8B;AAChE,SAAO,SAAS,QAAQ,qBAAqB,IAAI,IAAI;AACvD;AAqBA,SAAS,eAAe,OAAoB,QAA6B,MAAoB;AAC3F,QAAM,WAAW,WAAW,WAAW,gBAAgB;AACvD,QAAM,WAAW,WAAW,WAAW,oBAAoB;AAC3D,MAAI,MAAM,QAAQ,IAAI,kBAAkB;AACtC,UAAM,MAAM,KAAK,KAAK,SAAS;AAC/B,UAAM,QAAQ,KAAK,KAAK;AAAA,EAC1B,WAAW,CAAC,MAAM,QAAQ,GAAG;AAC3B,UAAM,QAAQ,IAAI;AAClB,qBAAiB,KAAK,GAAG,MAAM,oCAAoC;AAAA,EACrE;AACF;AA+BO,IAAe,uBAAf,cAA4C,eAAe;AAAA,EACvD,YAA0B;AAAA;AAAA,EAKhB,iBAAuC,EAAE,SAAS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWvD,iBAAiB,MAAyC;AAC3E,WAAO,KAAK,cAAc,CAAC,KAAK,eAAe;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcQ,qBAAqB,SAAyC;AACpE,QAAI,YAAY,OAAW;AAC3B,QAAI;AACF,YAAM,IAAI,QAAQ;AAClB,UAAI,aAAa,SAAS;AACxB,UAAE,MAAM,CAAC,MAAe;AACtB,eAAK,OAAO,KAAK,6BAA6B,EAAE,OAAO,OAAO,CAAC,EAAE,CAAC;AAAA,QACpE,CAAC;AAAA,MACH;AAAA,IACF,SAAS,GAAY;AACnB,WAAK,OAAO,KAAK,4BAA4B,EAAE,OAAO,OAAO,CAAC,EAAE,CAAC;AAAA,IACnE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,kBACN,OACA,QACA,SACM;AACN,UAAM,UAAU,MAAY;AAC1B,UAAI,MAAM,aAAa,QAAQ,MAAM,eAAe,MAAM;AACxD,cAAM,KAAK,SAAS;AAAA,MACtB;AACA,cAAQ,IAAI,KAAK,YAAY,WAAW,0BAA0B,CAAC,CAAC;AAAA,IACtE;AACA,WAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,UAAM,KAAK,SAAS,MAAM;AACxB,aAAO,oBAAoB,SAAS,OAAO;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,YACJ,MACA,SACwC;AAOxC,UAAM,YAAY,iBAAiB,WAAW,CAAC;AAC/C,UAAM,SAAS,MAAM,KAAK,gBAAgB,MAAM,SAAS,SAAS;AAClE,QAAI,OAAO,MAAM,CAAC,KAAK,eAAe,QAAS,QAAO;AACtD,QAAI,CAAC,iBAAiB,OAAO,MAAM,IAAI,EAAG,QAAO;AAEjD,WAAO,KAAK,eAAe,MAAM,SAAS,QAAQ,GAAG,SAAS;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eACZ,MACA,SACA,YACA,SACA,WACwC;AACxC,UAAM,eAAe,CAAC,WAAW,MAAM,WAAW,MAAM,SAAS;AACjE,UAAM,aAAa,eAAe,oBAAoB;AACtD,QAAI,WAAW,WAAY,QAAO;AAGlC,UAAM,UAAU,0BAA0B,OAAO;AACjD,UAAM,YAAY,CAAC,WAAW,MAAM,WAAW,MAAM,SAAS;AAC9D,qBAAiB,MAAM,4BAA4B;AAAA,MACjD,KAAK,KAAK;AAAA,MACV;AAAA,MACA,SAAS,UAAU;AAAA,MACnB;AAAA,MACA,WAAW,CAAC,WAAW,KAAK,WAAW,MAAM,OAAO;AAAA,IACtD,CAAC;AAED,UAAM,KAAK,MAAM,OAAO;AAGxB,UAAM,eAAe,YACjB,EAAE,GAAG,SAAS,WAAW,KAAK,MAAM,QAAQ,YAAY,wBAAwB,EAAE,IAClF;AACJ,UAAM,SAAS,MAAM,KAAK,gBAAgB,MAAM,cAAc,SAAS;AACvE,QAAI,OAAO,GAAI,QAAO;AACtB,QAAI,CAAC,iBAAiB,OAAO,MAAM,IAAI,EAAG,QAAO;AAEjD,WAAO,KAAK,eAAe,MAAM,cAAc,QAAQ,UAAU,GAAG,SAAS;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,gBACN,MACA,SACA,WACwC;AACxC,UAAM,YAAY,KAAK,WAAW,IAAI;AACtC,UAAM,YAAY,gBAAgB,EAAE,IAAI;AAKxC,UAAM,SAAS,QAAQ;AACvB,QAAI,QAAQ,YAAY,MAAM;AAC5B,aAAO,QAAQ,QAAQ,IAAI,KAAK,YAAY,WAAW,sBAAsB,CAAC,CAAC;AAAA,IACjF;AAEA,WAAO,IAAI,QAAQ,CAAC,iBAAiB;AACnC,YAAM,UAAU,CAAC,WAAgD;AAC/D,aAAK,qBAAqB,UAAU,OAAO;AAC3C,qBAAa,MAAM;AAAA,MACrB;AAKA,YAAM,WAAW,cAAc,KAAK,IAAI;AAExC,YAAM,QAAQ,MAAM,UAAU,SAAS,UAAU,MAAM;AAAA,QACrD,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,QAC9B,KAAK;AAAA,MACP,CAAC;AAED,YAAM,aAAa,QAAQ;AAC3B,YAAM,QAAQ,KAAK,0BAA0B;AAAA,QAC3C;AAAA,QACA;AAAA,QACA,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA;AAAA,QACA,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,MACnD,CAAC;AAED,UAAI,WAAW,QAAW;AACxB,aAAK,kBAAkB,OAAO,QAAQ,OAAO;AAAA,MAC/C;AAGA,UAAI,UAAU,UAAU,QAAW;AACjC,cAAM,MAAM,MAAM,UAAU,KAAK;AAAA,MACnC;AACA,YAAM,MAAM,IAAI;AAGhB,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,MAOlB;AACd,UAAM,EAAE,OAAO,WAAW,WAAW,SAAS,WAAW,WAAW,IAAI;AACxE,UAAM,QAAqB;AAAA,MACzB,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,aAAa;AAAA,MACb,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,MACjB,eAAe;AAAA,IACjB;AAEA,UAAM,cAAc,CAAC,WAAgD;AACnE,UAAI,CAAC,MAAM,UAAU;AACnB,cAAM,WAAW;AACjB,gBAAQ,MAAM;AAAA,MAChB;AAAA,IACF;AAEA,SAAK,qBAAqB,OAAO,OAAO,UAAU;AAElD,UAAM,GAAG,SAAS,CAAC,UAAiB;AAClC,kBAAY,KAAK,sBAAsB,KAAK,CAAC;AAAA,IAC/C,CAAC;AAED,UAAM,SAAS,KAAK,qCAAqC;AAAA,MACvD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,SAAwB;AACzC,mBAAa,OAAO,SAAS;AAC7B,UAAI,OAAO,mBAAmB,OAAW,cAAa,OAAO,cAAc;AAC3E,WAAK,mBAAmB,OAAO,WAAW,MAAM,SAAS;AACzD,kBAAY,KAAK,oBAAoB,MAAM,OAAO,SAAS,CAAC;AAAA,IAC9D,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,qCAAqC,MAKiC;AAC5E,UAAM,EAAE,OAAO,WAAW,WAAW,YAAY,IAAI;AACrD,UAAM,SAAoF;AAAA,MACxF,WAAW,WAAW,MAAM;AAC1B,cAAM,KAAK,SAAS;AACpB,oBAAY,IAAI,KAAK,YAAY,WAAW,qBAAqB,CAAC,CAAC;AACnE,eAAO,iBAAiB,WAAW,MAAM;AACvC,cAAI,MAAM,aAAa,QAAQ,MAAM,eAAe,MAAM;AACxD,iBAAK,OAAO,KAAK,gDAAgD;AAAA,cAC/D,KAAK,KAAK;AAAA,cACV;AAAA,cACA,gBAAgB;AAAA,YAClB,CAAC;AACD,kBAAM,KAAK,SAAS;AAAA,UACtB;AAAA,QACF,GAAG,gBAAgB;AACnB,eAAO,eAAe,MAAM;AAAA,MAC9B,GAAG,SAAS;AAAA,MACZ,gBAAgB;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,qBACN,OACA,OACA,YACM;AAEN,QAAI,MAAM,WAAW,MAAM;AACzB,YAAM,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACxC,YAAI,MAAM,kBAAkB,QAAQ,KAAK,SAAS,GAAG;AACnD,gBAAM,gBAAgB,gBAAgB,EAAE,IAAI;AAAA,QAC9C;AACA,uBAAe,OAAO,UAAU,IAAI;AACpC,qBAAa;AAAA,MACf,CAAC;AAAA,IACH;AACA,QAAI,MAAM,WAAW,MAAM;AACzB,YAAM,OAAO,GAAG,QAAQ,CAAC,SAAiB;AACxC,uBAAe,OAAO,UAAU,IAAI;AAAA,MACtC,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,mBACN,OACA,WACA,MACA,WACM;AACN,UAAM,MAAM,gBAAgB,EAAE,IAAI;AAClC,UAAM,UAAU,MAAM;AACtB,UAAM,iBAAiB,MAAM,kBAAkB,OAAO,OAAO,MAAM,gBAAgB;AACnF,UAAM,cAAc,MAAM,kBAAkB,OAAO,OAAO,MAAM,MAAM;AACtE,SAAK,OAAO,KAAK,qBAAqB;AAAA,MACpC,KAAK,KAAK;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,MAAM,kBAAkB;AAAA,MACtC,UAAU;AAAA,MACV,aAAa,MAAM;AAAA,MACnB,aAAa,MAAM;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,oBACN,MACA,OACA,WAC+B;AAE/B,UAAM,SAAS,eAAe,MAAM,MAAM;AAC1C,UAAM,SAAS,eAAe,MAAM,MAAM;AAE1C,QAAI,SAAS,KAAK,MAAM,WAAW,IAAI;AAErC,UAAI,MAAM,WAAW,IAAI;AACvB,cAAMC,OAAM,MAAM;AAClB,eAAO,IAAI,KAAK,YAAY,oBAAoB,MAAM,MAAM,GAAGA,IAAG,CAAC;AAAA,MACrE;AAGA,YAAM,MAAM,SAAS,OAAO,uBAAuB,IAAI,IAAI;AAC3D,UAAI,oBAAoB,IAAI,GAAG;AAC7B,eAAO,IAAI,KAAK,YAAY,oBAAoB,GAAG,CAAC;AAAA,MACtD;AACA,aAAO,IAAI,KAAK,YAAY,mBAAmB,GAAG,CAAC;AAAA,IACrD;AAGA,QAAI,SAAS,KAAK,MAAM,WAAW,MAAM,qBAAqB,MAAM,MAAM,GAAG;AAC3E,YAAM,MAAM,aAAa,OAAO,IAAI,CAAC,KAAK,MAAM,OAAO,MAAM,GAAG,GAAG,EAAE,KAAK,CAAC;AAC3E,aAAO,IAAI,KAAK,YAAY,oBAAoB,MAAM,MAAM,GAAG,GAAG,CAAC;AAAA,IACrE;AACA,WAAO,KAAK,uBAAuB,MAAM,QAAQ,MAAM,QAAQ,SAAS;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKQ,uBACN,QACA,QACA,WAC+B;AAC/B,QAAI,WAAW,MAAM,WAAW,IAAI;AAClC,aAAO,IAAI,KAAK,YAAY,mBAAmB,MAAM,CAAC;AAAA,IACxD;AAEA,UAAM,OAAO,KAAK,OAAO,gBAAgB,MAAM;AAC/C,QAAI,SAAS,MAAM;AAIjB,YAAM,YAAY,KAAK,wBAAwB,MAAM;AACrD,UAAI,cAAc,KAAM,QAAO;AAC/B,aAAO,KAAK,wBAAwB,QAAQ,QAAQ,SAAS;AAAA,IAC/D;AAEA,UAAM,QAAQ,KAAK,OAAO,aAAa,MAAM;AAC7C,UAAM,YAAY,KAAK,OAAO,iBAAiB,MAAM;AAErD,WAAO;AAAA,MACL,KAAK,kBAAkB,MAAM,SAAS,QAAW;AAAA,QAC/C,YAAY,gBAAgB,EAAE,IAAI,IAAI;AAAA,QACtC,KAAK;AAAA,QACL,GAAI,cAAc,QAAQ,EAAE,UAAU;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,wBAAwB,QAAsD;AACpF,UAAM,eAAe,KAAK,OAAO,sBAAsB,MAAM,KAAK;AAClE,QAAI,iBAAiB,QAAQ,iBAAiB,GAAI,QAAO;AACzD,UAAM,aAAa,uBAAuB,cAAc,KAAK,IAAI;AACjE,UAAM,MACJ,WAAW,SAAS,SAChB,GAAG,WAAW,OAAO;AAAA,WAAS,WAAW,IAAI,KAC7C,WAAW;AACjB,WAAO,IAAI,KAAK,YAAY,WAAW,MAAM,GAAG,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,wBACN,QACA,QACA,WAC+B;AAC/B,QAAI,gBAAgB,MAAM,GAAG;AAC3B,YAAMC,WAAU,OAAO,MAAM,GAAG,GAAG,EAAE,KAAK;AAC1C,aAAO,IAAI,KAAK,YAAY,gBAAgBA,QAAO,CAAC;AAAA,IACtD;AACA,UAAM,WAAW,sBAAsB,QAAQ,KAAK,IAAI;AACxD,QAAI,aAAa,MAAM;AACrB,YAAM,MACJ,SAAS,SAAS,SACd,GAAG,SAAS,OAAO;AAAA,WAAS,SAAS,IAAI,KACzC,SAAS;AAKf,uBAAiB,MAAM,gCAAgC;AAAA,QACrD,KAAK,KAAK;AAAA,QACV,MAAM,SAAS;AAAA,QACf,cAAc,eAAe,MAAM;AAAA,MACrC,CAAC;AACD,aAAO,IAAI,KAAK,YAAY,SAAS,MAAM,GAAG,CAAC;AAAA,IACjD;AACA,UAAM,YAAY,qBAAqB,MAAM;AAC7C,QAAI,cAAc,MAAM;AACtB,uBAAiB,MAAM,mDAAmD;AAAA,QACxE,cAAc,eAAe,MAAM;AAAA,MACrC,CAAC;AACD,aAAO;AAAA,QACL,KAAK,kBAAkB,WAAW,QAAW;AAAA,UAC3C,YAAY,gBAAgB,EAAE,IAAI,IAAI;AAAA,UACtC,KAAK;AAAA,QACP,CAAC;AAAA,MACH;AAAA,IACF;AACA,UAAM,UAAU,OAAO,MAAM,GAAG,GAAG,EAAE,KAAK;AAC1C,UAAM,aAAa,WAAW,KAAK,aAAa,OAAO,MAAM,GAAG,GAAG,EAAE,KAAK,CAAC,MAAM;AACjF,WAAO;AAAA,MACL,KAAK,YAAY,eAAe,6BAA6B,OAAO,GAAG,UAAU,EAAE;AAAA,IACrF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,OAA+C;AAC3E,QAAI,EAAE,iBAAiB,QAAQ;AAC7B,aAAO,IAAI,KAAK,YAAY,mBAAmB,eAAe,CAAC;AAAA,IACjE;AAEA,QAAI,MAAM,QAAQ,SAAS,WAAW,KAAK,MAAM,QAAQ,SAAS,SAAS,GAAG;AAC5E,aAAO,IAAI,KAAK,YAAY,WAAW,uBAAuB,KAAK,CAAC;AAAA,IACtE;AAEA,QAAI,MAAM,QAAQ,SAAS,QAAQ,GAAG;AACpC,aAAO,IAAI,KAAK,YAAY,aAAa,GAAG,KAAK,IAAI,kBAAkB,KAAK,CAAC;AAAA,IAC/E;AAEA,WAAO,IAAI,KAAK,YAAY,mBAAmB,eAAe,MAAM,OAAO,GAAG,KAAK,CAAC;AAAA,EACtF;AAAA;AAAA;AAAA;AAAA,EAKA,aAA4B;AAC1B,SAAK,oBAAoB;AACzB,SAAK,cAAc;AACnB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAyB;AACvB,SAAK,cAAc;AACnB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;;;AU/uBO,SAAS,SAAS,OAAgD;AACvE,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GAAG;AACxE,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAaO,SAAS,SAAS,OAAkD;AACzE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAoDO,SAAS,mBACd,QACA,KACoB;AACpB,QAAM,QAAQ,OAAO,GAAG;AACxB,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AASO,SAAS,mBAAmB,QAAiC,KAA4B;AAC9F,QAAM,QAAQ,OAAO,GAAG;AACxB,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;;;ACjGA,IAAM,SAAS,aAAa,EAAE,WAAW,gBAAgB,CAAC;AAqCnD,IAAM,uBAAN,MAA4E;AAAA,EACxE,OAAO;AAAA,EACP,wBAAwB;AAAA;AAAA;AAAA;AAAA,EAKjC,MAAM,KAAuC;AAC3C,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AAEpC,UAAI,CAAC,KAAK,gBAAgB,IAAI,GAAG;AAC/B,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,MAAM,iCAAiC,EAAE,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;AAC5E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,KAA4B;AAC1C,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AACpC,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,WAAW,KAAM,QAAO;AAG5B,UAAI,OAAO,aAAa,MAAM;AAC5B,eAAO;AAAA,MACT;AAEA,YAAM,SAAS,OAAO;AACtB,UAAI,OAAO,WAAW,UAAU;AAC9B,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,MAAM,iCAAiC,EAAE,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;AAC5E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAgC;AAC3C,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AACpC,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,WAAW,KAAM,QAAO;AAE5B,YAAM,cAAc,SAAS,OAAO,KAAK;AACzC,UAAI,gBAAgB,KAAM,QAAO;AAEjC,YAAM,cAAc,mBAAmB,aAAa,cAAc;AAClE,YAAM,eAAe,mBAAmB,aAAa,eAAe;AAEpE,UAAI,gBAAgB,QAAQ,iBAAiB,MAAM;AACjD,eAAO;AAAA,MACT;AAEA,YAAM,oBAAoB,mBAAmB,aAAa,yBAAyB;AAEnF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,aAAa,cAAc;AAAA,QAC3B,GAAI,sBAAsB,QAAQ,EAAE,kBAAkB;AAAA,MACxD;AAAA,IACF,QAAQ;AACN,aAAO,MAAM,iCAAiC,EAAE,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;AAC5E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,KAA4B;AAC3C,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AACpC,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,WAAW,KAAM,QAAO;AAE5B,YAAM,YAAY,OAAO;AACzB,UAAI,OAAO,cAAc,UAAU;AACjC,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO,MAAM,iCAAiC,EAAE,SAAS,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;AAC5E,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,MAA0C;AAChE,UAAM,SAAS,SAAS,IAAI;AAC5B,QAAI,WAAW,KAAM,QAAO;AAG5B,WAAO,OAAO,OAAO,WAAW;AAAA,EAClC;AACF;;;AClJA,IAAMC,UAAS,aAAa,EAAE,WAAW,uBAAuB,CAAC;AAM1D,IAAM,0BAA4D;AAAA,EACvE,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACV;AAOA,IAAI,SAAuC;AAE3C,SAAS,cAAqC;AAC5C,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI;AACF,UAAM,EAAE,QAAQ,IAAI,sBAAsB;AAG1C,aAAS,QAAQ,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,OAAO,EAAE;AAAA,EAC9D,SAAS,OAAgB;AACvB,IAAAA,QAAO,MAAM,sDAAsD;AAAA,MACjE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D,CAAC;AACD,aAAS,CAAC;AAAA,EACZ;AACA,SAAO;AACT;AAQO,SAAS,mBAAmB,QAA2C;AAC5E,SAAO,YAAY,EAChB,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EACjC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE;AAC9B;AAMO,SAAS,iBAAiB,SAA8D;AAC7F,QAAM,SAAS,wBAAwB,OAAO;AAC9C,MAAI,WAAW,OAAW,QAAO,CAAC;AAClC,SAAO,mBAAmB,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,UAAU,OAAO,EAAE;AAC/E;;;ACrCA,IAAM,qBAA6C,oBAAoB;AAEvE,SAAS,sBAA8C;AACrD,QAAM,MAA8B,CAAC;AACrC,aAAW,SAAS,gBAAgB,QAAQ,GAAG;AAC7C,QAAI,MAAM,aAAa,OAAW;AAClC,UAAM,QAAQ,MAAM;AACpB,QAAI,KAAK,IAAI;AACb,QAAI,MAAM,iBAAiB,OAAW,KAAI,MAAM,YAAY,IAAI;AAChE,eAAW,cAAc,MAAM,WAAW,CAAC,GAAG;AAC5C,UAAI,UAAU,IAAI;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAQA,IAAM,mCAAmC;AACzC,IAAM,oCAAoC;AAMnC,IAAM,mBAAN,cAA+B,qBAAqB;AAAA,EAChD,OAAgB;AAAA,EACN,SAA6B,IAAI,qBAAqB;AAAA,EAExD;AAAA,EAEjB,YAAY,SAA8B;AACxC,UAAM,SAAS,MAAM;AACrB,SAAK,QAAQ,SAAS,SAAS,gBAAgB,sBAAsB,QAAQ,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAA+C;AAC7C,WAAO,QAAQ,QAAQ,iBAAiB,KAAK,IAAI,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,eAA0B;AACxB,UAAM,eAAe,eAAe,UAAU,KAAK,KAAK;AACxD,QAAI,iBAAiB,OAAW,QAAO;AAEvC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX,eAAe;AAAA,MACf,WAAW;AAAA,MACX,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA,EAGQ,kBAAkB,MAAgB,MAAqB;AAC7D,UAAM,UAAU,KAAK,UAAU,SAAS;AACxC,QAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG;AACrD,WAAK,KAAK,aAAa,OAAO;AAAA,IAChC;AACA,UAAM,gBAAgB,KAAK,UAAU,eAAe;AACpD,QAAI,OAAO,kBAAkB,YAAY,cAAc,SAAS,GAAG;AACjE,WAAK,KAAK,gBAAgB,aAAa;AAAA,IACzC;AAEA,QAAI,KAAK,UAAU,iBAAiB,MAAM,MAAM;AAC9C,WAAK,KAAK,gCAAgC;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,WAAW,MAA8B;AACjD,UAAM,OAAiB,CAAC,MAAM,mBAAmB,MAAM;AAGvD,UAAM,gBAAgB,KAAK,SAAS,KAAK;AACzC,UAAM,WAAW,mBAAmB,aAAa,KAAK;AACtD,SAAK,KAAK,WAAW,QAAQ;AAG7B,QAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,IAAI;AAC/D,WAAK,KAAK,mBAAmB,KAAK,YAAY;AAAA,IAChD;AAGA,QAAI,KAAK,cAAc,UAAa,KAAK,cAAc,IAAI;AACzD,WAAK,KAAK,YAAY,KAAK,SAAS;AAAA,IACtC;AAEA,SAAK,kBAAkB,MAAM,IAAI;AAOjC,WAAO,EAAE,SAAS,UAAU,MAAM,OAAO,KAAK,QAAQ;AAAA,EACxD;AACF;;;AC/IA,SAAS,eAAe,QAAQ,mBAAmB;AACnD,SAAS,cAAc;AACvB,SAAS,YAAY;;;ACEd,SAAS,qBAAqB,QAA8C;AACjF,MAAI,aAAa;AACjB,MAAI,cAAc;AAClB,MAAI,cAAc;AAElB,aAAW,cAAc,OAAO,OAAO,MAAM,GAAG;AAC9C,UAAM,cAAc,SAAS,UAAU;AACvC,QAAI,gBAAgB,KAAM;AAE1B,UAAM,SAAS,SAAS,YAAY,MAAM;AAC1C,QAAI,WAAW,KAAM;AAErB,UAAM,QAAQ,mBAAmB,QAAQ,OAAO;AAChD,UAAM,aAAa,mBAAmB,QAAQ,YAAY;AAC1D,UAAMC,UAAS,mBAAmB,QAAQ,QAAQ;AAElD,QAAI,UAAU,KAAM,eAAc;AAClC,QAAI,eAAe,KAAM,gBAAe;AACxC,QAAIA,YAAW,KAAM,gBAAeA;AAAA,EACtC;AAEA,SAAO,EAAE,OAAO,YAAY,QAAQ,aAAa,QAAQ,YAAY;AACvE;AAKO,SAAS,uBAAuB,QAAyD;AAC9F,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,MAAI,UAAU,KAAM,QAAO;AAE3B,QAAM,SAAS,SAAS,MAAM,MAAM;AACpC,MAAI,WAAW,KAAM,QAAO;AAE5B,QAAM,SAAS,qBAAqB,MAAM;AAC1C,MAAI,OAAO,UAAU,KAAK,OAAO,WAAW,EAAG,QAAO;AAEtD,SAAO;AAAA,IACL,aAAa,OAAO;AAAA,IACpB,cAAc,OAAO;AAAA,IACrB,aAAa,OAAO,QAAQ,OAAO;AAAA,IACnC,GAAI,OAAO,SAAS,KAAK,EAAE,mBAAmB,OAAO,OAAO;AAAA,EAC9D;AACF;AAKO,SAAS,yBAAyB,KAA4B;AACnE,QAAM,WAAW,CAAC,mDAAmD,oBAAoB;AAEzF,aAAW,WAAW,UAAU;AAC9B,UAAM,QAAQ,QAAQ,KAAK,GAAG;AAC9B,UAAM,WAAW,QAAQ,CAAC;AAC1B,QAAI,aAAa,QAAW;AAC1B,aAAO,SAAS,WAAW,MAAM,IAAI,WAAW,OAAO,QAAQ;AAAA,IACjE;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,wBAAwB,KAAqB;AAC3D,MAAI,UAAU;AAGd,YAAU,QAAQ,QAAQ,mBAAmB,EAAE;AAG/C,YAAU,QAAQ,QAAQ,cAAc,EAAE;AAC1C,YAAU,QAAQ,QAAQ,0BAA0B,IAAI;AACxD,YAAU,QAAQ,QAAQ,cAAc,IAAI;AAE5C,SAAO,QAAQ,KAAK;AACtB;AAKO,SAAS,oBAAoB,KAAqB;AACvD,QAAM,QAAQ,IAAI,MAAM,IAAI,EAAE,OAAO,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC;AAGrE,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,YAAY;AAC/B,QAAI,MAAM,SAAS,QAAQ,GAAG;AAC5B,aAAO,KAAK,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AAAA,IAC/C;AAAA,EACF;AAGA,SAAO,MAAM,CAAC,GAAG,KAAK,KAAK;AAC7B;AAKO,SAAS,oBAAoB,KAAsB;AACxD,QAAM,QAAQ,IAAI,YAAY;AAC9B,QAAM,kBAAkB,CAAC,UAAU,cAAc,aAAa,eAAe,UAAU,QAAQ;AAG/F,aAAW,aAAa,iBAAiB;AACvC,QAAI,MAAM,WAAW,SAAS,EAAG,QAAO;AAAA,EAC1C;AAGA,MAAI,IAAI,SAAS,KAAK;AACpB,UAAM,gBAAgB,CAAC,UAAU,SAAS,UAAU,WAAW;AAC/D,UAAM,kBAAkB,cAAc,KAAK,CAAC,OAAO,MAAM,SAAS,EAAE,CAAC;AACrE,UAAM,eAAe,CAAC,MAAM,SAAS,MAAM,KAAK,CAAC,MAAM,SAAS,OAAO;AACvE,QAAI,mBAAmB,aAAc,QAAO;AAAA,EAC9C;AAEA,SAAO;AACT;;;AClGO,IAAM,wBAAN,MAA6E;AAAA,EACzE,OAAO;AAAA,EACP,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjC,MAAM,KAAuC;AAC3C,UAAM,SAAS,KAAK,eAAe,GAAG;AACtC,QAAI,WAAW,KAAM,QAAO;AAG5B,UAAM,WAA8B;AAAA,MAClC,UAAU,OAAO;AAAA,IACnB;AAGA,QAAI,OAAO,UAAU,QAAW;AAC9B,aAAO;AAAA,QACL,GAAG;AAAA,QACH,GAAI,OAAO,cAAc,UAAa,EAAE,YAAY,OAAO,UAAU;AAAA,QACrE,OAAO;AAAA,UACL,QAAQ;AAAA,YACN,kBAAkB;AAAA,cAChB,QAAQ;AAAA,gBACN,OAAO,OAAO,MAAM;AAAA,gBACpB,YAAY,OAAO,MAAM;AAAA,cAC3B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,OAAO,cAAc,QAAW;AAClC,aAAO,EAAE,GAAG,UAAU,YAAY,OAAO,UAAU;AAAA,IACrD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,KAA0C;AAEvD,UAAM,aAAa,KAAK,aAAa,GAAG;AACxC,QAAI,eAAe,KAAM,QAAO;AAGhC,UAAM,gBAAgB,KAAK,eAAe,GAAG;AAC7C,QAAI,kBAAkB,KAAM,QAAO;AAGnC,UAAM,iBAAiB,KAAK,uBAAuB,GAAG;AACtD,QAAI,mBAAmB,KAAM,QAAO;AAGpC,UAAM,kBAAkB,KAAK,aAAa,GAAG;AAC7C,QAAI,oBAAoB,KAAM,QAAO;AAErC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,KAA4B;AAC1C,UAAM,SAAS,KAAK,eAAe,GAAG;AACtC,WAAO,QAAQ,YAAY;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAgC;AAE3C,UAAM,aAAa,KAAK,aAAa,GAAG;AACxC,QAAI,YAAY,MAAO,QAAO,WAAW;AAEzC,UAAM,gBAAgB,KAAK,eAAe,GAAG;AAC7C,QAAI,eAAe,MAAO,QAAO,cAAc;AAE/C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,KAA4B;AAE3C,UAAM,aAAa,KAAK,aAAa,GAAG;AACxC,QAAI,YAAY,cAAc,UAAa,WAAW,cAAc,IAAI;AACtE,aAAO,WAAW;AAAA,IACpB;AAEA,UAAM,gBAAgB,KAAK,eAAe,GAAG;AAC7C,QAAI,eAAe,cAAc,UAAa,cAAc,cAAc,IAAI;AAC5E,aAAO,cAAc;AAAA,IACvB;AAGA,WAAO,yBAAyB,GAAG;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAqC;AAChD,UAAM,QAAQ,IAAI,YAAY;AAE9B,QAAI,MAAM,SAAS,SAAS,KAAK,MAAM,SAAS,WAAW,GAAG;AAC5D,aAAO,EAAE,MAAM,WAAW,SAAS,oBAAoB,GAAG,EAAE;AAAA,IAC9D;AAEA,QAAI,MAAM,SAAS,gBAAgB,KAAK,MAAM,SAAS,cAAc,GAAG;AACtE,aAAO,EAAE,MAAM,QAAQ,SAAS,oBAAoB,GAAG,EAAE;AAAA,IAC3D;AAEA,QAAI,MAAM,SAAS,YAAY,KAAK,MAAM,SAAS,gBAAgB,GAAG;AACpE,aAAO,EAAE,MAAM,cAAc,SAAS,oBAAoB,GAAG,EAAE;AAAA,IACjE;AAEA,QAAI,MAAM,SAAS,OAAO,KAAK,MAAM,SAAS,QAAQ,GAAG;AACvD,aAAO,EAAE,MAAM,aAAa,SAAS,oBAAoB,GAAG,EAAE;AAAA,IAChE;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,KAA0C;AAC7D,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AACpC,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,WAAW,KAAM,QAAO;AAE5B,YAAM,WAAW,OAAO;AACxB,UAAI,OAAO,aAAa,SAAU,QAAO;AAEzC,YAAM,YAAY,mBAAmB,QAAQ,YAAY;AACzD,YAAM,QAAQ,uBAAuB,MAAM;AAE3C,YAAM,SAA+B;AAAA,QACnC;AAAA,QACA,eAAe;AAAA,QACf;AAAA,MACF;AAEA,UAAI,cAAc,QAAW;AAC3B,QAAC,OAAkC,YAAY;AAAA,MACjD;AACA,UAAI,UAAU,QAAW;AACvB,QAAC,OAAkC,QAAQ;AAAA,MAC7C;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,eAAe,KAA0C;AAM/D,UAAM,YAAY,kBAAkB,GAAG;AACvC,QAAI,cAAc,OAAW,QAAO;AACpC,UAAM,SAAS,KAAK,aAAa,SAAS;AAC1C,QAAI,WAAW,MAAM;AACnB,aAAO,EAAE,GAAG,QAAQ,eAAe,kBAAkB,IAAI;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAAuB,KAA0C;AAEvE,UAAM,mBAAmB;AACzB,QAAI,QAAgC,iBAAiB,KAAK,GAAG;AAE7D,WAAO,UAAU,MAAM;AACrB,YAAM,WAAW,MAAM,CAAC;AACxB,UAAI,aAAa,QAAW;AAC1B,cAAM,UAAU,SAAS,KAAK;AAG9B,cAAM,aAAa,KAAK,aAAa,OAAO;AAC5C,YAAI,eAAe,MAAM;AACvB,iBAAO,EAAE,GAAG,YAAY,eAAe,uBAAuB,IAAI;AAAA,QACpE;AAAA,MACF;AAEA,cAAQ,iBAAiB,KAAK,GAAG;AAAA,IACnC;AAIA,QAAI,IAAI,SAAS,KAAK,GAAG;AACvB,YAAM,iBAAiB,wBAAwB,GAAG;AAClD,UAAI,eAAe,SAAS,GAAG;AAC7B,eAAO;AAAA,UACL,UAAU;AAAA,UACV,eAAe;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,KAA0C;AAC7D,UAAM,UAAU,IAAI,KAAK;AAGzB,QAAI,QAAQ,WAAW,EAAG,QAAO;AAGjC,QAAI,oBAAoB,OAAO,EAAG,QAAO;AAGzC,WAAO;AAAA,MACL,UAAU;AAAA,MACV,eAAe;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;;;AC3PO,IAAM,yBAAyB;AAAA,EACpC,cAAc,CAAC;AAAA,EACf,gBAAgB,CAAC;AAAA,EACjB,YAAY,CAAC;AAAA,EACb,aAAa,CAAC;AAAA,EACd,eAAe;AAAA,EACf,WAAW;AAAA,EACX,YAAY;AACd;AAaO,SAAS,uBAAuB,KAAwB;AAC7D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,6BAA6B,GAAG;AAAA,IACzC;AAAA,IACA,WAAW;AAAA,EACb;AACF;;;AHKA,IAAM,2BAAmC,gBAAgB,sBAAsB,QAAQ,CAAC;AAyBxF,IAAM,iBAAkF;AAAA,EACtF,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,sBAAsB;AACxB;AAOO,IAAM,mBAAN,cAA+B,qBAAqB;AAAA,EAChD,OAAgB;AAAA,EACN;AAAA,EAEF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAAwB;AAClC,UAAM,eAAe,EAAE,GAAG,gBAAgB,GAAG,QAAQ;AACrD,UAAM,SAAS,MAAM;AAErB,SAAK,QAAQ,aAAa;AAC1B,SAAK,aAAa,aAAa;AAC/B,SAAK,cAAc,aAAa;AAChC,SAAK,aAAa,aAAa;AAC/B,SAAK,SAAS,IAAI,sBAAsB;AACxC,SAAK,gBAAgB,SAAS,UAAU,aAAa,EAAE,WAAW,iBAAiB,CAAC;AAGpF,QAAI,aAAa,sBAAsB;AACrC,YAAM,WAAiC;AAAA,QACrC,GAAG;AAAA,QACH,GAAG,SAAS;AAAA,MACd;AACA,WAAK,iBAAiB,IAAI,kBAAkB,UAAU,QAAQ;AAAA,IAChE,OAAO;AACL,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA,EAGA,aAA+C;AAC7C,WAAO,QAAQ,QAAQ,iBAAiB,KAAK,IAAI,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,eAA0B;AACxB,UAAM,eAAe,eAAe,UAAU,KAAK,KAAK;AACxD,QAAI,iBAAiB,QAAW;AAC9B,aAAO,EAAE,GAAG,cAAc,WAAW,KAAM;AAAA,IAC7C;AACA,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,uBAAuB,aAAa,KAAK,KAAK,KAAK,KAAK;AAAA,MAC9D,eACE,uBAAuB,eAAe,KAAK,KAAK,KAAK,uBAAuB;AAAA,MAC9E,WAAW;AAAA,MACX,qBACE,uBAAuB,WAAW,KAAK,KAAK,KAAK,uBAAuB;AAAA,MAC1E,sBACE,uBAAuB,YAAY,KAAK,KAAK,KAAK,uBAAuB;AAAA,IAC7E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAe,QACb,MACA,SACwC;AACxC,UAAM,SAAS,MAAM,KAAK,oBAAoB,MAAM,OAAO;AAE3D,QAAI,OAAO,IAAI;AACb,aAAO,GAAG,OAAO,MAAM,QAAQ;AAAA,IACjC;AAEA,WAAO,IAAI,OAAO,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBACJ,MACA,SACkD;AAClD,UAAM,qBAAqB,KAAK,oBAAoB;AACpD,QAAI,uBAAuB,MAAM;AAC/B,aAAO,IAAI,kBAAkB;AAAA,IAC/B;AAEA,UAAM,YAAY,gBAAgB,EAAE,IAAI;AACxC,UAAM,aAAaC,wBAAuB,KAAK,OAAO;AACtD,UAAM,mBAAmB,KAAK,sBAAsB,KAAK,SAAS,OAAO;AAEzE,UAAM,SAAS,MAAM,KAAK,yBAAyB,MAAM,gBAAgB;AAEzE,WAAO,KAAK,qBAAqB,QAAQ,WAAW,UAAU;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA,EAKA,4BAA2D;AACzD,WAAO,KAAK,gBAAgB,YAAY,KAAK;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA4B;AAC1B,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKmB,WAAW,MAA8B;AAC1D,UAAM,OAAiB,CAAC;AAGxB,SAAK,KAAK,KAAK,OAAO;AAGtB,SAAK,KAAK,MAAM,MAAM;AAGtB,UAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,SAAK,KAAK,MAAM,KAAK;AAGrB,QAAI,KAAK,cAAc,UAAa,KAAK,cAAc,IAAI;AACzD,WAAK,KAAK,YAAY,KAAK,SAAS;AAAA,IACtC;AAQA,QAAI;AACJ,QAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,IAAI;AAC/D,YAAM,MAAM,YAAY,KAAK,OAAO,GAAG,yBAAyB,CAAC;AACjE,YAAM,OAAO,KAAK,KAAK,WAAW;AAClC,oBAAc,MAAM,KAAK,cAAc,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACxE,WAAK,KAAK,YAAY,IAAI;AAC1B,gBAAU,MAAY;AAKpB,YAAI;AACF,iBAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QAC9C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,WAAO,YAAY,SACf,EAAE,SAAS,UAAU,KAAK,IAC1B,EAAE,SAAS,UAAU,MAAM,QAAQ;AAAA,EACzC;AAAA,EAEQ,sBAAuC;AAC7C,QAAI,KAAK,mBAAmB,MAAM;AAChC,aAAO;AAAA,IACT;AACA,QAAI,KAAK,eAAe,SAAS,MAAM,QAAQ;AAC7C,aAAO,uBAAuB,QAAQ;AAAA,IACxC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,sBACN,aACA,SAC0B;AAC1B,UAAM,aAAaA,wBAAuB,WAAW;AACrD,UAAM,YAAY,SAAS,aAAa,kBAAkB,KAAK,MAAM,UAAU;AAE/E,WAAO;AAAA,MACL;AAAA,MACA,YAAY,SAAS,cAAc;AAAA,MACnC,YAAY,SAAS,cAAc,KAAK;AAAA,MACxC,YAAY,SAAS,cAAc;AAAA,MACnC,YAAY,SAAS;AAAA,IACvB;AAAA,EACF;AAAA,EAEQ,qBACN,QACA,WACA,YACyC;AACzC,UAAM,kBAAkB,gBAAgB,EAAE,IAAI,IAAI;AAClD,UAAM,eAAe,KAAK,gBAAgB,SAAS,KAAK;AAExD,QAAI,OAAO,IAAI;AACb,WAAK,gBAAgB,cAAc;AACnC,aAAO,GAAG;AAAA,QACR,UAAU,OAAO,MAAM;AAAA,QACvB,YAAY,OAAO,MAAM;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO,IAAI,OAAO,KAAK;AAAA,EACzB;AAAA,EAEA,MAAc,yBACZ,MACA,SAC0E;AAC1E,WAAO,oBAAoB,MAAM,KAAK,YAAY,MAAM,OAAO,GAAG;AAAA,MAChE,YAAY,QAAQ;AAAA,MACpB,YAAY,KAAK,iBAAiB,OAAO;AAAA,MACzC,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,gBAAgB,KAAK;AAAA,MACrB,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AACF;;;AIhTA,SAAS,iBAAAC,gBAAe,UAAAC,SAAQ,eAAAC,oBAAmB;AACnD,SAAS,UAAAC,eAAc;AACvB,SAAS,QAAAC,aAAY;;;ACFrB,IAAMC,UAAS,aAAa,EAAE,WAAW,eAAe,CAAC;AAgElD,IAAM,sBAAN,MAA0E;AAAA,EACtE,OAAO;AAAA,EACP,wBAAwB;AAAA;AAAA;AAAA;AAAA,EAKjC,MAAM,KAAsC;AAC1C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AACnC,QAAI;AACJ,UAAM,WAAqB,CAAC;AAC5B,UAAM,YAAsB,CAAC;AAC7B,QAAI;AAEJ,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AACxB,WAAK;AAAA,QACH;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,OAAQ,WAAW;AAAA,QACpB,CAAC,MAAO,QAAQ;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,KAAK,UAAU,WAAW,GAAG;AACnD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAI,aAAa,UAAa,EAAE,SAAS;AAAA,MACzC,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YACN,MACA,UACA,WACA,aACA,UACM;AACN,QAAI;AACF,YAAM,QAAiB,KAAK,MAAM,IAAI;AACtC,YAAM,SAAS,SAAS,KAAK;AAC7B,UAAI,WAAW,KAAM;AAErB,YAAM,YAAY,OAAO;AAEzB,UAAI,cAAc,kBAAkB;AAClC,cAAM,MAAM,OAAO;AACnB,YAAI,OAAO,QAAQ,SAAU,aAAY,GAAG;AAAA,MAC9C,WAAW,cAAc,kBAAkB;AACzC,aAAK,qBAAqB,QAAQ,UAAU,SAAS;AAAA,MACvD,WAAW,cAAc,kBAAkB;AACzC,cAAM,QAAQ,KAAK,sBAAsB,MAAM;AAC/C,YAAI,UAAU,KAAM,UAAS,KAAK;AAAA,MACpC;AAAA,IACF,QAAQ;AAEN,MAAAA,QAAO,MAAM,iCAAiC,EAAE,SAAS,KAAK,MAAM,GAAG,GAAG,EAAE,CAAC;AAAA,IAC/E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,KAA4B;AAC1C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,WAAW,QAAQ,OAAO,SAAS,WAAW,GAAG;AACnD,aAAO;AAAA,IACT;AAEA,WAAO,OAAO,SAAS,KAAK,IAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAgC;AAC3C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AAEnC,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AAExB,UAAI;AACF,cAAM,QAAiB,KAAK,MAAM,IAAI;AACtC,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,KAAM;AAErB,YAAI,OAAO,SAAS,kBAAkB;AACpC,iBAAO,KAAK,sBAAsB,MAAM;AAAA,QAC1C;AAAA,MACF,QAAQ;AACN,QAAAA,QAAO,MAAM,iCAAiC,EAAE,SAAS,KAAK,MAAM,GAAG,GAAG,EAAE,CAAC;AAC7E;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,KAA4B;AAC3C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AAEnC,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AAExB,UAAI;AACF,cAAM,QAAiB,KAAK,MAAM,IAAI;AACtC,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,KAAM;AAErB,YAAI,OAAO,SAAS,kBAAkB;AACpC,gBAAM,WAAW,OAAO;AACxB,cAAI,OAAO,aAAa,UAAU;AAChC,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF,QAAQ;AACN,QAAAA,QAAO,MAAM,iCAAiC,EAAE,SAAS,KAAK,MAAM,GAAG,GAAG,EAAE,CAAC;AAC7E;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,qBACN,QACA,UACA,WACM;AACN,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,QAAI,SAAS,KAAM;AAEnB,UAAM,WAAW,KAAK;AACtB,UAAM,OAAO,KAAK;AAElB,QAAI,OAAO,SAAS,SAAU;AAE9B,QAAI,aAAa,iBAAiB;AAChC,eAAS,KAAK,IAAI;AAAA,IACpB,WAAW,aAAa,aAAa;AACnC,gBAAU,KAAK,IAAI;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAsB,QAAoD;AAChF,UAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAI,UAAU,KAAM,QAAO;AAE3B,UAAM,cAAc,mBAAmB,OAAO,cAAc;AAC5D,UAAM,eAAe,mBAAmB,OAAO,eAAe;AAE9D,QAAI,gBAAgB,QAAQ,iBAAiB,MAAM;AACjD,aAAO;AAAA,IACT;AAEA,UAAM,oBAAoB,mBAAmB,OAAO,qBAAqB;AAEzE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa,cAAc;AAAA,MAC3B,GAAI,sBAAsB,QAAQ,EAAE,kBAAkB;AAAA,IACxD;AAAA,EACF;AACF;;;ACtPO,IAAM,wBAAwB;AAAA,EACnC,cAAc;AAAA,IACZ,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AAAA,EACA,YAAY;AAAA,IACV,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AAAA,EACA,aAAa;AAAA,IACX,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,EACb;AAAA,EACA,eAAe;AAAA,EACf,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AACd;;;AFYO,IAAM,kBAAN,cAA8B,qBAAqB;AAAA,EAC/C,OAAgB;AAAA,EACN,SAA6B,IAAI,oBAAoB;AAAA,EAEvD;AAAA,EAEjB,YAAY,SAA8B;AACxC,UAAM,SAAS,MAAM;AACrB,SAAK,QAAQ,SAAS,SAAS,gBAAgB,sBAAsB,OAAO,CAAC;AAAA,EAC/E;AAAA;AAAA,EAGA,aAA+C;AAC7C,WAAO,QAAQ,QAAQ,iBAAiB,KAAK,IAAI,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAA0B;AACxB,UAAM,eAAe,eAAe,SAAS,KAAK,KAAK;AACvD,QAAI,iBAAiB,OAAW,QAAO;AACvC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,sBAAsB,aAAa,KAAK,KAAK,KAAK,KAAK;AAAA,MAC7D,eAAe,sBAAsB;AAAA,MACrC,WAAW,sBAAsB;AAAA,MACjC,qBACE,sBAAsB,WAAW,KAAK,KAAK,KAAK,sBAAsB;AAAA,MACxE,sBACE,sBAAsB,YAAY,KAAK,KAAK,KAAK,sBAAsB;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMU,WAAW,MAA8B;AACjD,UAAM,OAAiB,CAAC,MAAM;AAG9B,SAAK,KAAK,QAAQ;AAGlB,UAAM,QAAQ,KAAK,SAAS,KAAK;AACjC,QAAI,UAAU,IAAI;AAChB,WAAK,KAAK,MAAM,KAAK;AAAA,IACvB;AAGA,SAAK,KAAK,MAAM,WAAW;AAG3B,SAAK,KAAK,uBAAuB;AAKjC,QAAI;AACJ,QAAI,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,IAAI;AAC/D,YAAM,MAAMC,aAAYC,MAAKC,QAAO,GAAG,wBAAwB,CAAC;AAChE,YAAM,OAAOD,MAAK,KAAK,iBAAiB;AACxC,MAAAE,eAAc,MAAM,KAAK,cAAc,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AACxE,WAAK,KAAK,MAAM,2BAA2B,IAAI,EAAE;AACjD,gBAAU,MAAY;AAKpB,YAAI;AACF,UAAAC,QAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QAC9C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAGA,SAAK,KAAK,KAAK,OAAO;AAEtB,WAAO,YAAY,SAAY,EAAE,SAAS,SAAS,KAAK,IAAI,EAAE,SAAS,SAAS,MAAM,QAAQ;AAAA,EAChG;AACF;;;AGvHA,SAAS,cAAc;AACvB,SAAS,4BAA4B;;;ACU9B,IAAM,4BAAsD;AAAA,EACjE,WAAW,mBAAmB;AAAA,EAC9B,YAAY;AAAA,EACZ,YAAY,mBAAmB;AAAA,EAC/B,YAAY;AAAA,EACZ,YAAY;AACd;AAYO,IAAM,sBAAsB;AAO5B,IAAM,4BAA4B;AAGlC,SAAS,aAAa,MAAyB,QAAQ,KAAa;AACzE,QAAM,MAAM,OAAO,SAAS,IAAI,mBAAmB,KAAK,KAAK,EAAE;AAC/D,SAAO,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;AACjD;AAQO,SAAS,yBAAyB,MAAyB,QAAQ,KAAa;AACrF,QAAM,QAAQ,aAAa,GAAG;AAC9B,MAAI,QAAQ,2BAA2B;AACrC,UAAM,IAAI;AAAA,MACR,kGACsC,mBAAmB,IAAI,OAAO,KAAK,CAAC;AAAA,IAI5E;AAAA,EACF;AACA,SAAO,OAAO,QAAQ,CAAC;AACzB;AAyCO,SAAS,uBACd,SACe;AACf,MAAI,YAAY,UAAa,QAAQ,WAAW,GAAG;AACjD,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,QAClB,OAAO,CAAC,MAA2C,EAAE,SAAS,UAAU,EAAE,SAAS,MAAS,EAC5F,IAAI,CAAC,MAAM,EAAE,IAAI;AAEpB,SAAO,aAAa,SAAS,IAAI,aAAa,KAAK,IAAI,IAAI;AAC7D;AAMO,SAAS,cAAc,IAA2B;AACvD,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,eAAW,MAAM;AACf,cAAQ,IAAI;AAAA,IACd,GAAG,EAAE;AAAA,EACP,CAAC;AACH;AAGO,SAAS,mBAAmB,SAAmC;AACpE,MAAI,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,WAAW,GAAG;AAC/D,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,WAAW,GAAG;AAChE,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,SAAS,YAAY,KAAK,QAAQ,SAAS,YAAY,GAAG;AACpE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ADxGO,IAAM,kBAAN,cAA8B,eAAe;AAAA,EACzC,OAAgB;AAAA,EAChB,YAA0B;AAAA,EAElB;AAAA,EACT;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EAEpB,YAAY,SAA8B;AACxC,UAAM,SAAS,UAAU,aAAa,EAAE,WAAW,oBAAoB,CAAC,CAAC;AACzE,SAAK,QAAQ,SAAS,SAAS,gBAAgB,sBAAsB,OAAO,CAAC;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,eAA0B;AACxB,UAAM,eAAe,eAAe,SAAS,KAAK,KAAK;AACvD,QAAI,iBAAiB,OAAW,QAAO;AACvC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,sBAAsB,aAAa,KAAK,KAAK,KAAK,KAAK;AAAA,MAC7D,eAAe,sBAAsB;AAAA,MACrC,WAAW,sBAAsB;AAAA,MACjC,qBACE,sBAAsB,WAAW,KAAK,KAAK,KAAK,sBAAsB;AAAA,MACxE,sBACE,sBAAsB,YAAY,KAAK,KAAK,KAAK,sBAAsB;AAAA,IAC3E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA4B;AAChC,QAAI,KAAK,WAAW;AAClB;AAAA,IACF;AAEA,SAAK,oBAAoB;AACzB,SAAK,OAAO,MAAM,mCAAmC;AAMrD,UAAM,aAAa,yBAAyB;AAE5C,QAAI;AACF,WAAK,eAAe,IAAI,qBAAqB;AAAA,QAC3C,SAAS;AAAA,QACT,MAAM,CAAC,YAAY;AAAA,QACnB,QAAQ;AAAA,QACR,KAAK,EAAE,CAAC,mBAAmB,GAAG,WAAW;AAAA,MAC3C,CAAC;AAED,WAAK,SAAS,IAAI,OAAO,EAAE,MAAM,gBAAgB,SAAS,QAAQ,GAAG,EAAE,cAAc,CAAC,EAAE,CAAC;AACzF,YAAM,KAAK,OAAO,QAAQ,KAAK,YAAY;AAC3C,WAAK,YAAY;AACjB,WAAK,cAAc;AACnB,WAAK,OAAO,KAAK,kCAAkC;AAAA,IACrD,SAAS,OAAO;AACd,WAAK,YAAY;AACjB,YAAM,kBAAkB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,mBAAmB;AACtF,WAAK,OAAO,MAAM,6CAA6C,eAAe;AAC9E,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YACJ,OACA,SACwC;AACxC,UAAM,YAAY,gBAAgB,EAAE,IAAI;AAExC,QAAI,KAAK,WAAW,QAAW;AAC7B,aAAO,IAAI,KAAK,YAAY,oBAAoB,4BAA4B,CAAC;AAAA,IAC/E;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,QAChC,KAAK,cAAc,KAAK;AAAA,QACxB,cAAc,QAAQ,SAAS;AAAA,MACjC,CAAC;AAED,UAAI,WAAW,MAAM;AACnB,eAAO,IAAI,KAAK,YAAY,WAAW,qBAAqB,CAAC;AAAA,MAC/D;AAEA,aAAO,KAAK,gBAAgB,QAAQ,SAAS;AAAA,IAC/C,SAAS,OAAO;AACd,aAAO,KAAK,qBAAqB,KAAK;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAc,MAAuC;AACjE,QAAI,KAAK,WAAW,QAAW;AAC7B,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAEA,UAAM,UAAU,KAAK,cAAc,UAAa,KAAK,cAAc;AACnE,UAAM,WAAW,UAAU,gBAAgB;AAE3C,UAAM,WAAW;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,GAAI,KAAK,UAAU,UAAa,EAAE,OAAO,KAAK,MAAM;AAAA,IACtD;AAEA,UAAM,OAAO,UACT,EAAE,GAAG,UAAU,UAAU,KAAK,UAAU,IACxC;AAAA,MACE,GAAG;AAAA,MACH,SAAS;AAAA,MACT,mBAAmB;AAAA,IACrB;AAEJ,UAAM,SAAS,MAAM,KAAK,OAAO,SAAS;AAAA,MACxC,MAAM;AAAA,MACN,WAAW;AAAA,IACb,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,QAAuB,WAAkD;AAC/F,QAAI,OAAO,YAAY,MAAM;AAC3B,YAAM,YAAY,uBAAuB,OAAO,OAAO;AACvD,aAAO,IAAI,KAAK,YAAY,mBAAmB,aAAa,uBAAuB,CAAC;AAAA,IACtF;AAEA,UAAM,OAAO,uBAAuB,OAAO,OAAO;AAClD,QAAI,SAAS,MAAM;AACjB,aAAO,IAAI,KAAK,YAAY,eAAe,6BAA6B,CAAC;AAAA,IAC3E;AAEA,WAAO,GAAG;AAAA,MACR;AAAA,MACA,YAAY,gBAAgB,EAAE,IAAI,IAAI;AAAA,MACtC,KAAK;AAAA,IACP,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,OAA+C;AAC1E,UAAM,UAAU,gBAAgB,KAAK;AACrC,UAAM,YAAY,mBAAmB,OAAO;AAE5C,QAAI,cAAc,oBAAoB;AACpC,WAAK,YAAY;AAAA,IACnB;AAEA,WAAO,IAAI,KAAK,YAAY,WAAW,SAAS,KAAc,CAAC;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAyB;AAC7B,QAAI,KAAK,iBAAiB,QAAW;AACnC,WAAK,OAAO,MAAM,8BAA8B;AAChD,YAAM,KAAK,aAAa,MAAM;AAC9B,WAAK,eAAe;AAAA,IACtB;AACA,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,cAAc;AAAA,EACrB;AACF;;;AEjOA,SAAS,gBAAgB;;;ACSzB,IAAMC,UAAS,aAAa,EAAE,WAAW,kBAAkB,CAAC;AAG5D,IAAM,uBAAuB;AAG7B,SAAS,gBAAgB,MAAuB;AAC9C,QAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,MAAM,EAAE;AAC5D,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,QAAM,gBAAgB,MAAM,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,GAAG,CAAC,EAAE;AACzE,SAAO,gBAAgB,MAAM,SAAS;AACxC;AAsDO,IAAM,yBAAN,MAAgF;AAAA,EAC5E,OAAO;AAAA,EACP,wBAAwB;AAAA;AAAA;AAAA;AAAA,EAKjC,MAAM,KAAyC;AAC7C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AACnC,UAAM,QAAQ,KAAK,gBAAgB,KAAK;AAExC,UAAM,eACJ,MAAM,cAAc,SAAS,IAAI,MAAM,cAAc,KAAK,IAAI,IAAI;AAEpE,QAAI,MAAM,aAAa,WAAW,GAAG;AAKnC,UAAI,iBAAiB,QAAW;AAC9B,eAAO,KAAK,cAAc,IAAI,MAAM,WAAW,MAAM,OAAO,YAAY;AAAA,MAC1E;AACA,aAAO,KAAK,mBAAmB,KAAK,MAAM,QAAQ,KAAK;AAAA,IACzD;AAEA,WAAO,KAAK;AAAA,MACV,MAAM,aAAa,KAAK,EAAE;AAAA,MAC1B,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,gBAAgB,OAA4C;AAClE,QAAI;AACJ,UAAM,eAAyB,CAAC;AAChC,UAAM,gBAA0B,CAAC;AACjC,QAAI;AACJ,QAAI,gBAAgB;AACpB,QAAI,wBAAwB;AAE5B,aAAS,MAAM,GAAG,MAAM,MAAM,QAAQ,OAAO;AAC3C,YAAM,OAAO,MAAM,GAAG;AACtB,UAAI,SAAS,UAAa,KAAK,KAAK,MAAM,GAAI;AAC9C,YAAM,WAAW,KAAK;AAAA,QACpB;AAAA,QACA,EAAE,cAAc,cAAc;AAAA,QAC9B,CAAC,OAAQ,YAAY;AAAA,QACrB,CAAC,MAAO,QAAQ;AAAA,QAChB;AAAA,MACF;AACA,UAAI,SAAU,iBAAgB;AAC9B,UAAI,YAAY,KAAK,wBAAwB,IAAI,EAAG,yBAAwB;AAAA,IAC9E;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,mBACN,KACA,WACA,OAC4B;AAE5B,QAAI,MAAM,eAAe;AACvB,aAAO,KAAK;AAAA,QACV;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAEA,IAAAA,QAAO,MAAM,qDAAqD;AAAA,MAChE,WAAW,IAAI;AAAA,MACf;AAAA,MACA,eAAe,MAAM;AAAA,MACrB,uBAAuB,MAAM;AAAA,IAC/B,CAAC;AACD,WAAO,KAAK,eAAe,KAAK,MAAM,qBAAqB;AAAA,EAC7D;AAAA;AAAA,EAGQ,cACN,SACA,WACA,OACA,cACqB;AACrB,WAAO;AAAA,MACL;AAAA,MACA,GAAI,cAAc,UAAa,EAAE,UAAU;AAAA,MAC3C,GAAI,UAAU,UAAa,EAAE,MAAM;AAAA,MACnC,GAAI,iBAAiB,UAAa,EAAE,aAAa;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,KAA4B;AAC1C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,WAAW,QAAQ,OAAO,YAAY,IAAI;AAC5C,MAAAA,QAAO,MAAM,iCAAiC;AAAA,QAC5C,WAAW,IAAI;AAAA,QACf,SAAS,IAAI,MAAM,GAAG,GAAG;AAAA,QACzB,YAAY,WAAW;AAAA,MACzB,CAAC;AACD,aAAO;AAAA,IACT;AACA,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,oBAAoB,KAA4B;AAC9C,WAAO,KAAK,MAAM,GAAG,GAAG,gBAAgB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAgC;AAC3C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AAEnC,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AACxB,UAAI;AACF,cAAM,QAAiB,KAAK,MAAM,IAAI;AACtC,cAAM,SAAS,SAAS,KAAK;AAC7B,YAAI,WAAW,KAAM;AAGrB,YAAI,OAAO,SAAS,eAAe;AACjC,gBAAM,QAAQ,KAAK,qBAAqB,MAAM;AAC9C,cAAI,UAAU,KAAM,QAAO;AAAA,QAC7B;AAGA,YAAI,OAAO,SAAS,sBAAsB,OAAO,SAAS,oBAAoB;AAC5E,gBAAM,QAAQ,KAAK,uBAAuB,MAAM;AAChD,cAAI,UAAU,KAAM,QAAO;AAAA,QAC7B;AAAA,MACF,QAAQ;AACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,KAA4B;AAC3C,UAAM,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI;AAEnC,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AACxB,YAAM,MAAM,KAAK,yBAAyB,IAAI;AAC9C,UAAI,QAAQ,KAAM,QAAO;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,yBAAyB,MAA6B;AAC5D,QAAI;AACF,YAAM,SAAS,SAAS,KAAK,MAAM,IAAI,CAAY;AACnD,UAAI,WAAW,KAAM,QAAO;AAG5B,UAAI,OAAO,OAAO,cAAc,SAAU,QAAO,OAAO;AAGxD,YAAM,MAAM,OAAO,cAAc,OAAO;AACxC,UAAI,OAAO,QAAQ,SAAU,QAAO;AAEpC,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YACN,MACA,YACA,cACA,UACA,WACS;AACT,QAAI;AACF,YAAM,SAAS,SAAS,KAAK,MAAM,IAAI,CAAY;AACnD,UAAI,WAAW,KAAM,QAAO;AAE5B,YAAM,SAAS,KAAK,iBAAiB,QAAQ,YAAY,cAAc,QAAQ;AAC/E,UAAI,OAAQ,QAAO;AAEnB,WAAK,mBAAmB,QAAQ,WAAW,cAAc,cAAc,QAAQ;AAC/E,aAAO;AAAA,IACT,QAAQ;AACN,MAAAA,QAAO,MAAM,iCAAiC;AAAA,QAC5C,YAAY,YAAY;AAAA,QACxB,SAAS,KAAK,MAAM,GAAG,GAAG;AAAA,MAC5B,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGQ,iBACN,QACA,YACA,cACA,UACS;AACT,YAAQ,OAAO,MAAM;AAAA,MACnB,KAAK;AAAA,MACL,KAAK;AACH,aAAK,oBAAoB,QAAQ,YAAY;AAC7C,eAAO;AAAA,MACT,KAAK;AACH,aAAK,oBAAoB,QAAQ,YAAY;AAC7C,aAAK,oBAAoB,QAAQ,WAAW,YAAY;AACxD,eAAO;AAAA,MACT,KAAK;AACH,aAAK,oBAAoB,QAAQ,YAAY;AAC7C,aAAK,cAAc,QAAQ,QAAQ;AACnC,eAAO;AAAA,MACT,KAAK;AACH,aAAK,oBAAoB,QAAQ,YAAY;AAC7C,aAAK,oBAAoB,QAAQ,WAAW,aAAa;AACzD,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,oBAAoB,QAAiC,eAA+B;AAC1F,UAAM,WAAW,SAAS,OAAO,KAAK;AACtC,QAAI,aAAa,KAAM;AAEvB,UAAM,OAAO,SAAS,SAAS,IAAI;AACnC,UAAM,UACJ,SAAS,QAAQ,OAAO,KAAK,YAAY,WACrC,KAAK,UACL,OAAO,SAAS,SAAS,WACvB,SAAS,OACT;AAER,IAAAA,QAAO,KAAK,iCAAiC,EAAE,QAAQ,CAAC;AACxD,kBAAc,KAAK,OAAO;AAAA,EAC5B;AAAA;AAAA,EAGQ,mBACN,QACA,cACA,cACA,UACM;AACN,YAAQ,OAAO,MAAM;AAAA,MACnB,KAAK;AACH,aAAK,yBAAyB,QAAQ,YAAY;AAClD;AAAA,MACF,KAAK;AACH,aAAK,sBAAsB,QAAQ,YAAY;AAC/C;AAAA,MACF,KAAK;AACH,aAAK,sBAAsB,QAAQ,YAAY;AAC/C,aAAK,gBAAgB,QAAQ,QAAQ;AACrC;AAAA,MACF,KAAK;AACH,aAAK,gBAAgB,QAAQ,QAAQ;AACrC;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA,EAKQ,oBACN,QACA,cACM;AACN,QAAI,OAAO,OAAO,cAAc,SAAU,cAAa,OAAO,SAAS;AAAA,EACzE;AAAA;AAAA,EAGQ,oBAAoB,QAAiC,OAAuB;AAClF,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,QAAI,SAAS,KAAM;AAEnB,QAAI,OAAO,KAAK,SAAS,SAAU,OAAM,KAAK,KAAK,IAAI;AAAA,EACzD;AAAA;AAAA,EAGQ,cACN,QACA,UACM;AACN,UAAM,QAAQ,KAAK,qBAAqB,MAAM;AAC9C,QAAI,UAAU,KAAM,UAAS,KAAK;AAAA,EACpC;AAAA;AAAA,EAGQ,qBAAqB,QAAoD;AAC/E,UAAM,OAAO,SAAS,OAAO,IAAI;AACjC,QAAI,SAAS,KAAM,QAAO;AAE1B,UAAM,SAAS,SAAS,KAAK,MAAM;AACnC,QAAI,WAAW,KAAM,QAAO;AAE5B,UAAM,cAAc,mBAAmB,QAAQ,OAAO;AACtD,UAAM,eAAe,mBAAmB,QAAQ,QAAQ;AAExD,QAAI,gBAAgB,QAAQ,iBAAiB,KAAM,QAAO;AAE1D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa,cAAc;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA,EAKQ,yBACN,QACA,cACM;AACN,UAAM,MAAM,OAAO,cAAc,OAAO;AACxC,QAAI,OAAO,QAAQ,SAAU,cAAa,GAAG;AAAA,EAC/C;AAAA;AAAA,EAGQ,sBAAsB,QAAiC,OAAuB;AACpF,UAAM,OAAO,OAAO,WAAW,OAAO,SAAS,OAAO;AACtD,QAAI,OAAO,SAAS,SAAU,OAAM,KAAK,IAAI;AAAA,EAC/C;AAAA;AAAA,EAGQ,gBACN,QACA,UACM;AACN,UAAM,QAAQ,KAAK,uBAAuB,MAAM;AAChD,QAAI,UAAU,KAAM,UAAS,KAAK;AAAA,EACpC;AAAA;AAAA,EAGQ,wBAAwB,MAAuB;AACrD,QAAI;AACF,YAAM,SAAS,SAAS,KAAK,MAAM,IAAI,CAAY;AACnD,UAAI,WAAW,KAAM,QAAO;AAC5B,YAAM,IAAI,OAAO;AACjB,aACE,MAAM,mBACN,MAAM,mBACN,MAAM,mBACN,MAAM,sBACN,MAAM;AAAA,IAEV,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eAAe,KAAa,uBAA4D;AAC9F,QAAI;AACF,YAAM,OAAgB,KAAK,MAAM,GAAG;AACpC,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,WAAW,KAAM,QAAO,KAAK,eAAe,KAAK,qBAAqB;AAG1E,YAAM,UAAU,OAAO,WAAW,OAAO,UAAU,OAAO,QAAQ,OAAO;AACzE,UAAI,OAAO,YAAY,SAAU,QAAO;AAExC,YAAM,QAAQ,KAAK,uBAAuB,MAAM;AAChD,YAAM,MAAM,OAAO,cAAc,OAAO;AAExC,aAAO;AAAA,QACL;AAAA,QACA,GAAI,OAAO,QAAQ,WAAW,EAAE,WAAW,IAAI,IAAI,CAAC;AAAA,QACpD,GAAI,UAAU,OAAO,EAAE,MAAM,IAAI,CAAC;AAAA,MACpC;AAAA,IACF,QAAQ;AACN,aAAO,KAAK,eAAe,KAAK,qBAAqB;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,eAAe,KAAa,uBAA4D;AAC9F,UAAM,UAAU,IAAI,KAAK;AACzB,QAAI,QAAQ,SAAS,sBAAsB;AACzC,MAAAA,QAAO,MAAM,0CAA0C,EAAE,QAAQ,QAAQ,OAAO,CAAC;AACjF,aAAO;AAAA,IACT;AACA,QAAI,gBAAgB,OAAO,GAAG;AAC5B,UAAI,uBAAuB;AACzB,QAAAA,QAAO,MAAM,kEAAkE;AAAA,UAC7E,QAAQ,QAAQ;AAAA,QAClB,CAAC;AACD,eAAO;AAAA,MACT;AACA,MAAAA,QAAO,MAAM,0DAA0D;AAAA,QACrE,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH;AACA,WAAO,EAAE,SAAS,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAuB,QAAoD;AACjF,UAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,QAAI,UAAU,KAAM,QAAO;AAE3B,UAAM,cACJ,mBAAmB,OAAO,cAAc,KAAK,mBAAmB,OAAO,aAAa;AACtF,UAAM,eACJ,mBAAmB,OAAO,eAAe,KAAK,mBAAmB,OAAO,cAAc;AAExF,QAAI,gBAAgB,QAAQ,iBAAiB,KAAM,QAAO;AAE1D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,aAAa,cAAc;AAAA,IAC7B;AAAA,EACF;AACF;;;ACnhBA,SAAS,UAAU,IAA4C;AAC7D,QAAM,QAAQ,GAAG,QAAQ,GAAG;AAC5B,SAAO,SAAS,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,MAAM,GAAG;AACjG;AAQA,SAAS,sBAAsB,QAAgB,MAAuB;AACpE,MAAI,OAAO,SAAS,KAAK,UAAU,CAAC,KAAK,WAAW,MAAM,EAAG,QAAO;AACpE,MAAI,KAAK,WAAW,OAAO,OAAQ,QAAO;AAC1C,QAAM,OAAO,KAAK,OAAO,MAAM;AAC/B,SAAO,SAAS,OAAO,SAAS;AAClC;AAaO,SAAS,mBAAmB,YAAoB,WAAqC;AAC1F,QAAM,MACJ,qBAAqB,MAAO,YAA4B,IAAI,IAAI,SAAS;AAC3E,MAAI,IAAI,SAAS,KAAK,IAAI,IAAI,UAAU,EAAG,QAAO;AAElD,QAAM,QAAQ,WAAW,QAAQ,GAAG;AACpC,QAAM,iBAAiB,QAAQ,IAAI,WAAW,MAAM,GAAG,QAAQ,CAAC,IAAI;AACpE,QAAM,MAAM,UAAU,UAAU;AAEhC,QAAM,aAAa,CAAC,GAAG,GAAG,EACvB,OAAO,CAAC,MAAM,mBAAmB,MAAM,EAAE,WAAW,cAAc,CAAC,EACnE,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC,EACvB,OAAO,CAAC,SAAS,sBAAsB,KAAK,MAAM,IAAI,IAAI,CAAC,EAC3D,IAAI,CAAC,UAAU;AAAA,IACd,IAAI,KAAK,OAAO,KAAK;AAAA,IACrB,SAAS,KAAK,KAAK;AAAA,IACnB,WAAW,KAAK,SAAS,IAAI;AAAA,EAC/B,EAAE;AAEJ,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,aAAW;AAAA,IACT,CAAC,GAAG,MACF,EAAE,UAAU,EAAE;AAAA,IACd,OAAO,EAAE,SAAS,IAAI,OAAO,EAAE,SAAS;AAAA,IACxC,EAAE,GAAG,SAAS,EAAE,GAAG;AAAA,KAClB,EAAE,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI;AAAA;AAAA,EAC1C;AACA,SAAO,WAAW,CAAC,GAAG,MAAM;AAC9B;;;AFvCA,IAAMC,UAAS,aAAa,EAAE,WAAW,mBAAmB,CAAC;AAG7D,IAAM,mBAAmB,CAAC,QAAQ,OAAO,SAAS;AAOlD,IAAM,oBAA4C,sBAAsB;AAExE,SAAS,wBAAgD;AACvD,QAAM,MAA8B,CAAC;AACrC,aAAW,SAAS,gBAAgB,UAAU,GAAG;AAC/C,QAAI,MAAM,iBAAiB,OAAW;AAEtC,QAAI,MAAM,EAAE,IAAI,MAAM;AAEtB,QAAI,MAAM,aAAa,QAAW;AAChC,UAAI,MAAM,QAAQ,IAAI,MAAM;AAAA,IAC9B;AAEA,QAAI,MAAM,YAAY,IAAI,MAAM;AAAA,EAClC;AACA,SAAO;AACT;AAGA,SAAS,qBAAqB,OAAuB;AACnD,SAAO,kBAAkB,KAAK,KAAK;AACrC;AAGA,IAAM,mBAAmB;AAOzB,IAAI;AAEJ,IAAI;AAEJ,SAAS,uBAA6C;AACpD,MAAI,iBAAiB,OAAW,QAAO,QAAQ,QAAQ,YAAY;AACnE,MAAI,iBAAiB,OAAW,QAAO;AAEvC,iBAAe,IAAI,QAAqB,CAAC,YAAY;AACnD,aAAS,YAAY,CAAC,QAAQ,GAAG,EAAE,SAAS,iBAAiB,GAAG,CAAC,OAAO,WAAW;AACjF,UAAI,UAAU,QAAQ,OAAO,KAAK,MAAM,IAAI;AAC1C,QAAAA,QAAO,MAAM,2DAA2D;AAAA,UACtE,OAAO,OAAO;AAAA,QAChB,CAAC;AACD,uBAAe,oBAAI,IAAI;AACvB,gBAAQ,YAAY;AACpB;AAAA,MACF;AACA,YAAM,SAAS,IAAI;AAAA,QACjB,OACG,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,MAC/B;AACA,MAAAA,QAAO,MAAM,0BAA0B,EAAE,OAAO,OAAO,KAAK,CAAC;AAC7D,qBAAe;AACf,cAAQ,YAAY;AAAA,IACtB,CAAC;AAAA,EACH,CAAC,EAAE,QAAQ,MAAM;AACf,mBAAe;AAAA,EACjB,CAAC;AAED,SAAO;AACT;AAGA,IAAM,2BAA2B,CAAC,cAAc,eAAe;AAM/D,SAAS,wBAAwB,QAA2B;AAC1D,QAAM,kBAAkB,CAAC,GAAG,MAAM,EAAE;AAAA,IAAO,CAAC,MAC1C,yBAAyB,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAAA,EAClE;AACA,MAAI,gBAAgB,SAAS,GAAG;AAC9B,IAAAA,QAAO;AAAA,MACL;AAAA,MAGA,EAAE,gBAAgB,gBAAgB;AAAA,IACpC;AAAA,EACF;AACF;AASO,IAAM,qBAAN,cAAiC,qBAAqB;AAAA,EAClD,OAAgB;AAAA,EACN,SAA6B,IAAI,uBAAuB;AAAA;AAAA,EAG/C,iBAAuC,EAAE,SAAS,KAAK;AAAA,EAElE;AAAA,EACT;AAAA,EAER,YAAY,SAA8B;AACxC,UAAM,SAAS,MAAM;AACrB,SAAK,QAAQ,SAAS,SAAS,gBAAgB,sBAAsB,UAAU,CAAC;AAAA,EAClF;AAAA;AAAA;AAAA;AAAA,EAKA,eAA0B;AACxB,UAAM,eAAe,eAAe,YAAY,KAAK,KAAK;AAC1D,QAAI,iBAAiB,OAAW,QAAO;AAEvC,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,aAAa,KAAK,KAAK;AAAA,MAC7B,eAAe;AAAA,MACf,WAAW;AAAA;AAAA,MAEX,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAe,aAA4B;AACzC,SAAK,kBAAkB,MAAM,qBAAqB;AAClD,4BAAwB,KAAK,eAAe;AAC5C,UAAM,MAAM,WAAW;AAAA,EACzB;AAAA;AAAA,EAGQ,iBAAiB,UAA2B;AAClD,QAAI,KAAK,oBAAoB,UAAa,KAAK,gBAAgB,SAAS,EAAG,QAAO;AAClF,WAAO,KAAK,gBAAgB,IAAI,QAAQ;AAAA,EAC1C;AAAA;AAAA,EAGQ,SAAS,UAA2B;AAC1C,WACE,uBAAuB,KAAK,qBAAqB,EAAE,mBAAmB,QAAmB;AAAA,EAE7F;AAAA;AAAA,EAGQ,cAAc,UAA2B;AAC/C,WAAO,KAAK,iBAAiB,QAAQ,KAAK,CAAC,KAAK,SAAS,QAAQ;AAAA,EACnE;AAAA;AAAA,EAGQ,eAAe,MAAgB,MAAqB;AAC1D,UAAM,gBAAgB,KAAK,SAAS,KAAK;AACzC,QAAI,WAAW,qBAAqB,aAAa;AAQjD,QACE,CAAC,KAAK,cAAc,QAAQ,KAC5B,uBAAuB,KACvB,KAAK,oBAAoB,QACzB;AACA,YAAM,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;AACjF,YAAM,WAAW,mBAAmB,UAAU,MAAM;AACpD,UAAI,aAAa,UAAU;AACzB,QAAAA,QAAO,MAAM,mDAAmD;AAAA,UAC9D,MAAM;AAAA,UACN,IAAI;AAAA,QACN,CAAC;AACD,mBAAW;AAAA,MACb;AAAA,IACF;AAEA,QAAI,KAAK,cAAc,QAAQ,GAAG;AAChC,WAAK,KAAK,WAAW,QAAQ;AAAA,IAC/B,OAAO;AACL,MAAAA,QAAO,MAAM,oEAAoE;AAAA,QAC/E,WAAW;AAAA,QACX,WAAW,KAAK,iBAAiB,QAAQ;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAe,YACb,MACA,SACwC;AACxC,UAAM,SAAS,MAAM,MAAM,YAAY,MAAM,OAAO;AACpD,QAAI,uBAAuB,KAAK,CAAC,OAAO,MAAM,OAAO,MAAM,SAAS,gBAAgB;AAClF,YAAM,WAAW,qBAAqB,KAAK,SAAS,KAAK,KAAK;AAC9D,2BAAqB,EAAE,gBAAgB,UAAqB,oBAAoB;AAChF,MAAAA,QAAO,MAAM,+CAA+C,EAAE,OAAO,SAAS,CAAC;AAAA,IACjF;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,gBAAgB,MAAgB,MAAqB;AAC3D,UAAM,UAAU,KAAK,UAAU,SAAS;AACxC,QAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG;AACrD,WAAK,KAAK,SAAS,OAAO;AAAA,IAC5B;AACA,UAAM,UAAU,KAAK,UAAU,SAAS;AACxC,QAAI,OAAO,YAAY,YAAY,iBAAiB,SAAS,OAAO,GAAG;AACrE,WAAK,KAAK,aAAa,OAAO;AAAA,IAChC;AACA,QAAI,KAAK,UAAU,UAAU,MAAM,MAAM;AACvC,WAAK,KAAK,YAAY;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,WAAW,MAA8B;AACjD,UAAM,OAAiB,CAAC,OAAO,YAAY,MAAM;AACjD,SAAK,eAAe,MAAM,IAAI;AAC9B,SAAK,gBAAgB,MAAM,IAAI;AAO/B,UAAM,UACJ,KAAK,iBAAiB,UAAa,KAAK,iBAAiB,KACrD,GAAG,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA,EAAc,KAAK,OAAO,KAC9C,KAAK;AAEX,WAAO,EAAE,SAAS,YAAY,MAAM,OAAO,QAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,aAA+C;AACnD,UAAM,MAAM,MAAM,qBAAqB;AACvC,UAAM,MAAsB,CAAC;AAC7B,eAAW,OAAO,KAAK;AACrB,YAAM,QAAQ,IAAI,QAAQ,GAAG;AAC7B,UAAI,QAAQ,KAAK,QAAQ,IAAI,SAAS,GAAG;AACvC,YAAI,KAAK,EAAE,IAAI,KAAK,UAAU,IAAI,MAAM,GAAG,KAAK,EAAE,CAAC;AAAA,MACrD,OAAO;AACL,YAAI,KAAK,EAAE,IAAI,IAAI,CAAC;AAAA,MACtB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;;;AGzSA,SAAS,YAAAC,iBAAgB;AACzB,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,QAAAC,aAAY;AAKrB,IAAM,gBAAgBC,WAAUC,SAAQ;AAuCxC,IAAM,OAAO,QAAQ;AAMrB,SAAS,iBAAiB,QAAiC;AACzD,SAAO;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,cAA+B;AACtC,MAAI,QAAQ,IAAI,mBAAmB,MAAM,UAAa,QAAQ,IAAI,mBAAmB,MAAM,IAAI;AAC7F,WAAO,EAAE,KAAK,UAAU,OAAO,iBAAiB,KAAK,UAAU;AAAA,EACjE;AACA,QAAM,WAAWC,MAAK,MAAM,WAAW,mBAAmB;AAC1D,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,UAAM,SAAkB,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC;AAClE,QAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,aAAO;AAAA,QACL;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,OAAO,cAAc;AACvC,QAAI,OAAO,cAAc,YAAY,YAAY,KAAK,IAAI,GAAG;AAC3D,aAAO,iBAAiB,uBAAuB,IAAI,KAAK,SAAS,EAAE,YAAY,CAAC,EAAE;AAAA,IACpF;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,MACP,KAAK;AAAA,MACL,GAAI,OAAO,cAAc,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC;AAAA,IACjE;AAAA,EACF,SAAS,GAAY;AACnB,WAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,sCAAsC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IAC1F;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,QAAiC;AACxD,SAAO;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,oBAAoB,QAAiC;AAE5D,MAAI,cAAc,KAAK,MAAM,KAAK,aAAa,KAAK,MAAM,GAAG;AAC3D,WAAO,gBAAgB,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC,KAAK,eAAe;AAAA,EACxE;AAEA,SAAO,EAAE,KAAK,SAAS,OAAO,iBAAiB,KAAK,kBAAkB;AACxE;AAEA,eAAe,aAAuC;AACpD,MAAI,QAAQ,IAAI,gBAAgB,MAAM,UAAa,QAAQ,IAAI,gBAAgB,MAAM,IAAI;AACvF,WAAO,EAAE,KAAK,SAAS,OAAO,iBAAiB,KAAK,UAAU;AAAA,EAChE;AACA,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,SAAS,CAAC,SAAS,QAAQ,GAAG;AAAA,MACnE,SAAS,wBAAwB;AAAA,IACnC,CAAC;AACD,WAAO,oBAAoB,MAAM;AAAA,EACnC,SAAS,GAAY;AACnB,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,QAAI,oBAAoB,KAAK,GAAG,GAAG;AACjC,aAAO,EAAE,KAAK,SAAS,OAAO,iBAAiB,QAAQ,2BAA2B;AAAA,IACpF;AACA,WAAO,gBAAgB,sDAAsD;AAAA,EAC/E;AACF;AAEA,SAAS,iBAAiB,QAAiC;AACzD,SAAO;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,QAAQ;AAAA,EACV;AACF;AAEA,SAAS,oBAAoB,QAAkC;AAC7D,MAAI,CAAC,mBAAmB,MAAM,GAAG;AAC/B,WAAO,iBAAiB,0DAA0D;AAAA,EACpF;AACA,MAAI,OAAO,OAAO,gBAAgB,YAAY,OAAO,cAAc,KAAK,IAAI,GAAG;AAC7E,WAAO;AAAA,MACL,8BAA8B,IAAI,KAAK,OAAO,WAAW,EAAE,YAAY,CAAC;AAAA,IAC1E;AAAA,EACF;AACA,SAAO;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,IACL,GAAI,OAAO,OAAO,gBAAgB,WAAW,EAAE,MAAM,EAAE,WAAW,OAAO,YAAY,EAAE,IAAI,CAAC;AAAA,EAC9F;AACF;AAEA,SAAS,cAA+B;AACtC,QAAM,MAAM,QAAQ,IAAI,mBAAmB,KAAK,QAAQ,IAAI,gBAAgB;AAC5E,MAAI,QAAQ,UAAa,QAAQ,IAAI;AACnC,WAAO,EAAE,KAAK,UAAU,OAAO,iBAAiB,KAAK,UAAU;AAAA,EACjE;AACA,QAAM,WAAWA,MAAK,MAAM,WAAW,kBAAkB;AACzD,MAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,WAAO,oBAAoB,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC,CAAC;AAAA,EACxE,SAAS,GAAY;AACnB,WAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,sCAAsC,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AAAA,IAC1F;AAAA,EACF;AACF;AAEA,eAAe,gBAA0C;AAGvD,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,YAAY,CAAC,QAAQ,MAAM,GAAG;AAAA,MACnE,SAAS,wBAAwB;AAAA,IACnC,CAAC;AACD,QAAI,iBAAiB,KAAK,MAAM,GAAG;AACjC,aAAO;AAAA,QACL,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,IACF;AACA,WAAO,EAAE,KAAK,YAAY,OAAO,iBAAiB,KAAK,kBAAkB;AAAA,EAC3E,SAAS,GAAY;AACnB,UAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,QAAI,oBAAoB,KAAK,GAAG,GAAG;AACjC,aAAO,EAAE,KAAK,YAAY,OAAO,iBAAiB,QAAQ,8BAA8B;AAAA,IAC1F;AACA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,IAAI,MAAM,IAAI,EAAE,CAAC,KAAK;AAAA,IAChC;AAAA,EACF;AACF;AAaA,SAAS,mBAAmB,GAA8B;AACxD,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,QAAM,QAAS,EAAkC;AACjD,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,SAAO,OAAQ,MAAoC,gBAAgB;AACrE;AAOA,SAAS,mBAAmB,GAA8B;AACxD,MAAI,OAAO,MAAM,YAAY,MAAM,KAAM,QAAO;AAChD,SAAO,OAAQ,EAAiC,iBAAiB;AACnE;AAOA,eAAsB,SAAS,KAAwC;AACrE,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO,QAAQ,QAAQ,YAAY,CAAC;AAAA,IACtC,KAAK;AACH,aAAO,WAAW;AAAA,IACpB,KAAK;AACH,aAAO,QAAQ,QAAQ,YAAY,CAAC;AAAA,IACtC,KAAK;AACH,aAAO,cAAc;AAAA,EACzB;AACF;AAGA,eAAsB,eAAoD;AACxE,QAAM,OAA2B,CAAC,UAAU,UAAU,SAAS,UAAU;AACzE,SAAO,QAAQ,IAAI,KAAK,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC;AACjD;;;ACnPO,SAAS,iBAAiB,QAAuC;AACtE,QAAM,UAAU;AAAA,IACd,GAAI,OAAO,UAAU,UAAa,EAAE,OAAO,OAAO,MAAM;AAAA,IACxD,GAAI,OAAO,WAAW,UAAa,EAAE,QAAQ,OAAO,OAAO;AAAA,EAC7D;AAEA,UAAQ,OAAO,KAAK;AAAA,IAClB,KAAK;AACH,aAAO,IAAI,iBAAiB,OAAO;AAAA,IAErC,KAAK;AACH,aAAO,IAAI,iBAAiB,OAAO;AAAA,IAErC,KAAK;AACH,aAAO,mBAAmB,OAAO,WAAW,OAAO;AAAA,IAErD,KAAK;AACH,aAAO,IAAI,mBAAmB,OAAO;AAAA,IAEvC,SAAS;AACP,YAAM,kBAAyB,OAAO;AACtC,YAAM,IAAI,MAAM,oBAAoB,OAAO,eAAe,CAAC,EAAE;AAAA,IAC/D;AAAA,EACF;AACF;AAUA,SAAS,mBACP,WACA,SACa;AAEb,MAAI,cAAc,cAAc;AAC9B,WAAO,IAAI,gBAAgB,OAAO;AAAA,EACpC;AACA,SAAO,IAAI,gBAAgB,OAAO;AACpC;AAiBO,SAAS,kBACdC,SACA,iBAA+B,OACC;AAChC,QAAM,WAAW,oBAAI,IAA+B;AACpD,QAAM,UAAUA,YAAW,SAAY,EAAE,QAAAA,QAAO,IAAI;AAEpD,WAAS,IAAI,UAAU,IAAI,iBAAiB,OAAO,CAAC;AACpD,WAAS,IAAI,UAAU,IAAI,iBAAiB,OAAO,CAAC;AACpD,WAAS,IAAI,SAAS,mBAAmB,gBAAgB,WAAW,CAAC,CAAC,CAAC;AACvE,WAAS,IAAI,YAAY,IAAI,mBAAmB,OAAO,CAAC;AAGxD,MAAI,QAAQ,IAAI,oBAAoB,MAAM,OAAO;AAC/C,eAAW,EAAE,OAAO,QAAQ,KAAK,sBAAsBA,OAAM,GAAG;AAC9D,eAAS,IAAI,OAAO,OAAO;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAUA,eAAsB,eAAe,KAAc,OAA8C;AAE/F,MAAI,UAAU,QAAW;AACvB,UAAMC,UAAS,MAAM,IAAI,GAAG;AAC5B,QAAIA,YAAW,QAAW;AACxB,aAAOA,QAAO;AAAA,IAChB;AAAA,EACF;AAEA,MAAI;AACF,UAAM,UAAU,iBAAiB,EAAE,IAAI,CAAC;AAMxC,UAAM,CAAC,QAAQ,IAAI,IAAI,MAAM,QAAQ,IAAI,CAAC,QAAQ,YAAY,GAAG,SAAS,GAAG,CAAC,CAAC;AAC/E,UAAM,YAAY,OAAO,WAAW,KAAK,UAAU;AAKnD,QAAI,UAAU,QAAW;AACvB,UAAI,WAAW;AACb,cAAM,IAAI,KAAK,kBAAkB,iBAAiB,MAAM,CAAC;AAAA,MAC3D,OAAO;AACL,cAAM,IAAI,KAAK;AAAA,UACb,SAAS;AAAA,UACT,SAAS,OAAO;AAAA,UAChB,eAAe,OAAO;AAAA,UACtB,WAAW,oBAAI,KAAK;AAAA,UACpB,SACE,KAAK,UAAU,kBACX,OAAO,UACP,SAAS,KAAK,KAAK,MAAM,YAAY,OAAO,KAAK,KAAK,MAAM,MAAM;AAAA,QAC1E,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAgB;AAKvB,4BAAwB,OAAO,KAAK,KAAK;AACzC,WAAO;AAAA,EACT;AACF;AAGA,SAAS,wBACP,OACA,KACA,OACM;AACN,MAAI,UAAU,OAAW;AACzB,QAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,QAAM,IAAI,KAAK;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,IACT,eAAe;AAAA,IACf,WAAW,IAAI,KAAK,gBAAgB,EAAE,IAAI,CAAC;AAAA,IAC3C,SAAS,wBAAwB,OAAO;AAAA,EAC1C,CAAC;AACH;AASA,eAAsB,iBAAiB,OAAgD;AACrF,QAAM,OAAkB,CAAC,UAAU,UAAU,SAAS,UAAU;AAGhE,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,KAAK,IAAI,OAAO,SAAS,EAAE,KAAK,WAAW,MAAM,eAAe,KAAK,KAAK,EAAE,EAAE;AAAA,EAChF;AAEA,SAAO,QACJ;AAAA,IACC,CAAC,MACC,EAAE,WAAW,eAAe,EAAE,MAAM;AAAA,EACxC,EACC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG;AAC3B;","names":["Anthropic","Anthropic","logger","logger","cliAdapter","estimateTaskComplexity","categorizeError","logger","msg","snippet","logger","cached","estimateTaskComplexity","writeFileSync","rmSync","mkdtempSync","tmpdir","join","logger","mkdtempSync","join","tmpdir","writeFileSync","rmSync","logger","logger","execFile","promisify","join","promisify","execFile","join","logger","cached"]}