nexus-agents 2.174.2 → 2.176.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 (145) hide show
  1. package/dist/{child-mcp-config-GWB7JLIS.js → child-mcp-config-HPWYQFLG.js} +9 -7
  2. package/dist/child-mcp-config-HPWYQFLG.js.map +1 -0
  3. package/dist/{chunk-E35RUETV.js → chunk-2DE5L734.js} +2 -2
  4. package/dist/{chunk-AXTD4TFK.js → chunk-2HUC6NZN.js} +2 -2
  5. package/dist/{chunk-DJZGCMNU.js → chunk-46XEDJRB.js} +2 -2
  6. package/dist/{chunk-OCTNNEXT.js → chunk-4OPEUDHY.js} +10 -10
  7. package/dist/{chunk-H5KLPUAL.js → chunk-4S6S6S2S.js} +3 -3
  8. package/dist/{chunk-Z77MIV3C.js → chunk-5ALUADB6.js} +2 -2
  9. package/dist/{chunk-YE2XMU3T.js → chunk-5LTRHNOI.js} +3 -3
  10. package/dist/{chunk-KWKGX7LC.js → chunk-5YXHHEAG.js} +5 -5
  11. package/dist/{chunk-JSIX5L3C.js → chunk-7TXEBDRM.js} +2 -2
  12. package/dist/{chunk-2CB6QMRX.js → chunk-AHXJCVMV.js} +39 -39
  13. package/dist/{chunk-YUCJ7VSJ.js → chunk-APXGDZV4.js} +13 -10
  14. package/dist/chunk-APXGDZV4.js.map +1 -0
  15. package/dist/{chunk-OGR5Q6QO.js → chunk-CGD63GSC.js} +7 -7
  16. package/dist/{chunk-Y5JA7XEO.js → chunk-CNHPSIHY.js} +21 -16
  17. package/dist/chunk-CNHPSIHY.js.map +1 -0
  18. package/dist/{chunk-PINS44XA.js → chunk-DVKS77O5.js} +2 -2
  19. package/dist/{chunk-OM2VVQKB.js → chunk-ECBV4JNL.js} +2 -2
  20. package/dist/{chunk-VSETLO4Q.js → chunk-G42V4A5Q.js} +2 -2
  21. package/dist/{chunk-PN43VH6Z.js → chunk-G5URP3V7.js} +7 -7
  22. package/dist/{chunk-ASJTVA7W.js → chunk-H4LZLG3P.js} +6 -6
  23. package/dist/{chunk-UB6APBIY.js → chunk-J4BGV5VE.js} +2 -2
  24. package/dist/{chunk-RAIFOYRM.js → chunk-J55NMZ7R.js} +2 -2
  25. package/dist/{chunk-3P7SMHBU.js → chunk-JGL5HYZL.js} +3 -3
  26. package/dist/{chunk-HUYP2XXH.js → chunk-JRKF4FYO.js} +2 -2
  27. package/dist/{chunk-K6NXLBHG.js → chunk-N3XDPW64.js} +13 -11
  28. package/dist/{chunk-K6NXLBHG.js.map → chunk-N3XDPW64.js.map} +1 -1
  29. package/dist/{chunk-EDWON3X5.js → chunk-NQU4LNN7.js} +6 -6
  30. package/dist/{chunk-DHVMSIT5.js → chunk-OQLFRJCW.js} +9 -1
  31. package/dist/chunk-OQLFRJCW.js.map +1 -0
  32. package/dist/{chunk-6RRAQFSX.js → chunk-QI5U2YUL.js} +2 -2
  33. package/dist/{chunk-MRRKFMYJ.js → chunk-QQ3CUUBU.js} +8 -216
  34. package/dist/chunk-QQ3CUUBU.js.map +1 -0
  35. package/dist/{chunk-IVINLVGP.js → chunk-U5CV76ZW.js} +2 -2
  36. package/dist/{chunk-DGR27REV.js → chunk-WMV2CXBB.js} +2 -2
  37. package/dist/{chunk-JVBI4WKP.js → chunk-WT4BJODZ.js} +5 -5
  38. package/dist/{chunk-5QVJCBM4.js → chunk-XAWRBQB7.js} +4 -4
  39. package/dist/{chunk-KYF4YAZO.js → chunk-XES5DPHV.js} +4 -4
  40. package/dist/{chunk-KU2HPCJG.js → chunk-XZJU6WLL.js} +4 -4
  41. package/dist/chunk-YAF73ZMR.js +38 -0
  42. package/dist/chunk-YAF73ZMR.js.map +1 -0
  43. package/dist/{chunk-SGIWJYLJ.js → chunk-YB4QE7MD.js} +2 -2
  44. package/dist/{chunk-KAL22DYO.js → chunk-YU2JCUM7.js} +2 -2
  45. package/dist/{chunk-4PTAG65V.js → chunk-Z55WHIRU.js} +2 -2
  46. package/dist/{cli-circuit-breaker-EINPV2CX.js → cli-circuit-breaker-PJOQTGFZ.js} +5 -5
  47. package/dist/cli.js +58 -48
  48. package/dist/cli.js.map +1 -1
  49. package/dist/{composite-router-CUJAG7O4.js → composite-router-IRXFQSB6.js} +4 -4
  50. package/dist/{consensus-vote-BLCQCWPV.js → consensus-vote-O6Q266QE.js} +20 -19
  51. package/dist/{context-retriever-MTJR3AQM.js → context-retriever-GO6ET3MF.js} +11 -11
  52. package/dist/doctor-deep-6HCHHMRP.js +13 -0
  53. package/dist/{expert-bridge-2W2JMFQW.js → expert-bridge-6OLG6THF.js} +6 -6
  54. package/dist/factory-7OM526WB.js +25 -0
  55. package/dist/factory-MJFGYMNE.js +15 -0
  56. package/dist/{improvement-review-ZMUJQSX3.js → improvement-review-PALAAG7V.js} +7 -7
  57. package/dist/index.d.ts +19 -137
  58. package/dist/index.js +36 -39
  59. package/dist/index.js.map +1 -1
  60. package/dist/{init-opencode-I5XSFY34.js → init-opencode-NUMHNVIF.js} +8 -8
  61. package/dist/issue-triage-N7GFXNPY.js +18 -0
  62. package/dist/{learning-persistence-6D5GGT7D.js → learning-persistence-EGY4VKKO.js} +3 -3
  63. package/dist/{pr-reviewer-helpers-CZDMP5UJ.js → pr-reviewer-helpers-6EIUJPXS.js} +6 -6
  64. package/dist/{registry-command-5J6RJZMS.js → registry-command-SVTX7FKB.js} +4 -4
  65. package/dist/{repo-security-plan-MKSCD567.js → repo-security-plan-AT7LOXLG.js} +5 -5
  66. package/dist/research-helpers-synthesize-R722YWRS.js +15 -0
  67. package/dist/{routing-memory-HAWL7RKO.js → routing-memory-4FXQT5H6.js} +4 -4
  68. package/dist/{session-memory-RPSM7Y4Q.js → session-memory-ZQJ6AUSQ.js} +5 -5
  69. package/dist/setup-command-VAAYESH5.js +43 -0
  70. package/dist/setup-config-MYLZ2UHR.js +11 -0
  71. package/dist/{setup-custom-api-BZSHB2M5.js → setup-custom-api-WZPLTGRQ.js} +6 -6
  72. package/dist/{tool-memory-FCEJMKEH.js → tool-memory-5REJXBCB.js} +8 -8
  73. package/dist/{tool-memory-registry-adapters-PMMKJQF5.js → tool-memory-registry-adapters-YQLOSV4S.js} +3 -3
  74. package/dist/unified-registry-FM3QB2VN.js +26 -0
  75. package/dist/{weather-report-VNABZRH7.js → weather-report-Y2GYJA6I.js} +4 -4
  76. package/package.json +1 -1
  77. package/dist/child-mcp-config-GWB7JLIS.js.map +0 -1
  78. package/dist/chunk-DHVMSIT5.js.map +0 -1
  79. package/dist/chunk-MRRKFMYJ.js.map +0 -1
  80. package/dist/chunk-Y5JA7XEO.js.map +0 -1
  81. package/dist/chunk-YUCJ7VSJ.js.map +0 -1
  82. package/dist/doctor-deep-X2KP2G4M.js +0 -13
  83. package/dist/factory-7UFJ6LXW.js +0 -24
  84. package/dist/factory-SC5D5P3C.js +0 -15
  85. package/dist/issue-triage-KOIPTNDH.js +0 -18
  86. package/dist/research-helpers-synthesize-TIT43XF4.js +0 -15
  87. package/dist/setup-command-SORJLYU3.js +0 -42
  88. package/dist/setup-config-YDA4MY4N.js +0 -11
  89. package/dist/unified-registry-JWPD2ES2.js +0 -27
  90. /package/dist/{chunk-E35RUETV.js.map → chunk-2DE5L734.js.map} +0 -0
  91. /package/dist/{chunk-AXTD4TFK.js.map → chunk-2HUC6NZN.js.map} +0 -0
  92. /package/dist/{chunk-DJZGCMNU.js.map → chunk-46XEDJRB.js.map} +0 -0
  93. /package/dist/{chunk-OCTNNEXT.js.map → chunk-4OPEUDHY.js.map} +0 -0
  94. /package/dist/{chunk-H5KLPUAL.js.map → chunk-4S6S6S2S.js.map} +0 -0
  95. /package/dist/{chunk-Z77MIV3C.js.map → chunk-5ALUADB6.js.map} +0 -0
  96. /package/dist/{chunk-YE2XMU3T.js.map → chunk-5LTRHNOI.js.map} +0 -0
  97. /package/dist/{chunk-KWKGX7LC.js.map → chunk-5YXHHEAG.js.map} +0 -0
  98. /package/dist/{chunk-JSIX5L3C.js.map → chunk-7TXEBDRM.js.map} +0 -0
  99. /package/dist/{chunk-2CB6QMRX.js.map → chunk-AHXJCVMV.js.map} +0 -0
  100. /package/dist/{chunk-OGR5Q6QO.js.map → chunk-CGD63GSC.js.map} +0 -0
  101. /package/dist/{chunk-PINS44XA.js.map → chunk-DVKS77O5.js.map} +0 -0
  102. /package/dist/{chunk-OM2VVQKB.js.map → chunk-ECBV4JNL.js.map} +0 -0
  103. /package/dist/{chunk-VSETLO4Q.js.map → chunk-G42V4A5Q.js.map} +0 -0
  104. /package/dist/{chunk-PN43VH6Z.js.map → chunk-G5URP3V7.js.map} +0 -0
  105. /package/dist/{chunk-ASJTVA7W.js.map → chunk-H4LZLG3P.js.map} +0 -0
  106. /package/dist/{chunk-UB6APBIY.js.map → chunk-J4BGV5VE.js.map} +0 -0
  107. /package/dist/{chunk-RAIFOYRM.js.map → chunk-J55NMZ7R.js.map} +0 -0
  108. /package/dist/{chunk-3P7SMHBU.js.map → chunk-JGL5HYZL.js.map} +0 -0
  109. /package/dist/{chunk-HUYP2XXH.js.map → chunk-JRKF4FYO.js.map} +0 -0
  110. /package/dist/{chunk-EDWON3X5.js.map → chunk-NQU4LNN7.js.map} +0 -0
  111. /package/dist/{chunk-6RRAQFSX.js.map → chunk-QI5U2YUL.js.map} +0 -0
  112. /package/dist/{chunk-IVINLVGP.js.map → chunk-U5CV76ZW.js.map} +0 -0
  113. /package/dist/{chunk-DGR27REV.js.map → chunk-WMV2CXBB.js.map} +0 -0
  114. /package/dist/{chunk-JVBI4WKP.js.map → chunk-WT4BJODZ.js.map} +0 -0
  115. /package/dist/{chunk-5QVJCBM4.js.map → chunk-XAWRBQB7.js.map} +0 -0
  116. /package/dist/{chunk-KYF4YAZO.js.map → chunk-XES5DPHV.js.map} +0 -0
  117. /package/dist/{chunk-KU2HPCJG.js.map → chunk-XZJU6WLL.js.map} +0 -0
  118. /package/dist/{chunk-SGIWJYLJ.js.map → chunk-YB4QE7MD.js.map} +0 -0
  119. /package/dist/{chunk-KAL22DYO.js.map → chunk-YU2JCUM7.js.map} +0 -0
  120. /package/dist/{chunk-4PTAG65V.js.map → chunk-Z55WHIRU.js.map} +0 -0
  121. /package/dist/{cli-circuit-breaker-EINPV2CX.js.map → cli-circuit-breaker-PJOQTGFZ.js.map} +0 -0
  122. /package/dist/{composite-router-CUJAG7O4.js.map → composite-router-IRXFQSB6.js.map} +0 -0
  123. /package/dist/{consensus-vote-BLCQCWPV.js.map → consensus-vote-O6Q266QE.js.map} +0 -0
  124. /package/dist/{context-retriever-MTJR3AQM.js.map → context-retriever-GO6ET3MF.js.map} +0 -0
  125. /package/dist/{doctor-deep-X2KP2G4M.js.map → doctor-deep-6HCHHMRP.js.map} +0 -0
  126. /package/dist/{expert-bridge-2W2JMFQW.js.map → expert-bridge-6OLG6THF.js.map} +0 -0
  127. /package/dist/{factory-7UFJ6LXW.js.map → factory-7OM526WB.js.map} +0 -0
  128. /package/dist/{factory-SC5D5P3C.js.map → factory-MJFGYMNE.js.map} +0 -0
  129. /package/dist/{improvement-review-ZMUJQSX3.js.map → improvement-review-PALAAG7V.js.map} +0 -0
  130. /package/dist/{init-opencode-I5XSFY34.js.map → init-opencode-NUMHNVIF.js.map} +0 -0
  131. /package/dist/{issue-triage-KOIPTNDH.js.map → issue-triage-N7GFXNPY.js.map} +0 -0
  132. /package/dist/{learning-persistence-6D5GGT7D.js.map → learning-persistence-EGY4VKKO.js.map} +0 -0
  133. /package/dist/{pr-reviewer-helpers-CZDMP5UJ.js.map → pr-reviewer-helpers-6EIUJPXS.js.map} +0 -0
  134. /package/dist/{registry-command-5J6RJZMS.js.map → registry-command-SVTX7FKB.js.map} +0 -0
  135. /package/dist/{repo-security-plan-MKSCD567.js.map → repo-security-plan-AT7LOXLG.js.map} +0 -0
  136. /package/dist/{research-helpers-synthesize-TIT43XF4.js.map → research-helpers-synthesize-R722YWRS.js.map} +0 -0
  137. /package/dist/{routing-memory-HAWL7RKO.js.map → routing-memory-4FXQT5H6.js.map} +0 -0
  138. /package/dist/{session-memory-RPSM7Y4Q.js.map → session-memory-ZQJ6AUSQ.js.map} +0 -0
  139. /package/dist/{setup-command-SORJLYU3.js.map → setup-command-VAAYESH5.js.map} +0 -0
  140. /package/dist/{setup-config-YDA4MY4N.js.map → setup-config-MYLZ2UHR.js.map} +0 -0
  141. /package/dist/{setup-custom-api-BZSHB2M5.js.map → setup-custom-api-WZPLTGRQ.js.map} +0 -0
  142. /package/dist/{tool-memory-FCEJMKEH.js.map → tool-memory-5REJXBCB.js.map} +0 -0
  143. /package/dist/{tool-memory-registry-adapters-PMMKJQF5.js.map → tool-memory-registry-adapters-YQLOSV4S.js.map} +0 -0
  144. /package/dist/{unified-registry-JWPD2ES2.js.map → unified-registry-FM3QB2VN.js.map} +0 -0
  145. /package/dist/{weather-report-VNABZRH7.js.map → weather-report-Y2GYJA6I.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/agents/collaboration/event-bus-helpers.ts","../src/agents/collaboration/event-bus.ts","../src/agents/collaboration/event-bus-topics.ts","../src/adapters/resilient-adapter.ts","../src/adapters/model-not-found-fallback.ts","../src/adapters/unified-registry.ts"],"sourcesContent":["/**\n * Event Bus Helper Functions\n *\n * Pure utility functions for event bus operations.\n * Extracted from event-bus.ts to maintain file size limits.\n *\n * @module agents/collaboration/event-bus-helpers\n * (Source: Issue #182, ARCHITECTURE.md Hybrid Architecture)\n */\n\nimport { randomUUID } from 'node:crypto';\nimport { getTimeProvider } from '../../core/index.js';\nimport type { SubscriptionId, TopicPattern, DomainEvent, EventFilter } from './event-bus-types.js';\n\n/** Default maximum history size */\nexport const DEFAULT_MAX_HISTORY_SIZE = 1000;\n\n/** Maximum number of subscriptions per bus */\nexport const MAX_SUBSCRIPTIONS = 500;\n\n/**\n * Internal subscription record.\n */\nexport interface SubscriptionRecord {\n readonly id: SubscriptionId;\n readonly pattern: TopicPattern;\n readonly regex: RegExp;\n readonly listener: (event: DomainEvent) => void | Promise<void>;\n}\n\n/** Maximum allowed topic pattern length */\nconst MAX_TOPIC_PATTERN_LENGTH = 200;\n\n/**\n * Convert a topic pattern to a regex for matching.\n * Supports wildcard patterns:\n * - 'session.created' -> exact match\n * - 'session.*' -> matches session.anything\n * - '*' -> matches everything\n *\n * Security Note (Issue #341): This function is safe from ReDoS because:\n * 1. The input is fully escaped before regex construction\n * 2. Only `*` wildcards are converted to `[^.]+` (bounded, non-greedy)\n * 3. Pattern length is bounded to prevent memory issues\n *\n * @throws Error if pattern exceeds MAX_TOPIC_PATTERN_LENGTH\n */\nexport function patternToRegex(pattern: TopicPattern): RegExp {\n // Validate length to prevent memory issues (Issue #341)\n if (pattern.length > MAX_TOPIC_PATTERN_LENGTH) {\n throw new Error(`Topic pattern exceeds maximum length of ${String(MAX_TOPIC_PATTERN_LENGTH)}`);\n }\n\n if (pattern === '*') {\n return /^.+$/;\n }\n // Use placeholder for * before escaping, then restore as regex wildcard\n // WILDCARD_PLACEHOLDER is a static constant, safe for RegExp (Issue #341)\n const WILDCARD_PLACEHOLDER = '\\x00WILDCARD\\x00';\n const withPlaceholder = pattern.replace(/\\*/g, WILDCARD_PLACEHOLDER);\n // Escape all regex special characters - this makes the pattern safe\n const escaped = withPlaceholder.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n // Replace placeholder with bounded wildcard - safe since input was escaped\n const withWildcards = escaped.replace(new RegExp(WILDCARD_PLACEHOLDER, 'g'), '[^.]+');\n return new RegExp(`^${withWildcards}$`);\n}\n\n/**\n * Check if a topic matches a pattern.\n */\nexport function topicMatchesPattern(topic: string, regex: RegExp): boolean {\n return regex.test(topic);\n}\n\n/**\n * Generate a unique event ID.\n */\nexport function generateEventId(): string {\n return `evt-${String(getTimeProvider().now())}-${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Generate a unique subscription ID.\n */\nexport function generateSubscriptionId(): SubscriptionId {\n return `sub-${String(getTimeProvider().now())}-${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Generate a unique correlation ID for request tracing.\n * (Source: Issue #224, Sprint #228)\n *\n * @example\n * ```typescript\n * const correlationId = generateCorrelationId();\n * // -> 'cor_a1b2c3d4'\n * ```\n */\nexport function generateCorrelationId(): string {\n return `cor_${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Create a child correlation ID that chains to a parent.\n * Enables hierarchical tracing of subtasks.\n * (Source: Issue #224, Sprint #228)\n *\n * @param parentCorrelationId - The parent correlation ID to chain from\n * @returns A new correlation ID in format 'parentId.child_xxxxxxxx'\n *\n * @example\n * ```typescript\n * const parentId = generateCorrelationId();\n * // -> 'cor_a1b2c3d4'\n *\n * const childId = createChildCorrelationId(parentId);\n * // -> 'cor_a1b2c3d4.child_e5f6g7h8'\n * ```\n */\nexport function createChildCorrelationId(parentCorrelationId: string): string {\n return `${parentCorrelationId}.child_${randomUUID().slice(0, 8)}`;\n}\n\n/**\n * Apply topic, session, correlation, and timestamp filters to events.\n */\nexport function applyHistoryFilters(history: DomainEvent[], filter: EventFilter): DomainEvent[] {\n let result: DomainEvent[] = history;\n\n if (filter.topic !== undefined && filter.topic !== '') {\n const regex = patternToRegex(filter.topic);\n result = result.filter((e) => topicMatchesPattern(e.topic, regex));\n }\n\n if (filter.sessionId !== undefined && filter.sessionId !== '') {\n result = result.filter((e) => e.sessionId === filter.sessionId);\n }\n\n if (filter.correlationId !== undefined && filter.correlationId !== '') {\n result = result.filter((e) => e.correlationId === filter.correlationId);\n }\n\n return applyTimestampFilters(result, filter);\n}\n\n/**\n * Apply timestamp-based filters to events.\n */\nexport function applyTimestampFilters(result: DomainEvent[], filter: EventFilter): DomainEvent[] {\n let filtered = result;\n\n if (filter.after !== undefined && filter.after !== '') {\n const afterTimestamp = filter.after;\n filtered = filtered.filter((e) => e.timestamp > afterTimestamp);\n }\n\n if (filter.before !== undefined && filter.before !== '') {\n const beforeTimestamp = filter.before;\n filtered = filtered.filter((e) => e.timestamp < beforeTimestamp);\n }\n\n return filtered;\n}\n\n/**\n * Apply limit to history results.\n */\nexport function applyHistoryLimit(result: DomainEvent[], filter: EventFilter): DomainEvent[] {\n if (filter.limit !== undefined && filter.limit > 0) {\n return result.slice(-filter.limit);\n }\n return result;\n}\n\n/**\n * Enrich event with generated fields if missing.\n */\nexport function enrichEvent(event: DomainEvent): DomainEvent {\n return {\n ...event,\n eventId: event.eventId || generateEventId(),\n timestamp: event.timestamp || getTimeProvider().nowIso(),\n };\n}\n\n/**\n * Count subscribers matching a topic from a subscription map.\n */\nexport function countMatchingSubscribers(\n topic: string,\n subscriptions: Map<SubscriptionId, SubscriptionRecord>\n): number {\n let count = 0;\n for (const record of subscriptions.values()) {\n if (topicMatchesPattern(topic, record.regex)) {\n count++;\n }\n }\n return count;\n}\n","/**\n * Event Bus Implementation\n *\n * Async message passing for agent-to-agent communication.\n * Supports topic-based routing, wildcard patterns, and event history.\n *\n * @module agents/collaboration/event-bus\n * (Source: Issue #182, ARCHITECTURE.md Hybrid Architecture)\n */\n\nimport { getTimeProvider } from '../../core/index.js';\nimport type {\n IEventBus,\n DomainEvent,\n EventListener,\n Subscription,\n SubscriptionId,\n TopicPattern,\n EventFilter,\n EventBusOptions,\n EventBusStats,\n} from './event-bus-types.js';\n\nimport {\n DEFAULT_MAX_HISTORY_SIZE,\n MAX_SUBSCRIPTIONS,\n type SubscriptionRecord,\n patternToRegex,\n topicMatchesPattern,\n generateEventId,\n generateSubscriptionId,\n applyHistoryFilters,\n applyHistoryLimit,\n enrichEvent,\n countMatchingSubscribers,\n} from './event-bus-helpers.js';\n\nimport { CircularBuffer } from '../../core/circular-buffer.js';\n\n// Re-export correlation ID helpers for public API\nexport { generateCorrelationId, createChildCorrelationId } from './event-bus-helpers.js';\n\n/**\n * Event Bus for agent-to-agent communication.\n *\n * Features:\n * - Topic-based pub/sub with wildcard support\n * - Async and sync event emission\n * - Event history with filtering\n * - Error isolation (one listener failure doesn't block others)\n *\n * @example\n * ```typescript\n * const bus = new EventBus();\n *\n * // Subscribe to all session events\n * const sub = bus.subscribe('session.*', (event) => {\n * console.log('Session event:', event.topic);\n * });\n *\n * // Emit an event\n * bus.emit(createSessionCreatedEvent({ sessionId: '123', ... }));\n *\n * // Cleanup\n * sub.unsubscribe();\n * ```\n */\nexport class EventBus implements IEventBus {\n private readonly subscriptions: Map<SubscriptionId, SubscriptionRecord> = new Map();\n private readonly history: CircularBuffer<DomainEvent>;\n private readonly asyncHandling: boolean;\n private readonly logger?: EventBusOptions['logger'];\n\n private stats: EventBusStats = {\n eventsEmitted: 0,\n subscriptionsCreated: 0,\n activeSubscriptions: 0,\n historySize: 0,\n errorCount: 0,\n };\n\n constructor(options: EventBusOptions = {}) {\n const maxHistorySize = options.maxHistorySize ?? DEFAULT_MAX_HISTORY_SIZE;\n this.history = new CircularBuffer<DomainEvent>(maxHistorySize);\n this.asyncHandling = options.asyncHandling ?? false;\n this.logger = options.logger;\n }\n\n /**\n * Emit an event synchronously to all matching subscribers.\n */\n emit(event: DomainEvent): void {\n const enrichedEvent = enrichEvent(event);\n this.addToHistory(enrichedEvent);\n this.stats.eventsEmitted++;\n\n this.logger?.debug('Event emitted', {\n topic: enrichedEvent.topic,\n eventId: enrichedEvent.eventId,\n subscriberCount: countMatchingSubscribers(enrichedEvent.topic, this.subscriptions),\n });\n\n for (const record of this.subscriptions.values()) {\n if (topicMatchesPattern(enrichedEvent.topic, record.regex)) {\n this.invokeListener(record, enrichedEvent);\n }\n }\n }\n\n /**\n * Emit an event and wait for all async handlers to complete.\n */\n async emitAsync(event: DomainEvent): Promise<void> {\n const enrichedEvent = enrichEvent(event);\n this.addToHistory(enrichedEvent);\n this.stats.eventsEmitted++;\n\n this.logger?.debug('Async event emitted', {\n topic: enrichedEvent.topic,\n eventId: enrichedEvent.eventId,\n });\n\n const promises: Promise<void>[] = [];\n\n for (const record of this.subscriptions.values()) {\n if (topicMatchesPattern(enrichedEvent.topic, record.regex)) {\n promises.push(this.invokeListenerAsync(record, enrichedEvent));\n }\n }\n\n await Promise.all(promises);\n }\n\n /**\n * Subscribe to events matching a topic pattern.\n */\n subscribe<T extends DomainEvent = DomainEvent>(\n pattern: TopicPattern,\n listener: EventListener<T>\n ): Subscription {\n if (this.subscriptions.size >= MAX_SUBSCRIPTIONS) {\n throw new Error(\n `Maximum subscription limit reached (${String(MAX_SUBSCRIPTIONS)}). ` +\n 'Unsubscribe from unused patterns before adding new ones.'\n );\n }\n\n const id = generateSubscriptionId();\n const regex = patternToRegex(pattern);\n\n const record: SubscriptionRecord = {\n id,\n pattern,\n regex,\n listener: listener as EventListener,\n };\n\n this.subscriptions.set(id, record);\n this.stats.subscriptionsCreated++;\n this.stats.activeSubscriptions = this.subscriptions.size;\n\n this.logger?.debug('Subscription created', { id, pattern });\n\n return {\n id,\n pattern,\n unsubscribe: () => {\n this.unsubscribe(id);\n },\n };\n }\n\n /**\n * Unsubscribe from events.\n */\n unsubscribe(subscriptionId: SubscriptionId): void {\n const existed = this.subscriptions.delete(subscriptionId);\n if (existed) {\n this.stats.activeSubscriptions = this.subscriptions.size;\n this.logger?.debug('Subscription removed', { subscriptionId });\n }\n }\n\n /**\n * Get event history matching filter criteria.\n */\n getHistory(filter?: EventFilter): readonly DomainEvent[] {\n const historyArray = this.history.toArray();\n if (filter === undefined) {\n return historyArray;\n }\n\n const filtered = applyHistoryFilters(historyArray, filter);\n return applyHistoryLimit(filtered, filter);\n }\n\n /**\n * Clear event history.\n */\n clearHistory(): void {\n this.history.clear();\n this.stats.historySize = 0;\n this.logger?.debug('History cleared');\n }\n\n /**\n * Get event bus statistics.\n */\n getStats(): EventBusStats {\n return { ...this.stats };\n }\n\n /**\n * Check if a topic pattern has any subscribers.\n */\n hasSubscribers(pattern: TopicPattern): boolean {\n const regex = patternToRegex(pattern);\n for (const record of this.subscriptions.values()) {\n // Check if the patterns could overlap\n if (\n topicMatchesPattern(pattern, record.regex) ||\n topicMatchesPattern(record.pattern, regex)\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Add event to history, maintaining size limit via O(1) circular buffer.\n * @see Issue #407 - Performance optimization\n */\n private addToHistory(event: DomainEvent): void {\n this.history.push(event);\n this.stats.historySize = this.history.size;\n }\n\n /**\n * Invoke a listener synchronously with error isolation.\n */\n private invokeListener(record: SubscriptionRecord, event: DomainEvent): void {\n try {\n const result = record.listener(event);\n // If async handling is enabled and listener returns a promise, don't wait\n if (this.asyncHandling && result instanceof Promise) {\n result.catch((error: unknown) => {\n this.handleListenerError(record, event, error);\n });\n }\n } catch (error) {\n this.handleListenerError(record, event, error);\n }\n }\n\n /**\n * Invoke a listener asynchronously.\n */\n private async invokeListenerAsync(record: SubscriptionRecord, event: DomainEvent): Promise<void> {\n try {\n await record.listener(event);\n } catch (error) {\n this.handleListenerError(record, event, error);\n }\n }\n\n /**\n * Handle listener errors without disrupting other listeners.\n */\n private handleListenerError(\n record: SubscriptionRecord,\n event: DomainEvent,\n error: unknown\n ): void {\n this.stats.errorCount++;\n const errorObj = error instanceof Error ? error : new Error(String(error));\n this.logger?.error('Event listener error', errorObj, {\n subscriptionId: record.id,\n pattern: record.pattern,\n eventTopic: event.topic,\n eventId: event.eventId,\n });\n }\n}\n\n/**\n * Create a singleton event bus instance for global coordination.\n * Use with caution - prefer dependency injection for testability.\n */\nlet globalBus: EventBus | null = null;\n\nexport function getGlobalEventBus(options?: EventBusOptions): EventBus {\n globalBus ??= new EventBus(options);\n return globalBus;\n}\n\n/**\n * Reset the global event bus (for testing).\n */\nexport function resetGlobalEventBus(): void {\n globalBus = null;\n}\n\n/**\n * Factory functions for creating typed events.\n */\nexport function createEvent<T extends DomainEvent>(\n topic: T['topic'],\n payload: T['payload'],\n options?: {\n sessionId?: string;\n correlationId?: string;\n }\n): T {\n return {\n eventId: generateEventId(),\n timestamp: getTimeProvider().nowIso(),\n topic,\n payload,\n sessionId: options?.sessionId,\n correlationId: options?.correlationId,\n } as T;\n}\n","/**\n * Event Bus Topic Constants\n *\n * Type-safe topic constants for event subscription.\n *\n * @module agents/collaboration/event-bus-topics\n * (Source: Issue #182, ARCHITECTURE.md Hybrid Architecture)\n */\n\n/**\n * Topic constants for type-safe subscription.\n */\nexport const EventTopics = {\n // Session events\n SESSION_CREATED: 'session.created',\n SESSION_STATUS_CHANGED: 'session.status_changed',\n SESSION_PARTICIPANT_JOINED: 'session.participant_joined',\n SESSION_RESULT_SUBMITTED: 'session.result_submitted',\n SESSION_FINALIZED: 'session.finalized',\n SESSION_ALL: 'session.*',\n\n // Message events\n MESSAGE_SENT: 'message.sent',\n MESSAGE_RECEIVED: 'message.received',\n MESSAGE_ALL: 'message.*',\n\n // Agent events\n AGENT_TASK_DELEGATED: 'agent.task_delegated',\n AGENT_RESULT_BROADCAST: 'agent.result_broadcast',\n AGENT_ALL: 'agent.*',\n\n // Consensus events\n CONSENSUS_VOTE_REQUESTED: 'consensus.vote_requested',\n CONSENSUS_VOTE_CAST: 'consensus.vote_cast',\n CONSENSUS_REACHED: 'consensus.reached',\n CONSENSUS_ALL: 'consensus.*',\n\n // Protocol events\n PROTOCOL_STARTED: 'protocol.started',\n PROTOCOL_ITERATION: 'protocol.iteration',\n PROTOCOL_COMPLETED: 'protocol.completed',\n PROTOCOL_ALL: 'protocol.*',\n\n // Aegean phase events (Issue #216)\n AEGEAN_ROUND_STARTED: 'protocol.aegean.round_started',\n AEGEAN_VOTE_COLLECTED: 'protocol.aegean.vote_collected',\n AEGEAN_QUORUM_DETECTED: 'protocol.aegean.quorum_detected',\n AEGEAN_ALL: 'protocol.aegean.*',\n\n // Reflexion phase events (Issue #216)\n REFLEXION_CRITIQUE_STARTED: 'protocol.reflexion.critique_started',\n REFLEXION_CRITIQUE_COMPLETED: 'protocol.reflexion.critique_completed',\n REFLEXION_SYNTHESIS: 'protocol.reflexion.synthesis',\n REFLEXION_ALL: 'protocol.reflexion.*',\n\n // Trinity phase events (Issue #216)\n TRINITY_PHASE_STARTED: 'protocol.trinity.phase_started',\n TRINITY_PHASE_COMPLETED: 'protocol.trinity.phase_completed',\n TRINITY_ALL: 'protocol.trinity.*',\n\n // Byzantine detection events (Issue #218)\n BYZANTINE_WEIGHT_UPDATED: 'byzantine.weight_updated',\n BYZANTINE_PATTERN_DETECTED: 'byzantine.pattern_detected',\n BYZANTINE_AGENT_FLAGGED: 'byzantine.agent_flagged',\n BYZANTINE_COLLUSION_SUSPECTED: 'byzantine.collusion_suspected',\n BYZANTINE_ALL: 'byzantine.*',\n\n // Wildcard\n ALL: '*',\n} as const;\n","/**\n * Resilient Model Adapter\n *\n * Transparent proxy implementing IModelAdapter with lazy detection,\n * automatic failover on circuit breaker events, and observable health.\n *\n * Key design: ResilientAdapter IS an IModelAdapter. Every existing consumer\n * works unchanged. The health/failover API lives on IResilientAdapter for\n * dashboard and monitoring consumers only.\n *\n * @module adapters/resilient-adapter\n * (Source: Issue #811 - Resilient model adapter architecture)\n */\n\nimport type {\n IModelAdapter,\n CompletionRequest,\n CompletionResponse,\n StreamChunk,\n ModelCapability,\n} from '../core/types/model.js';\nimport type { Result } from '../core/result.js';\nimport { ok, err } from '../core/result.js';\nimport { ModelError, ConfigError } from '../core/errors.js';\nimport type { ILogger } from '../core/index.js';\nimport { getTimeProvider, getRandomProvider } from '../core/index.js';\nimport { getErrorMessage, createLogger } from '../core/index.js';\n\nimport { createAutoAdapter, type AdapterSelection } from './auto-adapter.js';\nimport {\n isRateLimitLikeError,\n toRateLimitError,\n recordRateLimitEvent,\n} from './rate-limit-detector.js';\nimport type { CliName } from '../cli-adapters/types.js';\nimport type {\n IResilientAdapter,\n AdapterHealthInfo,\n ResilientAdapterConfig,\n} from './resilient-adapter-types.js';\nimport type { CircuitStateChangeEvent } from '../cli-adapters/circuit-breaker-types.js';\nimport type { CircuitBreakerRegistry } from '../cli-adapters/circuit-breaker.js';\nimport { mapModelErrorToCategory } from '../cli-adapters/circuit-breaker.js';\nimport { getGlobalEventBus } from '../core/event-bus.js';\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Creates a resilient adapter with lazy detection and automatic failover.\n *\n * @example\n * ```typescript\n * const adapter = createResilientAdapter({ logger });\n * // No detection at creation time — detection happens on first use\n * const result = await adapter.complete(request); // triggers detection\n * ```\n */\nexport function createResilientAdapter(config?: ResilientAdapterConfig): IResilientAdapter {\n return new ResilientAdapter(config);\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Resilient adapter proxy. Implements IModelAdapter transparently.\n */\nexport class ResilientAdapter implements IResilientAdapter {\n private readonly logger: ILogger;\n private currentAdapter: IModelAdapter | undefined;\n private currentSelection: AdapterSelection | undefined;\n private hasEverDetected = false;\n private health: AdapterHealthInfo | undefined;\n private preferredCli: CliName | undefined;\n private readonly failoverCallbacks = new Set<(info: AdapterHealthInfo) => void>();\n private circuitBreakerRegistry: CircuitBreakerRegistry | undefined;\n private circuitListener: ((event: CircuitStateChangeEvent) => void) | undefined;\n private disposed = false;\n private readonly defaultCliTimeoutMs: number | undefined;\n /** Inflight detection promise for coalescing concurrent calls (Issue #1423). */\n private detectionPromise: Promise<IModelAdapter | undefined> | undefined;\n\n constructor(config?: ResilientAdapterConfig) {\n this.logger = config?.logger ?? createLogger({ component: 'resilient-adapter' });\n this.preferredCli = config?.preferredCli;\n this.defaultCliTimeoutMs = config?.defaultCliTimeoutMs;\n }\n\n // --- IModelAdapter properties (forwarded) ---\n\n get providerId(): string {\n return this.currentAdapter?.providerId ?? 'resilient-proxy';\n }\n\n get modelId(): string {\n return this.currentAdapter?.modelId ?? 'pending-detection';\n }\n\n get capabilities(): readonly ModelCapability[] {\n return this.currentAdapter?.capabilities ?? [];\n }\n\n // --- IModelAdapter methods ---\n\n async complete(request: CompletionRequest): Promise<Result<CompletionResponse, ModelError>> {\n const adapter = await this.ensureAdapter();\n if (adapter === undefined) {\n return err(new ModelError('No model adapter available'));\n }\n const result = await adapter.complete(request);\n if (!result.ok) {\n if (isRateLimitLikeError(result.error)) {\n const rlError = toRateLimitError(result.error, adapter.providerId);\n recordRateLimitEvent({\n provider: adapter.providerId,\n timestamp: getTimeProvider().now(),\n retryAfterMs: rlError.retryAfterMs,\n });\n this.logger.warn('Rate limit detected', {\n provider: adapter.providerId,\n retryAfterMs: rlError.retryAfterMs,\n });\n }\n this.recordBreakerFailure(adapter, result.error);\n }\n return result;\n }\n\n async *stream(request: CompletionRequest): AsyncIterable<StreamChunk> {\n const adapter = await this.ensureAdapter();\n if (adapter === undefined) {\n // #3105: error like complete() rather than yielding an empty stream — a\n // silent-empty stream masks \"no adapter available\" as a clean empty\n // completion, so streamWithFallback can't tell failure from a\n // legitimately-empty result.\n throw new ModelError('No model adapter available');\n }\n yield* adapter.stream(request);\n }\n\n async countTokens(text: string): Promise<number> {\n const adapter = await this.ensureAdapter();\n if (adapter === undefined) {\n return 0;\n }\n return adapter.countTokens(text);\n }\n\n validateConfig(): Result<void, ConfigError> {\n if (this.currentAdapter !== undefined) {\n return this.currentAdapter.validateConfig();\n }\n // Before first use, config is trivially valid\n return ok(undefined);\n }\n\n // --- IResilientAdapter methods ---\n\n getHealth(): AdapterHealthInfo | undefined {\n return this.health;\n }\n\n async refresh(): Promise<void> {\n this.currentAdapter = undefined;\n this.currentSelection = undefined;\n this.detectionPromise = undefined;\n await this.ensureAdapter();\n }\n\n setPreferredCli(cli: CliName | undefined): void {\n this.preferredCli = cli;\n this.currentAdapter = undefined;\n this.currentSelection = undefined;\n }\n\n onFailover(cb: (info: AdapterHealthInfo) => void): () => void {\n this.failoverCallbacks.add(cb);\n return () => {\n this.failoverCallbacks.delete(cb);\n };\n }\n\n /**\n * Attach a circuit breaker registry for automatic failover.\n * When the current adapter's circuit opens, the cached adapter\n * is cleared so the next call triggers re-detection.\n */\n attachCircuitBreakerRegistry(registry: CircuitBreakerRegistry): void {\n this.detachCircuitBreakerRegistry();\n this.circuitBreakerRegistry = registry;\n this.circuitListener = (event: CircuitStateChangeEvent) => {\n this.handleCircuitStateChange(event);\n };\n registry.addGlobalStateChangeListener(this.circuitListener);\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.detachCircuitBreakerRegistry();\n this.failoverCallbacks.clear();\n }\n\n // --- Private methods ---\n\n private async ensureAdapter(): Promise<IModelAdapter | undefined> {\n if (this.currentAdapter !== undefined) {\n return this.currentAdapter;\n }\n // Coalesce concurrent detection calls into a single probe (Issue #1423)\n this.detectionPromise ??= this.detectAdapter().finally(() => {\n this.detectionPromise = undefined;\n });\n return this.detectionPromise;\n }\n\n private async detectAdapter(): Promise<IModelAdapter | undefined> {\n try {\n this.logger.info('Detecting model adapter (lazy)');\n const config = {\n logger: this.logger,\n ...(this.preferredCli !== undefined && { preferredCli: this.preferredCli }),\n ...(this.defaultCliTimeoutMs !== undefined && {\n defaultCliTimeoutMs: this.defaultCliTimeoutMs,\n }),\n };\n const selection = await createAutoAdapter(config);\n this.applySelection(selection);\n return this.currentAdapter;\n } catch (error) {\n const message = getErrorMessage(error);\n this.logger.warn('No model adapter available', { error: message });\n this.health = {\n source: 'api',\n state: 'unavailable',\n selectedAt: new Date(),\n failoverCount: this.health?.failoverCount ?? 0,\n lastError: message,\n };\n return undefined;\n }\n }\n\n private applySelection(selection: AdapterSelection): void {\n const isFailover = this.hasEverDetected;\n this.currentAdapter = selection.adapter;\n this.currentSelection = selection;\n this.hasEverDetected = true;\n\n const source = mapSelectionSource(selection);\n const failoverCount = (this.health?.failoverCount ?? 0) + (isFailover ? 1 : 0);\n\n this.health = {\n source,\n state: 'healthy',\n selectedAt: new Date(),\n failoverCount,\n };\n\n this.logger.info('Adapter selected', {\n source: selection.source,\n name: selection.name,\n model: selection.adapter.modelId,\n provider: selection.adapter.providerId,\n failover: isFailover,\n });\n\n if (isFailover) {\n this.emitFailover();\n }\n }\n\n /**\n * Record a direct-API failure to the circuit breaker so API adapters get the\n * same degradation/failover learning that CLI subprocess failures get (#3423).\n *\n * The breaker key is `currentSelection.name` — distinct from the `api:<vendor>`\n * arm key used by the ModelToCliAdapter path (#3422), so the two paths never\n * double-count the same failure.\n *\n * Rate-limit failures are deliberately skipped here: they are already recorded\n * by the `recordRateLimitEvent` telemetry branch in `complete()`, and the\n * breaker counts rate limits as failures by default\n * (`countRateLimitsAsFailures`), so recording them again would double-count.\n *\n * Security (#3422 constraint): the logged payload carries only `provider` and\n * `category` — never `error.message`, the request, or the ModelError object,\n * any of which could embed credentials.\n */\n private recordBreakerFailure(adapter: IModelAdapter, error: ModelError): void {\n if (this.circuitBreakerRegistry === undefined || this.currentSelection === undefined) {\n return;\n }\n\n const category = mapModelErrorToCategory(error);\n // Skip rate limits: already accounted for by the rate-limit telemetry branch\n // (and the breaker counts them by default). Check BOTH the mapped category\n // AND the telemetry predicate — their rate-limit pattern lists differ\n // (`isRateLimitLikeError` matches \"quota exceeded\"/\"throttl\"/… that\n // `categorizeError` does not), so a code-less MODEL_ERROR could otherwise\n // fire the telemetry branch yet fall through to a counted failure here,\n // double-counting against the threshold (#3423 review).\n if (category === 'rate_limit' || isRateLimitLikeError(error)) {\n return;\n }\n\n this.circuitBreakerRegistry\n .getBreaker(this.currentSelection.name as CliName)\n .recordFailure(category);\n\n this.logger.warn('API failure recorded to circuit breaker', {\n provider: adapter.providerId,\n category,\n });\n }\n\n private handleCircuitStateChange(event: CircuitStateChangeEvent): void {\n if (event.newState !== 'open') return;\n\n const currentSource = this.currentSelection?.name;\n if (currentSource === undefined || currentSource !== event.cliName) {\n return; // Not our current adapter\n }\n\n this.logger.warn('Current adapter circuit opened, clearing cache for re-detection', {\n cli: event.cliName,\n reason: event.reason,\n });\n\n this.currentAdapter = undefined;\n this.currentSelection = undefined;\n\n if (this.health !== undefined) {\n this.health = {\n ...this.health,\n state: 'degraded',\n lastError: event.reason,\n };\n }\n }\n\n private emitFailover(): void {\n const info = this.health;\n if (info === undefined) return;\n\n for (const cb of this.failoverCallbacks) {\n try {\n cb(info);\n } catch (error: unknown) {\n this.logger.debug('Failover callback error', { error: getErrorMessage(error) });\n }\n }\n\n try {\n const eventBus = getGlobalEventBus();\n eventBus.emit({\n eventId: `failover-${getTimeProvider().now().toString(36)}-${getRandomProvider().random().toString(36).slice(2, 8)}`,\n timestamp: new Date().toISOString(),\n topic: 'adapter.failover',\n payload: info,\n });\n } catch (error: unknown) {\n this.logger.debug('EventBus emit failed during failover', {\n error: getErrorMessage(error),\n });\n }\n }\n\n private detachCircuitBreakerRegistry(): void {\n if (this.circuitBreakerRegistry !== undefined && this.circuitListener !== undefined) {\n this.circuitBreakerRegistry.removeGlobalStateChangeListener(this.circuitListener);\n }\n this.circuitBreakerRegistry = undefined;\n this.circuitListener = undefined;\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction mapSelectionSource(selection: AdapterSelection): CliName | 'api' {\n if (selection.source === 'cli') {\n return selection.name as CliName;\n }\n return 'api';\n}\n","/**\n * withModelNotFoundFallback (#2540 PR 8 of 8).\n *\n * Wraps an `IModelAdapter` so that calls that fail with `MODEL_NOT_FOUND`\n * (404 / \"model is deprecated\" / etc.) are retried once with the closest\n * available alternative from the same vendor family — picked from the\n * adapter's `listModels()` and the registry.\n *\n * Why this exists: nexus-agents has historically baked model ids into\n * configuration. When a vendor retires a model (Codex on GPT-5.4 vs an\n * older 5.1, Claude bumping minor versions, etc.), the next request 404s.\n * This primitive turns that 404 into a single observable retry against\n * the latest sibling — operators see the retirement in the log, work\n * keeps moving, and the cache (PR 6) is invalidated so subsequent calls\n * pick up the new ground truth.\n *\n * Design notes:\n * - Single retry only. If the fallback also 404s, surface the second\n * error (callers can escalate). Don't loop — that risks wedging.\n * - The wrapper keeps the same `providerId`/`modelId` shape as the\n * wrapped adapter so downstream consumers (telemetry, OutcomeStore)\n * don't see schema changes. The chosen fallback id appears in\n * `errorMessage` of the original error and in the logger.\n * - `stream()` is left as passthrough — streaming retries belong in\n * a future iteration where partial-result reconciliation is handled.\n */\n\nimport type {\n CompletionRequest,\n CompletionResponse,\n IModelAdapter,\n ModelError,\n Result,\n StreamChunk,\n} from '../core/index.js';\nimport { err, ErrorCode, ok, ModelError as ModelErrorClass } from '../core/index.js';\nimport { createLogger } from '../core/logger.js';\nimport { getDefaultRegistry, type ModelRegistry } from '../config/model-registry.js';\nimport {\n type AvailableModelsCache,\n getDefaultAvailableModelsCache,\n} from '../config/available-models-cache.js';\n\nconst logger = createLogger({ component: 'model-not-found-fallback' });\n\nexport interface ModelNotFoundFallbackOptions {\n /**\n * Process-local cache of routable models. Refreshed on a 404. Defaults\n * to `getDefaultAvailableModelsCache()` — passing one explicitly is the\n * right move for tests and for multi-cache topologies.\n */\n readonly cache?: AvailableModelsCache;\n /** Registry used to resolve vendor/family from a model id. Defaults to global. */\n readonly registry?: ModelRegistry;\n /**\n * Optional adapter factory used to build a new IModelAdapter for the\n * fallback model id. When provided, the wrapper retries through the\n * factory's adapter. When omitted, the wrapper logs + emits a\n * `MODEL_NOT_FOUND` error enriched with the suggested fallback id —\n * the caller (orchestrator / router) is responsible for re-routing.\n */\n readonly adapterFactory?: (modelId: string) => IModelAdapter;\n /**\n * Optional callback invoked when a retirement is detected. Use for\n * telemetry / sticky-state updates. Failures in the callback are\n * swallowed — the user's call is what matters.\n */\n readonly onRetirement?: (info: RetirementInfo) => void;\n}\n\nexport interface RetirementInfo {\n readonly retiredModelId: string;\n readonly fallbackModelId: string;\n readonly providerId: string;\n readonly errorMessage: string;\n}\n\n/**\n * Decorate an IModelAdapter with retire-and-retry. Behaviour:\n *\n * 1. Forward `complete(request)` to the inner adapter.\n * 2. On `MODEL_NOT_FOUND`: refresh the cache, find the closest\n * same-family alternative, retry once with `request.model =\n * <fallback>`. Original error is returned if no fallback found.\n * 3. The wrapper returns the SECOND error if the retry also fails.\n * 4. `stream()` retries via restart-from-zero (#2550): when the inner\n * stream throws a `MODEL_NOT_FOUND` ModelError, the wrapper closes\n * the failed stream, picks a same-family fallback via the cache +\n * registry, builds a new adapter through `adapterFactory`, and\n * yields chunks from the fallback stream. The consumer sees a clean\n * second stream — partial content already delivered by the first\n * stream is NOT replayed; that's a known trade-off (the alternative\n * resume-with-reconciliation strategy is heavier and only useful\n * for tool-use loops; not implemented per the deliberate scoping in\n * #2550). Without `adapterFactory`, the original throw propagates\n * unchanged.\n * 5. `countTokens`, `validateConfig`, `listModels` are passthrough.\n */\nexport function withModelNotFoundFallback(\n inner: IModelAdapter,\n options: ModelNotFoundFallbackOptions = {}\n): IModelAdapter {\n const registry = options.registry ?? getDefaultRegistry();\n const cache = options.cache ?? getDefaultAvailableModelsCache();\n const resolvedOptions: ResolvedOptions = {\n cache,\n registry,\n adapterFactory: options.adapterFactory,\n onRetirement: options.onRetirement,\n };\n const wrapped: IModelAdapter = {\n providerId: inner.providerId,\n modelId: inner.modelId,\n capabilities: inner.capabilities,\n countTokens: (text) => inner.countTokens(text),\n validateConfig: () => inner.validateConfig(),\n stream: (request: CompletionRequest): AsyncIterable<StreamChunk> =>\n streamWithFallback(inner, request, resolvedOptions),\n complete: (request: CompletionRequest) => completeWithFallback(inner, request, resolvedOptions),\n };\n if (typeof inner.listModels === 'function') {\n const list = inner.listModels.bind(inner);\n wrapped.listModels = () => list();\n }\n return wrapped;\n}\n\ninterface ResolvedOptions {\n readonly cache: AvailableModelsCache;\n readonly registry: ModelRegistry;\n readonly adapterFactory?: ((modelId: string) => IModelAdapter) | undefined;\n readonly onRetirement?: ((info: RetirementInfo) => void) | undefined;\n}\n\nasync function completeWithFallback(\n inner: IModelAdapter,\n request: CompletionRequest,\n options: ResolvedOptions\n): Promise<Result<CompletionResponse, ModelError>> {\n const first = await inner.complete(request);\n if (first.ok) return first;\n if (first.error.code !== ErrorCode.MODEL_NOT_FOUND) return first;\n\n const fallback = await pickFallback(inner.modelId, options.cache, options.registry);\n if (fallback === null) {\n logger.warn('Model not found and no fallback available', {\n modelId: inner.modelId,\n providerId: inner.providerId,\n errorMessage: first.error.message,\n });\n return first;\n }\n\n logger.info('Model retirement detected; retrying with fallback', {\n retiredModelId: inner.modelId,\n fallbackModelId: fallback,\n providerId: inner.providerId,\n });\n notifyRetirement(options.onRetirement, {\n retiredModelId: inner.modelId,\n fallbackModelId: fallback,\n providerId: inner.providerId,\n errorMessage: first.error.message,\n });\n\n // No factory wired → enrich the original error with a suggested\n // fallback id and let the caller decide. This is the safe default\n // for adapters where reconfiguring per-call isn't supported.\n if (options.adapterFactory === undefined) {\n return err(\n new ModelErrorClass(`${first.error.message} — suggested fallback: ${fallback}`, {\n code: ErrorCode.MODEL_NOT_FOUND,\n cause: first.error,\n })\n );\n }\n\n const fallbackAdapter = options.adapterFactory(fallback);\n const retried = await fallbackAdapter.complete(request);\n if (retried.ok) return retried;\n // Surface the SECOND error so callers see the retry's failure\n // mode, not the (already-handled) original 404.\n return err(\n new ModelErrorClass(`Fallback ${fallback} also failed: ${retried.error.message}`, {\n code: retried.error.code,\n cause: retried.error,\n })\n );\n}\n\n/**\n * Restart-from-zero streaming retry on MODEL_NOT_FOUND (#2550).\n *\n * Iterates the inner stream; if it throws a `ModelError` with code\n * `MODEL_NOT_FOUND`, refreshes the cache, picks a same-family fallback,\n * builds a new adapter via `adapterFactory`, and yields chunks from\n * the fallback stream. The consumer sees a clean second stream — any\n * partial content already delivered by the first stream is NOT\n * replayed; that's the documented trade-off of restart-from-zero\n * (alternative resume-with-reconciliation strategy is heavier and\n * deferred per #2550's scope decision).\n *\n * Without `adapterFactory` the original throw propagates unchanged —\n * the wrapper has no way to construct the retry adapter, so the\n * consumer can re-route at a higher layer if it wants.\n */\nasync function* streamWithFallback(\n inner: IModelAdapter,\n request: CompletionRequest,\n options: ResolvedOptions\n): AsyncGenerator<StreamChunk> {\n try {\n for await (const chunk of inner.stream(request)) {\n yield chunk;\n }\n return;\n } catch (e: unknown) {\n if (!isModelNotFoundError(e)) throw e;\n const fallbackAdapter = await resolveStreamFallback(inner, e, options);\n // Restart-from-zero: the consumer gets a fresh stream starting from\n // the first chunk. Any partial chunks the inner stream already\n // yielded are NOT replayed.\n for await (const chunk of fallbackAdapter.stream(request)) {\n yield chunk;\n }\n }\n}\n\n/**\n * Pick a same-family fallback model, run the retirement callback, and\n * return the constructed fallback adapter. Throws (with appropriate\n * enrichment) when no factory is wired or no fallback is available.\n */\nasync function resolveStreamFallback(\n inner: IModelAdapter,\n cause: unknown,\n options: ResolvedOptions\n): Promise<IModelAdapter> {\n const fallback = await pickFallback(inner.modelId, options.cache, options.registry);\n if (fallback === null) {\n logger.warn('Stream model not found and no fallback available', {\n modelId: inner.modelId,\n providerId: inner.providerId,\n errorMessage: cause instanceof Error ? cause.message : String(cause),\n });\n throw cause;\n }\n\n logger.info('Stream retirement detected; restarting with fallback (restart-from-zero)', {\n retiredModelId: inner.modelId,\n fallbackModelId: fallback,\n providerId: inner.providerId,\n });\n notifyRetirement(options.onRetirement, {\n retiredModelId: inner.modelId,\n fallbackModelId: fallback,\n providerId: inner.providerId,\n errorMessage: cause instanceof Error ? cause.message : String(cause),\n });\n\n if (options.adapterFactory === undefined) {\n // No factory wired → can't construct the retry adapter. Re-throw\n // with the original error enriched so callers at a higher layer\n // can attempt their own re-routing.\n const message = `${cause instanceof Error ? cause.message : String(cause)} — suggested fallback: ${fallback}`;\n const causeErr = cause instanceof Error ? cause : undefined;\n throw new ModelErrorClass(\n message,\n causeErr !== undefined\n ? { code: ErrorCode.MODEL_NOT_FOUND, cause: causeErr }\n : { code: ErrorCode.MODEL_NOT_FOUND }\n );\n }\n\n return options.adapterFactory(fallback);\n}\n\nfunction isModelNotFoundError(e: unknown): boolean {\n if (e instanceof ModelErrorClass) {\n return e.code === ErrorCode.MODEL_NOT_FOUND;\n }\n // Some adapters throw a plain Error with the code as a string property.\n if (typeof e === 'object' && e !== null && 'code' in e) {\n return e.code === ErrorCode.MODEL_NOT_FOUND;\n }\n return false;\n}\n\nfunction notifyRetirement(\n cb: ((info: RetirementInfo) => void) | undefined,\n info: RetirementInfo\n): void {\n if (cb === undefined) return;\n try {\n cb(info);\n } catch (e: unknown) {\n logger.debug('onRetirement callback threw', {\n error: e instanceof Error ? e.message : String(e),\n });\n }\n}\n\n/**\n * Pick the closest available alternative to a retired model. Strategy:\n * 1. Refresh the cache (the retirement signal is authoritative).\n * 2. Resolve the retired id's vendor + family via the registry.\n * 3. Among the now-available ids, take the first match in the same\n * family. If none match family, fall back to vendor.\n * 4. If still nothing, return null — surfaces the original error.\n *\n * Deliberately simple — picking the \"best\" sibling deserves its own\n * scoring/ranking pass; here we just need ANY same-family id to keep\n * the user moving. Caller logs both ids so the behaviour is auditable.\n */\nasync function pickFallback(\n retiredModelId: string,\n cache: AvailableModelsCache,\n registry: ModelRegistry\n): Promise<string | null> {\n const refreshed = await cache.refresh();\n if (refreshed.length === 0) return null;\n const target = registry.getEntry(retiredModelId);\n\n const sameFamily = refreshed.find((m) => {\n if (m.id === retiredModelId) return false;\n const candidate = registry.getEntry(m.id);\n return candidate.family === target.family && candidate.vendor === target.vendor;\n });\n if (sameFamily !== undefined) return sameFamily.id;\n\n const sameVendor = refreshed.find((m) => {\n if (m.id === retiredModelId) return false;\n const candidate = registry.getEntry(m.id);\n return candidate.vendor === target.vendor;\n });\n return sameVendor?.id ?? null;\n}\n\n// Re-export ok for tests that synthesise success results.\nexport { ok };\n\n// ============================================================================\n// Resilient-adapter aware wrapper (#2549).\n//\n// `withModelNotFoundFallback` returns an `IModelAdapter` — fine for direct-API\n// adapters that satisfy that surface directly. For `IResilientAdapter` callers\n// who also depend on `getHealth` / `refresh` / `setPreferredCli` / `onFailover`\n// / `dispose`, this helper preserves those methods while routing `complete()`\n// through the fallback path.\n// ============================================================================\n\n/**\n * Minimal shape of `IResilientAdapter` — duplicated here as a local\n * type so that `model-not-found-fallback.ts` doesn't acquire a circular\n * import with `adapters/resilient-adapter-types.ts`. The shape matches\n * the resilient adapter's extension methods over `IModelAdapter`.\n */\nexport interface ResilientLike extends IModelAdapter {\n getHealth(): unknown;\n refresh(): Promise<void>;\n setPreferredCli(cli: unknown): void;\n onFailover(cb: (info: unknown) => void): () => void;\n dispose(): void;\n}\n\n/**\n * Wrap an `IResilientAdapter` (or anything that satisfies `ResilientLike`)\n * so its `complete()` path retries on MODEL_NOT_FOUND while its\n * health/lifecycle methods continue to work unchanged.\n */\nexport function wrapResilientWithFallback<T extends ResilientLike>(\n inner: T,\n options: ModelNotFoundFallbackOptions = {}\n): T {\n const wrapped = withModelNotFoundFallback(inner, options);\n // Closes #2945: pre-fix the `Object.assign(..., {5 methods}) as unknown as T`\n // pattern silently dropped any methods on a concrete T beyond the 5\n // explicitly re-attached. A future IResilientAdapter subtype adding\n // `getMetrics()` would type-check but throw `TypeError: x.getMetrics\n // is not a function` at runtime. Switched to a Proxy that forwards\n // unknown property access to `inner`, so methods on T not anticipated\n // by this wrapper remain transparently available.\n //\n // The five explicit bindings are kept so existing health/lifecycle\n // methods are pre-bound (avoids losing `this` if the caller\n // destructures), matching the prior semantics for the existing surface.\n const surface = {\n getHealth: inner.getHealth.bind(inner),\n refresh: inner.refresh.bind(inner),\n setPreferredCli: inner.setPreferredCli.bind(inner),\n onFailover: inner.onFailover.bind(inner),\n dispose: inner.dispose.bind(inner),\n };\n const explicit: ResilientLike = Object.assign(wrapped, surface);\n const innerAsRecord = inner as unknown as Record<PropertyKey, unknown>;\n return new Proxy(explicit, {\n get(target, prop, receiver): unknown {\n if (prop in target) return Reflect.get(target, prop, receiver);\n // Forward unknown reads to `inner` — covers future methods on T.\n // Bind functions so call-site `this` is the inner adapter, matching\n // the explicit-binding behavior above.\n const innerProp: unknown = innerAsRecord[prop];\n if (typeof innerProp === 'function') {\n return (innerProp as (...args: unknown[]) => unknown).bind(inner);\n }\n return innerProp;\n },\n }) as unknown as T;\n}\n","/**\n * Unified Adapter Registry — single entry point for all model adapter access.\n *\n * Pre-computes task-to-CLI routing from the canonical model registry and\n * task specialization matrix at creation time. All consumers get adapters\n * through this registry instead of calling createAutoAdapter/createResilientAdapter\n * directly.\n *\n * Design:\n * - One IResilientAdapter per CLI (claude/gemini/codex), created lazily on first access\n * - One \"default\" adapter for unscoped requests (uses createAutoAdapter priority)\n * - Task routing is deterministic: category → primary CLI → cached adapter\n * - Session-scoped: create once at MCP startup, reuse for the session lifetime\n *\n * @module adapters/unified-registry\n * (Source: Issue #1149 — Unified Adapter Registry)\n * (Source: Issue #1151 — Single adapter entry point)\n */\n\nimport type { ILogger } from '../core/index.js';\nimport { createLogger } from '../core/index.js';\nimport { createResilientAdapter } from './resilient-adapter.js';\nimport type { IResilientAdapter } from './resilient-adapter-types.js';\nimport {\n wrapResilientWithFallback,\n type ModelNotFoundFallbackOptions,\n} from './model-not-found-fallback.js';\nimport type { CliName } from '../cli-adapters/types.js';\nimport { TASK_SPECIALIZATION_MATRIX, detectTaskCategory } from '../config/task-specialization.js';\nimport type { TaskCategory } from '../config/task-specialization-types.js';\nimport {\n getDefaultModelForCli,\n getInTreeCapabilitiesMatrix,\n} from '../config/model-config-helpers.js';\nimport type { CliNameLiteral } from '../config/model-capabilities-types.js';\nimport { CLI_NAMES } from '../config/model-capabilities-types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Configuration for the unified registry. */\nexport interface UnifiedRegistryConfig {\n /** Logger instance */\n readonly logger?: ILogger;\n /** Default CLI timeout for subprocess calls (ms) */\n readonly defaultCliTimeoutMs?: number;\n /**\n * Auto-wrap every constructed adapter with `withModelNotFoundFallback`\n * (#2549). When enabled, the registry routes `complete()` through the\n * fallback path so a `MODEL_NOT_FOUND` error (typically from a vendor\n * 404 / \"model deprecated\" message) refreshes the AvailableModelsCache\n * and retries through the closest same-family alternative.\n *\n * Defaults to `false` — operators opt in by wiring up an\n * `AvailableModelsCache` via `setDefaultAvailableModelsCache()` and\n * setting this flag. Safe-on-empty: if no cache is provided or the\n * cache has no sources, the wrap is transparent (no retry happens,\n * original error surfaces).\n */\n readonly enableMissingModelFallback?: boolean;\n /**\n * Optional override for the fallback decorator. When omitted, the\n * decorator uses `getDefaultAvailableModelsCache()` and\n * `getDefaultRegistry()`.\n */\n readonly missingModelFallbackOptions?: ModelNotFoundFallbackOptions;\n}\n\n/** Summary of the pre-computed task routing table. */\nexport interface TaskRoutingEntry {\n readonly category: TaskCategory;\n readonly primaryCli: CliName;\n readonly secondaryCli: CliName;\n readonly primaryModel: string;\n}\n\n/** Snapshot of registry state for observability. */\nexport interface RegistrySnapshot {\n readonly taskRouting: readonly TaskRoutingEntry[];\n readonly cachedAdapters: readonly CliName[];\n readonly availableModels: number;\n}\n\n// ============================================================================\n// Registry\n// ============================================================================\n\n/**\n * Unified adapter registry. Centralizes all adapter creation and task routing.\n *\n * Usage:\n * ```typescript\n * const registry = createUnifiedRegistry({ logger });\n * const adapter = registry.getAdapter('code_generation'); // → codex adapter\n * const adapter2 = registry.getAdapterForCli('claude'); // → claude adapter\n * const adapter3 = registry.getDefault(); // → best available\n * ```\n */\n\n/**\n * Defaults `onRetirement` to a logging callback when the fallback is enabled, so\n * model retirements are observable rather than silent (the callback was a\n * declared-but-unwired bridge — system review). Callers can still override it.\n * Returns the options unchanged when the fallback is disabled.\n */\nexport function withDefaultOnRetirement(\n enabled: boolean,\n options: ModelNotFoundFallbackOptions | undefined,\n logger: ILogger\n): ModelNotFoundFallbackOptions | undefined {\n if (!enabled) return options;\n return {\n ...options,\n onRetirement:\n options?.onRetirement ??\n ((info): void => {\n logger.warn('Model retired via not-found fallback', { retirement: info });\n }),\n };\n}\n\nexport class UnifiedAdapterRegistry {\n private readonly logger: ILogger;\n private readonly defaultCliTimeoutMs: number | undefined;\n private readonly enableMissingModelFallback: boolean;\n private readonly missingModelFallbackOptions: ModelNotFoundFallbackOptions | undefined;\n\n /** Per-CLI adapter cache — max 3 entries (claude/gemini/codex). */\n private readonly cliAdapters = new Map<CliName, IResilientAdapter>();\n\n /** Default adapter for unscoped requests. */\n private defaultAdapter: IResilientAdapter | undefined;\n\n constructor(config?: UnifiedRegistryConfig) {\n this.logger = config?.logger ?? createLogger({ component: 'unified-registry' });\n this.defaultCliTimeoutMs = config?.defaultCliTimeoutMs;\n this.enableMissingModelFallback = config?.enableMissingModelFallback ?? false;\n this.missingModelFallbackOptions = withDefaultOnRetirement(\n this.enableMissingModelFallback,\n config?.missingModelFallbackOptions,\n this.logger\n );\n this.logger.info('UnifiedAdapterRegistry initialized', {\n categories: TASK_SPECIALIZATION_MATRIX.length,\n models: getInTreeCapabilitiesMatrix().models.length,\n missingModelFallback: this.enableMissingModelFallback,\n });\n }\n\n /**\n * Apply the MODEL_NOT_FOUND fallback decorator if enabled, otherwise\n * return the adapter unchanged. The recursion guard from the original\n * issue is unnecessary here: the decorator's retry path uses the\n * caller-supplied `adapterFactory`; without one, it surfaces an\n * enriched error and never re-enters the resilient layer.\n */\n private maybeWrap(adapter: IResilientAdapter): IResilientAdapter {\n if (!this.enableMissingModelFallback) return adapter;\n return wrapResilientWithFallback(adapter, this.missingModelFallbackOptions);\n }\n\n // --------------------------------------------------------------------------\n // Public API\n // --------------------------------------------------------------------------\n\n /** Logger used by this registry. Exposed so singleton helpers can warn. */\n getLogger(): ILogger {\n return this.logger;\n }\n\n /**\n * Get adapter for a task category. Routing is re-resolved on every read\n * (#3185) so a post-startup overlay/registry update propagates without a\n * restart. Falls back to default adapter if category unknown.\n */\n getAdapter(category: TaskCategory): IResilientAdapter {\n const routing = this.getRouting(category);\n if (routing === undefined) {\n this.logger.warn('Unknown task category, using default', { category });\n return this.getDefault();\n }\n return this.getAdapterForCli(routing.primaryCli);\n }\n\n /**\n * Get adapter for a free-text task description.\n * Detects category from keywords, falls back to default.\n */\n getAdapterForTask(taskDescription: string): IResilientAdapter {\n const match = detectTaskCategory(taskDescription);\n if (match !== null) {\n this.logger.debug('Task category detected', {\n category: match.category,\n cli: match.primaryCli,\n });\n return this.getAdapterForCli(match.primaryCli);\n }\n return this.getDefault();\n }\n\n /**\n * Get adapter pinned to a specific CLI.\n * Creates and caches one IResilientAdapter per CLI.\n */\n getAdapterForCli(cli: CliName): IResilientAdapter {\n const cached = this.cliAdapters.get(cli);\n if (cached !== undefined) return cached;\n\n const raw = createResilientAdapter({\n logger: this.logger,\n preferredCli: cli,\n ...(this.defaultCliTimeoutMs !== undefined && {\n defaultCliTimeoutMs: this.defaultCliTimeoutMs,\n }),\n });\n const adapter = this.maybeWrap(raw);\n this.cliAdapters.set(cli, adapter);\n this.logger.info('Created CLI-specific adapter', {\n cli,\n missingModelFallback: this.enableMissingModelFallback,\n });\n return adapter;\n }\n\n /**\n * Get adapter for a model preference string (e.g., \"claude-opus-4-6\").\n * Resolves the model to its CLI via the canonical registry.\n * Falls back to default adapter if model not recognized.\n */\n getAdapterForModel(modelPreference: string): IResilientAdapter {\n // Prefer exact matches (id / cliAlias / cliModelName) over prefix matches.\n // For prefix fallback, longest-prefix-wins so a future registry containing\n // both 'gemini-pro' and 'gemini-pro-experimental' resolves correctly even\n // though the registry's natural array order isn't sorted by id length.\n // Defense-in-depth — no current registry has prefix overlaps. (#2192)\n const allModels = getInTreeCapabilitiesMatrix().models;\n const exact = allModels.find(\n (m) =>\n m.id === modelPreference ||\n m.cliAlias === modelPreference ||\n m.cliModelName === modelPreference\n );\n const prefix =\n exact ??\n [...allModels]\n .filter((m) => modelPreference.startsWith(m.id))\n .sort((a, b) => b.id.length - a.id.length)[0];\n const model = prefix;\n if (model !== undefined) {\n this.logger.debug('Model resolved to CLI', {\n model: modelPreference,\n cli: model.cliName,\n });\n return this.getAdapterForCli(model.cliName as CliName);\n }\n this.logger.debug('Model not in registry, using default', {\n model: modelPreference,\n });\n return this.getDefault();\n }\n\n /**\n * Get adapter for an expert role (e.g., \"code_expert\").\n * Uses ROLE_TO_TASK_CATEGORY mapping → task specialization → CLI.\n */\n getAdapterForRole(role: string): IResilientAdapter {\n const category = ROLE_TO_CATEGORY[role];\n if (category !== undefined) return this.getAdapter(category);\n return this.getDefault();\n }\n\n /**\n * Get the default adapter (no CLI preference — auto-detection priority).\n */\n getDefault(): IResilientAdapter {\n if (this.defaultAdapter !== undefined) return this.defaultAdapter;\n const raw = createResilientAdapter({\n logger: this.logger,\n ...(this.defaultCliTimeoutMs !== undefined && {\n defaultCliTimeoutMs: this.defaultCliTimeoutMs,\n }),\n });\n this.defaultAdapter = this.maybeWrap(raw);\n return this.defaultAdapter;\n }\n\n /**\n * Get snapshot of registry state for observability/debugging. Routing is\n * re-resolved on read (#3185) so the snapshot reflects the live registry.\n */\n getSnapshot(): RegistrySnapshot {\n return {\n taskRouting: TASK_SPECIALIZATION_MATRIX.map((spec) => this.resolveRouting(spec)),\n cachedAdapters: [...this.cliAdapters.keys()],\n availableModels: getInTreeCapabilitiesMatrix().models.length,\n };\n }\n\n /**\n * Resolve the routing for a specific category.\n *\n * Computed on every read (#3185) rather than cached at construction, so a\n * post-startup model-registry / overlay update (e.g. a default-model change\n * surfaced via `getDefaultModelForCli`) propagates to routing decisions\n * without a process restart. The matrix is ~10 categories — the per-read\n * resolution cost is negligible.\n */\n getRouting(category: TaskCategory): TaskRoutingEntry | undefined {\n const spec = TASK_SPECIALIZATION_MATRIX.find((s) => s.category === category);\n if (spec === undefined) return undefined;\n return this.resolveRouting(spec);\n }\n\n /**\n * Dispose all cached adapters.\n */\n dispose(): void {\n for (const adapter of this.cliAdapters.values()) {\n adapter.dispose();\n }\n this.cliAdapters.clear();\n this.defaultAdapter?.dispose();\n this.defaultAdapter = undefined;\n this.logger.info('UnifiedAdapterRegistry disposed');\n }\n\n // --------------------------------------------------------------------------\n // Private\n // --------------------------------------------------------------------------\n\n /**\n * Resolve one specialization-matrix row into a routing entry, re-reading the\n * primary model from the (overlay-aware) model registry each call (#3185).\n */\n private resolveRouting(spec: (typeof TASK_SPECIALIZATION_MATRIX)[number]): TaskRoutingEntry {\n return {\n category: spec.category,\n primaryCli: spec.primaryCli,\n secondaryCli: spec.secondaryCli,\n primaryModel: resolveDefaultModel(spec.primaryCli),\n };\n }\n}\n\n// ============================================================================\n// Role → Category Mapping (consolidated from create-expert-routing.ts)\n// ============================================================================\n\n/** Maps expert roles to task categories for CLI specialization. */\nconst ROLE_TO_CATEGORY: Record<string, TaskCategory> = {\n code_expert: 'code_generation',\n architecture_expert: 'architecture',\n security_expert: 'security_review',\n documentation_expert: 'documentation',\n testing_expert: 'testing',\n devops_expert: 'devops',\n research_expert: 'research',\n pm_expert: 'planning',\n ux_expert: 'planning',\n infrastructure_expert: 'devops',\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Resolve the default model name for a CLI from the canonical registry. */\nfunction resolveDefaultModel(cli: string): string {\n if ((CLI_NAMES as readonly string[]).includes(cli)) {\n return getDefaultModelForCli(cli as CliNameLiteral);\n }\n return cli;\n}\n\n// ============================================================================\n// Factory & Singleton\n// ============================================================================\n\nlet globalRegistry: UnifiedAdapterRegistry | undefined;\n\n/**\n * Create a new UnifiedAdapterRegistry instance.\n * For most uses, prefer `getGlobalRegistry()` instead.\n */\nexport function createUnifiedRegistry(config?: UnifiedRegistryConfig): UnifiedAdapterRegistry {\n return new UnifiedAdapterRegistry(config);\n}\n\n/**\n * Get the global singleton registry.\n * Creates it on first access with default config.\n *\n * If the singleton already exists and a non-empty config is supplied, the\n * config is ignored — callers get the pre-existing instance. A warning is\n * emitted so this asymmetry is not silent.\n */\nexport function getGlobalRegistry(config?: UnifiedRegistryConfig): UnifiedAdapterRegistry {\n if (globalRegistry === undefined) {\n globalRegistry = new UnifiedAdapterRegistry(config);\n return globalRegistry;\n }\n if (config !== undefined && Object.keys(config).length > 0) {\n globalRegistry\n .getLogger()\n .warn(\n 'UnifiedAdapterRegistry singleton already initialized; provided config ignored. ' +\n 'Call resetGlobalRegistry() first if reconfiguration is intentional.',\n { providedKeys: Object.keys(config) }\n );\n }\n return globalRegistry;\n}\n\n/** Reset the global registry (for testing). */\nexport function resetGlobalRegistry(): void {\n globalRegistry?.dispose();\n globalRegistry = undefined;\n}\n"],"mappings":"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","names":["logger"]}