dual-brain 0.2.30 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) 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/precompact.mjs +3 -3
  240. package/hooks/session-end.mjs +3 -3
  241. package/hooks/task-classifier.mjs +328 -0
  242. package/hooks/vibe-router.mjs +387 -0
  243. package/install.mjs +2 -2
  244. package/package.json +29 -153
  245. package/src/agents/registry.mjs +0 -405
  246. package/src/awareness.mjs +0 -425
  247. package/src/brief.mjs +0 -266
  248. package/src/calibration.mjs +0 -148
  249. package/src/checkpoint.mjs +0 -109
  250. package/src/ci-triage.mjs +0 -191
  251. package/src/cognitive-loop.mjs +0 -562
  252. package/src/collaboration.mjs +0 -545
  253. package/src/context-intel.mjs +0 -158
  254. package/src/context.mjs +0 -389
  255. package/src/continuity.mjs +0 -298
  256. package/src/cost-tracker.mjs +0 -184
  257. package/src/debrief.mjs +0 -228
  258. package/src/decide.mjs +0 -1099
  259. package/src/decompose.mjs +0 -331
  260. package/src/detect.mjs +0 -702
  261. package/src/dispatch.mjs +0 -1447
  262. package/src/doctor.mjs +0 -1607
  263. package/src/envelope.mjs +0 -139
  264. package/src/failure-memory.mjs +0 -178
  265. package/src/fx.mjs +0 -276
  266. package/src/governance.mjs +0 -279
  267. package/src/handoff.mjs +0 -87
  268. package/src/head-protocol.mjs +0 -128
  269. package/src/head.mjs +0 -952
  270. package/src/health.mjs +0 -528
  271. package/src/inbox.mjs +0 -195
  272. package/src/index.mjs +0 -44
  273. package/src/install-hooks.mjs +0 -100
  274. package/src/integrity.mjs +0 -245
  275. package/src/intelligence.mjs +0 -447
  276. package/src/ledger.mjs +0 -196
  277. package/src/living-docs.mjs +0 -210
  278. package/src/memory-tiers.mjs +0 -193
  279. package/src/models.mjs +0 -363
  280. package/src/narrative.mjs +0 -169
  281. package/src/nextstep.mjs +0 -100
  282. package/src/observer.mjs +0 -241
  283. package/src/outcome.mjs +0 -400
  284. package/src/pipeline.mjs +0 -1711
  285. package/src/playbook.mjs +0 -257
  286. package/src/pr-agent.mjs +0 -214
  287. package/src/predictive.mjs +0 -250
  288. package/src/profile.mjs +0 -1411
  289. package/src/prompt-audit.mjs +0 -231
  290. package/src/prompt-intel.mjs +0 -325
  291. package/src/provider-context.mjs +0 -257
  292. package/src/receipt.mjs +0 -344
  293. package/src/recommendations.mjs +0 -296
  294. package/src/redact.mjs +0 -192
  295. package/src/replit.mjs +0 -1210
  296. package/src/repo.mjs +0 -445
  297. package/src/revert.mjs +0 -149
  298. package/src/routing-advisor.mjs +0 -204
  299. package/src/self-correct.mjs +0 -147
  300. package/src/session-lock.mjs +0 -160
  301. package/src/session.mjs +0 -1655
  302. package/src/settings-tui.mjs +0 -373
  303. package/src/setup-flow.mjs +0 -223
  304. package/src/signal.mjs +0 -115
  305. package/src/simmer.mjs +0 -241
  306. package/src/strategy.mjs +0 -235
  307. package/src/subscription.mjs +0 -212
  308. package/src/templates.mjs +0 -260
  309. package/src/think-engine.mjs +0 -428
  310. package/src/tui.mjs +0 -276
  311. package/src/update-check.mjs +0 -35
  312. 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 {};