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
package/src/decompose.mjs DELETED
@@ -1,331 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * decompose.mjs — Task graph decomposition for the Dual-Brain Orchestrator HEAD.
4
- *
5
- * Splits complex prompts into a dependency-aware task graph using heuristic
6
- * analysis. Pure data — returns a plan, does NOT spawn agents.
7
- *
8
- * Exports: decompose, isSimpleTask, taskGraphToWaves
9
- */
10
-
11
- import { detectTask, classifyIntent, extractPaths } from './detect.mjs';
12
- import { loadPlaybook } from './playbook.mjs';
13
-
14
- // ─── Role inference ───────────────────────────────────────────────────────────
15
-
16
- /**
17
- * Map a tier + intent to the appropriate agent role.
18
- * @param {string} tier
19
- * @param {string} intent
20
- * @returns {'researcher'|'implementer'|'reviewer'|'verifier'}
21
- */
22
- function inferRole(tier, intent) {
23
- if (tier === 'search') return 'researcher';
24
- if (tier === 'think') {
25
- if (intent === 'review') return 'reviewer';
26
- return 'researcher'; // architect/planner stays researcher (read-only)
27
- }
28
- // execute tier
29
- if (intent === 'test') return 'verifier';
30
- if (intent === 'review') return 'reviewer';
31
- return 'implementer';
32
- }
33
-
34
- // ─── Conjunction splitter ─────────────────────────────────────────────────────
35
-
36
- const CONJUNCTIONS = /\s+(?:and(?:\s+also)?|then|also|plus|after\s+that|additionally|as\s+well\s+as)\s+/i;
37
-
38
- /**
39
- * Split a prompt on natural-language conjunctions into clauses.
40
- * @param {string} prompt
41
- * @returns {string[]}
42
- */
43
- function splitClauses(prompt) {
44
- const parts = prompt.split(CONJUNCTIONS).map(s => s.trim()).filter(Boolean);
45
- return parts.length > 1 ? parts : [prompt];
46
- }
47
-
48
- // ─── File ownership inference ─────────────────────────────────────────────────
49
-
50
- /**
51
- * Extract file globs from a clause, falling back to intent-based heuristics.
52
- * @param {string} clause
53
- * @param {string} intent
54
- * @param {string[]} contextFiles — file paths provided in decompose context
55
- * @returns {string[]}
56
- */
57
- function inferOwnership(clause, intent, contextFiles = []) {
58
- const readOnly = ['search', 'explain', 'compare', 'review'];
59
- if (readOnly.includes(intent)) return []; // read-only roles own nothing
60
-
61
- // Paths mentioned explicitly in the clause
62
- const mentioned = extractPaths(clause);
63
- if (mentioned.length > 0) return mentioned;
64
-
65
- // Paths from context that relate to this clause (simple keyword match)
66
- const clauseLower = clause.toLowerCase();
67
- const related = contextFiles.filter(f => {
68
- const base = f.split('/').pop() ?? '';
69
- return clauseLower.includes(base.replace(/\.[^.]+$/, ''));
70
- });
71
- if (related.length > 0) return related;
72
-
73
- // Structural heuristics by intent
74
- if (intent === 'test') return ['**/*.test.*', '**/*.spec.*'];
75
- if (intent === 'document') return ['**/*.md'];
76
- if (intent === 'format') return ['**/*'];
77
-
78
- return [];
79
- }
80
-
81
- // ─── Dependency ordering ──────────────────────────────────────────────────────
82
-
83
- const ROLE_ORDER = { researcher: 0, reviewer: 1, implementer: 2, verifier: 3 };
84
-
85
- /**
86
- * Build dependency graph: earlier-role tasks must complete before later-role tasks.
87
- * @param {{ id: string, role: string }[]} tasks
88
- * @returns {{ [taskId: string]: string[] }} task id → list of dependent task ids
89
- */
90
- function buildDependencies(tasks) {
91
- const deps = {};
92
- for (const task of tasks) {
93
- deps[task.id] = [];
94
- }
95
-
96
- // Each task depends on all tasks with a strictly lower role rank
97
- for (let i = 0; i < tasks.length; i++) {
98
- for (let j = 0; j < i; j++) {
99
- if (ROLE_ORDER[tasks[j].role] < ROLE_ORDER[tasks[i].role]) {
100
- deps[tasks[i].id].push(tasks[j].id);
101
- }
102
- }
103
- }
104
-
105
- return deps;
106
- }
107
-
108
- // ─── Exported: taskGraphToWaves ───────────────────────────────────────────────
109
-
110
- /**
111
- * Topological sort: group tasks into dependency layers (waves).
112
- * Tasks with no unmet dependencies form the earliest wave.
113
- * @param {{ id: string, dependsOn: string[] }[]} tasks
114
- * @returns {string[][]} each element is an array of task IDs in that wave
115
- */
116
- export function taskGraphToWaves(tasks) {
117
- const remaining = new Set(tasks.map(t => t.id));
118
- const satisfied = new Set();
119
- const waves = [];
120
-
121
- while (remaining.size > 0) {
122
- const wave = [];
123
- for (const task of tasks) {
124
- if (!remaining.has(task.id)) continue;
125
- const allDepsSatisfied = task.dependsOn.every(dep => satisfied.has(dep));
126
- if (allDepsSatisfied) wave.push(task.id);
127
- }
128
-
129
- if (wave.length === 0) {
130
- // Cycle or unresolvable — dump remaining tasks into one last wave
131
- waves.push([...remaining]);
132
- break;
133
- }
134
-
135
- waves.push(wave);
136
- for (const id of wave) {
137
- remaining.delete(id);
138
- satisfied.add(id);
139
- }
140
- }
141
-
142
- return waves;
143
- }
144
-
145
- // ─── Exported: isSimpleTask ───────────────────────────────────────────────────
146
-
147
- /**
148
- * Returns true if the detection indicates a trivial or simple task that does
149
- * not need decomposition.
150
- * @param {{ complexity: string }} detection
151
- * @returns {boolean}
152
- */
153
- export function isSimpleTask(detection) {
154
- return detection.complexity === 'trivial' || detection.complexity === 'simple';
155
- }
156
-
157
- // ─── Playbook → task graph ────────────────────────────────────────────────────
158
-
159
- /**
160
- * Convert a loaded playbook's steps into a task graph.
161
- * @param {object} playbook
162
- * @param {string[]} contextFiles
163
- * @returns {{ id, title, goal, tier, role, owns, dependsOn, consensus, risk }[]}
164
- */
165
- function playbookToTasks(playbook, contextFiles = []) {
166
- const steps = playbook.steps ?? [];
167
- const tasks = steps.map(step => {
168
- const tier = step.tier ?? 'execute';
169
- const intent = tier === 'think' ? 'architecture' : tier === 'search' ? 'search' : 'edit';
170
- const role = inferRole(tier, intent);
171
- return {
172
- id: step.id,
173
- title: step.title,
174
- goal: step.goal,
175
- tier,
176
- role,
177
- owns: inferOwnership(step.goal, intent, contextFiles),
178
- dependsOn: [], // will be filled below
179
- consensus: step.consensus === true,
180
- risk: 'medium',
181
- };
182
- });
183
-
184
- // Each task depends on the immediately prior task (sequential playbook flow)
185
- for (let i = 1; i < tasks.length; i++) {
186
- tasks[i].dependsOn = [tasks[i - 1].id];
187
- }
188
-
189
- return tasks;
190
- }
191
-
192
- // ─── Heuristic task graph from clause splitting ───────────────────────────────
193
-
194
- /**
195
- * Build a task graph from clause-split sub-prompts via independent detection.
196
- * @param {string[]} clauses
197
- * @param {string[]} files
198
- * @returns {{ id, title, goal, tier, role, owns, dependsOn, consensus, risk }[]}
199
- */
200
- function clausesToTasks(clauses, files = []) {
201
- const raw = clauses.map((clause, idx) => {
202
- const detection = detectTask({ prompt: clause, files });
203
- const { intent, tier, risk } = detection;
204
- const role = inferRole(tier, intent);
205
- return {
206
- id: `task-${idx + 1}`,
207
- title: clause.length > 60 ? clause.slice(0, 57) + '...' : clause,
208
- goal: clause,
209
- tier,
210
- role,
211
- owns: inferOwnership(clause, intent, files),
212
- dependsOn: [], // placeholder
213
- consensus: risk === 'critical' || (risk === 'high' && tier === 'think'),
214
- risk,
215
- };
216
- });
217
-
218
- // Build dependency graph and fill in dependsOn
219
- const deps = buildDependencies(raw);
220
- for (const task of raw) {
221
- task.dependsOn = deps[task.id];
222
- }
223
-
224
- return raw;
225
- }
226
-
227
- // ─── Exported: decompose ──────────────────────────────────────────────────────
228
-
229
- /**
230
- * Decompose a prompt into a dependency-aware task graph.
231
- * Pure data — returns a plan, does NOT spawn agents.
232
- *
233
- * @param {string} prompt
234
- * @param {{ files?: string[], cwd?: string, repo?: object, profile?: object }} [context]
235
- * @returns {{
236
- * tasks: object[],
237
- * waves: string[][],
238
- * confidence: 'high'|'medium'|'low',
239
- * needsResearch: boolean,
240
- * parallelizable: boolean,
241
- * }}
242
- */
243
- export function decompose(prompt, context = {}) {
244
- const { files = [], cwd } = context;
245
-
246
- // 1. Classify the full prompt
247
- const detection = detectTask({ prompt, files });
248
-
249
- // 2. Trivial/simple → single-task graph
250
- if (isSimpleTask(detection)) {
251
- const { intent, tier, risk } = detection;
252
- const role = inferRole(tier, intent);
253
- const task = {
254
- id: 'task-1',
255
- title: prompt.length > 60 ? prompt.slice(0, 57) + '...' : prompt,
256
- goal: prompt,
257
- tier,
258
- role,
259
- owns: inferOwnership(prompt, intent, files),
260
- dependsOn: [],
261
- consensus: false,
262
- risk,
263
- };
264
- return {
265
- tasks: [task],
266
- waves: [['task-1']],
267
- confidence: 'high',
268
- needsResearch: false,
269
- parallelizable: false,
270
- };
271
- }
272
-
273
- // 3. Try to match a playbook
274
- const playbook = loadPlaybook(detection.intent, cwd);
275
- if (playbook) {
276
- const tasks = playbookToTasks(playbook, files);
277
- const waves = taskGraphToWaves(tasks);
278
- return {
279
- tasks,
280
- waves,
281
- confidence: 'high',
282
- needsResearch: false,
283
- parallelizable: waves.some(w => w.length > 1),
284
- };
285
- }
286
-
287
- // 4. Heuristic clause splitting
288
- const clauses = splitClauses(prompt);
289
- const hasResearch = files.length === 0 && detection.complexity !== 'trivial';
290
-
291
- // If splitting didn't help (single clause), add a research task prefix for complex tasks
292
- let allClauses = clauses;
293
- if (clauses.length === 1 && hasResearch) {
294
- allClauses = [`Research: find all files and context relevant to: ${prompt}`, ...clauses];
295
- }
296
-
297
- const tasks = clausesToTasks(allClauses, files);
298
- const waves = taskGraphToWaves(tasks);
299
-
300
- // Confidence: medium if we split cleanly (>1 clause), low if ambiguous
301
- const confidence = clauses.length > 1 ? 'medium' : 'low';
302
-
303
- return {
304
- tasks,
305
- waves,
306
- confidence,
307
- needsResearch: hasResearch,
308
- parallelizable: waves.some(w => w.length > 1),
309
- };
310
- }
311
-
312
- // ─── CLI ──────────────────────────────────────────────────────────────────────
313
-
314
- if (process.argv[1] && new URL(import.meta.url).pathname === process.argv[1]) {
315
- const args = process.argv.slice(2);
316
- const prompt = args.find(a => !a.startsWith('--')) || '';
317
-
318
- if (!prompt) {
319
- console.error('Usage: node src/decompose.mjs "task description" [--files a,b]');
320
- process.exit(1);
321
- }
322
-
323
- const filesFlag = args.find(a => a.startsWith('--files=')) ||
324
- (args.includes('--files') ? args[args.indexOf('--files') + 1] : null);
325
- const files = filesFlag
326
- ? filesFlag.replace(/^--files=/, '').split(',').map(f => f.trim()).filter(Boolean)
327
- : [];
328
-
329
- const result = decompose(prompt, { files });
330
- console.log(JSON.stringify(result, null, 2));
331
- }