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,261 @@
1
+ // governance.ts — Model tier enforcement + multi-model collaboration
2
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ export const MODEL_TIERS = Object.freeze({
5
+ 1: {
6
+ label: 'lightweight',
7
+ models: ['claude-haiku-4-5-20251001', 'haiku', 'gpt-4o-mini', 'o4-mini'],
8
+ autoApprove: true,
9
+ },
10
+ 2: {
11
+ label: 'standard',
12
+ models: ['claude-sonnet-4-6', 'sonnet', 'gpt-4o', 'gpt-4.1'],
13
+ autoApprove: true,
14
+ },
15
+ 3: {
16
+ label: 'heavy',
17
+ models: ['claude-opus-4-6', 'claude-opus-4-7', 'opus', 'o3'],
18
+ autoApprove: false, // requires consent check per profile
19
+ },
20
+ });
21
+ // Reverse lookup: model ID → tier number
22
+ export function getModelTier(modelId) {
23
+ if (!modelId)
24
+ return 2; // default to standard
25
+ const normalized = String(modelId).toLowerCase();
26
+ for (const [tier, def] of Object.entries(MODEL_TIERS)) {
27
+ if (def.models.some(m => normalized.includes(m)))
28
+ return Number(tier);
29
+ }
30
+ return 2; // unknown models default to standard
31
+ }
32
+ export function scoreTask(detection) {
33
+ const scores = {
34
+ complexity: 0,
35
+ risk: 0,
36
+ creativity: 0,
37
+ precision: 0,
38
+ contextVolume: 0,
39
+ };
40
+ // Complexity from file count / scope
41
+ const fileCount = detection?.files?.length || detection?.scope?.fileCount || 0;
42
+ if (fileCount >= 6)
43
+ scores.complexity = 3;
44
+ else if (fileCount >= 3)
45
+ scores.complexity = 2;
46
+ else if (fileCount >= 1)
47
+ scores.complexity = 1;
48
+ // Risk from explicit risk field or keywords
49
+ const risk = detection?.risk || detection?.riskLevel || 'low';
50
+ const riskMap = { low: 0, medium: 1, high: 2, critical: 3 };
51
+ scores.risk = riskMap[risk] ?? 0;
52
+ // Boost risk for security/auth/billing keywords
53
+ const text = (detection?.objective || detection?.intent || '').toLowerCase();
54
+ if (/\b(auth|security|credential|secret|billing|payment|migration|delete|drop)\b/.test(text)) {
55
+ scores.risk = Math.max(scores.risk, 2);
56
+ }
57
+ // Creativity from intent type
58
+ const intent = (detection?.intent || detection?.type || '').toLowerCase();
59
+ if (/\b(architect|design|brainstorm|explore|research)\b/.test(intent))
60
+ scores.creativity = 2;
61
+ else if (/\b(refactor|plan|decide)\b/.test(intent))
62
+ scores.creativity = 1;
63
+ // Precision — one-shot tasks need higher precision
64
+ if (/\b(security|deploy|publish|migration)\b/.test(text))
65
+ scores.precision = 2;
66
+ else if (/\b(implement|build|create)\b/.test(text))
67
+ scores.precision = 1;
68
+ // Context volume
69
+ const contextSize = detection?.contextTokens || detection?.estimatedContext || 0;
70
+ if (contextSize > 200000)
71
+ scores.contextVolume = 3;
72
+ else if (contextSize > 50000)
73
+ scores.contextVolume = 2;
74
+ else if (contextSize > 10000)
75
+ scores.contextVolume = 1;
76
+ return scores;
77
+ }
78
+ export function computeRequiredTier(scores) {
79
+ const total = Object.values(scores).reduce((a, b) => a + b, 0);
80
+ if (total <= 2)
81
+ return 1;
82
+ if (total <= 6)
83
+ return 2;
84
+ return 3;
85
+ }
86
+ const GOVERNANCE_PERMISSIONS = {
87
+ 'auto': { 1: 'auto', 2: 'auto', 3: 'ask' },
88
+ 'balanced': { 1: 'auto', 2: 'auto', 3: 'ask' },
89
+ 'cost-saver': { 1: 'auto', 2: 'auto', 3: 'deny' },
90
+ 'quality-first': { 1: 'auto', 2: 'auto', 3: 'auto' },
91
+ };
92
+ // Pricing per million tokens (input/output) for cost estimation
93
+ const MODEL_PRICING = {
94
+ 'haiku': { input: 1.00, output: 5.00 },
95
+ 'sonnet': { input: 3.00, output: 15.00 },
96
+ 'opus': { input: 5.00, output: 25.00 },
97
+ 'gpt-4o-mini': { input: 0.15, output: 0.60 },
98
+ 'gpt-4o': { input: 2.50, output: 10.00 },
99
+ 'gpt-4.1': { input: 2.00, output: 8.00 },
100
+ 'o3': { input: 2.00, output: 8.00 },
101
+ 'o4-mini': { input: 1.10, output: 4.40 },
102
+ };
103
+ function estimateCost(modelId, estimatedTokens = 8000) {
104
+ const normalized = String(modelId).toLowerCase();
105
+ let pricing = MODEL_PRICING['sonnet']; // default
106
+ for (const [key, p] of Object.entries(MODEL_PRICING)) {
107
+ if (normalized.includes(key)) {
108
+ pricing = p;
109
+ break;
110
+ }
111
+ }
112
+ // Assume 20% input, 80% output for agent tasks
113
+ const inputTokens = estimatedTokens * 0.2;
114
+ const outputTokens = estimatedTokens * 0.8;
115
+ return (inputTokens * pricing.input + outputTokens * pricing.output) / 1_000_000;
116
+ }
117
+ export function assessGovernance(model, detection, profile) {
118
+ const tier = getModelTier(model);
119
+ const scores = scoreTask(detection);
120
+ const requiredTier = computeRequiredTier(scores);
121
+ const workStyle = profile?.workStyle || profile?.name || 'auto';
122
+ const permissions = GOVERNANCE_PERMISSIONS[workStyle] || GOVERNANCE_PERMISSIONS['auto'];
123
+ const permission = permissions[tier] || 'ask';
124
+ const estimatedCost = estimateCost(model);
125
+ return {
126
+ requestedTier: tier,
127
+ requiredTier,
128
+ overProvisioned: tier > requiredTier,
129
+ underProvisioned: tier < requiredTier,
130
+ permission,
131
+ estimatedCost,
132
+ scores,
133
+ justification: buildJustification(scores, tier, requiredTier),
134
+ };
135
+ }
136
+ function buildJustification(scores, requestedTier, requiredTier) {
137
+ const parts = [];
138
+ if (scores.risk >= 2)
139
+ parts.push('high-risk');
140
+ if (scores.complexity >= 2)
141
+ parts.push('complex');
142
+ if (scores.creativity >= 2)
143
+ parts.push('creative/architectural');
144
+ if (scores.contextVolume >= 2)
145
+ parts.push('large-context');
146
+ if (requestedTier > requiredTier)
147
+ parts.push('over-provisioned');
148
+ if (requestedTier < requiredTier)
149
+ parts.push('under-provisioned');
150
+ return parts.join(', ') || 'standard task';
151
+ }
152
+ export function shouldCollaborate(detection, governance, profile) {
153
+ // Never collaborate on tier-1 tasks
154
+ if (governance.requiredTier <= 1)
155
+ return { collaborate: false };
156
+ // Never collaborate in cost-saver mode unless explicitly requested
157
+ const workStyle = profile?.workStyle || profile?.name || 'auto';
158
+ if (workStyle === 'cost-saver')
159
+ return { collaborate: false };
160
+ // Check collaboration triggers (need ANY two)
161
+ const triggers = [];
162
+ const text = (detection?.objective || detection?.intent || '').toLowerCase();
163
+ if (/\b(auth|security|credential|billing|migration)\b/.test(text))
164
+ triggers.push('irreversibility');
165
+ if (detection?.ambiguity === 'high' || /\b(should we|how to|best approach|tradeoff)\b/.test(text))
166
+ triggers.push('ambiguity');
167
+ if (detection?.novelty === 'high' || /\b(new|first time|never done|greenfield)\b/.test(text))
168
+ triggers.push('novelty');
169
+ if ((detection?.files?.length || 0) >= 4 && /\b(security|performance|ux)\b/.test(text))
170
+ triggers.push('cross-domain');
171
+ if (governance.requestedTier >= 3 && detection?.confidence != null && detection.confidence < 0.8)
172
+ triggers.push('low-confidence');
173
+ const shouldDo = triggers.length >= 2;
174
+ return {
175
+ collaborate: shouldDo,
176
+ triggers,
177
+ pattern: shouldDo ? selectPattern(triggers, detection) : null,
178
+ estimatedOverhead: shouldDo ? estimateCost('gpt-4.1') : 0,
179
+ };
180
+ }
181
+ function selectPattern(triggers, detection) {
182
+ const text = (detection?.objective || detection?.intent || '').toLowerCase();
183
+ // Security → adversarial review
184
+ if (triggers.includes('irreversibility') && /\b(auth|security|credential)\b/.test(text)) {
185
+ return 'adversarial-review';
186
+ }
187
+ // Architecture/greenfield → second opinion
188
+ if (triggers.includes('novelty') || triggers.includes('ambiguity')) {
189
+ return 'second-opinion';
190
+ }
191
+ // Default
192
+ return 'second-opinion';
193
+ }
194
+ // ─── Governance State (Session Budget Tracking) ──────────────────────────────
195
+ const STATE_FILE = '.dualbrain/governance-state.json';
196
+ const SESSION_GAP_MS = 30 * 60 * 1000; // 30 min gap = new session
197
+ export function loadGovernanceState(cwd) {
198
+ const statePath = join(cwd, STATE_FILE);
199
+ try {
200
+ const raw = JSON.parse(readFileSync(statePath, 'utf8'));
201
+ // Check if session is stale
202
+ const lastDispatch = raw.dispatches?.[raw.dispatches.length - 1];
203
+ if (lastDispatch && (Date.now() - Date.parse(lastDispatch.ts)) > SESSION_GAP_MS) {
204
+ return freshState();
205
+ }
206
+ return raw;
207
+ }
208
+ catch {
209
+ return freshState();
210
+ }
211
+ }
212
+ function freshState() {
213
+ return {
214
+ sessionStartedAt: new Date().toISOString(),
215
+ dispatches: [],
216
+ totalEstimatedCost: 0,
217
+ tierCounts: { 1: 0, 2: 0, 3: 0 },
218
+ };
219
+ }
220
+ export function recordDispatch(cwd, tier, model, estimatedCost, approved = true) {
221
+ const state = loadGovernanceState(cwd);
222
+ state.dispatches.push({
223
+ tier,
224
+ model: String(model),
225
+ estimatedCost,
226
+ approved,
227
+ ts: new Date().toISOString(),
228
+ });
229
+ state.totalEstimatedCost += estimatedCost;
230
+ state.tierCounts[tier] = (state.tierCounts[tier] || 0) + 1;
231
+ const dir = join(cwd, '.dualbrain');
232
+ mkdirSync(dir, { recursive: true });
233
+ writeFileSync(join(cwd, STATE_FILE), JSON.stringify(state, null, 2) + '\n');
234
+ return state;
235
+ }
236
+ export function checkBudget(cwd, orchestratorConfig) {
237
+ const state = loadGovernanceState(cwd);
238
+ const sessionLimit = orchestratorConfig?.budgets?.session_limit_usd || 10;
239
+ const remaining = sessionLimit - state.totalEstimatedCost;
240
+ return {
241
+ spent: state.totalEstimatedCost,
242
+ remaining,
243
+ limit: sessionLimit,
244
+ warning: remaining < sessionLimit * 0.2,
245
+ blocked: remaining <= 0,
246
+ tierCounts: state.tierCounts,
247
+ };
248
+ }
249
+ // ─── Format for User Display ─────────────────────────────────────────────────
250
+ export function formatGovernancePrompt(governance, collaboration) {
251
+ const tierLabel = MODEL_TIERS[governance.requestedTier]?.label || 'unknown';
252
+ const lines = [];
253
+ lines.push(`[governance] Task requires ${tierLabel} model (tier ${governance.requestedTier}, ~$${governance.estimatedCost.toFixed(2)})`);
254
+ if (governance.justification)
255
+ lines.push(` Reason: ${governance.justification}`);
256
+ if (collaboration?.collaborate) {
257
+ lines.push(` + ${collaboration.pattern} with secondary model (+$${(collaboration.estimatedOverhead || 0).toFixed(2)})`);
258
+ }
259
+ return lines.join('\n');
260
+ }
261
+ //# sourceMappingURL=governance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance.js","sourceRoot":"","sources":["../../src/governance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { HandoffStage, HandoffContract } from './types.js';
2
+ interface HandoffSchema {
3
+ required: string[];
4
+ optional: string[];
5
+ }
6
+ export declare const HANDOFF_TYPES: Record<string, HandoffSchema>;
7
+ export declare function createHandoff(fromStage: HandoffStage, toStage: HandoffStage, data: Record<string, unknown>, runId: string, cwd?: string): HandoffContract | null;
8
+ export declare function consumeHandoff(runId: string, fromStage: HandoffStage, toStage: HandoffStage, cwd?: string): HandoffContract | null;
9
+ export declare function buildHandoffContext(handoff: HandoffContract | null, targetRole: string): string;
10
+ export declare function cleanupHandoffs(runId: string, cwd?: string): void;
11
+ export {};
@@ -0,0 +1,90 @@
1
+ // handoff.ts — Typed handoffs between pipeline stages
2
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, renameSync, unlinkSync, readdirSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ export const HANDOFF_TYPES = {
5
+ 'think-to-work': { required: ['objective', 'files', 'criteria'], optional: ['context', 'confidence'] },
6
+ 'work-to-review': { required: ['filesChanged', 'objective'], optional: ['diff', 'criteria', 'testsRun'] },
7
+ 'review-to-head': { required: ['pass'], optional: ['findings', 'recommendation', 'severity'] },
8
+ };
9
+ const hDir = (cwd) => join(cwd || process.cwd(), '.dualbrain', 'handoffs');
10
+ const hPath = (id, f, t, cwd) => join(hDir(cwd), `${id}_${f}_${t}.json`);
11
+ function validate(from, to, data) {
12
+ const schema = HANDOFF_TYPES[`${from}-to-${to}`];
13
+ if (!schema)
14
+ return;
15
+ for (const f of schema.required) {
16
+ if (!(f in data))
17
+ process.stderr.write(`[handoff] warn: missing required field '${f}' in ${from}-to-${to}\n`);
18
+ }
19
+ }
20
+ export function createHandoff(fromStage, toStage, data, runId, cwd) {
21
+ try {
22
+ validate(fromStage, toStage, data);
23
+ const safeRunId = String(runId).replace(/[^a-z0-9_-]/gi, '_').slice(0, 50);
24
+ const dir = hDir(cwd);
25
+ if (!existsSync(dir))
26
+ mkdirSync(dir, { recursive: true });
27
+ const record = { fromStage, toStage, runId: safeRunId, createdAt: new Date().toISOString(), data: data };
28
+ const dest = hPath(safeRunId, fromStage, toStage, cwd);
29
+ const tmp = dest + '.tmp';
30
+ writeFileSync(tmp, JSON.stringify(record, null, 2), 'utf8');
31
+ try {
32
+ renameSync(tmp, dest);
33
+ }
34
+ catch {
35
+ writeFileSync(dest, JSON.stringify(record, null, 2), 'utf8');
36
+ }
37
+ return record;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ export function consumeHandoff(runId, fromStage, toStage, cwd) {
44
+ try {
45
+ const safeRunId = String(runId).replace(/[^a-z0-9_-]/gi, '_').slice(0, 50);
46
+ const p = hPath(safeRunId, fromStage, toStage, cwd);
47
+ if (!existsSync(p))
48
+ return null;
49
+ const record = JSON.parse(readFileSync(p, 'utf8'));
50
+ try {
51
+ unlinkSync(p);
52
+ }
53
+ catch { /* best-effort */ }
54
+ return record;
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ export function buildHandoffContext(handoff, targetRole) {
61
+ if (!handoff?.data)
62
+ return '';
63
+ const d = handoff.data;
64
+ const lines = (...parts) => parts.filter(Boolean).join('\n');
65
+ const list = (v) => Array.isArray(v) ? v.join(', ') : (v ?? '');
66
+ const items = (v) => Array.isArray(v) ? v.map(x => ` - ${x}`).join('\n') : (v ?? '');
67
+ if (targetRole === 'worker' && handoff.fromStage === 'thinker')
68
+ return lines('## Handoff from Think Stage', `**Objective:** ${d.objective ?? '(none)'}`, `**Files in scope:** ${list(d.files) || 'unspecified'}`, d.criteria ? `**Acceptance criteria:**\n${items(d.criteria)}` : '', d.context ? `**Context:** ${d.context}` : '', d.confidence != null ? `**Thinker confidence:** ${d.confidence}` : '');
69
+ if (targetRole === 'reviewer' && handoff.fromStage === 'worker')
70
+ return lines('## Handoff from Work Stage', `**Objective:** ${d.objective ?? '(none)'}`, `**Files changed:** ${list(d.filesChanged) || 'unknown'}`, d.criteria ? `**Original criteria:** ${Array.isArray(d.criteria) ? d.criteria.join('; ') : d.criteria}` : '', d.testsRun ? `**Tests run:** ${d.testsRun}` : '', d.diff ? `**Diff summary:**\n\`\`\`\n${d.diff.slice(0, 1200)}\n\`\`\`` : '');
71
+ if (targetRole === 'head' && handoff.fromStage === 'reviewer')
72
+ return lines(`## Review Result: ${d.pass ? 'PASS' : 'FAIL'}`, d.findings ? `**Findings:**\n${items(d.findings)}` : '', d.recommendation ? `**Recommendation:** ${d.recommendation}` : '', d.severity ? `**Severity:** ${d.severity}` : '');
73
+ return JSON.stringify(handoff.data, null, 2);
74
+ }
75
+ export function cleanupHandoffs(runId, cwd) {
76
+ try {
77
+ const dir = hDir(cwd);
78
+ if (!existsSync(dir))
79
+ return;
80
+ for (const name of readdirSync(dir)) {
81
+ if (name.startsWith(`${runId}_`))
82
+ try {
83
+ unlinkSync(join(dir, name));
84
+ }
85
+ catch { /* best-effort */ }
86
+ }
87
+ }
88
+ catch { /* non-throwing */ }
89
+ }
90
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/handoff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ export interface DispatchPlan {
2
+ strategy: string;
3
+ id: string;
4
+ expectedParallel: number;
5
+ waveSize: number;
6
+ subtasks?: string[];
7
+ reason: string;
8
+ }
9
+ export interface DeliberationArtifact {
10
+ timestamp: number;
11
+ createdAt: number;
12
+ message: string;
13
+ action: unknown;
14
+ result: unknown;
15
+ shouldAskUser: boolean;
16
+ confidence: unknown;
17
+ obligations: unknown[];
18
+ surfaceNoticings: unknown[];
19
+ dispatchPlan: DispatchPlan | null;
20
+ depth: string;
21
+ rationale: string;
22
+ situation: {
23
+ taskShape: unknown;
24
+ urgency: unknown;
25
+ scope: unknown;
26
+ };
27
+ }
28
+ interface ProcessTurnResult {
29
+ action: {
30
+ type: string;
31
+ mode?: string;
32
+ };
33
+ result: {
34
+ confidence?: {
35
+ score?: number;
36
+ } | null;
37
+ surfaceNoticings?: unknown[];
38
+ depth?: string;
39
+ };
40
+ shouldAskUser: boolean;
41
+ obligations?: unknown[];
42
+ depth: string;
43
+ rationale: string;
44
+ situation?: {
45
+ taskShape?: {
46
+ scope?: string;
47
+ } | null;
48
+ urgency?: string;
49
+ material?: {
50
+ touchedFiles?: string[];
51
+ };
52
+ };
53
+ }
54
+ interface DispatchContext {
55
+ subtasks?: Array<string | {
56
+ name?: string;
57
+ description?: string;
58
+ }>;
59
+ situation?: unknown;
60
+ result?: unknown;
61
+ [key: string]: unknown;
62
+ }
63
+ /**
64
+ * Write the deliberation artifact after running HEAD's cognitive pipeline.
65
+ * This is the contract between HEAD's thinking and the deliberation-gate hook.
66
+ */
67
+ export declare function writeDeliberation(userMessage: string, context?: DispatchContext): ProcessTurnResult;
68
+ /**
69
+ * Read the current deliberation artifact.
70
+ */
71
+ export declare function readDeliberation(): DeliberationArtifact | null;
72
+ /**
73
+ * Check if the current deliberation is fresh (within maxAgeMs).
74
+ */
75
+ export declare function isDeliberationFresh(maxAgeMs?: number): boolean;
76
+ export {};
@@ -0,0 +1,109 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { processTurn, loadState } from './head.js';
4
+ const DUALBRAIN = join(process.cwd(), '.dualbrain');
5
+ const DELIBERATION_FILE = join(DUALBRAIN, 'deliberation.json');
6
+ /**
7
+ * Write the deliberation artifact after running HEAD's cognitive pipeline.
8
+ * This is the contract between HEAD's thinking and the deliberation-gate hook.
9
+ */
10
+ export function writeDeliberation(userMessage, context = {}) {
11
+ const state = loadState();
12
+ const result = processTurn(state, userMessage, context);
13
+ // Determine if there are multiple independent sub-tasks that could be parallelized
14
+ const dispatchPlan = _deriveDispatchPlan(result, context);
15
+ // Build the artifact
16
+ const artifact = {
17
+ timestamp: Date.now(),
18
+ createdAt: Date.now(),
19
+ message: userMessage.slice(0, 500),
20
+ // Core deliberation fields
21
+ action: result.action,
22
+ result: result.result,
23
+ shouldAskUser: result.shouldAskUser,
24
+ confidence: result.result?.confidence || null,
25
+ // Obligations and noticings
26
+ obligations: result.obligations || [],
27
+ surfaceNoticings: result.result?.surfaceNoticings || [],
28
+ // Dispatch plan (parallel-wave support)
29
+ dispatchPlan,
30
+ // Metadata
31
+ depth: result.depth,
32
+ rationale: result.rationale,
33
+ situation: {
34
+ taskShape: result.situation?.taskShape || null,
35
+ urgency: result.situation?.urgency || null,
36
+ scope: result.situation?.taskShape?.scope || null,
37
+ },
38
+ };
39
+ // Write atomically
40
+ mkdirSync(DUALBRAIN, { recursive: true });
41
+ const tmpFile = DELIBERATION_FILE + '.tmp.' + process.pid;
42
+ writeFileSync(tmpFile, JSON.stringify(artifact, null, 2));
43
+ renameSync(tmpFile, DELIBERATION_FILE);
44
+ return result;
45
+ }
46
+ /**
47
+ * Read the current deliberation artifact.
48
+ */
49
+ export function readDeliberation() {
50
+ try {
51
+ if (!existsSync(DELIBERATION_FILE))
52
+ return null;
53
+ return JSON.parse(readFileSync(DELIBERATION_FILE, 'utf8'));
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * Check if the current deliberation is fresh (within maxAgeMs).
61
+ */
62
+ export function isDeliberationFresh(maxAgeMs = 60_000) {
63
+ const delib = readDeliberation();
64
+ if (!delib)
65
+ return false;
66
+ const timestamp = delib.timestamp || delib.createdAt || 0;
67
+ return (Date.now() - timestamp) <= maxAgeMs;
68
+ }
69
+ // ── Internal helpers ─────────────────────────────────────────────────────────
70
+ /**
71
+ * Derive a dispatch plan when the situation has multiple independent sub-tasks.
72
+ * Returns null if parallel dispatch is not applicable.
73
+ */
74
+ function _deriveDispatchPlan(result, context) {
75
+ const situation = result.situation;
76
+ if (!situation)
77
+ return null;
78
+ // Only generate a parallel plan for multi-file, non-trivial work
79
+ const scope = situation.taskShape?.scope;
80
+ const actionType = result.action?.type;
81
+ if (scope !== 'large' && scope !== 'medium')
82
+ return null;
83
+ if (actionType !== 'dispatch' && actionType !== 'proceed')
84
+ return null;
85
+ // Check for independent sub-tasks from context
86
+ const subtasks = context.subtasks || [];
87
+ if (subtasks.length < 2) {
88
+ // Heuristic: large scope with multiple files could be parallel
89
+ const fileCount = situation.material?.touchedFiles?.length || 0;
90
+ if (fileCount < 3)
91
+ return null;
92
+ return {
93
+ strategy: 'parallel-wave',
94
+ id: Date.now().toString(36),
95
+ expectedParallel: Math.min(fileCount, 5),
96
+ waveSize: Math.min(fileCount, 5),
97
+ reason: `${fileCount} independent files detected`,
98
+ };
99
+ }
100
+ return {
101
+ strategy: 'parallel-wave',
102
+ id: Date.now().toString(36),
103
+ expectedParallel: subtasks.length,
104
+ waveSize: subtasks.length,
105
+ subtasks: subtasks.map(t => typeof t === 'string' ? t : t.name || t.description || ''),
106
+ reason: `${subtasks.length} independent sub-tasks identified`,
107
+ };
108
+ }
109
+ //# sourceMappingURL=head-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head-protocol.js","sourceRoot":"","sources":["../../src/head-protocol.ts"],"names":[],"mappings":"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"}