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,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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"}