dual-brain 0.2.29 → 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 +122 -51
  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 -85
  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 -386
  281. package/src/pipeline.mjs +0 -1689
  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 -291
  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 -200
  296. package/src/self-correct.mjs +0 -146
  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 -215
  301. package/src/signal.mjs +0 -114
  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
@@ -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
- }