dual-brain 0.2.30 → 0.3.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 (309) hide show
  1. package/.dual-brain/docs/claude-code-extension-points.md +32 -0
  2. package/.dual-brain/docs/data-tools-capabilities.md +181 -0
  3. package/.dual-brain/docs/ecosystem-tools.md +91 -0
  4. package/.dual-brain/docs/panel-handoff.md +124 -0
  5. package/.dual-brain/docs/ruflo-analysis.md +48 -0
  6. package/bin/dual-brain.mjs +56 -56
  7. package/dist/mcp-server/index.d.ts +27 -0
  8. package/dist/mcp-server/index.js +359 -0
  9. package/dist/mcp-server/index.js.map +1 -0
  10. package/dist/src/agent-protocol.d.ts +163 -0
  11. package/dist/src/agent-protocol.js +368 -0
  12. package/dist/src/agent-protocol.js.map +1 -0
  13. package/dist/src/agents/registry.d.ts +52 -0
  14. package/dist/src/agents/registry.js +393 -0
  15. package/dist/src/agents/registry.js.map +1 -0
  16. package/dist/src/awareness.d.ts +93 -0
  17. package/dist/src/awareness.js +406 -0
  18. package/dist/src/awareness.js.map +1 -0
  19. package/dist/src/brief.d.ts +48 -0
  20. package/dist/src/brief.js +179 -0
  21. package/dist/src/brief.js.map +1 -0
  22. package/dist/src/calibration.d.ts +32 -0
  23. package/dist/src/calibration.js +133 -0
  24. package/dist/src/calibration.js.map +1 -0
  25. package/dist/src/checkpoint.d.ts +33 -0
  26. package/dist/src/checkpoint.js +99 -0
  27. package/dist/src/checkpoint.js.map +1 -0
  28. package/dist/src/ci-triage.d.ts +33 -0
  29. package/dist/src/ci-triage.js +193 -0
  30. package/dist/src/ci-triage.js.map +1 -0
  31. package/dist/src/cognitive-loop.d.ts +56 -0
  32. package/dist/src/cognitive-loop.js +495 -0
  33. package/dist/src/cognitive-loop.js.map +1 -0
  34. package/dist/src/collaboration.d.ts +147 -0
  35. package/dist/src/collaboration.js +438 -0
  36. package/dist/src/collaboration.js.map +1 -0
  37. package/dist/src/context-intel.d.ts +47 -0
  38. package/dist/src/context-intel.js +156 -0
  39. package/dist/src/context-intel.js.map +1 -0
  40. package/dist/src/context.d.ts +53 -0
  41. package/dist/src/context.js +332 -0
  42. package/dist/src/context.js.map +1 -0
  43. package/dist/src/continuity.d.ts +89 -0
  44. package/dist/src/continuity.js +230 -0
  45. package/dist/src/continuity.js.map +1 -0
  46. package/dist/src/cost-tracker.d.ts +47 -0
  47. package/dist/src/cost-tracker.js +170 -0
  48. package/dist/src/cost-tracker.js.map +1 -0
  49. package/dist/src/debrief.d.ts +53 -0
  50. package/dist/src/debrief.js +222 -0
  51. package/dist/src/debrief.js.map +1 -0
  52. package/dist/src/decide.d.ts +96 -0
  53. package/dist/src/decide.js +744 -0
  54. package/dist/src/decide.js.map +1 -0
  55. package/dist/src/decompose.d.ts +39 -0
  56. package/dist/src/decompose.js +218 -0
  57. package/dist/src/decompose.js.map +1 -0
  58. package/dist/src/detect.d.ts +91 -0
  59. package/dist/src/detect.js +544 -0
  60. package/dist/src/detect.js.map +1 -0
  61. package/dist/src/dispatch.d.ts +154 -0
  62. package/dist/src/dispatch.js +1306 -0
  63. package/dist/src/dispatch.js.map +1 -0
  64. package/dist/src/doctor.d.ts +421 -0
  65. package/dist/src/doctor.js +1689 -0
  66. package/dist/src/doctor.js.map +1 -0
  67. package/dist/src/engine.d.ts +70 -0
  68. package/dist/src/engine.js +155 -0
  69. package/dist/src/engine.js.map +1 -0
  70. package/dist/src/envelope.d.ts +36 -0
  71. package/dist/src/envelope.js +80 -0
  72. package/dist/src/envelope.js.map +1 -0
  73. package/dist/src/failure-memory.d.ts +55 -0
  74. package/dist/src/failure-memory.js +175 -0
  75. package/dist/src/failure-memory.js.map +1 -0
  76. package/dist/src/fx.d.ts +87 -0
  77. package/dist/src/fx.js +272 -0
  78. package/dist/src/fx.js.map +1 -0
  79. package/dist/src/governance.d.ts +93 -0
  80. package/dist/src/governance.js +261 -0
  81. package/dist/src/governance.js.map +1 -0
  82. package/dist/src/handoff.d.ts +11 -0
  83. package/dist/src/handoff.js +90 -0
  84. package/dist/src/handoff.js.map +1 -0
  85. package/dist/src/head-protocol.d.ts +76 -0
  86. package/dist/src/head-protocol.js +109 -0
  87. package/dist/src/head-protocol.js.map +1 -0
  88. package/dist/src/head.d.ts +222 -0
  89. package/dist/src/head.js +765 -0
  90. package/dist/src/head.js.map +1 -0
  91. package/dist/src/health.d.ts +132 -0
  92. package/dist/src/health.js +435 -0
  93. package/dist/src/health.js.map +1 -0
  94. package/dist/src/inbox.d.ts +70 -0
  95. package/dist/src/inbox.js +218 -0
  96. package/dist/src/inbox.js.map +1 -0
  97. package/dist/src/index.d.ts +33 -0
  98. package/dist/src/index.js +38 -0
  99. package/dist/src/index.js.map +1 -0
  100. package/dist/src/install-hooks.d.ts +13 -0
  101. package/dist/src/install-hooks.js +88 -0
  102. package/dist/src/install-hooks.js.map +1 -0
  103. package/dist/src/integrity.d.ts +59 -0
  104. package/dist/src/integrity.js +206 -0
  105. package/dist/src/integrity.js.map +1 -0
  106. package/dist/src/intelligence.d.ts +104 -0
  107. package/dist/src/intelligence.js +391 -0
  108. package/dist/src/intelligence.js.map +1 -0
  109. package/dist/src/ledger.d.ts +54 -0
  110. package/dist/src/ledger.js +179 -0
  111. package/dist/src/ledger.js.map +1 -0
  112. package/dist/src/living-docs.d.ts +14 -0
  113. package/dist/src/living-docs.js +197 -0
  114. package/dist/src/living-docs.js.map +1 -0
  115. package/dist/src/memory-tiers.d.ts +37 -0
  116. package/dist/src/memory-tiers.js +160 -0
  117. package/dist/src/memory-tiers.js.map +1 -0
  118. package/dist/src/model-profiles.d.ts +65 -0
  119. package/dist/src/model-profiles.js +568 -0
  120. package/dist/src/model-profiles.js.map +1 -0
  121. package/dist/src/models.d.ts +58 -0
  122. package/dist/src/models.js +327 -0
  123. package/dist/src/models.js.map +1 -0
  124. package/dist/src/narrative.d.ts +54 -0
  125. package/dist/src/narrative.js +163 -0
  126. package/dist/src/narrative.js.map +1 -0
  127. package/dist/src/nextstep.d.ts +16 -0
  128. package/dist/src/nextstep.js +103 -0
  129. package/dist/src/nextstep.js.map +1 -0
  130. package/dist/src/observer.d.ts +18 -0
  131. package/dist/src/observer.js +251 -0
  132. package/dist/src/observer.js.map +1 -0
  133. package/dist/src/outcome.d.ts +110 -0
  134. package/dist/src/outcome.js +377 -0
  135. package/dist/src/outcome.js.map +1 -0
  136. package/dist/src/pipeline.d.ts +167 -0
  137. package/dist/src/pipeline.js +1503 -0
  138. package/dist/src/pipeline.js.map +1 -0
  139. package/dist/src/playbook.d.ts +59 -0
  140. package/dist/src/playbook.js +238 -0
  141. package/dist/src/playbook.js.map +1 -0
  142. package/dist/src/pr-agent.d.ts +97 -0
  143. package/dist/src/pr-agent.js +195 -0
  144. package/dist/src/pr-agent.js.map +1 -0
  145. package/dist/src/predictive.d.ts +57 -0
  146. package/dist/src/predictive.js +230 -0
  147. package/dist/src/predictive.js.map +1 -0
  148. package/dist/src/profile.d.ts +294 -0
  149. package/dist/src/profile.js +1347 -0
  150. package/dist/src/profile.js.map +1 -0
  151. package/dist/src/prompt-audit.d.ts +22 -0
  152. package/dist/src/prompt-audit.js +194 -0
  153. package/dist/src/prompt-audit.js.map +1 -0
  154. package/dist/src/prompt-intel.d.ts +12 -0
  155. package/dist/src/prompt-intel.js +321 -0
  156. package/dist/src/prompt-intel.js.map +1 -0
  157. package/dist/src/provider-context.d.ts +121 -0
  158. package/dist/src/provider-context.js +222 -0
  159. package/dist/src/provider-context.js.map +1 -0
  160. package/dist/src/provider-manager.d.ts +92 -0
  161. package/dist/src/provider-manager.js +428 -0
  162. package/dist/src/provider-manager.js.map +1 -0
  163. package/dist/src/receipt.d.ts +87 -0
  164. package/dist/src/receipt.js +326 -0
  165. package/dist/src/receipt.js.map +1 -0
  166. package/dist/src/recommendations.d.ts +13 -0
  167. package/dist/src/recommendations.js +291 -0
  168. package/dist/src/recommendations.js.map +1 -0
  169. package/dist/src/redact.d.ts +15 -0
  170. package/dist/src/redact.js +129 -0
  171. package/dist/src/redact.js.map +1 -0
  172. package/dist/src/replit.d.ts +397 -0
  173. package/dist/src/replit.js +1160 -0
  174. package/dist/src/replit.js.map +1 -0
  175. package/dist/src/repo.d.ts +149 -0
  176. package/dist/src/repo.js +416 -0
  177. package/dist/src/repo.js.map +1 -0
  178. package/dist/src/revert.d.ts +30 -0
  179. package/dist/src/revert.js +166 -0
  180. package/dist/src/revert.js.map +1 -0
  181. package/dist/src/room.d.ts +102 -0
  182. package/dist/src/room.js +212 -0
  183. package/dist/src/room.js.map +1 -0
  184. package/dist/src/routing-advisor.d.ts +57 -0
  185. package/dist/src/routing-advisor.js +221 -0
  186. package/dist/src/routing-advisor.js.map +1 -0
  187. package/dist/src/self-correct.d.ts +40 -0
  188. package/dist/src/self-correct.js +137 -0
  189. package/dist/src/self-correct.js.map +1 -0
  190. package/dist/src/session-lock.d.ts +35 -0
  191. package/dist/src/session-lock.js +134 -0
  192. package/dist/src/session-lock.js.map +1 -0
  193. package/dist/src/session.d.ts +267 -0
  194. package/dist/src/session.js +1660 -0
  195. package/dist/src/session.js.map +1 -0
  196. package/dist/src/settings-tui.d.ts +5 -0
  197. package/dist/src/settings-tui.js +422 -0
  198. package/dist/src/settings-tui.js.map +1 -0
  199. package/dist/src/setup-flow.d.ts +63 -0
  200. package/dist/src/setup-flow.js +233 -0
  201. package/dist/src/setup-flow.js.map +1 -0
  202. package/dist/src/signal.d.ts +19 -0
  203. package/dist/src/signal.js +122 -0
  204. package/dist/src/signal.js.map +1 -0
  205. package/dist/src/simmer.d.ts +85 -0
  206. package/dist/src/simmer.js +224 -0
  207. package/dist/src/simmer.js.map +1 -0
  208. package/dist/src/state-export.d.ts +129 -0
  209. package/dist/src/state-export.js +233 -0
  210. package/dist/src/state-export.js.map +1 -0
  211. package/dist/src/strategy.d.ts +54 -0
  212. package/dist/src/strategy.js +95 -0
  213. package/dist/src/strategy.js.map +1 -0
  214. package/dist/src/subscription.d.ts +40 -0
  215. package/dist/src/subscription.js +189 -0
  216. package/dist/src/subscription.js.map +1 -0
  217. package/dist/src/templates.d.ts +208 -0
  218. package/dist/src/templates.js +238 -0
  219. package/dist/src/templates.js.map +1 -0
  220. package/dist/src/test.d.ts +9 -0
  221. package/dist/src/test.js +1173 -0
  222. package/dist/src/test.js.map +1 -0
  223. package/dist/src/think-engine.d.ts +67 -0
  224. package/dist/src/think-engine.js +412 -0
  225. package/dist/src/think-engine.js.map +1 -0
  226. package/dist/src/tui.d.ts +71 -0
  227. package/dist/src/tui.js +242 -0
  228. package/dist/src/tui.js.map +1 -0
  229. package/dist/src/types.d.ts +177 -0
  230. package/dist/src/types.js +6 -0
  231. package/dist/src/types.js.map +1 -0
  232. package/dist/src/update-check.d.ts +7 -0
  233. package/dist/src/update-check.js +36 -0
  234. package/dist/src/update-check.js.map +1 -0
  235. package/dist/src/wave-planner.d.ts +30 -0
  236. package/dist/src/wave-planner.js +281 -0
  237. package/dist/src/wave-planner.js.map +1 -0
  238. package/hooks/head-guard.sh +41 -0
  239. package/hooks/task-classifier.mjs +328 -0
  240. package/hooks/vibe-router.mjs +387 -0
  241. package/package.json +29 -153
  242. package/src/agents/registry.mjs +0 -405
  243. package/src/awareness.mjs +0 -425
  244. package/src/brief.mjs +0 -266
  245. package/src/calibration.mjs +0 -148
  246. package/src/checkpoint.mjs +0 -109
  247. package/src/ci-triage.mjs +0 -191
  248. package/src/cognitive-loop.mjs +0 -562
  249. package/src/collaboration.mjs +0 -545
  250. package/src/context-intel.mjs +0 -158
  251. package/src/context.mjs +0 -389
  252. package/src/continuity.mjs +0 -298
  253. package/src/cost-tracker.mjs +0 -184
  254. package/src/debrief.mjs +0 -228
  255. package/src/decide.mjs +0 -1099
  256. package/src/decompose.mjs +0 -331
  257. package/src/detect.mjs +0 -702
  258. package/src/dispatch.mjs +0 -1447
  259. package/src/doctor.mjs +0 -1607
  260. package/src/envelope.mjs +0 -139
  261. package/src/failure-memory.mjs +0 -178
  262. package/src/fx.mjs +0 -276
  263. package/src/governance.mjs +0 -279
  264. package/src/handoff.mjs +0 -87
  265. package/src/head-protocol.mjs +0 -128
  266. package/src/head.mjs +0 -952
  267. package/src/health.mjs +0 -528
  268. package/src/inbox.mjs +0 -195
  269. package/src/index.mjs +0 -44
  270. package/src/install-hooks.mjs +0 -100
  271. package/src/integrity.mjs +0 -245
  272. package/src/intelligence.mjs +0 -447
  273. package/src/ledger.mjs +0 -196
  274. package/src/living-docs.mjs +0 -210
  275. package/src/memory-tiers.mjs +0 -193
  276. package/src/models.mjs +0 -363
  277. package/src/narrative.mjs +0 -169
  278. package/src/nextstep.mjs +0 -100
  279. package/src/observer.mjs +0 -241
  280. package/src/outcome.mjs +0 -400
  281. package/src/pipeline.mjs +0 -1711
  282. package/src/playbook.mjs +0 -257
  283. package/src/pr-agent.mjs +0 -214
  284. package/src/predictive.mjs +0 -250
  285. package/src/profile.mjs +0 -1411
  286. package/src/prompt-audit.mjs +0 -231
  287. package/src/prompt-intel.mjs +0 -325
  288. package/src/provider-context.mjs +0 -257
  289. package/src/receipt.mjs +0 -344
  290. package/src/recommendations.mjs +0 -296
  291. package/src/redact.mjs +0 -192
  292. package/src/replit.mjs +0 -1210
  293. package/src/repo.mjs +0 -445
  294. package/src/revert.mjs +0 -149
  295. package/src/routing-advisor.mjs +0 -204
  296. package/src/self-correct.mjs +0 -147
  297. package/src/session-lock.mjs +0 -160
  298. package/src/session.mjs +0 -1655
  299. package/src/settings-tui.mjs +0 -373
  300. package/src/setup-flow.mjs +0 -223
  301. package/src/signal.mjs +0 -115
  302. package/src/simmer.mjs +0 -241
  303. package/src/strategy.mjs +0 -235
  304. package/src/subscription.mjs +0 -212
  305. package/src/templates.mjs +0 -260
  306. package/src/think-engine.mjs +0 -428
  307. package/src/tui.mjs +0 -276
  308. package/src/update-check.mjs +0 -35
  309. package/src/wave-planner.mjs +0 -294
@@ -0,0 +1,428 @@
1
+ /**
2
+ * provider-manager.ts — Provider health, failover, and rate-limit management
3
+ *
4
+ * The "invisible failover" layer: when Claude is rate-limited, work seamlessly
5
+ * continues on GPT. When GPT is down, Claude handles everything.
6
+ *
7
+ * State storage:
8
+ * - Provider states: .dual-brain/providers/{provider}.json (atomic writes)
9
+ * - Global dispatch log: .dual-brain/dispatch-log.ndjson (append-only)
10
+ */
11
+ import { existsSync, readFileSync, appendFileSync, mkdirSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { atomicWriteJson, readJsonSafe } from './integrity.js';
14
+ // ─── Constants ──────────────────────────────────────────────────────────────
15
+ /** Maximum dispatches allowed per rolling window (default: 30 per 5 min). */
16
+ export const MAX_DISPATCHES_PER_WINDOW = 30;
17
+ /** Default rolling window in minutes. */
18
+ export const DEFAULT_WINDOW_MINUTES = 5;
19
+ /** Cooldown duration in ms when rate-limited without a known reset time. */
20
+ const DEFAULT_COOLDOWN_MS = 5 * 60 * 1000;
21
+ /** Consecutive failures before marking a provider as "down". */
22
+ const DOWN_THRESHOLD = 5;
23
+ /** Consecutive failures before marking a provider as "degraded". */
24
+ const DEGRADED_THRESHOLD = 2;
25
+ /** Known providers. */
26
+ const KNOWN_PROVIDERS = ['anthropic', 'openai'];
27
+ // ─── Path helpers ───────────────────────────────────────────────────────────
28
+ function providersDir(cwd) {
29
+ return join(cwd || process.cwd(), '.dual-brain', 'providers');
30
+ }
31
+ function providerFile(provider, cwd) {
32
+ return join(providersDir(cwd), `${provider}.json`);
33
+ }
34
+ function dispatchLogPath(cwd) {
35
+ return join(cwd || process.cwd(), '.dual-brain', 'dispatch-log.ndjson');
36
+ }
37
+ // ─── Default state ──────────────────────────────────────────────────────────
38
+ function defaultState(provider) {
39
+ const now = new Date().toISOString();
40
+ return {
41
+ provider,
42
+ status: 'healthy',
43
+ lastCheck: now,
44
+ lastSuccess: now,
45
+ remainingCapacity: 1,
46
+ recentDispatches: 0,
47
+ consecutiveFailures: 0,
48
+ };
49
+ }
50
+ // ─── Tier-to-model mapping (for failover) ───────────────────────────────────
51
+ const TIER_MODELS = {
52
+ // tier 1: cheap/fast search
53
+ 1: { anthropic: 'claude-haiku', openai: 'gpt-4.1-mini' },
54
+ // tier 2: routine execution
55
+ 2: { anthropic: 'claude-sonnet', openai: 'gpt-4.1' },
56
+ // tier 3: complex reasoning
57
+ 3: { anthropic: 'claude-sonnet', openai: 'o4-mini' },
58
+ // tier 4: heavy thinking / architecture
59
+ 4: { anthropic: 'claude-opus', openai: 'o3' },
60
+ };
61
+ function modelForTier(tier, provider) {
62
+ const clamped = Math.max(1, Math.min(4, tier));
63
+ return TIER_MODELS[clamped]?.[provider] ?? (provider === 'anthropic' ? 'claude-sonnet' : 'gpt-4.1');
64
+ }
65
+ // Map a model name back to an approximate tier
66
+ function tierForModel(model) {
67
+ const lower = model.toLowerCase();
68
+ if (lower.includes('haiku') || lower.includes('mini'))
69
+ return 1;
70
+ if (lower.includes('opus') || lower === 'o3')
71
+ return 4;
72
+ if (lower.includes('o4-mini'))
73
+ return 3;
74
+ return 2;
75
+ }
76
+ // ─── Provider state I/O ─────────────────────────────────────────────────────
77
+ /**
78
+ * Get the current health state for a provider.
79
+ */
80
+ export function getProviderState(provider, cwd) {
81
+ const p = provider === 'claude' ? 'anthropic' : provider;
82
+ const filePath = providerFile(p, cwd);
83
+ if (!existsSync(filePath)) {
84
+ return defaultState(p);
85
+ }
86
+ const raw = readJsonSafe(filePath);
87
+ if (!raw || typeof raw !== 'object') {
88
+ return defaultState(p);
89
+ }
90
+ const state = raw;
91
+ // Re-evaluate cooldown: if cooldownUntil has passed, transition to healthy
92
+ if (state.status === 'rate-limited' && state.cooldownUntil) {
93
+ const cooldownEnd = new Date(state.cooldownUntil).getTime();
94
+ if (Date.now() >= cooldownEnd) {
95
+ const updated = {
96
+ ...state,
97
+ status: 'healthy',
98
+ cooldownUntil: undefined,
99
+ consecutiveFailures: 0,
100
+ remainingCapacity: 0.5, // conservative after cooldown
101
+ lastCheck: new Date().toISOString(),
102
+ };
103
+ atomicWriteJson(filePath, updated);
104
+ return updated;
105
+ }
106
+ }
107
+ // Attach recent dispatch count from the log
108
+ const dispatches = countRecentDispatches(p, DEFAULT_WINDOW_MINUTES, cwd);
109
+ return {
110
+ provider: p,
111
+ status: state.status || 'healthy',
112
+ lastCheck: state.lastCheck || new Date().toISOString(),
113
+ lastSuccess: state.lastSuccess || new Date().toISOString(),
114
+ lastFailure: state.lastFailure,
115
+ cooldownUntil: state.cooldownUntil,
116
+ remainingCapacity: typeof state.remainingCapacity === 'number' ? state.remainingCapacity : 1,
117
+ recentDispatches: dispatches,
118
+ consecutiveFailures: typeof state.consecutiveFailures === 'number' ? state.consecutiveFailures : 0,
119
+ };
120
+ }
121
+ /**
122
+ * Get health states for all known providers.
123
+ */
124
+ export function getAllProviderStates(cwd) {
125
+ return KNOWN_PROVIDERS.map(p => getProviderState(p, cwd));
126
+ }
127
+ // ─── State mutations ────────────────────────────────────────────────────────
128
+ function saveState(state, cwd) {
129
+ const filePath = providerFile(state.provider, cwd);
130
+ atomicWriteJson(filePath, state);
131
+ }
132
+ /**
133
+ * Record a successful dispatch to a provider.
134
+ */
135
+ export function recordSuccess(provider, model, cwd) {
136
+ const p = (provider === 'claude' ? 'anthropic' : provider);
137
+ const current = getProviderState(p, cwd);
138
+ const updated = {
139
+ ...current,
140
+ status: 'healthy',
141
+ lastCheck: new Date().toISOString(),
142
+ lastSuccess: new Date().toISOString(),
143
+ cooldownUntil: undefined,
144
+ consecutiveFailures: 0,
145
+ // Nudge capacity up on success, cap at 1
146
+ remainingCapacity: Math.min(1, current.remainingCapacity + 0.1),
147
+ };
148
+ saveState(updated, cwd);
149
+ }
150
+ /**
151
+ * Record a dispatch failure. Detects rate limits automatically.
152
+ */
153
+ export function recordFailure(provider, model, error, cwd) {
154
+ const p = (provider === 'claude' ? 'anthropic' : provider);
155
+ // Check if this is a rate limit
156
+ const rl = detectRateLimit(error);
157
+ if (rl.isRateLimit) {
158
+ recordRateLimit(p, rl.resetTime, cwd);
159
+ return;
160
+ }
161
+ const current = getProviderState(p, cwd);
162
+ const failures = current.consecutiveFailures + 1;
163
+ let status = current.status;
164
+ if (failures >= DOWN_THRESHOLD) {
165
+ status = 'down';
166
+ }
167
+ else if (failures >= DEGRADED_THRESHOLD) {
168
+ status = 'degraded';
169
+ }
170
+ const updated = {
171
+ ...current,
172
+ status,
173
+ lastCheck: new Date().toISOString(),
174
+ lastFailure: new Date().toISOString(),
175
+ consecutiveFailures: failures,
176
+ remainingCapacity: Math.max(0, current.remainingCapacity - 0.2),
177
+ };
178
+ saveState(updated, cwd);
179
+ }
180
+ /**
181
+ * Explicitly record a rate limit event.
182
+ */
183
+ export function recordRateLimit(provider, resetTime, cwd) {
184
+ const p = (provider === 'claude' ? 'anthropic' : provider);
185
+ const current = getProviderState(p, cwd);
186
+ const cooldownUntil = resetTime
187
+ ? new Date(resetTime).toISOString()
188
+ : new Date(Date.now() + DEFAULT_COOLDOWN_MS).toISOString();
189
+ const updated = {
190
+ ...current,
191
+ status: 'rate-limited',
192
+ lastCheck: new Date().toISOString(),
193
+ lastFailure: new Date().toISOString(),
194
+ cooldownUntil,
195
+ remainingCapacity: 0,
196
+ consecutiveFailures: current.consecutiveFailures + 1,
197
+ };
198
+ saveState(updated, cwd);
199
+ }
200
+ // ─── Pre-dispatch checks ────────────────────────────────────────────────────
201
+ /**
202
+ * Check whether dispatching to a provider is allowed right now.
203
+ */
204
+ export function canDispatch(provider, cwd) {
205
+ const p = provider === 'claude' ? 'anthropic' : provider;
206
+ const state = getProviderState(p, cwd);
207
+ const other = p === 'anthropic' ? 'openai' : 'anthropic';
208
+ // 1. Rate-limited with active cooldown
209
+ if (state.status === 'rate-limited' && state.cooldownUntil) {
210
+ const remaining = new Date(state.cooldownUntil).getTime() - Date.now();
211
+ if (remaining > 0) {
212
+ return {
213
+ allowed: false,
214
+ reason: `${p} is rate-limited, cooldown expires in ${Math.ceil(remaining / 1000)}s`,
215
+ suggestedDelay: remaining,
216
+ alternativeProvider: other,
217
+ };
218
+ }
219
+ // Cooldown expired — allow but note it
220
+ }
221
+ // 2. Provider is down
222
+ if (state.status === 'down') {
223
+ return {
224
+ allowed: false,
225
+ reason: `${p} is down (${state.consecutiveFailures} consecutive failures)`,
226
+ alternativeProvider: other,
227
+ };
228
+ }
229
+ // 3. Global dispatch budget check
230
+ if (!isWithinBudget(MAX_DISPATCHES_PER_WINDOW, DEFAULT_WINDOW_MINUTES, cwd)) {
231
+ return {
232
+ allowed: false,
233
+ reason: `Global dispatch limit reached (${MAX_DISPATCHES_PER_WINDOW} per ${DEFAULT_WINDOW_MINUTES}min)`,
234
+ suggestedDelay: 60_000,
235
+ };
236
+ }
237
+ // 4. Degraded — allow but warn
238
+ if (state.status === 'degraded') {
239
+ return {
240
+ allowed: true,
241
+ reason: `${p} is degraded (${state.consecutiveFailures} failures), proceeding with caution`,
242
+ };
243
+ }
244
+ return { allowed: true, reason: `${p} is healthy` };
245
+ }
246
+ // ─── Failover ───────────────────────────────────────────────────────────────
247
+ /**
248
+ * If the preferred provider cannot handle work right now, find the best alternative.
249
+ */
250
+ export function getFailoverTarget(preferredProvider, preferredModel, cwd) {
251
+ const p = preferredProvider === 'claude' ? 'anthropic' : preferredProvider;
252
+ const permission = canDispatch(p, cwd);
253
+ if (permission.allowed) {
254
+ return {
255
+ provider: p,
256
+ model: preferredModel,
257
+ reason: permission.reason,
258
+ wasFailover: false,
259
+ };
260
+ }
261
+ // Attempt failover to the other provider
262
+ const other = p === 'anthropic' ? 'openai' : 'anthropic';
263
+ const otherPermission = canDispatch(other, cwd);
264
+ if (otherPermission.allowed) {
265
+ // Map the model to an equivalent tier on the other provider
266
+ const tier = tierForModel(preferredModel);
267
+ const altModel = modelForTier(tier, other);
268
+ return {
269
+ provider: other,
270
+ model: altModel,
271
+ reason: `Failover from ${p} (${permission.reason}). Using ${other}:${altModel}`,
272
+ wasFailover: true,
273
+ };
274
+ }
275
+ // Both providers unavailable — return the preferred with a warning
276
+ return {
277
+ provider: p,
278
+ model: preferredModel,
279
+ reason: `Both providers unavailable. ${p}: ${permission.reason}. ${other}: ${otherPermission.reason}`,
280
+ wasFailover: false,
281
+ };
282
+ }
283
+ /**
284
+ * Choose the best provider right now based on health + task tier.
285
+ */
286
+ export function selectProvider(taskTier, preferredProvider, cwd) {
287
+ // If a preference is given, try it first
288
+ if (preferredProvider) {
289
+ const model = modelForTier(taskTier, preferredProvider === 'claude' ? 'anthropic' : preferredProvider);
290
+ return getFailoverTarget(preferredProvider, model, cwd);
291
+ }
292
+ // No preference: pick the healthiest provider
293
+ const states = getAllProviderStates(cwd);
294
+ // Sort by: healthy > degraded > rate-limited > down, then by remaining capacity
295
+ const statusOrder = {
296
+ healthy: 0,
297
+ degraded: 1,
298
+ 'rate-limited': 2,
299
+ down: 3,
300
+ };
301
+ states.sort((a, b) => {
302
+ const sDiff = (statusOrder[a.status] ?? 9) - (statusOrder[b.status] ?? 9);
303
+ if (sDiff !== 0)
304
+ return sDiff;
305
+ return b.remainingCapacity - a.remainingCapacity;
306
+ });
307
+ const best = states[0];
308
+ const model = modelForTier(taskTier, best.provider);
309
+ return {
310
+ provider: best.provider,
311
+ model,
312
+ reason: `Selected ${best.provider} (status: ${best.status}, capacity: ${Math.round(best.remainingCapacity * 100)}%)`,
313
+ wasFailover: false,
314
+ };
315
+ }
316
+ // ─── Global dispatch counter ────────────────────────────────────────────────
317
+ function countRecentDispatches(provider, windowMinutes, cwd) {
318
+ const logPath = dispatchLogPath(cwd);
319
+ if (!existsSync(logPath))
320
+ return 0;
321
+ const cutoff = Date.now() - windowMinutes * 60 * 1000;
322
+ let count = 0;
323
+ try {
324
+ const lines = readFileSync(logPath, 'utf8').split('\n');
325
+ for (const line of lines) {
326
+ if (!line.trim())
327
+ continue;
328
+ try {
329
+ const entry = JSON.parse(line);
330
+ const ts = new Date(entry.timestamp).getTime();
331
+ if (ts >= cutoff) {
332
+ if (!provider || entry.provider === provider) {
333
+ count++;
334
+ }
335
+ }
336
+ }
337
+ catch {
338
+ // Skip malformed lines
339
+ }
340
+ }
341
+ }
342
+ catch {
343
+ return 0;
344
+ }
345
+ return count;
346
+ }
347
+ /**
348
+ * Get the total number of dispatches across all providers in the given window.
349
+ */
350
+ export function getGlobalDispatchCount(windowMinutes, cwd) {
351
+ return countRecentDispatches(undefined, windowMinutes ?? DEFAULT_WINDOW_MINUTES, cwd);
352
+ }
353
+ /**
354
+ * Append a dispatch attempt to the global log (file-based, shared across processes).
355
+ */
356
+ export function recordDispatchAttempt(provider, model, taskId, cwd) {
357
+ const logPath = dispatchLogPath(cwd);
358
+ const dir = join(cwd || process.cwd(), '.dual-brain');
359
+ if (!existsSync(dir))
360
+ mkdirSync(dir, { recursive: true });
361
+ const entry = {
362
+ provider: provider === 'claude' ? 'anthropic' : provider,
363
+ model,
364
+ taskId,
365
+ timestamp: new Date().toISOString(),
366
+ };
367
+ appendFileSync(logPath, JSON.stringify(entry) + '\n', 'utf8');
368
+ }
369
+ /**
370
+ * Check whether dispatch rate is within budget.
371
+ */
372
+ export function isWithinBudget(maxPerWindow, windowMinutes, cwd) {
373
+ const max = maxPerWindow ?? MAX_DISPATCHES_PER_WINDOW;
374
+ const window = windowMinutes ?? DEFAULT_WINDOW_MINUTES;
375
+ return getGlobalDispatchCount(window, cwd) < max;
376
+ }
377
+ // ─── Rate limit detection ───────────────────────────────────────────────────
378
+ const RATE_LIMIT_PATTERNS = [
379
+ /429/i,
380
+ /rate.?limit/i,
381
+ /too many requests/i,
382
+ /capacity/i,
383
+ /quota/i,
384
+ /exceeded/i,
385
+ /throttl/i,
386
+ /overloaded/i,
387
+ ];
388
+ /**
389
+ * Parse an error message for rate limit signals.
390
+ */
391
+ export function detectRateLimit(error) {
392
+ if (!error)
393
+ return { isRateLimit: false };
394
+ const isRateLimit = RATE_LIMIT_PATTERNS.some(p => p.test(error));
395
+ if (!isRateLimit)
396
+ return { isRateLimit: false };
397
+ // Try to extract a reset time from the error
398
+ // Common patterns: "retry after 123s", "Retry-After: 123", "reset at 2024-..."
399
+ let resetTime;
400
+ const retryAfterMatch = error.match(/retry.?after:?\s*(\d+)/i);
401
+ if (retryAfterMatch) {
402
+ const seconds = parseInt(retryAfterMatch[1], 10);
403
+ resetTime = new Date(Date.now() + seconds * 1000).toISOString();
404
+ }
405
+ const isoMatch = error.match(/reset.+?(20\d{2}-\d{2}-\d{2}T[\d:.]+Z?)/i);
406
+ if (!resetTime && isoMatch) {
407
+ resetTime = new Date(isoMatch[1]).toISOString();
408
+ }
409
+ return { isRateLimit, resetTime };
410
+ }
411
+ // ─── Health summary ─────────────────────────────────────────────────────────
412
+ /**
413
+ * One-line health status string for TUI display.
414
+ */
415
+ export function getHealthSummary(cwd) {
416
+ const states = getAllProviderStates(cwd);
417
+ const dispatches = getGlobalDispatchCount(DEFAULT_WINDOW_MINUTES, cwd);
418
+ const parts = states.map(s => {
419
+ const icon = s.status === 'healthy' ? 'OK'
420
+ : s.status === 'degraded' ? 'WARN'
421
+ : s.status === 'rate-limited' ? 'LIMIT'
422
+ : 'DOWN';
423
+ return `${s.provider}:${icon}`;
424
+ });
425
+ parts.push(`${dispatches}/${MAX_DISPATCHES_PER_WINDOW} dispatches`);
426
+ return parts.join(' | ');
427
+ }
428
+ //# sourceMappingURL=provider-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-manager.js","sourceRoot":"","sources":["../../src/provider-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ interface ReceiptPlan {
2
+ risk?: string;
3
+ tier?: string;
4
+ challengerPolicy?: string;
5
+ useChallenger?: boolean;
6
+ primaryModel?: string;
7
+ reasoningDepth?: string;
8
+ workStyle?: string;
9
+ primaryProvider?: string;
10
+ approvalRequired?: boolean;
11
+ }
12
+ interface ReceiptResult {
13
+ success?: boolean;
14
+ filesChanged?: string[];
15
+ error?: string | null;
16
+ duration?: number;
17
+ output?: string | null;
18
+ provider?: string;
19
+ model?: string;
20
+ }
21
+ interface ReceiptVerification {
22
+ filesVerified?: boolean;
23
+ testsRun?: boolean;
24
+ testsPassed?: boolean | null;
25
+ ok?: boolean;
26
+ notes?: string[];
27
+ }
28
+ interface Receipt {
29
+ changed: string;
30
+ verified: string;
31
+ risk: string;
32
+ challenger: string;
33
+ next: string;
34
+ success: boolean;
35
+ }
36
+ interface SessionReceipt {
37
+ timestamp: string;
38
+ goal: string;
39
+ filesChanged: string[];
40
+ decisions: string[];
41
+ testsRun: string | null;
42
+ risksUnresolved: string[];
43
+ blockers: string[];
44
+ nextAction: string;
45
+ provider: string | null;
46
+ model: string | null;
47
+ duration: number | null;
48
+ status: string;
49
+ }
50
+ interface PipelineRun {
51
+ prompt?: string;
52
+ result?: ReceiptResult;
53
+ verification?: ReceiptVerification;
54
+ plan?: ReceiptPlan;
55
+ outcome?: {
56
+ approved?: boolean;
57
+ };
58
+ gates?: Record<string, {
59
+ passed?: boolean;
60
+ reason?: string;
61
+ } | null>;
62
+ completedAt?: number;
63
+ startedAt?: number;
64
+ }
65
+ interface OutcomeInput {
66
+ success?: boolean;
67
+ result?: ReceiptResult;
68
+ filesChanged?: string[];
69
+ error?: string;
70
+ duration?: number;
71
+ output?: string;
72
+ primaryModel?: string;
73
+ reasoningDepth?: string;
74
+ challengerPolicy?: string;
75
+ tier?: string;
76
+ workStyle?: string;
77
+ risk?: string;
78
+ verification?: ReceiptVerification;
79
+ }
80
+ export declare function buildReceipt(result: ReceiptResult, plan: ReceiptPlan, verification: ReceiptVerification): Receipt;
81
+ export declare function formatReceipt(receipt: Receipt): string;
82
+ export declare function formatFailureReceipt(receipt: Receipt, failureContext?: string): string;
83
+ export declare function generateReceipt(run?: PipelineRun, cwd?: string): SessionReceipt;
84
+ export declare function buildResumeBrief(cwd?: string): string | null;
85
+ export declare function getLatestReceipt(cwd?: string): SessionReceipt | null;
86
+ export declare function buildReceiptFromOutcome(outcome?: OutcomeInput): Receipt;
87
+ export {};