@cleocode/core 2026.5.133 → 2026.6.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 (560) hide show
  1. package/binaries/README.md +49 -27
  2. package/dist/agents/{agent-registry.d.ts → agent-capacity-tracker.d.ts} +2 -2
  3. package/dist/agents/agent-capacity-tracker.d.ts.map +1 -0
  4. package/dist/agents/{agent-registry.js → agent-capacity-tracker.js} +2 -2
  5. package/dist/agents/agent-capacity-tracker.js.map +1 -0
  6. package/dist/agents/index.d.ts +1 -1
  7. package/dist/agents/index.d.ts.map +1 -1
  8. package/dist/agents/index.js +4 -2
  9. package/dist/agents/index.js.map +1 -1
  10. package/dist/agents/seed-install.d.ts +1 -1
  11. package/dist/agents/seed-install.d.ts.map +1 -1
  12. package/dist/agents/seed-install.js +42 -36
  13. package/dist/agents/seed-install.js.map +1 -1
  14. package/dist/caamp-export.d.ts +18 -0
  15. package/dist/caamp-export.d.ts.map +1 -0
  16. package/dist/caamp-export.js +18 -0
  17. package/dist/caamp-export.js.map +1 -0
  18. package/dist/conduit/local-transport.d.ts +1 -1
  19. package/dist/conduit/local-transport.d.ts.map +1 -1
  20. package/dist/conduit/local-transport.js +69 -43
  21. package/dist/conduit/local-transport.js.map +1 -1
  22. package/dist/dispatch/mutate-projection.d.ts.map +1 -1
  23. package/dist/dispatch/mutate-projection.js +11 -0
  24. package/dist/dispatch/mutate-projection.js.map +1 -1
  25. package/dist/docs/docs-read-model.d.ts +7 -0
  26. package/dist/docs/docs-read-model.d.ts.map +1 -1
  27. package/dist/docs/docs-read-model.js +5 -0
  28. package/dist/docs/docs-read-model.js.map +1 -1
  29. package/dist/docs/supersede.d.ts.map +1 -1
  30. package/dist/docs/supersede.js +12 -7
  31. package/dist/docs/supersede.js.map +1 -1
  32. package/dist/doctor/db-substrate.d.ts.map +1 -1
  33. package/dist/doctor/db-substrate.js +10 -9
  34. package/dist/doctor/db-substrate.js.map +1 -1
  35. package/dist/git-shim-export.d.ts +18 -0
  36. package/dist/git-shim-export.d.ts.map +1 -0
  37. package/dist/git-shim-export.js +18 -0
  38. package/dist/git-shim-export.js.map +1 -0
  39. package/dist/hooks/payload-schemas.d.ts +2 -2
  40. package/dist/init.d.ts.map +1 -1
  41. package/dist/init.js +39 -32
  42. package/dist/init.js.map +1 -1
  43. package/dist/internal.d.ts +11 -3
  44. package/dist/internal.d.ts.map +1 -1
  45. package/dist/internal.js +14 -5
  46. package/dist/internal.js.map +1 -1
  47. package/dist/lafs-export.d.ts +18 -0
  48. package/dist/lafs-export.d.ts.map +1 -0
  49. package/dist/lafs-export.js +18 -0
  50. package/dist/lafs-export.js.map +1 -0
  51. package/dist/lifecycle/effective-stage.js +1 -1
  52. package/dist/lifecycle/index.js +1 -1
  53. package/dist/lifecycle/index.js.map +1 -1
  54. package/dist/lifecycle/rollup.js +1 -1
  55. package/dist/llm/credential-pool.d.ts +17 -0
  56. package/dist/llm/credential-pool.d.ts.map +1 -1
  57. package/dist/llm/credential-pool.js +40 -1
  58. package/dist/llm/credential-pool.js.map +1 -1
  59. package/dist/llm/plugin-facade.d.ts.map +1 -1
  60. package/dist/llm/plugin-facade.js +11 -19
  61. package/dist/llm/plugin-facade.js.map +1 -1
  62. package/dist/llm/role-executor.d.ts +8 -0
  63. package/dist/llm/role-executor.d.ts.map +1 -1
  64. package/dist/llm/role-executor.js +96 -4
  65. package/dist/llm/role-executor.js.map +1 -1
  66. package/dist/llm/role-resolver.d.ts.map +1 -1
  67. package/dist/llm/role-resolver.js +56 -1
  68. package/dist/llm/role-resolver.js.map +1 -1
  69. package/dist/llm/transports/codex-oauth-headers.d.ts +51 -0
  70. package/dist/llm/transports/codex-oauth-headers.d.ts.map +1 -0
  71. package/dist/llm/transports/codex-oauth-headers.js +89 -0
  72. package/dist/llm/transports/codex-oauth-headers.js.map +1 -0
  73. package/dist/memory/claude-mem-migration.d.ts.map +1 -1
  74. package/dist/memory/claude-mem-migration.js +1 -3
  75. package/dist/memory/claude-mem-migration.js.map +1 -1
  76. package/dist/memory/decisions.d.ts.map +1 -1
  77. package/dist/memory/decisions.js +77 -23
  78. package/dist/memory/decisions.js.map +1 -1
  79. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  80. package/dist/memory/graph-memory-bridge.js +12 -6
  81. package/dist/memory/graph-memory-bridge.js.map +1 -1
  82. package/dist/memory/learnings.d.ts +2 -2
  83. package/dist/memory/nexus-plasticity.d.ts +21 -9
  84. package/dist/memory/nexus-plasticity.d.ts.map +1 -1
  85. package/dist/memory/nexus-plasticity.js +44 -22
  86. package/dist/memory/nexus-plasticity.js.map +1 -1
  87. package/dist/memory/patterns.d.ts +2 -2
  88. package/dist/memory/redaction.d.ts +19 -3
  89. package/dist/memory/redaction.d.ts.map +1 -1
  90. package/dist/memory/redaction.js +22 -94
  91. package/dist/memory/redaction.js.map +1 -1
  92. package/dist/metrics/token-service.d.ts +8 -2
  93. package/dist/metrics/token-service.d.ts.map +1 -1
  94. package/dist/metrics/token-service.js +1 -1
  95. package/dist/metrics/token-service.js.map +1 -1
  96. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  97. package/dist/nexus/analyze-orchestrator.js +6 -8
  98. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  99. package/dist/nexus/api-extractors/http-extractor.d.ts.map +1 -1
  100. package/dist/nexus/api-extractors/http-extractor.js +3 -3
  101. package/dist/nexus/api-extractors/http-extractor.js.map +1 -1
  102. package/dist/nexus/clusters.d.ts.map +1 -1
  103. package/dist/nexus/clusters.js +3 -2
  104. package/dist/nexus/clusters.js.map +1 -1
  105. package/dist/nexus/context.d.ts.map +1 -1
  106. package/dist/nexus/context.js +10 -16
  107. package/dist/nexus/context.js.map +1 -1
  108. package/dist/nexus/diff.d.ts.map +1 -1
  109. package/dist/nexus/diff.js +6 -4
  110. package/dist/nexus/diff.js.map +1 -1
  111. package/dist/nexus/export.d.ts.map +1 -1
  112. package/dist/nexus/export.js +7 -4
  113. package/dist/nexus/export.js.map +1 -1
  114. package/dist/nexus/flows.d.ts.map +1 -1
  115. package/dist/nexus/flows.js +3 -1
  116. package/dist/nexus/flows.js.map +1 -1
  117. package/dist/nexus/impact.d.ts +1 -1
  118. package/dist/nexus/impact.d.ts.map +1 -1
  119. package/dist/nexus/impact.js +31 -17
  120. package/dist/nexus/impact.js.map +1 -1
  121. package/dist/nexus/living-brain.d.ts.map +1 -1
  122. package/dist/nexus/living-brain.js +27 -15
  123. package/dist/nexus/living-brain.js.map +1 -1
  124. package/dist/nexus/nexus-bridge.d.ts.map +1 -1
  125. package/dist/nexus/nexus-bridge.js +28 -29
  126. package/dist/nexus/nexus-bridge.js.map +1 -1
  127. package/dist/nexus/plasticity-queries.d.ts +4 -2
  128. package/dist/nexus/plasticity-queries.d.ts.map +1 -1
  129. package/dist/nexus/plasticity-queries.js +27 -15
  130. package/dist/nexus/plasticity-queries.js.map +1 -1
  131. package/dist/nexus/query.d.ts.map +1 -1
  132. package/dist/nexus/query.js +6 -2
  133. package/dist/nexus/query.js.map +1 -1
  134. package/dist/nexus/registry.d.ts.map +1 -1
  135. package/dist/nexus/registry.js +65 -30
  136. package/dist/nexus/registry.js.map +1 -1
  137. package/dist/nexus/route-analysis.d.ts +3 -2
  138. package/dist/nexus/route-analysis.d.ts.map +1 -1
  139. package/dist/nexus/route-analysis.js +11 -10
  140. package/dist/nexus/route-analysis.js.map +1 -1
  141. package/dist/nexus/sigil.d.ts.map +1 -1
  142. package/dist/nexus/sigil.js +60 -13
  143. package/dist/nexus/sigil.js.map +1 -1
  144. package/dist/nexus/user-profile.d.ts +2 -1
  145. package/dist/nexus/user-profile.d.ts.map +1 -1
  146. package/dist/nexus/user-profile.js +8 -4
  147. package/dist/nexus/user-profile.js.map +1 -1
  148. package/dist/orchestrate/index.d.ts +1 -1
  149. package/dist/orchestrate/index.d.ts.map +1 -1
  150. package/dist/orchestrate/index.js +1 -1
  151. package/dist/orchestrate/index.js.map +1 -1
  152. package/dist/orchestrate/plan.d.ts +3 -3
  153. package/dist/orchestrate/plan.d.ts.map +1 -1
  154. package/dist/orchestrate/plan.js +7 -7
  155. package/dist/orchestrate/plan.js.map +1 -1
  156. package/dist/orchestrate/spawn-ops.js +2 -2
  157. package/dist/orchestrate/spawn-ops.js.map +1 -1
  158. package/dist/orchestration/classify.d.ts +2 -2
  159. package/dist/orchestration/classify.js +3 -3
  160. package/dist/orchestration/classify.js.map +1 -1
  161. package/dist/orchestration/validate-spawn.d.ts.map +1 -1
  162. package/dist/orchestration/validate-spawn.js +5 -5
  163. package/dist/orchestration/validate-spawn.js.map +1 -1
  164. package/dist/paths-export.d.ts +18 -0
  165. package/dist/paths-export.d.ts.map +1 -0
  166. package/dist/paths-export.js +18 -0
  167. package/dist/paths-export.js.map +1 -0
  168. package/dist/paths.d.ts.map +1 -1
  169. package/dist/paths.js +24 -11
  170. package/dist/paths.js.map +1 -1
  171. package/dist/playbooks/index.d.ts +1 -0
  172. package/dist/playbooks/index.d.ts.map +1 -1
  173. package/dist/playbooks/index.js +4 -0
  174. package/dist/playbooks/index.js.map +1 -1
  175. package/dist/playbooks/skill-node-executor.d.ts +155 -0
  176. package/dist/playbooks/skill-node-executor.d.ts.map +1 -0
  177. package/dist/playbooks/skill-node-executor.js +156 -0
  178. package/dist/playbooks/skill-node-executor.js.map +1 -0
  179. package/dist/repair.d.ts +3 -7
  180. package/dist/repair.d.ts.map +1 -1
  181. package/dist/repair.js +5 -43
  182. package/dist/repair.js.map +1 -1
  183. package/dist/sagas/migrate-containment.js +7 -7
  184. package/dist/sagas/migrate-containment.js.map +1 -1
  185. package/dist/scaffold/ensure-dirs.d.ts +8 -2
  186. package/dist/scaffold/ensure-dirs.d.ts.map +1 -1
  187. package/dist/scaffold/ensure-dirs.js +24 -11
  188. package/dist/scaffold/ensure-dirs.js.map +1 -1
  189. package/dist/scaffold/project-detection.d.ts +5 -1
  190. package/dist/scaffold/project-detection.d.ts.map +1 -1
  191. package/dist/scaffold/project-detection.js +9 -5
  192. package/dist/scaffold/project-detection.js.map +1 -1
  193. package/dist/sentient/hygiene-scan.js +6 -6
  194. package/dist/sentient/hygiene-scan.js.map +1 -1
  195. package/dist/sentient/proposal-dedup.js +2 -2
  196. package/dist/sentient/proposal-rate-limiter.js +1 -1
  197. package/dist/sentient/propose-tick.js +5 -5
  198. package/dist/sentient/propose-tick.js.map +1 -1
  199. package/dist/sentient/stage-drift-tick.js +3 -3
  200. package/dist/sentient/stage-drift-tick.js.map +1 -1
  201. package/dist/sequence/index.d.ts.map +1 -1
  202. package/dist/sequence/index.js +6 -2
  203. package/dist/sequence/index.js.map +1 -1
  204. package/dist/setup/sections/verification.js +2 -2
  205. package/dist/setup/sections/verification.js.map +1 -1
  206. package/dist/shutdown.d.ts +81 -0
  207. package/dist/shutdown.d.ts.map +1 -0
  208. package/dist/shutdown.js +105 -0
  209. package/dist/shutdown.js.map +1 -0
  210. package/dist/skills/index.d.ts +2 -0
  211. package/dist/skills/index.d.ts.map +1 -1
  212. package/dist/skills/index.js +1 -0
  213. package/dist/skills/index.js.map +1 -1
  214. package/dist/skills/skill-executor-adapter.d.ts +136 -0
  215. package/dist/skills/skill-executor-adapter.d.ts.map +1 -0
  216. package/dist/skills/skill-executor-adapter.js +137 -0
  217. package/dist/skills/skill-executor-adapter.js.map +1 -0
  218. package/dist/skills/usage-recorder.d.ts.map +1 -1
  219. package/dist/skills/usage-recorder.js +30 -0
  220. package/dist/skills/usage-recorder.js.map +1 -1
  221. package/dist/skills-export.d.ts +23 -0
  222. package/dist/skills-export.d.ts.map +1 -0
  223. package/dist/skills-export.js +23 -0
  224. package/dist/skills-export.js.map +1 -0
  225. package/dist/stats/index.d.ts.map +1 -1
  226. package/dist/stats/index.js +8 -3
  227. package/dist/stats/index.js.map +1 -1
  228. package/dist/store/agent-doctor.d.ts +3 -3
  229. package/dist/store/agent-doctor.d.ts.map +1 -1
  230. package/dist/store/agent-doctor.js +18 -13
  231. package/dist/store/agent-doctor.js.map +1 -1
  232. package/dist/store/agent-install.d.ts +6 -5
  233. package/dist/store/agent-install.d.ts.map +1 -1
  234. package/dist/store/agent-install.js +20 -16
  235. package/dist/store/agent-install.js.map +1 -1
  236. package/dist/store/agent-registry-accessor.d.ts +66 -28
  237. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  238. package/dist/store/agent-registry-accessor.js +248 -167
  239. package/dist/store/agent-registry-accessor.js.map +1 -1
  240. package/dist/store/agent-registry-store.d.ts +242 -0
  241. package/dist/store/agent-registry-store.d.ts.map +1 -0
  242. package/dist/store/agent-registry-store.js +501 -0
  243. package/dist/store/agent-registry-store.js.map +1 -0
  244. package/dist/store/agent-resolver.d.ts +8 -8
  245. package/dist/store/agent-resolver.d.ts.map +1 -1
  246. package/dist/store/agent-resolver.js +19 -17
  247. package/dist/store/agent-resolver.js.map +1 -1
  248. package/dist/store/backup-pack.d.ts.map +1 -1
  249. package/dist/store/backup-pack.js +24 -8
  250. package/dist/store/backup-pack.js.map +1 -1
  251. package/dist/store/conduit-sqlite.d.ts +181 -74
  252. package/dist/store/conduit-sqlite.d.ts.map +1 -1
  253. package/dist/store/conduit-sqlite.js +307 -528
  254. package/dist/store/conduit-sqlite.js.map +1 -1
  255. package/dist/store/cross-db-cleanup.d.ts +5 -5
  256. package/dist/store/cross-db-cleanup.d.ts.map +1 -1
  257. package/dist/store/cross-db-cleanup.js +12 -10
  258. package/dist/store/cross-db-cleanup.js.map +1 -1
  259. package/dist/store/data-accessor.d.ts +4 -4
  260. package/dist/store/data-accessor.js +5 -5
  261. package/dist/store/data-accessor.js.map +1 -1
  262. package/dist/store/data-safety-central.d.ts +83 -1
  263. package/dist/store/data-safety-central.d.ts.map +1 -1
  264. package/dist/store/data-safety-central.js +257 -0
  265. package/dist/store/data-safety-central.js.map +1 -1
  266. package/dist/store/db-helpers.d.ts +8 -2
  267. package/dist/store/db-helpers.d.ts.map +1 -1
  268. package/dist/store/db-helpers.js +6 -2
  269. package/dist/store/db-helpers.js.map +1 -1
  270. package/dist/store/dual-scope-db.d.ts +46 -4
  271. package/dist/store/dual-scope-db.d.ts.map +1 -1
  272. package/dist/store/dual-scope-db.js +103 -9
  273. package/dist/store/dual-scope-db.js.map +1 -1
  274. package/dist/store/exodus/__fixtures__/representative-fixture.d.ts +116 -0
  275. package/dist/store/exodus/__fixtures__/representative-fixture.d.ts.map +1 -0
  276. package/dist/store/exodus/__fixtures__/representative-fixture.js +274 -0
  277. package/dist/store/exodus/__fixtures__/representative-fixture.js.map +1 -0
  278. package/dist/store/exodus/index.d.ts +18 -0
  279. package/dist/store/exodus/index.d.ts.map +1 -0
  280. package/dist/store/exodus/index.js +18 -0
  281. package/dist/store/exodus/index.js.map +1 -0
  282. package/dist/store/exodus/migrate.d.ts +160 -0
  283. package/dist/store/exodus/migrate.d.ts.map +1 -0
  284. package/dist/store/exodus/migrate.js +1220 -0
  285. package/dist/store/exodus/migrate.js.map +1 -0
  286. package/dist/store/exodus/on-open.d.ts +189 -0
  287. package/dist/store/exodus/on-open.d.ts.map +1 -0
  288. package/dist/store/exodus/on-open.js +464 -0
  289. package/dist/store/exodus/on-open.js.map +1 -0
  290. package/dist/store/exodus/plan.d.ts +44 -0
  291. package/dist/store/exodus/plan.d.ts.map +1 -0
  292. package/dist/store/exodus/plan.js +178 -0
  293. package/dist/store/exodus/plan.js.map +1 -0
  294. package/dist/store/exodus/status.d.ts +22 -0
  295. package/dist/store/exodus/status.d.ts.map +1 -0
  296. package/dist/store/exodus/status.js +88 -0
  297. package/dist/store/exodus/status.js.map +1 -0
  298. package/dist/store/exodus/table-name-map.d.ts +173 -0
  299. package/dist/store/exodus/table-name-map.d.ts.map +1 -0
  300. package/dist/store/exodus/table-name-map.js +660 -0
  301. package/dist/store/exodus/table-name-map.js.map +1 -0
  302. package/dist/store/exodus/types.d.ts +169 -0
  303. package/dist/store/exodus/types.d.ts.map +1 -0
  304. package/dist/store/exodus/types.js +21 -0
  305. package/dist/store/exodus/types.js.map +1 -0
  306. package/dist/store/exodus/verify-migration.d.ts +72 -0
  307. package/dist/store/exodus/verify-migration.d.ts.map +1 -0
  308. package/dist/store/exodus/verify-migration.js +678 -0
  309. package/dist/store/exodus/verify-migration.js.map +1 -0
  310. package/dist/store/exodus/verify.d.ts +58 -0
  311. package/dist/store/exodus/verify.d.ts.map +1 -0
  312. package/dist/store/exodus/verify.js +74 -0
  313. package/dist/store/exodus/verify.js.map +1 -0
  314. package/dist/store/index.d.ts +2 -3
  315. package/dist/store/index.d.ts.map +1 -1
  316. package/dist/store/index.js +2 -3
  317. package/dist/store/index.js.map +1 -1
  318. package/dist/store/memory-accessor.d.ts +31 -0
  319. package/dist/store/memory-accessor.d.ts.map +1 -1
  320. package/dist/store/memory-accessor.js +38 -0
  321. package/dist/store/memory-accessor.js.map +1 -1
  322. package/dist/store/memory-sqlite.d.ts +86 -13
  323. package/dist/store/memory-sqlite.d.ts.map +1 -1
  324. package/dist/store/memory-sqlite.js +326 -528
  325. package/dist/store/memory-sqlite.js.map +1 -1
  326. package/dist/store/migrate-signaldock-to-conduit.d.ts +1 -1
  327. package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -1
  328. package/dist/store/migrate-signaldock-to-conduit.js +126 -35
  329. package/dist/store/migrate-signaldock-to-conduit.js.map +1 -1
  330. package/dist/store/migration-manager.d.ts +49 -0
  331. package/dist/store/migration-manager.d.ts.map +1 -1
  332. package/dist/store/migration-manager.js +167 -67
  333. package/dist/store/migration-manager.js.map +1 -1
  334. package/dist/store/migration-sqlite.d.ts +1 -1
  335. package/dist/store/migration-sqlite.d.ts.map +1 -1
  336. package/dist/store/migration-sqlite.js +32 -3
  337. package/dist/store/migration-sqlite.js.map +1 -1
  338. package/dist/store/nexus-sqlite.d.ts +152 -29
  339. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  340. package/dist/store/nexus-sqlite.js +496 -177
  341. package/dist/store/nexus-sqlite.js.map +1 -1
  342. package/dist/store/nexus-validation-schemas.d.ts +32 -32
  343. package/dist/store/open-cleo-db.d.ts +37 -40
  344. package/dist/store/open-cleo-db.d.ts.map +1 -1
  345. package/dist/store/open-cleo-db.js +76 -153
  346. package/dist/store/open-cleo-db.js.map +1 -1
  347. package/dist/store/role-accessors-impl.d.ts +4 -4
  348. package/dist/store/role-accessors-impl.d.ts.map +1 -1
  349. package/dist/store/role-accessors-impl.js +18 -15
  350. package/dist/store/role-accessors-impl.js.map +1 -1
  351. package/dist/store/schema/{signaldock-schema.d.ts → agent-registry-schema.d.ts} +15 -5
  352. package/dist/store/schema/agent-registry-schema.d.ts.map +1 -0
  353. package/dist/store/schema/{signaldock-schema.js → agent-registry-schema.js} +15 -5
  354. package/dist/store/schema/agent-registry-schema.js.map +1 -0
  355. package/dist/store/schema/agent-schema.d.ts +1 -1
  356. package/dist/store/schema/agent-schema.js +4 -4
  357. package/dist/store/schema/agent-schema.js.map +1 -1
  358. package/dist/store/schema/attachments.d.ts +1 -1
  359. package/dist/store/schema/audit.d.ts +15 -5
  360. package/dist/store/schema/audit.d.ts.map +1 -1
  361. package/dist/store/schema/audit.js +12 -2
  362. package/dist/store/schema/audit.js.map +1 -1
  363. package/dist/store/schema/background-jobs.d.ts +1 -1
  364. package/dist/store/schema/cleo-global/{signaldock.d.ts → agent-registry.d.ts} +277 -271
  365. package/dist/store/schema/cleo-global/agent-registry.d.ts.map +1 -0
  366. package/dist/store/schema/cleo-global/{signaldock.js → agent-registry.js} +136 -125
  367. package/dist/store/schema/cleo-global/agent-registry.js.map +1 -0
  368. package/dist/store/schema/cleo-global/index.d.ts +29 -22
  369. package/dist/store/schema/cleo-global/index.d.ts.map +1 -1
  370. package/dist/store/schema/cleo-global/index.js +29 -22
  371. package/dist/store/schema/cleo-global/index.js.map +1 -1
  372. package/dist/store/schema/cleo-global/nexus.d.ts +36 -1034
  373. package/dist/store/schema/cleo-global/nexus.d.ts.map +1 -1
  374. package/dist/store/schema/cleo-global/nexus.js +32 -337
  375. package/dist/store/schema/cleo-global/nexus.js.map +1 -1
  376. package/dist/store/schema/cleo-global/skills.d.ts +16 -0
  377. package/dist/store/schema/cleo-global/skills.d.ts.map +1 -1
  378. package/dist/store/schema/cleo-global/skills.js +11 -0
  379. package/dist/store/schema/cleo-global/skills.js.map +1 -1
  380. package/dist/store/schema/{cleo-project → cleo-global}/telemetry.d.ts +33 -17
  381. package/dist/store/schema/cleo-global/telemetry.d.ts.map +1 -0
  382. package/dist/store/schema/{cleo-project → cleo-global}/telemetry.js +30 -18
  383. package/dist/store/schema/cleo-global/telemetry.js.map +1 -0
  384. package/dist/store/schema/cleo-project/audit.d.ts +8 -8
  385. package/dist/store/schema/cleo-project/audit.d.ts.map +1 -1
  386. package/dist/store/schema/cleo-project/audit.js +2 -6
  387. package/dist/store/schema/cleo-project/audit.js.map +1 -1
  388. package/dist/store/schema/cleo-project/docs.d.ts +1 -1
  389. package/dist/store/schema/cleo-project/index.d.ts +29 -12
  390. package/dist/store/schema/cleo-project/index.d.ts.map +1 -1
  391. package/dist/store/schema/cleo-project/index.js +29 -12
  392. package/dist/store/schema/cleo-project/index.js.map +1 -1
  393. package/dist/store/schema/cleo-project/lifecycle.d.ts +2 -2
  394. package/dist/store/schema/cleo-project/nexus-graph.d.ts +1067 -0
  395. package/dist/store/schema/cleo-project/nexus-graph.d.ts.map +1 -0
  396. package/dist/store/schema/cleo-project/nexus-graph.js +407 -0
  397. package/dist/store/schema/cleo-project/nexus-graph.js.map +1 -0
  398. package/dist/store/schema/cleo-project/provenance-orphans.d.ts +385 -0
  399. package/dist/store/schema/cleo-project/provenance-orphans.d.ts.map +1 -0
  400. package/dist/store/schema/cleo-project/provenance-orphans.js +142 -0
  401. package/dist/store/schema/cleo-project/provenance-orphans.js.map +1 -0
  402. package/dist/store/schema/cleo-project/provenance-rest.d.ts +1 -1
  403. package/dist/store/schema/cleo-project/runtime.d.ts +1 -1
  404. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts +1 -1
  405. package/dist/store/schema/cleo-project/tasks-core.d.ts +3 -3
  406. package/dist/store/schema/cleo-shared/brain.d.ts +711 -494
  407. package/dist/store/schema/cleo-shared/brain.d.ts.map +1 -1
  408. package/dist/store/schema/cleo-shared/brain.js +215 -134
  409. package/dist/store/schema/cleo-shared/brain.js.map +1 -1
  410. package/dist/store/schema/conduit-schema.d.ts +63 -51
  411. package/dist/store/schema/conduit-schema.d.ts.map +1 -1
  412. package/dist/store/schema/conduit-schema.js +23 -11
  413. package/dist/store/schema/conduit-schema.js.map +1 -1
  414. package/dist/store/schema/goal.d.ts +3 -2
  415. package/dist/store/schema/goal.d.ts.map +1 -1
  416. package/dist/store/schema/goal.js +3 -2
  417. package/dist/store/schema/goal.js.map +1 -1
  418. package/dist/store/schema/index.d.ts +1 -0
  419. package/dist/store/schema/index.d.ts.map +1 -1
  420. package/dist/store/schema/index.js +1 -0
  421. package/dist/store/schema/index.js.map +1 -1
  422. package/dist/store/schema/lifecycle.d.ts +2 -2
  423. package/dist/store/schema/memory-schema.d.ts +2 -2
  424. package/dist/store/schema/nexus-schema.d.ts +174 -115
  425. package/dist/store/schema/nexus-schema.d.ts.map +1 -1
  426. package/dist/store/schema/nexus-schema.js +175 -55
  427. package/dist/store/schema/nexus-schema.js.map +1 -1
  428. package/dist/store/schema/provenance/releases.d.ts +1 -1
  429. package/dist/store/schema/schema-utils.d.ts +78 -0
  430. package/dist/store/schema/schema-utils.d.ts.map +1 -0
  431. package/dist/store/schema/schema-utils.js +49 -0
  432. package/dist/store/schema/schema-utils.js.map +1 -0
  433. package/dist/store/schema/skills-schema.d.ts +81 -44
  434. package/dist/store/schema/skills-schema.d.ts.map +1 -1
  435. package/dist/store/schema/skills-schema.js +49 -16
  436. package/dist/store/schema/skills-schema.js.map +1 -1
  437. package/dist/store/schema/tasks.d.ts +3 -3
  438. package/dist/store/skills-db.d.ts +90 -50
  439. package/dist/store/skills-db.d.ts.map +1 -1
  440. package/dist/store/skills-db.js +132 -146
  441. package/dist/store/skills-db.js.map +1 -1
  442. package/dist/store/sqlite-backup.d.ts +2 -2
  443. package/dist/store/sqlite-backup.d.ts.map +1 -1
  444. package/dist/store/sqlite-backup.js +11 -10
  445. package/dist/store/sqlite-backup.js.map +1 -1
  446. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  447. package/dist/store/sqlite-data-accessor.js +25 -18
  448. package/dist/store/sqlite-data-accessor.js.map +1 -1
  449. package/dist/store/sqlite.d.ts +72 -12
  450. package/dist/store/sqlite.d.ts.map +1 -1
  451. package/dist/store/sqlite.js +153 -89
  452. package/dist/store/sqlite.js.map +1 -1
  453. package/dist/store/tasks-schema.d.ts +4 -0
  454. package/dist/store/tasks-schema.d.ts.map +1 -1
  455. package/dist/store/tasks-schema.js +60 -0
  456. package/dist/store/tasks-schema.js.map +1 -1
  457. package/dist/store/tasks-sqlite.d.ts +2 -2
  458. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  459. package/dist/store/tasks-sqlite.js +10 -5
  460. package/dist/store/tasks-sqlite.js.map +1 -1
  461. package/dist/store/umbrella-data-accessor.d.ts +17 -6
  462. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  463. package/dist/store/umbrella-data-accessor.js +8 -8
  464. package/dist/store/umbrella-data-accessor.js.map +1 -1
  465. package/dist/store/validation-schemas.d.ts +241 -208
  466. package/dist/store/validation-schemas.d.ts.map +1 -1
  467. package/dist/system/health.d.ts.map +1 -1
  468. package/dist/system/health.js +11 -6
  469. package/dist/system/health.js.map +1 -1
  470. package/dist/system/project-health.d.ts.map +1 -1
  471. package/dist/system/project-health.js +58 -12
  472. package/dist/system/project-health.js.map +1 -1
  473. package/dist/tasks/add.d.ts +8 -0
  474. package/dist/tasks/add.d.ts.map +1 -1
  475. package/dist/tasks/add.js +101 -0
  476. package/dist/tasks/add.js.map +1 -1
  477. package/dist/tasks/cancelled-child-waiver-audit.d.ts +47 -0
  478. package/dist/tasks/cancelled-child-waiver-audit.d.ts.map +1 -0
  479. package/dist/tasks/cancelled-child-waiver-audit.js +34 -0
  480. package/dist/tasks/cancelled-child-waiver-audit.js.map +1 -0
  481. package/dist/tasks/complete.d.ts +22 -2
  482. package/dist/tasks/complete.d.ts.map +1 -1
  483. package/dist/tasks/complete.js +71 -6
  484. package/dist/tasks/complete.js.map +1 -1
  485. package/dist/tasks/compute-task-view.js +1 -1
  486. package/dist/tasks/session-scope.d.ts +5 -0
  487. package/dist/tasks/session-scope.d.ts.map +1 -1
  488. package/dist/tasks/session-scope.js +4 -0
  489. package/dist/tasks/session-scope.js.map +1 -1
  490. package/dist/tools/guard.d.ts +71 -1
  491. package/dist/tools/guard.d.ts.map +1 -1
  492. package/dist/tools/guard.js +73 -1
  493. package/dist/tools/guard.js.map +1 -1
  494. package/dist/tools/index.d.ts +21 -0
  495. package/dist/tools/index.d.ts.map +1 -1
  496. package/dist/tools/index.js +25 -0
  497. package/dist/tools/index.js.map +1 -1
  498. package/dist/upgrade.d.ts.map +1 -1
  499. package/dist/upgrade.js +22 -13
  500. package/dist/upgrade.js.map +1 -1
  501. package/dist/workgraph/containment.js +18 -18
  502. package/dist/workgraph/relations.js +2 -2
  503. package/dist/worktree/list.d.ts +1 -1
  504. package/dist/worktree/list.d.ts.map +1 -1
  505. package/dist/worktree/list.js +19 -21
  506. package/dist/worktree/list.js.map +1 -1
  507. package/dist/worktree-export.d.ts +18 -0
  508. package/dist/worktree-export.d.ts.map +1 -0
  509. package/dist/worktree-export.js +18 -0
  510. package/dist/worktree-export.js.map +1 -0
  511. package/migrations/drizzle-agent-registry/20260412000000_initial-global-agent-registry/migration.sql +29 -0
  512. package/migrations/drizzle-brain/20260601000001_t11522-brain-task-observations/migration.sql +28 -0
  513. package/migrations/drizzle-brain/20260601000002_t11522-inline-only-brain-tables/migration.sql +75 -0
  514. package/migrations/drizzle-cleo-global/20260531000001_t11363-consolidation-cleo-global/migration.sql +49 -144
  515. package/migrations/drizzle-cleo-global/20260531000001_t11363-consolidation-cleo-global/snapshot.json +8 -8
  516. package/migrations/drizzle-cleo-global/20260531000002_t11546-brain-usage-log/migration.sql +16 -0
  517. package/migrations/drizzle-cleo-global/20260601000001_t11544-skills-usage-project-id/migration.sql +12 -0
  518. package/migrations/drizzle-cleo-global/20260602000001_t11622-agent-registry-rename/migration.sql +80 -0
  519. package/migrations/drizzle-cleo-project/20260531000001_t11363-consolidation-cleo-project/migration.sql +26 -167
  520. package/migrations/drizzle-cleo-project/20260531000001_t11363-consolidation-cleo-project/snapshot.json +8 -8
  521. package/migrations/drizzle-cleo-project/20260531000002_t11546-brain-usage-log/migration.sql +21 -0
  522. package/migrations/drizzle-cleo-project/20260601000001_t11549-agent-credentials-brain-release-links/migration.sql +49 -0
  523. package/migrations/drizzle-cleo-project/20260601000002_t11538-project-nexus-graph/migration.sql +140 -0
  524. package/migrations/drizzle-cleo-project/20260602000002_t11649-token-usage-transport-mcp/migration.sql +146 -0
  525. package/migrations/drizzle-conduit/20260601000003_t11523-conduit-inline-schema/migration.sql +82 -0
  526. package/migrations/drizzle-nexus/20260421200001_t1165-baseline-reset/migration.sql +26 -8
  527. package/migrations/drizzle-nexus/20260601000001_t11545-nexus-relation-weights-partition/migration.sql +97 -0
  528. package/package.json +43 -11
  529. package/scripts/install-supervisor-binary.mjs +50 -201
  530. package/scripts/napi-binary-picker.mjs +267 -0
  531. package/dist/agents/agent-registry.d.ts.map +0 -1
  532. package/dist/agents/agent-registry.js.map +0 -1
  533. package/dist/store/data-safety.d.ts +0 -92
  534. package/dist/store/data-safety.d.ts.map +0 -1
  535. package/dist/store/data-safety.js +0 -274
  536. package/dist/store/data-safety.js.map +0 -1
  537. package/dist/store/schema/cleo-global/signaldock.d.ts.map +0 -1
  538. package/dist/store/schema/cleo-global/signaldock.js.map +0 -1
  539. package/dist/store/schema/cleo-project/telemetry.d.ts.map +0 -1
  540. package/dist/store/schema/cleo-project/telemetry.js.map +0 -1
  541. package/dist/store/schema/signaldock-schema.d.ts.map +0 -1
  542. package/dist/store/schema/signaldock-schema.js.map +0 -1
  543. package/dist/store/signaldock-sqlite.d.ts +0 -173
  544. package/dist/store/signaldock-sqlite.d.ts.map +0 -1
  545. package/dist/store/signaldock-sqlite.js +0 -445
  546. package/dist/store/signaldock-sqlite.js.map +0 -1
  547. package/migrations/drizzle-nexus/20260318205558_initial/migration.sql +0 -46
  548. package/migrations/drizzle-nexus/20260412000001_t529-nexus-graph-tables/migration.sql +0 -49
  549. package/migrations/drizzle-nexus/20260415000001_t622-project-registry-paths/migration.sql +0 -12
  550. package/migrations/drizzle-nexus/20260419000001_t998-nexus-plasticity/migration.sql +0 -13
  551. package/migrations/drizzle-nexus/20260423052640_t1077-add-user-profile-table/migration.sql +0 -16
  552. package/migrations/drizzle-nexus/20260423052640_t1077-add-user-profile-table/snapshot.json +0 -1531
  553. package/migrations/drizzle-nexus/20260424140538_t1148-add-sigils-table/migration.sql +0 -13
  554. package/migrations/drizzle-nexus/20260424140538_t1148-add-sigils-table/snapshot.json +0 -1652
  555. package/migrations/drizzle-nexus/20260504000001_t1839-fts5-nexus-symbols/migration.sql +0 -68
  556. package/migrations/drizzle-nexus/20260507135519_t9163-nexus-is-external/migration.sql +0 -20
  557. package/migrations/drizzle-nexus/20260507135519_t9163-nexus-is-external/snapshot.json +0 -1652
  558. package/migrations/drizzle-nexus/20260526222449_t11025-project-id-aliases/migration.sql +0 -16
  559. package/migrations/drizzle-signaldock/20260412000000_initial-global-signaldock/migration.sql +0 -209
  560. package/migrations/drizzle-signaldock/20260412000000_initial-global-signaldock/snapshot.json +0 -2060
@@ -1,30 +1,80 @@
1
1
  /**
2
- * SQLite store for brain.db via drizzle-orm/node-sqlite + node:sqlite (DatabaseSync).
2
+ * SQLite store for the project-scope BRAIN domain via drizzle-orm/node-sqlite +
3
+ * node:sqlite (DatabaseSync).
3
4
  *
4
- * Separate database from tasks.db for cognitive infrastructure (decisions,
5
- * patterns, learnings). Follows the same singleton + WAL + migration pattern
6
- * as sqlite.ts.
5
+ * ## E6-L2 thin-facade migration (T11522)
6
+ *
7
+ * `getBrainDb()` is now a thin facade that delegates the database open to
8
+ * {@link openDualScopeDb}('project', cwd) — the canonical dual-scope chokepoint
9
+ * introduced by E3/E4 (T11512/T11517) and already adopted by the tasks domain
10
+ * (E6-L1, T11521). This ensures:
11
+ *
12
+ * - Every brain-domain open flows through the single pragma SSoT (ADR-068/069).
13
+ * - The brain tables now live inside the consolidated project `cleo.db` — NOT a
14
+ * separate `brain.db` file — co-existing with `tasks_*` / `conduit_*` / etc.
15
+ * - DB Open Guard Gate 3 (`scripts/lint-no-direct-db-open.mjs`) stays green: the
16
+ * only native open is inside `dual-scope-db.ts`.
17
+ *
18
+ * The legacy `drizzle-brain` migrations are still applied to this handle during
19
+ * the E3→E6 transition (every brain migration is `CREATE TABLE IF NOT EXISTS` /
20
+ * additive `ALTER TABLE`, so re-applying onto the consolidated `cleo.db` is
21
+ * idempotent). This creates the legacy runtime-queried physical tables — most
22
+ * notably `deriver_queue` (unprefixed; the consolidated schema carries the
23
+ * prefixed `brain_deriver_queue`) — alongside the consolidated `brain_*` tables.
24
+ * The exodus migration (T11248) renames them; E6-L7/L8 remove the legacy ones.
25
+ *
26
+ * ## Post-hoc DDL removal (T11522 acceptance criteria)
27
+ *
28
+ * Every `ensureColumns` band-aid (~15) and raw `CREATE TABLE IF NOT EXISTS`
29
+ * (~8) that previously lived in {@link runBrainMigrations} has been removed. All
30
+ * of them were redundant safety-nets fully covered by the `drizzle-brain`
31
+ * migration files (the journal reconciler `probeAndMarkApplied` is robust enough
32
+ * to detect already-applied DDL — see migration-manager.ts, T632). The ONE table
33
+ * with no migration anywhere — `brain_task_observations` (T1615, a runtime-only
34
+ * join cache mapped to `null` by exodus) — was converted to a forward Drizzle
35
+ * migration under `migrations/drizzle-cleo-project/20260601000002_t11522-brain-task-observations`,
36
+ * matching the T9179 precedent (ensureColumns → forward migration).
7
37
  *
8
38
  * @epic T5149
9
39
  * @task T5128
40
+ * @task T11522 - E6-L2: route getBrainDb through openDualScopeDb (SG-DB-SUBSTRATE-V2)
10
41
  */
11
- import { mkdirSync } from 'node:fs';
12
42
  import { createRequire } from 'node:module';
13
- import { dirname, join } from 'node:path';
14
- import { drizzle } from 'drizzle-orm/node-sqlite';
43
+ // E6-L2 (T11522): dual-scope chokepoint the brain domain now opens the
44
+ // consolidated project `cleo.db` through here. openDualScopeDb manages the
45
+ // DatabaseSync lifecycle, pragmas, and consolidated migrations. We extract the
46
+ // native handle and re-wrap it with the legacy brain-schema drizzle instance so
47
+ // existing callers (brainSchema.* queries) compile and run without change.
15
48
  import { getLogger } from '../logger.js';
16
- import { resolveCleoDir } from '../paths.js';
17
- import { createSafetyBackup, ensureColumns, migrateWithRetry, reconcileJournal, tableExists, } from './migration-manager.js';
18
- import { recoverMalformedBrainDb } from './recover-brain-db.js';
49
+ import { openDualScopeDb, resolveDualScopeDbPath } from './dual-scope-db.js';
50
+ import { createSafetyBackup, migrateWithRetry, reconcileBrainMigrationsForConsolidatedDb, reconcileJournal, tableExists, } from './migration-manager.js';
19
51
  import { resolveCorePackageMigrationsFolder } from './resolve-migrations-folder.js';
20
52
  import * as brainSchema from './schema/memory-schema.js';
21
- // Import openNativeDatabase directly from the leaf module (sqlite-native.ts) to
22
- // avoid any static import from sqlite.ts that could re-enter the circular chain
23
- // agent-resolver → ... → memory-sqlite → sqlite.ts (T1325/T1331 v3).
24
- import { openNativeDatabase } from './sqlite-native.js';
25
53
  const _require = createRequire(import.meta.url);
26
- /** Database file name within .cleo/ directory. */
27
- const DB_FILENAME = 'brain.db';
54
+ /**
55
+ * Cached `drizzle` factory from `drizzle-orm/node-sqlite`, loaded on first use.
56
+ *
57
+ * Loaded via `createRequire` rather than a top-level import so that importing
58
+ * `memory-sqlite.ts` does not eagerly pull in `node:sqlite` (which the drizzle
59
+ * driver statically imports). Memoized after the first call. Mirrors the
60
+ * `_getDrizzle` lazy pattern in sqlite.ts (T11280/T11521).
61
+ *
62
+ * @internal
63
+ */
64
+ let _drizzle = null;
65
+ /**
66
+ * Returns the `drizzle` factory, loading `drizzle-orm/node-sqlite` on first call.
67
+ *
68
+ * @internal
69
+ * @task T11522
70
+ */
71
+ function _getDrizzle() {
72
+ if (_drizzle === null) {
73
+ const mod = _require('drizzle-orm/node-sqlite');
74
+ _drizzle = mod.drizzle;
75
+ }
76
+ return _drizzle;
77
+ }
28
78
  /** Schema version for newly created brain databases. Single source of truth. */
29
79
  export const BRAIN_SCHEMA_VERSION = '1.0.0';
30
80
  /** Singleton state for lazy initialization. */
@@ -36,10 +86,18 @@ let _initPromise = null;
36
86
  /** Whether sqlite-vec extension loaded successfully. */
37
87
  let _vecLoaded = false;
38
88
  /**
39
- * Get the path to the brain.db SQLite database file.
89
+ * Get the path to the brain-domain SQLite database file.
90
+ *
91
+ * ## E6-L2 (T11522)
92
+ *
93
+ * After the dual-scope migration, `getBrainDb()` opens the consolidated project
94
+ * `cleo.db` via {@link openDualScopeDb} — not the legacy standalone `brain.db`.
95
+ * This function therefore returns the dual-scope `cleo.db` path so that callers
96
+ * checking for the file `getBrainDb()` created (existence / backup / health
97
+ * probes) point at the correct file.
40
98
  */
41
99
  export function getBrainDbPath(cwd) {
42
- return join(resolveCleoDir(cwd), DB_FILENAME);
100
+ return resolveDualScopeDbPath('project', cwd);
43
101
  }
44
102
  /**
45
103
  * Resolve the absolute path to the drizzle-brain migrations folder inside
@@ -53,373 +111,172 @@ export function resolveBrainMigrationsFolder() {
53
111
  return resolveCorePackageMigrationsFolder('drizzle-brain');
54
112
  }
55
113
  // tableExists — delegated to migration-manager.ts (T132)
114
+ //
115
+ // E6-L2 (T11522): the legacy `runBrainMigrations` helper that ran the
116
+ // `drizzle-brain` migration folder (with ~15 ensureColumns + ~8 raw CREATE TABLE
117
+ // band-aids). After getBrainDb() routes through openDualScopeDb('project'), the
118
+ // brain domain is served from the consolidated `cleo.db`. See
119
+ // `establishLegacyBrainSchema` below for why the runtime keeps the LEGACY brain
120
+ // table shape during the E3→E6 transition.
56
121
  /**
57
- * Run drizzle migrations to create/update brain.db tables.
122
+ * The set of brain-domain physical tables the T11363 consolidation migration
123
+ * creates in the project `cleo.db`. Each is dropped + recreated in its LEGACY
124
+ * runtime shape by {@link establishLegacyBrainSchema} (see that function for the
125
+ * rationale). `deriver_queue` is included because the legacy `t1145` migration
126
+ * creates it (unprefixed) and we must clear any prior shape first.
58
127
  *
59
- * Delegates to shared migration-manager.ts for journal reconciliation,
60
- * retry logic, and safety backups. See T132 for consolidation rationale.
128
+ * @internal
129
+ * @task T11522
130
+ */
131
+ const CONSOLIDATED_BRAIN_TABLES = [
132
+ 'brain_attention',
133
+ 'brain_backfill_runs',
134
+ 'brain_consolidation_events',
135
+ 'brain_decisions',
136
+ 'brain_deriver_queue',
137
+ 'brain_embeddings',
138
+ 'brain_learnings',
139
+ 'brain_memory_links',
140
+ 'brain_memory_trees',
141
+ 'brain_modulators',
142
+ 'brain_observations',
143
+ 'brain_observations_staging',
144
+ 'brain_page_edges',
145
+ 'brain_page_nodes',
146
+ 'brain_patterns',
147
+ 'brain_plasticity_events',
148
+ 'brain_promotion_log',
149
+ 'brain_retrieval_log',
150
+ 'brain_schema_meta',
151
+ 'brain_session_narrative',
152
+ 'brain_sticky_notes',
153
+ 'brain_sticky_tags',
154
+ 'brain_transcript_events',
155
+ 'brain_usage_log',
156
+ 'brain_weight_history',
157
+ ];
158
+ /**
159
+ * Detect whether the brain tables in the open handle carry the CONSOLIDATED
160
+ * (exodus-target) shape rather than the LEGACY runtime shape.
61
161
  *
62
- * @task T5128
63
- * @task T132 - Unified migration system
162
+ * The consolidation migration (T11363) types `brain_attention.created_at` as
163
+ * `text` (ISO-8601, with a GLOB CHECK constraint); the legacy runtime schema
164
+ * (`memory-schema.ts`) types it as `integer` (epoch-ms, `unixepoch() * 1000`).
165
+ * The column affinity is therefore a reliable, cheap discriminator.
166
+ *
167
+ * @internal
168
+ * @task T11522
169
+ */
170
+ function brainTablesAreConsolidatedShape(nativeDb) {
171
+ if (!tableExists(nativeDb, 'brain_attention'))
172
+ return false;
173
+ const cols = nativeDb.prepare('PRAGMA table_info(brain_attention)').all();
174
+ const createdAt = cols.find((c) => c.name === 'created_at');
175
+ // Legacy = INTEGER; consolidated target = TEXT. Anything non-INTEGER means we
176
+ // are looking at the consolidated target shape and must rebuild to legacy.
177
+ return createdAt !== undefined && createdAt.type.toUpperCase() !== 'INTEGER';
178
+ }
179
+ /**
180
+ * Establish the LEGACY brain-domain schema inside the consolidated project
181
+ * `cleo.db`, replacing the consolidated (exodus-target) brain tables.
182
+ *
183
+ * ## Why (T11522 · E6-L2)
184
+ *
185
+ * Routing `getBrainDb()` through {@link openDualScopeDb} runs the T11363
186
+ * consolidation migration, which creates every `brain_*` table in its
187
+ * **exodus-target** shape: ISO-8601 `text` timestamps and enum/format `CHECK`
188
+ * constraints (e.g. `brain_attention.created_at GLOB '[0-9][0-9][0-9][0-9]-…'`,
189
+ * `brain_page_nodes.node_type IN (…)`). The runtime brain writers and the
190
+ * `brainSchema` (`memory-schema.ts`) still use the **legacy** shape — epoch-ms
191
+ * `integer` timestamps and no enum CHECKs — exactly as the tasks domain keeps
192
+ * using the legacy `tasks` table after E6-L1.
193
+ *
194
+ * Unlike tasks (legacy `tasks` ≠ consolidated `tasks_tasks`, so both co-exist),
195
+ * the brain tables were already domain-prefixed, so legacy and consolidated
196
+ * share the SAME physical names — they cannot co-exist. The runtime must win, so
197
+ * on first open we drop the consolidated brain tables and run the legacy
198
+ * `drizzle-brain` migrations to recreate them in the runtime shape. The
199
+ * consolidated-target cutover (epoch→ISO conversion, CHECK constraints) is the
200
+ * exodus's job — see T11248 / exodus-on-open T11553, which migrate the standalone
201
+ * legacy `brain.db` into `cleo.db`.
202
+ *
203
+ * Idempotent: after the first rebuild the tables are already legacy-shaped, so
204
+ * {@link brainTablesAreConsolidatedShape} returns `false` and this is a no-op
205
+ * (the `drizzle-brain` journal is reconciled, nothing is dropped).
206
+ *
207
+ * @internal
208
+ * @task T11522
64
209
  */
65
- function runBrainMigrations(nativeDb, db) {
210
+ function establishLegacyBrainSchema(nativeDb, db) {
211
+ const log = getLogger('brain-schema');
212
+ if (brainTablesAreConsolidatedShape(nativeDb)) {
213
+ // Drop the consolidated (exodus-target) brain tables so the legacy
214
+ // `drizzle-brain` migrations can recreate them in the runtime shape.
215
+ // `brain_embeddings` is a vec0 virtual table once the extension is loaded;
216
+ // DROP TABLE handles both regular and virtual tables when sqlite-vec is
217
+ // present. Disable FKs during the drop so cross-table references do not
218
+ // block the teardown — then RESTORE the prior pragma state (the dual-scope
219
+ // pragma SSoT enables foreign_keys; leaving it OFF would break the
220
+ // idempotent-pragma contract, T10314).
221
+ const fkRow = nativeDb.prepare('PRAGMA foreign_keys').get();
222
+ const fkWasOn = fkRow?.foreign_keys === 1;
223
+ nativeDb.exec('PRAGMA foreign_keys=OFF');
224
+ try {
225
+ for (const table of CONSOLIDATED_BRAIN_TABLES) {
226
+ try {
227
+ nativeDb.exec(`DROP TABLE IF EXISTS \`${table}\``);
228
+ }
229
+ catch (err) {
230
+ log.warn({ table, err }, 'Failed to drop consolidated brain table during legacy rebuild.');
231
+ }
232
+ }
233
+ }
234
+ finally {
235
+ // Restore the pragma to its pre-drop state (ON under the dual-scope SSoT).
236
+ nativeDb.exec(`PRAGMA foreign_keys=${fkWasOn ? 'ON' : 'OFF'}`);
237
+ }
238
+ log.debug({ count: CONSOLIDATED_BRAIN_TABLES.length }, 'Dropped consolidated (exodus-target) brain tables — rebuilding in legacy runtime shape.');
239
+ }
66
240
  const migrationsFolder = resolveBrainMigrationsFolder();
67
- // Safety backup before any migration work
241
+ // T11647 CONSOLIDATED `cleo.db` path. The consolidated `drizzle-cleo-project`
242
+ // / `drizzle-cleo-global` migration already created every DOMAIN-PREFIXED
243
+ // `brain_*` table in the LEGACY RUNTIME shape (the exodus target was aligned to
244
+ // the runtime shape — see `cleo-shared/brain.ts`), so `brain_decisions` exists
245
+ // and `brainTablesAreConsolidatedShape` is false (no DROP fired above). The
246
+ // standalone `drizzle-brain` migrations must NOT be re-run wholesale: their
247
+ // non-`IF NOT EXISTS` `CREATE TABLE`s / table-rebuilds for already-present
248
+ // prefixed tables (e.g. `brain_observations_staging`) and their ALTER-ADD-COLUMN
249
+ // for already-present columns would collide.
250
+ if (tableExists(nativeDb, 'brain_decisions') && !brainTablesAreConsolidatedShape(nativeDb)) {
251
+ // Additive reconcile-and-apply: for each not-yet-journaled `drizzle-brain`
252
+ // migration, mark-applied-without-running when its net effect is already
253
+ // present (the prefixed `brain_*` tables + their final columns the
254
+ // consolidated migration created), else exec it directly (the UNPREFIXED
255
+ // runtime tables `deriver_queue`/`sticky_tags`/`session_narrative`/
256
+ // `brain_task_observations` the consolidated migration omits but the runtime
257
+ // queries). This NEVER deletes a journal row and never engages drizzle's
258
+ // shared-handle transaction, so it cannot corrupt the tasks-domain journal
259
+ // entries that share this consolidated `cleo.db`'s `__drizzle_migrations` —
260
+ // see reconcileBrainMigrationsForConsolidatedDb for the full rationale. The
261
+ // exodus-migrated rows in the prefixed tables survive untouched (the
262
+ // data-loss fix).
263
+ const { marked, applied } = reconcileBrainMigrationsForConsolidatedDb(nativeDb, migrationsFolder);
264
+ log.debug({ marked, applied }, 'brain consolidated cleo.db reconcile (T11647) — marked already-present migrations applied + executed the missing unprefixed-table migrations directly.');
265
+ return;
266
+ }
267
+ // LEGACY standalone `brain.db` (or brand-new DB) path: no prefixed brain tables
268
+ // pre-created, so run the full `drizzle-brain` migrate via the generic
269
+ // reconcile (its Scenario-2 orphan-delete is safe here — a standalone brain.db
270
+ // journal contains only brain hashes).
68
271
  if (tableExists(nativeDb, 'brain_decisions') && _dbPath) {
69
272
  createSafetyBackup(_dbPath);
70
273
  }
71
- // Bootstrap baseline + reconcile stale journal entries
72
274
  reconcileJournal(nativeDb, migrationsFolder, 'brain_decisions', 'brain');
73
- // Run pending migrations with SQLITE_BUSY retry.
74
- // Pass nativeDb + existenceTable so migrateWithRetry can auto-reconcile any
75
- // partial migration (Scenario 3) that slips through the proactive check above.
76
275
  migrateWithRetry(db, migrationsFolder, nativeDb, 'brain_decisions', 'brain');
77
- // T632 root-cause fix (complete): the migration journal reconciler (Sub-case B)
78
- // uses a per-migration DDL probe (probeAndMarkApplied in migration-manager.ts)
79
- // instead of wholesale-marking-all-applied. ALTER TABLE ADD COLUMN migrations
80
- // (T417 agent, T528 graph schema, T531 quality-score, T549 tiered-memory, etc.)
81
- // now run correctly when their columns are missing — the reconciler leaves them
82
- // unjournaled so Drizzle's migrate() runs the DDL.
83
- //
84
- // The ensureColumns band-aids for T528/T531/T549 were removed here as part of
85
- // T632 because all their columns are covered by Drizzle migration files. If a
86
- // schema regression recurs, debug probeAndMarkApplied in migration-manager.ts —
87
- // do NOT add new band-aids here.
88
- //
89
- // ensureColumns below are retained ONLY for columns that have NO corresponding
90
- // Drizzle migration file (self-healing DDL only — see each comment).
91
- // T626-M1: Normalize co_retrieved edge type — idempotent safety-net UPDATE.
92
- // The shipped Hebbian strengthener emitted edge_type = 'relates_to' instead of
93
- // 'co_retrieved'. Relabel only rows from the consolidation provenance so no
94
- // semantic edges are affected. The Drizzle migration file does the same UPDATE;
95
- // this guard handles installs where the journal reconciler already marked
96
- // the migration applied before the SQL ran.
97
- //
98
- // T759: Guard provenance column existence before UPDATE. If T528 migration has
99
- // not yet run (e.g. on a fresh install where only the initial migration is
100
- // present), brain_page_edges will not have a provenance column and the UPDATE
101
- // will throw "no such column: provenance". ensureColumns adds the column if
102
- // missing so the UPDATE is always safe to execute.
103
- if (tableExists(nativeDb, 'brain_page_edges')) {
104
- ensureColumns(nativeDb, 'brain_page_edges', [{ name: 'provenance', ddl: 'text' }], 'brain');
105
- nativeDb
106
- .prepare(`UPDATE brain_page_edges
107
- SET edge_type = 'co_retrieved'
108
- WHERE edge_type = 'relates_to'
109
- AND provenance LIKE 'consolidation:%'`)
110
- .run();
111
- }
112
- // T673-M1: STDP plasticity columns on brain_retrieval_log.
113
- // session_id was declared in the Drizzle schema but never applied to the live table.
114
- // reward_signal, retrieval_order, delta_ms are new additions per spec §2.1.1.
115
- if (tableExists(nativeDb, 'brain_retrieval_log')) {
116
- ensureColumns(nativeDb, 'brain_retrieval_log', [
117
- { name: 'session_id', ddl: 'text' },
118
- { name: 'reward_signal', ddl: 'real' },
119
- { name: 'retrieval_order', ddl: 'integer' },
120
- { name: 'delta_ms', ddl: 'integer' },
121
- ], 'brain');
122
- }
123
- // T673-M2: observability columns on brain_plasticity_events
124
- // session_id is declared in Drizzle schema and included in M2 CREATE TABLE IF NOT EXISTS,
125
- // but may be missing from installs where the table was created before M2.
126
- if (tableExists(nativeDb, 'brain_plasticity_events')) {
127
- ensureColumns(nativeDb, 'brain_plasticity_events', [
128
- { name: 'session_id', ddl: 'text' },
129
- { name: 'weight_before', ddl: 'real' },
130
- { name: 'weight_after', ddl: 'real' },
131
- { name: 'retrieval_log_id', ddl: 'integer' },
132
- { name: 'reward_signal', ddl: 'real' },
133
- { name: 'delta_t_ms', ddl: 'integer' },
134
- ], 'brain');
135
- }
136
- // T673-M3: plasticity tracking columns on brain_page_edges
137
- ensureColumns(nativeDb, 'brain_page_edges', [
138
- { name: 'last_reinforced_at', ddl: 'text' },
139
- { name: 'reinforcement_count', ddl: 'integer NOT NULL DEFAULT 0' },
140
- { name: 'plasticity_class', ddl: "text NOT NULL DEFAULT 'static'" },
141
- { name: 'last_depressed_at', ddl: 'text' },
142
- { name: 'depression_count', ddl: 'integer NOT NULL DEFAULT 0' },
143
- { name: 'stability_score', ddl: 'real' },
144
- ], 'brain');
145
- // T673-M3: seed co_retrieved edges as hebbian (idempotent)
146
- if (tableExists(nativeDb, 'brain_page_edges')) {
147
- nativeDb
148
- .prepare(`UPDATE brain_page_edges SET plasticity_class = 'hebbian'
149
- WHERE edge_type = 'co_retrieved' AND plasticity_class = 'static'`)
150
- .run();
151
- }
152
- // T673-M4: new plasticity infrastructure tables — self-healing CREATE IF NOT EXISTS.
153
- // These guards ensure the tables exist even on installs where the Drizzle migration
154
- // journal was already partially applied. All three tables are CREATE IF NOT EXISTS
155
- // so re-running is safe.
156
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_weight_history (
157
- id INTEGER PRIMARY KEY AUTOINCREMENT,
158
- edge_from_id TEXT NOT NULL,
159
- edge_to_id TEXT NOT NULL,
160
- edge_type TEXT NOT NULL,
161
- weight_before REAL,
162
- weight_after REAL NOT NULL,
163
- delta_weight REAL NOT NULL,
164
- event_kind TEXT NOT NULL,
165
- source_plasticity_event_id INTEGER,
166
- retrieval_log_id INTEGER,
167
- reward_signal REAL,
168
- changed_at TEXT NOT NULL DEFAULT (datetime('now'))
169
- )`);
170
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_weight_history_edge
171
- ON brain_weight_history (edge_from_id, edge_to_id, edge_type)`);
172
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_weight_history_changed_at
173
- ON brain_weight_history (changed_at)`);
174
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_modulators (
175
- id INTEGER PRIMARY KEY AUTOINCREMENT,
176
- modulator_type TEXT NOT NULL,
177
- valence REAL NOT NULL,
178
- magnitude REAL NOT NULL DEFAULT 1.0,
179
- source_event_id TEXT,
180
- session_id TEXT,
181
- description TEXT,
182
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
183
- )`);
184
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_modulators_session
185
- ON brain_modulators (session_id)`);
186
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_consolidation_events (
187
- id INTEGER PRIMARY KEY AUTOINCREMENT,
188
- trigger TEXT NOT NULL,
189
- session_id TEXT,
190
- step_results_json TEXT NOT NULL,
191
- duration_ms INTEGER,
192
- succeeded INTEGER NOT NULL DEFAULT 1,
193
- started_at TEXT NOT NULL DEFAULT (datetime('now'))
194
- )`);
195
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_consolidation_events_started_at
196
- ON brain_consolidation_events (started_at)`);
197
- // T1002: brain_transcript_events — full-fidelity Claude session block store.
198
- // CREATE IF NOT EXISTS so re-runs on existing databases are safe.
199
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_transcript_events (
200
- id TEXT PRIMARY KEY,
201
- session_id TEXT NOT NULL,
202
- seq INTEGER NOT NULL,
203
- role TEXT NOT NULL,
204
- block_type TEXT NOT NULL,
205
- content TEXT NOT NULL,
206
- tokens INTEGER,
207
- redacted_at TEXT,
208
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
209
- )`);
210
- nativeDb.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_transcript_events_session_seq
211
- ON brain_transcript_events (session_id, seq)`);
212
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_transcript_events_session
213
- ON brain_transcript_events (session_id)`);
214
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_transcript_events_role
215
- ON brain_transcript_events (role)`);
216
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_transcript_events_block_type
217
- ON brain_transcript_events (block_type)`);
218
- // T1001: stability_score column on brain_observations (distinct from brain_page_edges.stability_score).
219
- // Added via ensureColumns — idempotent, safe on existing databases.
220
- ensureColumns(nativeDb, 'brain_observations', [{ name: 'stability_score', ddl: 'real DEFAULT 0.5' }], 'brain');
221
- // T1084: PSYCHE Wave 2 — peer_id + peer_scope on all four brain memory tables.
222
- // Drizzle migration 20260423000001_t1084-peer-id-memory-isolation handles fresh installs.
223
- // ensureColumns here is the safety-net for installs where the migration journal was
224
- // already partially applied or the journal reconciler skips DDL-only migrations.
225
- // Both columns are NOT NULL with a DEFAULT so the ALTER is safe on non-empty tables.
226
- const peerColumns = [
227
- { name: 'peer_id', ddl: "text NOT NULL DEFAULT 'global'" },
228
- { name: 'peer_scope', ddl: "text NOT NULL DEFAULT 'project'" },
229
- ];
230
- ensureColumns(nativeDb, 'brain_decisions', peerColumns, 'brain');
231
- ensureColumns(nativeDb, 'brain_patterns', peerColumns, 'brain');
232
- ensureColumns(nativeDb, 'brain_learnings', peerColumns, 'brain');
233
- ensureColumns(nativeDb, 'brain_observations', peerColumns, 'brain');
234
- // Companion indexes — idempotent CREATE INDEX IF NOT EXISTS.
235
- for (const [table, idxName] of [
236
- ['brain_decisions', 'idx_brain_decisions_peer_scope'],
237
- ['brain_patterns', 'idx_brain_patterns_peer_scope'],
238
- ['brain_learnings', 'idx_brain_learnings_peer_scope'],
239
- ['brain_observations', 'idx_brain_observations_peer_scope'],
240
- ]) {
241
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS ${idxName} ON ${table} (peer_id, peer_scope)`);
242
- }
243
- // T1260: PSYCHE E3 — provenance_class on all four brain memory tables (M6 refusal gate).
244
- // Drizzle migration 20260424000001_t1260-provenance-class handles fresh installs.
245
- // ensureColumns here is the safety-net for installs where the journal reconciler
246
- // already marked prior migrations applied before this column was added, or where
247
- // the test runner uses a module-cached DB from before the migration ran.
248
- const provenanceColumn = [{ name: 'provenance_class', ddl: "text DEFAULT 'swept-clean'" }];
249
- ensureColumns(nativeDb, 'brain_decisions', provenanceColumn, 'brain');
250
- ensureColumns(nativeDb, 'brain_patterns', provenanceColumn, 'brain');
251
- ensureColumns(nativeDb, 'brain_learnings', provenanceColumn, 'brain');
252
- ensureColumns(nativeDb, 'brain_observations', provenanceColumn, 'brain');
253
- // T1826: Decision Storage Consolidation — ADR tracking + governance columns.
254
- // Drizzle migration 20260504000001_t1826-decisions-v2 handles fresh installs, BUT
255
- // node:sqlite's prepare() only executes the first SQL statement when multiple
256
- // statements are joined without "--> statement-breakpoint" separators. The migration
257
- // file has 7+ ALTER TABLE statements with no breakpoints, so only adr_number gets
258
- // applied by Drizzle. ensureColumns here is the safety-net that guarantees all 7
259
- // new columns exist, matching the pattern used by T1084, T1260, T1145, etc.
260
- ensureColumns(nativeDb, 'brain_decisions', [
261
- { name: 'adr_number', ddl: 'integer' },
262
- { name: 'adr_path', ddl: 'text' },
263
- { name: 'supersedes', ddl: 'text' },
264
- { name: 'superseded_by', ddl: 'text' },
265
- { name: 'confirmation_state', ddl: "text NOT NULL DEFAULT 'proposed'" },
266
- { name: 'decided_by', ddl: "text NOT NULL DEFAULT 'agent'" },
267
- { name: 'validator_run_at', ddl: 'integer' },
268
- ], 'brain');
269
- // T1826: Idempotent companion indexes for the new columns.
270
- nativeDb.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_brain_decisions_adr_number
271
- ON brain_decisions(adr_number)
272
- WHERE adr_number IS NOT NULL`);
273
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_decisions_confirmation_state
274
- ON brain_decisions(confirmation_state)`);
275
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_decisions_decided_by
276
- ON brain_decisions(decided_by)`);
277
- // T1001: brain_promotion_log — typed promotion audit trail.
278
- // One row per observation evaluated (and promoted) by promoteObservationsToTyped().
279
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_promotion_log (
280
- id TEXT PRIMARY KEY,
281
- observation_id TEXT NOT NULL,
282
- from_tier TEXT NOT NULL,
283
- to_tier TEXT NOT NULL,
284
- score REAL NOT NULL,
285
- decided_at TEXT NOT NULL DEFAULT (datetime('now')),
286
- decided_by TEXT NOT NULL DEFAULT 'composite-scorer',
287
- rationale_json TEXT,
288
- fulfilled_at TEXT,
289
- fulfillment_note TEXT
290
- )`);
291
- // T1903: migrate existing brain_promotion_log tables to add fulfillment columns (idempotent).
292
- try {
293
- nativeDb.exec(`ALTER TABLE brain_promotion_log ADD COLUMN fulfilled_at TEXT`);
294
- }
295
- catch {
296
- /* column already exists */
297
- }
298
- try {
299
- nativeDb.exec(`ALTER TABLE brain_promotion_log ADD COLUMN fulfillment_note TEXT`);
300
- }
301
- catch {
302
- /* column already exists */
303
- }
304
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_promotion_log_observation
305
- ON brain_promotion_log (observation_id)`);
306
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_promotion_log_decided_at
307
- ON brain_promotion_log (decided_at)`);
308
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_promotion_log_to_tier
309
- ON brain_promotion_log (to_tier)`);
310
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_promotion_log_score
311
- ON brain_promotion_log (score)`);
312
- // T1003: brain_backfill_runs — staged backfill audit log.
313
- // CREATE IF NOT EXISTS so re-runs on existing databases are safe.
314
- // Staged rows are held in rollback_snapshot_json until approved/rolled-back.
315
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_backfill_runs (
316
- id TEXT PRIMARY KEY,
317
- kind TEXT NOT NULL,
318
- status TEXT NOT NULL DEFAULT 'staged',
319
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
320
- approved_at TEXT,
321
- rows_affected INTEGER NOT NULL DEFAULT 0,
322
- rollback_snapshot_json TEXT,
323
- source TEXT NOT NULL DEFAULT 'unknown',
324
- target_table TEXT NOT NULL DEFAULT 'brain_observations',
325
- approved_by TEXT
326
- )`);
327
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_backfill_runs_status
328
- ON brain_backfill_runs (status)`);
329
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_backfill_runs_kind
330
- ON brain_backfill_runs (kind)`);
331
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_backfill_runs_created_at
332
- ON brain_backfill_runs (created_at)`);
333
- // T1145: Wave 5 Deriver Queue — deriver lineage + level columns on brain_observations.
334
- // Drizzle migration 20260424000003_t1145-extend-brain-observations handles fresh installs.
335
- // ensureColumns here is the safety-net for test DBs and existing installs where the
336
- // journal reconciler may skip the ALTER TABLE migration.
337
- ensureColumns(nativeDb, 'brain_observations', [
338
- { name: 'source_ids', ddl: 'text' },
339
- { name: 'times_derived', ddl: 'integer DEFAULT 1' },
340
- { name: 'level', ddl: "text DEFAULT 'explicit'" },
341
- { name: 'tree_id', ddl: 'integer' },
342
- ], 'brain');
343
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_observations_level ON brain_observations (level)`);
344
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_observations_tree_id ON brain_observations (tree_id)`);
345
- // T1145: deriver_queue — durable background derivation work queue.
346
- // CREATE IF NOT EXISTS so re-runs on existing databases are safe.
347
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS deriver_queue (
348
- id TEXT PRIMARY KEY,
349
- item_type TEXT NOT NULL,
350
- item_id TEXT NOT NULL,
351
- priority INTEGER NOT NULL DEFAULT 0,
352
- status TEXT NOT NULL DEFAULT 'pending',
353
- claimed_at TEXT,
354
- claimed_by TEXT,
355
- error_msg TEXT,
356
- retry_count INTEGER NOT NULL DEFAULT 0,
357
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
358
- completed_at TEXT
359
- )`);
360
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_deriver_queue_status_priority
361
- ON deriver_queue (status, priority DESC, created_at ASC)`);
362
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_deriver_queue_item
363
- ON deriver_queue (item_type, item_id)`);
364
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_deriver_queue_claimed_at
365
- ON deriver_queue (claimed_at)`);
366
- // T1146: brain_memory_trees — hierarchical RPTree clustering (W6 Dreamer Upgrade).
367
- // CREATE IF NOT EXISTS so re-runs on existing databases are safe.
368
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_memory_trees (
369
- id INTEGER PRIMARY KEY AUTOINCREMENT,
370
- depth INTEGER NOT NULL DEFAULT 0,
371
- leaf_ids TEXT NOT NULL DEFAULT '[]',
372
- centroid TEXT,
373
- parent_id INTEGER REFERENCES brain_memory_trees(id) ON DELETE CASCADE,
374
- created_at TEXT NOT NULL DEFAULT (datetime('now')),
375
- updated_at TEXT
376
- )`);
377
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_trees_parent ON brain_memory_trees (parent_id)`);
378
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_trees_depth ON brain_memory_trees (depth)`);
379
- // T1615: brain_task_observations — join table linking brain_observations to task IDs.
380
- // Enables cleo memory find queries to surface session context for a given task.
381
- // CREATE IF NOT EXISTS so re-runs on existing databases are safe.
382
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_task_observations (
383
- id INTEGER PRIMARY KEY AUTOINCREMENT,
384
- observation_id TEXT NOT NULL,
385
- task_id TEXT NOT NULL,
386
- link_type TEXT NOT NULL DEFAULT 'session-completed',
387
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
388
- )`);
389
- nativeDb.exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_brain_task_obs_unique
390
- ON brain_task_observations (observation_id, task_id)`);
391
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_task_obs_observation
392
- ON brain_task_observations (observation_id)`);
393
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_task_obs_task
394
- ON brain_task_observations (task_id)`);
395
- // T11371: brain_attention — Tier-2 scope-keyed, decaying working-memory buffer
396
- // (Epic T11288 · Saga T11283). The Drizzle migration
397
- // 20260530000001_t11371-add-attention-table handles fresh installs; this
398
- // self-healing CREATE IF NOT EXISTS is the safety-net for installs where the
399
- // journal reconciler marked prior migrations applied before this table was
400
- // added, or where the test runner uses a module-cached DB from before the
401
- // migration ran (mirrors the brain_task_observations / deriver_queue pattern).
402
- // `tags` is a JSONB BLOB (E4 jsonb<string[]>() helper) — read in-SQL via
403
- // json_each(tags) / json(tags), NEVER JSON.parse off the raw BLOB.
404
- nativeDb.exec(`CREATE TABLE IF NOT EXISTS brain_attention (
405
- id TEXT PRIMARY KEY,
406
- content TEXT NOT NULL,
407
- session_id TEXT,
408
- agent_id TEXT,
409
- scope_kind TEXT NOT NULL,
410
- scope_id TEXT NOT NULL,
411
- tags BLOB DEFAULT (jsonb('[]')),
412
- created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000),
413
- expires_at INTEGER,
414
- decay_score REAL,
415
- status TEXT NOT NULL DEFAULT 'open'
416
- )`);
417
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_attention_scope
418
- ON brain_attention (scope_kind, scope_id)`);
419
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_attention_session
420
- ON brain_attention (session_id)`);
421
- nativeDb.exec(`CREATE INDEX IF NOT EXISTS idx_brain_attention_status_expires
422
- ON brain_attention (status, expires_at)`);
276
+ // The `drizzle-brain` set now includes `brain_task_observations` (T1615) via
277
+ // the forward migration `20260601000001_t11522-brain-task-observations`, so the
278
+ // previous post-hoc `CREATE TABLE IF NOT EXISTS` band-aid for it is no longer
279
+ // needed here (T11522 AC: post-hoc DDL forward Drizzle migration).
423
280
  }
424
281
  /**
425
282
  * Load the sqlite-vec extension into a native DatabaseSync instance.
@@ -486,163 +343,105 @@ async function initEmbeddingProvider(cwd) {
486
343
  }
487
344
  }
488
345
  /**
489
- * Run a fast malformation probe against an open native handle.
490
- *
491
- * Uses `PRAGMA quick_check` rather than `integrity_check` — quick_check
492
- * skips index-sort and out-of-order rowid scans, returning in milliseconds
493
- * on a healthy DB. A live malformed schema (the T10260/T10265 incident
494
- * pattern) surfaces here as either a throw from `prepare()` or a non-`ok`
495
- * return value.
496
- *
497
- * @returns `true` when the DB passes quick_check, `false` otherwise.
498
- * @task T10303
499
- * @internal
500
- */
501
- function probeBrainDbIntegrity(db) {
502
- try {
503
- const row = db.prepare('PRAGMA quick_check').get();
504
- return row?.quick_check === 'ok';
505
- }
506
- catch {
507
- // prepare() threw — schema is malformed (the T10260/T10265 signature).
508
- return false;
509
- }
510
- }
511
- /**
512
- * Detect whether an open-time exception matches the brain.db malformation
513
- * signature `ERR_SQLITE_ERROR errcode=11` (SQLITE_CORRUPT) — the live
514
- * failure pattern that triggered Saga T10281.
346
+ * Initialize the project-scope BRAIN domain SQLite database (lazy, singleton).
515
347
  *
516
- * @internal
517
- */
518
- function isMalformationError(err) {
519
- if (!(err instanceof Error))
520
- return false;
521
- const code = err.code;
522
- const errcode = err.errcode;
523
- if (code === 'ERR_SQLITE_ERROR' && errcode === 11)
524
- return true;
525
- const msg = err.message ?? '';
526
- // Belt-and-suspenders: some node:sqlite versions stringify "malformed
527
- // database schema" into the message even when errcode is unset.
528
- return /malformed/i.test(msg);
529
- }
530
- /**
531
- * Open the brain.db with auto-recovery on malformation.
532
- *
533
- * Synchronous by design — recovery runs on the open-blocking critical path.
534
- * The alternative is silent broken cognition (T10260, T10265).
348
+ * ## E6-L2 façade (T11522)
535
349
  *
536
- * Recovery flow:
537
- * 1. Try `openNativeDatabase()`. If it throws with the malformation
538
- * signature, run recovery and re-attempt once.
539
- * 2. If the open succeeded, run `PRAGMA quick_check`. If it fails (schema
540
- * malformation that survives the open), close the handle, run recovery,
541
- * and re-attempt.
350
+ * Delegates the physical DB open to {@link openDualScopeDb}('project', cwd) —
351
+ * the canonical dual-scope chokepoint. The returned `NodeSQLiteDatabase` wraps
352
+ * the same `DatabaseSync` handle as the consolidated project `cleo.db` but is
353
+ * typed against the legacy brain schema (`brainSchema`, physical tables
354
+ * `brain_decisions`, …) so all existing brain callers compile and run without
355
+ * change. The legacy `drizzle-brain` migrations are still applied to this handle
356
+ * during the E3→E6 transition (additive / `IF NOT EXISTS` — idempotent on the
357
+ * consolidated DB) so the runtime-queried legacy physical tables (notably
358
+ * `deriver_queue`) co-exist with the consolidated `brain_*` tables.
542
359
  *
543
- * @internal
544
- * @task T10303
545
- */
546
- function openBrainDbWithRecovery(dbPath, cwd) {
547
- const tryOpen = () => openNativeDatabase(dbPath, { allowExtension: true });
548
- const runRecovery = () => {
549
- const cleoDir = resolveCleoDir(cwd);
550
- recoverMalformedBrainDb({
551
- corruptPath: dbPath,
552
- snapshotDir: join(cleoDir, 'backups', 'snapshot'),
553
- vacuumSnapshotDir: join(cleoDir, 'backups', 'sqlite'),
554
- legacyArtifactDir: cleoDir,
555
- quarantineRoot: join(cleoDir, 'quarantine'),
556
- logger: getLogger('brain-recover'),
557
- });
558
- };
559
- let nativeDb;
560
- try {
561
- nativeDb = tryOpen();
562
- }
563
- catch (err) {
564
- if (!isMalformationError(err))
565
- throw err;
566
- runRecovery();
567
- nativeDb = tryOpen();
568
- }
569
- if (!probeBrainDbIntegrity(nativeDb)) {
570
- try {
571
- nativeDb.close();
572
- }
573
- catch {
574
- // close errors are non-fatal — handle terminal anyway
575
- }
576
- runRecovery();
577
- nativeDb = tryOpen();
578
- // One final check — if recovery couldn't produce a clean DB, we still
579
- // return the handle. The downstream migration path will surface the
580
- // failure with full context rather than silently degrading.
581
- }
582
- return nativeDb;
583
- }
584
- /**
585
- * Initialize the brain.db SQLite database (lazy, singleton).
586
- * Creates the database file and tables if they don't exist.
587
- * Returns the drizzle ORM instance (async via sqlite-proxy).
360
+ * Brain-specific malformation auto-recovery (T10303 / Saga T10281) previously
361
+ * ran here against the standalone `brain.db` file. That file no longer backs the
362
+ * brain domain after this leaf — the brain tables live inside `cleo.db`, whose
363
+ * malformation recovery is a dual-scope-level concern (the brain-only
364
+ * quarantine/snapshot-restore pipeline would corrupt the co-resident `tasks_*` /
365
+ * `conduit_*` domains). The recovery primitive itself (`recoverMalformedBrainDb`)
366
+ * is retained for `doctor` use; only its wiring into this chokepoint is removed.
588
367
  *
589
- * Uses a promise guard so concurrent callers wait for the same
590
- * initialization to complete (migrations are async).
368
+ * Uses a promise guard so concurrent callers wait for the same initialization to
369
+ * complete (migrations are async).
591
370
  */
592
371
  export async function getBrainDb(cwd) {
593
372
  const requestedPath = getBrainDbPath(cwd);
594
- // T1906: guard against prod-DB writes in test mode
373
+ // T1906: guard against prod-DB writes in test mode.
595
374
  const { assertTestEnv } = await import('./data-accessor.js');
596
375
  assertTestEnv(requestedPath);
597
- // If singleton exists but points to different path, reset it
376
+ // If singleton exists but points to different path, reset it.
598
377
  if (_db && _dbPath !== requestedPath) {
599
378
  resetBrainDbState();
600
379
  }
380
+ // Liveness guard (T11522): the brain domain shares the consolidated cleo.db
381
+ // handle with the tasks domain. The tasks side may have closed + re-opened the
382
+ // shared `DatabaseSync` (e.g. its `resetDbState()` / auto-recovery path) while
383
+ // our brain singleton still references the now-closed handle. Detect a stale
384
+ // (closed) handle and drop the singleton so we re-derive from the live
385
+ // openDualScopeDb cache below.
386
+ if (_db && (_nativeDb === null || !_nativeDb.isOpen)) {
387
+ resetBrainDbState();
388
+ }
601
389
  if (_db)
602
390
  return _db;
603
- // If already initializing, wait for the in-flight init
391
+ // If already initializing, wait for the in-flight init.
604
392
  if (_initPromise)
605
393
  return _initPromise;
606
394
  _initPromise = (async () => {
607
- const dbPath = requestedPath;
608
- _dbPath = dbPath;
609
- // Ensure directory exists
610
- mkdirSync(dirname(dbPath), { recursive: true });
611
- // Open file-backed SQLite via node:sqlite with WAL mode.
612
- // allowExtension: true enables sqlite-vec extension loading.
613
- //
614
- // T10303 (Saga T10281 / Epic T10286): wrap the open in malformation
615
- // detection + auto-recovery. Catches both `ERR_SQLITE_ERROR errcode=11`
616
- // (raised by the open itself or by the post-open quick_check probe)
617
- // and silent schema corruption that surfaces during the first prepare()
618
- // call. On detection, the corrupt DB is quarantined and the freshest
619
- // validated snapshot is restored; we then re-attempt the open ONCE.
620
- const nativeDb = openBrainDbWithRecovery(dbPath, cwd);
395
+ // ── Dual-scope chokepoint delegation (T11522 · E6-L2) ─────────────────
396
+ // openDualScopeDb applies the pragma SSoT, creates the directory, runs the
397
+ // consolidated cleo-project migrations (which create the `brain_*` tables),
398
+ // and manages the singleton cache. We extract its native handle so we can
399
+ // re-wrap it with the legacy brain-schema for caller compatibility.
400
+ const dualHandle = await openDualScopeDb('project', cwd);
401
+ // Extract the underlying DatabaseSync. Drizzle exposes it via `$client`.
402
+ const nativeDb = dualHandle.db.$client ?? null;
403
+ if (!nativeDb) {
404
+ throw new Error('E6-L2: openDualScopeDb returned a handle without $client ' +
405
+ 'cannot extract DatabaseSync for legacy brain-schema wrapping.');
406
+ }
621
407
  _nativeDb = nativeDb;
622
- // Load sqlite-vec extension for vector similarity search (T5157).
623
- // Non-fatal if unavailable vec0 tables simply won't be created.
408
+ _dbPath = requestedPath;
409
+ // Load the sqlite-vec extension for vector similarity search (T5157). The
410
+ // dual-scope handle is opened with `allowExtension: true`, so loading is
411
+ // permitted. Non-fatal if unavailable — vec0 tables simply won't be created.
624
412
  _vecLoaded = loadBrainVecExtension(nativeDb);
625
- // Create drizzle ORM wrapper via node-sqlite
626
- const db = drizzle({ client: nativeDb, schema: brainSchema });
627
- // Run drizzle migrations (creates/updates tables)
628
- runBrainMigrations(nativeDb, db);
629
- // Create vec0 virtual table for embeddings if extension is loaded (T5157).
630
- // Must run after migrations so the schema is consistent.
413
+ // Wrap the native handle with the legacy brain-schema drizzle instance so
414
+ // existing callers (brainSchema.* queries) continue to work unchanged.
415
+ const db = _getDrizzle()({ client: nativeDb, schema: brainSchema });
416
+ // Reconcile the LEGACY brain-domain schema inside the consolidated cleo.db.
417
+ // Since T11647 the consolidated `cleo.db` migration already creates every
418
+ // `brain_*` table in the LEGACY RUNTIME shape (epoch-ms integer timestamps,
419
+ // no SQL CHECK constraints — the exodus target was aligned to the runtime
420
+ // shape in `cleo-shared/brain.ts`). So this is now a no-op reconcile: it
421
+ // marks the `drizzle-brain` lineage applied and skips the migrate, leaving
422
+ // any exodus-migrated brain rows intact. The legacy standalone-`brain.db`
423
+ // path (DB with no consolidated brain tables) still runs the full
424
+ // `drizzle-brain` migrate. The pre-T11647 DROP+recreate path is retained as
425
+ // a defensive fallback for any DB still carrying the old consolidated shape.
426
+ // (T11522 · T11647)
427
+ establishLegacyBrainSchema(nativeDb, db);
428
+ // Create the vec0 virtual table for embeddings if the extension is loaded
429
+ // (T5157). Must run after migrations so the schema is consistent.
631
430
  if (_vecLoaded) {
632
431
  initializeBrainVec(nativeDb);
633
432
  }
634
- // Seed schema version for new databases (no-op if already set)
433
+ // Seed schema version for new databases (no-op if already set).
635
434
  nativeDb
636
435
  .prepare(`INSERT OR IGNORE INTO brain_schema_meta (key, value) VALUES ('schemaVersion', '${BRAIN_SCHEMA_VERSION}')`)
637
436
  .run();
638
- // Set singleton only after migrations complete
437
+ // Set singleton only after migrations complete.
639
438
  _db = db;
640
- // Wire the default embedding provider when vec is loaded and embedding is enabled.
641
- // Best-effort, async, never blocks DB access. (T539)
439
+ // Wire the default embedding provider when vec is loaded and embedding is
440
+ // enabled. Best-effort, async, never blocks DB access. (T539)
642
441
  if (_vecLoaded) {
643
442
  setImmediate(() => {
644
443
  initEmbeddingProvider(cwd).catch(() => {
645
- // Non-fatal — embedding will be unavailable until next startup
444
+ // Non-fatal — embedding will be unavailable until next startup.
646
445
  });
647
446
  });
648
447
  }
@@ -656,41 +455,40 @@ export async function getBrainDb(cwd) {
656
455
  }
657
456
  }
658
457
  /**
659
- * Close the brain.db database connection and release resources.
458
+ * Close the brain-domain database connection and release resources.
459
+ *
460
+ * ## E6-L2 (T11522)
461
+ *
462
+ * The brain domain now SHARES the consolidated project `cleo.db` handle with the
463
+ * tasks domain (both open it via {@link openDualScopeDb}, same cache key). This
464
+ * function therefore must NOT close the underlying `DatabaseSync` nor evict the
465
+ * dual-scope cache — doing so would break in-flight tasks-domain queries with
466
+ * "database is not open". It only drops the brain-domain singleton references;
467
+ * the shared handle's lifecycle is owned by `openDualScopeDb` and torn down by a
468
+ * coordinated reset (`closeAllDatabases` → `closeDb` → `_resetDualScopeDbCache`).
660
469
  */
661
470
  export function closeBrainDb() {
662
- if (_nativeDb) {
663
- try {
664
- if (_nativeDb.isOpen) {
665
- _nativeDb.close();
666
- }
667
- }
668
- catch {
669
- // Ignore close errors
670
- }
671
- _nativeDb = null;
672
- }
471
+ // Drop only the brain singleton references. Do NOT close `_nativeDb` — it is
472
+ // the shared dual-scope handle, possibly still in use by the tasks domain.
473
+ _nativeDb = null;
673
474
  _db = null;
674
475
  _dbPath = null;
476
+ _initPromise = null;
675
477
  _vecLoaded = false;
676
478
  }
677
479
  /**
678
- * Reset brain.db singleton state without saving.
679
- * Used during tests or when database file is recreated.
480
+ * Reset brain-domain singleton state without saving.
481
+ * Used during tests or when the database file is recreated.
680
482
  * Safe to call multiple times.
483
+ *
484
+ * ## E6-L2 (T11522)
485
+ *
486
+ * Drops only the brain-domain singleton references — does NOT close the shared
487
+ * dual-scope `cleo.db` handle nor evict the dual-scope cache (that handle is
488
+ * shared with the tasks domain). Mirrors {@link closeBrainDb}.
681
489
  */
682
490
  export function resetBrainDbState() {
683
- if (_nativeDb) {
684
- try {
685
- if (_nativeDb.isOpen) {
686
- _nativeDb.close();
687
- }
688
- }
689
- catch {
690
- // Ignore close errors
691
- }
692
- _nativeDb = null;
693
- }
491
+ _nativeDb = null;
694
492
  _db = null;
695
493
  _dbPath = null;
696
494
  _initPromise = null;