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
@@ -1,210 +0,0 @@
1
- // living-docs.mjs — Living document system for .dualbrain/.
2
- // Manages project.json, vision.md, roadmap.md, state.md, actions.jsonl, decisions.jsonl, checkpoints.jsonl.
3
-
4
- import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync } from 'node:fs';
5
- import { join } from 'node:path';
6
- import { execSync } from 'node:child_process';
7
-
8
- const DIR = '.dualbrain';
9
-
10
- function docsDir(cwd = process.cwd()) {
11
- return join(cwd, DIR);
12
- }
13
-
14
- function ensureDir(cwd) {
15
- mkdirSync(docsDir(cwd), { recursive: true });
16
- }
17
-
18
- function filePath(name, cwd) {
19
- return join(docsDir(cwd), name);
20
- }
21
-
22
- function readFileSafe(name, cwd, fallback = '') {
23
- try {
24
- return readFileSync(filePath(name, cwd), 'utf8');
25
- } catch {
26
- return fallback;
27
- }
28
- }
29
-
30
- function readJsonSafe(name, cwd, fallback = {}) {
31
- try {
32
- return JSON.parse(readFileSync(filePath(name, cwd), 'utf8'));
33
- } catch {
34
- return fallback;
35
- }
36
- }
37
-
38
- function readPackageJson(cwd) {
39
- try {
40
- return JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
41
- } catch {
42
- return {};
43
- }
44
- }
45
-
46
- function gitExec(cmd, cwd) {
47
- try {
48
- return execSync(cmd, { cwd, stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
49
- } catch {
50
- return null;
51
- }
52
- }
53
-
54
- export function initLivingDocs(cwd = process.cwd()) {
55
- const dir = docsDir(cwd);
56
- const existed = existsSync(dir);
57
- ensureDir(cwd);
58
-
59
- const pkg = readPackageJson(cwd);
60
-
61
- if (!existsSync(filePath('project.json', cwd))) {
62
- const project = {
63
- name: pkg.name ?? '',
64
- version: pkg.version ?? '0.0.1',
65
- created: new Date().toISOString(),
66
- workStyle: 'balanced',
67
- userCalibration: { specificity: 3, corrections: 3, autonomy: 3 },
68
- team: [],
69
- providers: {},
70
- };
71
- writeFileSync(filePath('project.json', cwd), JSON.stringify(project, null, 2));
72
- }
73
-
74
- if (!existsSync(filePath('vision.md', cwd))) {
75
- writeFileSync(filePath('vision.md', cwd), '# Vision\n\n_Not yet defined. Type your vision and HEAD will maintain this document._\n');
76
- }
77
-
78
- if (!existsSync(filePath('roadmap.md', cwd))) {
79
- writeFileSync(filePath('roadmap.md', cwd), '# Roadmap\n\n_No roadmap yet. As you work, HEAD will build this from your actions._\n');
80
- }
81
-
82
- if (!existsSync(filePath('state.md', cwd))) {
83
- writeFileSync(filePath('state.md', cwd), '# Current State\n\n_Fresh project. No history yet._\n');
84
- }
85
-
86
- for (const log of ['actions.jsonl', 'decisions.jsonl', 'checkpoints.jsonl']) {
87
- if (!existsSync(filePath(log, cwd))) {
88
- writeFileSync(filePath(log, cwd), '');
89
- }
90
- }
91
-
92
- return { created: !existed, path: dir };
93
- }
94
-
95
- export function appendAction(action, cwd = process.cwd()) {
96
- ensureDir(cwd);
97
- const entry = {
98
- id: `act_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
99
- timestamp: new Date().toISOString(),
100
- type: 'task',
101
- intent: '',
102
- status: 'started',
103
- owner: 'head',
104
- files: [],
105
- proof: null,
106
- cost: null,
107
- result: null,
108
- ...action,
109
- };
110
- appendFileSync(filePath('actions.jsonl', cwd), JSON.stringify(entry) + '\n');
111
- return entry;
112
- }
113
-
114
- export function appendDecision(decision, cwd = process.cwd()) {
115
- ensureDir(cwd);
116
- const entry = {
117
- id: `dec_${Date.now()}`,
118
- timestamp: new Date().toISOString(),
119
- question: '',
120
- decision: '',
121
- reasoning: '',
122
- participants: [],
123
- supersedes: null,
124
- ...decision,
125
- };
126
- appendFileSync(filePath('decisions.jsonl', cwd), JSON.stringify(entry) + '\n');
127
- return entry;
128
- }
129
-
130
- export function createCheckpoint(summary, cwd = process.cwd()) {
131
- ensureDir(cwd);
132
- const gitRef = gitExec('git rev-parse HEAD', cwd) ?? 'unknown';
133
- const branch = gitExec('git rev-parse --abbrev-ref HEAD', cwd) ?? 'unknown';
134
- const stateSnapshot = readFileSafe('state.md', cwd, '');
135
- const entry = {
136
- id: `cp_${Date.now()}`,
137
- timestamp: new Date().toISOString(),
138
- gitRef,
139
- branch,
140
- summary,
141
- stateSnapshot,
142
- };
143
- appendFileSync(filePath('checkpoints.jsonl', cwd), JSON.stringify(entry) + '\n');
144
- return entry;
145
- }
146
-
147
- export function updateState(newContent, cwd = process.cwd()) {
148
- ensureDir(cwd);
149
- writeFileSync(filePath('state.md', cwd), newContent);
150
- }
151
-
152
- export function updateRoadmap(newContent, cwd = process.cwd()) {
153
- ensureDir(cwd);
154
- writeFileSync(filePath('roadmap.md', cwd), newContent);
155
- }
156
-
157
- export function updateVision(newContent, cwd = process.cwd()) {
158
- ensureDir(cwd);
159
- const prev = readFileSafe('vision.md', cwd, '');
160
- writeFileSync(filePath('vision.md', cwd), newContent);
161
- if (prev !== newContent) {
162
- appendDecision({
163
- question: 'What is the project vision?',
164
- decision: newContent.slice(0, 200),
165
- reasoning: 'Vision document updated.',
166
- participants: ['head'],
167
- supersedes: null,
168
- }, cwd);
169
- }
170
- }
171
-
172
- export function getProjectState(cwd = process.cwd()) {
173
- const project = readJsonSafe('project.json', cwd, {});
174
- const state = readFileSafe('state.md', cwd, '');
175
- const actions = getRecentActions(cwd, 20);
176
- const decisions = readLastLines('decisions.jsonl', cwd, 5);
177
- const checkpoints = readLastLines('checkpoints.jsonl', cwd, 1);
178
- return {
179
- project,
180
- state,
181
- recentActions: actions,
182
- recentDecisions: decisions,
183
- lastCheckpoint: checkpoints[0] ?? null,
184
- };
185
- }
186
-
187
- function readLastLines(name, cwd, n) {
188
- const raw = readFileSafe(name, cwd, '');
189
- const lines = raw.split('\n').filter(l => l.trim());
190
- return lines.slice(-n).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
191
- }
192
-
193
- export function getRecentActions(cwd = process.cwd(), limit = 20) {
194
- return readLastLines('actions.jsonl', cwd, limit);
195
- }
196
-
197
- export function getOpenTasks(cwd = process.cwd()) {
198
- const raw = readFileSafe('actions.jsonl', cwd, '');
199
- const lines = raw.split('\n').filter(l => l.trim());
200
- const entries = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
201
- return entries.filter(e => e.status === 'started' || e.status === 'blocked');
202
- }
203
-
204
- export function updateProject(updates, cwd = process.cwd()) {
205
- ensureDir(cwd);
206
- const current = readJsonSafe('project.json', cwd, {});
207
- const merged = { ...current, ...updates };
208
- writeFileSync(filePath('project.json', cwd), JSON.stringify(merged, null, 2));
209
- return merged;
210
- }
@@ -1,193 +0,0 @@
1
- // memory-tiers.mjs — Hot/Warm/Cold memory with active paging.
2
- //
3
- // Hot: loaded every turn (narrative + active simmer). Always in HEAD's context.
4
- // Warm: loaded on demand (recent debriefs, narrative history, relevant past decisions).
5
- // Cold: past sessions, archived patterns. Only retrieved when explicitly needed.
6
- //
7
- // The paging mechanism: HEAD doesn't decide what to load — this module does,
8
- // based on what the current situation seems to need.
9
-
10
- import { existsSync, readFileSync, readdirSync } from 'node:fs';
11
- import { join } from 'node:path';
12
- import * as narrative from './narrative.mjs';
13
- import * as simmer from './simmer.mjs';
14
-
15
- const STATE_DIR = join(process.cwd(), '.dualbrain');
16
-
17
- /**
18
- * @typedef {object} MemoryContext
19
- * @property {string} narrative - Current running narrative
20
- * @property {string} simmerBrief - What's brewing
21
- * @property {Array} warmItems - Paged-in warm memory items
22
- * @property {string} combined - Single string ready to inject into HEAD's context
23
- */
24
-
25
- /**
26
- * Load hot memory — always returned, every turn.
27
- * This is the minimum context HEAD needs to be "in the song."
28
- *
29
- * @returns {{narrative: string, simmerBrief: string, combined: string}}
30
- */
31
- export function loadHot() {
32
- const narr = narrative.load();
33
- const simmering = simmer.brief();
34
-
35
- const parts = [];
36
- if (narr) parts.push(narr);
37
- if (simmering) parts.push(`[Simmering]\n${simmering}`);
38
-
39
- return {
40
- narrative: narr,
41
- simmerBrief: simmering,
42
- combined: parts.join('\n\n'),
43
- };
44
- }
45
-
46
- /**
47
- * Load warm memory — contextually relevant items paged in based on signals.
48
- *
49
- * @param {object} signals - What the current turn is about
50
- * @param {string} signals.userMessage - The user's message
51
- * @param {string[]} signals.files - Files being discussed
52
- * @param {string} signals.intent - Detected intent (from HEAD's perception)
53
- * @returns {Array<{source: string, content: string}>}
54
- */
55
- export function loadWarm(signals = {}) {
56
- const items = [];
57
-
58
- // Recent narrative history if we're resuming or context feels thin
59
- if (_looksLikeResume(signals.userMessage) || !narrative.load()) {
60
- const history = narrative.recentHistory(3);
61
- if (history.length > 0) {
62
- items.push({
63
- source: 'narrative-history',
64
- content: history.map(h => h.text).join('\n---\n'),
65
- });
66
- }
67
- }
68
-
69
- // Recent debriefs if we're continuing dispatch work
70
- if (signals.intent === 'dispatch' || signals.intent === 'proceed') {
71
- const debriefs = _loadRecentDebriefs(3);
72
- if (debriefs.length > 0) {
73
- items.push({
74
- source: 'recent-debriefs',
75
- content: debriefs.map(d => `[${d.status}] ${d.objective || d.summary || ''}`).join('\n'),
76
- });
77
- }
78
- }
79
-
80
- // Routing decisions if making a new routing choice
81
- if (signals.intent === 'route' || signals.intent === 'dispatch') {
82
- const decisions = _loadRecentDecisions(5);
83
- if (decisions.length > 0) {
84
- items.push({
85
- source: 'routing-history',
86
- content: decisions.map(d => `${d.provider}/${d.model}: ${d.reason || ''}`).join('\n'),
87
- });
88
- }
89
- }
90
-
91
- return items;
92
- }
93
-
94
- /**
95
- * Load cold memory — only when explicitly requested or when signals strongly indicate need.
96
- *
97
- * @param {string} query - What we're looking for
98
- * @returns {Array<{source: string, content: string}>}
99
- */
100
- export function loadCold(query) {
101
- const items = [];
102
-
103
- // Search past handoffs (from continuity.mjs)
104
- const handoffs = _searchHandoffs(query);
105
- if (handoffs.length > 0) {
106
- items.push({
107
- source: 'past-sessions',
108
- content: handoffs.map(h => `[${h.timestamp}] ${h.task || ''}: ${h.resumeHint || ''}`).join('\n'),
109
- });
110
- }
111
-
112
- return items;
113
- }
114
-
115
- /**
116
- * Full context assembly — combines hot + warm based on current signals.
117
- * This is what gets injected into HEAD's turn context.
118
- *
119
- * @param {object} signals
120
- * @returns {MemoryContext}
121
- */
122
- export function assemble(signals = {}) {
123
- const hot = loadHot();
124
- const warm = loadWarm(signals);
125
-
126
- const parts = [];
127
- if (hot.combined) parts.push(hot.combined);
128
-
129
- if (warm.length > 0) {
130
- const warmText = warm.map(w => `[${w.source}]\n${w.content}`).join('\n\n');
131
- parts.push(warmText);
132
- }
133
-
134
- return {
135
- narrative: hot.narrative,
136
- simmerBrief: hot.simmerBrief,
137
- warmItems: warm,
138
- combined: parts.join('\n\n---\n\n'),
139
- };
140
- }
141
-
142
- // ── Internal helpers ──────────────────────────────────────────────────────────
143
-
144
- function _looksLikeResume(msg) {
145
- if (!msg) return false;
146
- const lower = msg.toLowerCase();
147
- return /continue|where were we|pick up|resume|what's next|whats next/.test(lower);
148
- }
149
-
150
- function _loadRecentDebriefs(n) {
151
- try {
152
- const loopFile = join(STATE_DIR, 'cognitive-loop.json');
153
- if (!existsSync(loopFile)) return [];
154
- const loop = JSON.parse(readFileSync(loopFile, 'utf8'));
155
- return (loop.debriefs || []).slice(-n);
156
- } catch {
157
- return [];
158
- }
159
- }
160
-
161
- function _loadRecentDecisions(n) {
162
- try {
163
- const file = join(STATE_DIR, 'decisions.jsonl');
164
- if (!existsSync(file)) return [];
165
- const lines = readFileSync(file, 'utf8').trim().split('\n').filter(Boolean);
166
- return lines.slice(-n).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
167
- } catch {
168
- return [];
169
- }
170
- }
171
-
172
- function _searchHandoffs(query) {
173
- try {
174
- const handoffDir = join(STATE_DIR, 'handoffs');
175
- if (!existsSync(handoffDir)) return [];
176
- const files = readdirSync(handoffDir).filter(f => f.endsWith('.json')).slice(-10);
177
- const results = [];
178
- const queryLower = query.toLowerCase();
179
-
180
- for (const f of files) {
181
- try {
182
- const data = JSON.parse(readFileSync(join(handoffDir, f), 'utf8'));
183
- const text = JSON.stringify(data).toLowerCase();
184
- if (text.includes(queryLower)) {
185
- results.push(data);
186
- }
187
- } catch {}
188
- }
189
- return results.slice(-3);
190
- } catch {
191
- return [];
192
- }
193
- }