@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
@@ -0,0 +1,678 @@
1
+ /**
2
+ * Reusable CORE migration-parity primitive — `verifyMigration()`.
3
+ *
4
+ * This is the durable guard (T11551 · DHQ-045) that prevents the exodus
5
+ * dual-DB consolidation from silently losing rows. It is intentionally generic:
6
+ * given a set of legacy source DBs and the consolidated target DB paths, it
7
+ * returns a typed {@link VerifyMigrationResult} covering FOUR failure classes:
8
+ *
9
+ * 1. **Per-table row-count parity** — every data-bearing source table's
10
+ * consolidated counterpart MUST NOT have FEWER rows than the source (a
11
+ * DEFICIT = data loss → failure). A SURPLUS (target > source — e.g.
12
+ * `nexus_audit_log` gaining the migration's own audit writes during the
13
+ * migrating open) is NOT loss and is tolerated with a WARN (T11577). The
14
+ * per-table `countMatch` field stays a strict `source === target`
15
+ * diagnostic; only a deficit contributes a failure.
16
+ * 2. **`PRAGMA foreign_key_check`** — genuine referential orphans on the
17
+ * consolidated target surface as failures (not copy-order artifacts).
18
+ * 3. **Content checksum** — an ordered canonical-JSON SHA-256 digest over the
19
+ * sorted intersection of source/target columns catches content drift even
20
+ * when counts match.
21
+ * 4. **Enum/type-drift report** — source values outside the target column's
22
+ * CHECK enum. This is the EXACT class that `INSERT OR IGNORE` used to drop
23
+ * silently (the root cause of the ~805K-row exodus loss).
24
+ *
25
+ * ## Relationship to `runExodusVerify`
26
+ *
27
+ * `runExodusVerify` ({@link ./verify.ts}) is the exodus-specific entry point.
28
+ * It now DELEGATES the row-count + checksum parity to this primitive (DRY —
29
+ * T11551 AC2) and additionally surfaces the FK + enum-drift checks this module
30
+ * adds. The digest, name-mapping, and rowid-safe ordering logic that the exodus
31
+ * campaign hardened (T11531/32/33) live here as the single implementation.
32
+ *
33
+ * ## False-pass guard (T11531, preserved)
34
+ *
35
+ * When `ok === false`, `error` is ALWAYS populated with a human-readable
36
+ * failure summary so a caller that only checks `result.error` cannot mistake a
37
+ * silent loss for success.
38
+ *
39
+ * @task T11551 (DHQ-045 — exodus zero-loss durable guard)
40
+ * @epic T10878
41
+ * @saga T11242
42
+ */
43
+ import { existsSync } from 'node:fs';
44
+ import { createRequire } from 'node:module';
45
+ import { MIGRATION_ENUM_DRIFT_SAMPLE_LIMIT } from '@cleocode/contracts';
46
+ import { getLogger } from '../../logger.js';
47
+ import { openCleoDbSnapshot } from '../open-cleo-db.js';
48
+ import { resolveConsolidatedTableName, resolveTableTargetScope } from './table-name-map.js';
49
+ const log = getLogger('verify-migration');
50
+ const _require = createRequire(import.meta.url);
51
+ // ---------------------------------------------------------------------------
52
+ // Digest helpers (rowid-safe ORDER BY + column-intersection digest)
53
+ // ---------------------------------------------------------------------------
54
+ /**
55
+ * Determine a deterministic ORDER BY clause for a table.
56
+ *
57
+ * Uses the table's declared primary-key columns (from `PRAGMA table_info`
58
+ * where `pk > 0`) so ordering is stable for both WITH ROWID and WITHOUT ROWID
59
+ * tables. Falls back to `rowid` only for ordinary tables that declare no
60
+ * explicit primary key. Avoids the `no such column: rowid` crash on virtual /
61
+ * WITHOUT ROWID tables (T11532 ROOT CAUSE 3).
62
+ *
63
+ * @param db - Database handle to introspect.
64
+ * @param tableName - Physical table name.
65
+ * @returns A SQL ORDER BY column list.
66
+ */
67
+ function orderByClause(db, tableName) {
68
+ try {
69
+ const pragma = db.prepare(`PRAGMA table_info("${tableName}")`).all();
70
+ const pkCols = pragma
71
+ .filter((r) => r.pk > 0)
72
+ .sort((a, b) => a.pk - b.pk)
73
+ .map((r) => `"${r.name}"`);
74
+ if (pkCols.length > 0) {
75
+ return pkCols.join(', ');
76
+ }
77
+ }
78
+ catch {
79
+ // Ignore — fall through to rowid
80
+ }
81
+ return 'rowid';
82
+ }
83
+ /**
84
+ * Compute an ordered canonical-JSON SHA-256 digest (32 hex chars) for all rows
85
+ * in a table, restricted to the given column list.
86
+ *
87
+ * When the caller passes the SORTED INTERSECTION of source and target columns,
88
+ * both sides produce identically-structured JSON rows, eliminating spurious
89
+ * hash mismatches from schema-definition column reordering (T11533 ROOT CAUSE
90
+ * 4). Returns `{ count: 0, hash: '' }` for virtual tables that cannot be
91
+ * selected from, rather than throwing.
92
+ *
93
+ * @param db - Database handle to query.
94
+ * @param tableName - Physical table name.
95
+ * @param columns - Explicit column list in canonical order, or `null` for
96
+ * `SELECT *` (used when there is no counterpart table to intersect with).
97
+ * @returns `{ count, hash }` for the table.
98
+ */
99
+ function computeTableDigest(db, tableName, columns) {
100
+ const { createHash } = _require('node:crypto');
101
+ const hasher = createHash('sha256');
102
+ const orderBy = orderByClause(db, tableName);
103
+ const selectClause = columns !== null && columns.length > 0 ? columns.map((c) => `"${c}"`).join(', ') : '*';
104
+ let rows;
105
+ try {
106
+ rows = db
107
+ .prepare(`SELECT ${selectClause} FROM "${tableName}" ORDER BY ${orderBy}`)
108
+ .all();
109
+ }
110
+ catch (err) {
111
+ const msg = err instanceof Error ? err.message : String(err);
112
+ log.warn({ tableName, err: msg }, 'computeTableDigest: SELECT failed (possibly a virtual/FTS table) — treating as 0 rows');
113
+ return { count: 0, hash: '' };
114
+ }
115
+ for (const row of rows) {
116
+ hasher.update(JSON.stringify(row));
117
+ }
118
+ return {
119
+ count: rows.length,
120
+ hash: hasher.digest('hex').slice(0, 32),
121
+ };
122
+ }
123
+ /**
124
+ * Return the sorted intersection of column names present in both the source and
125
+ * target tables, for use as the canonical column ordering in
126
+ * {@link computeTableDigest}. Returns `null` when either side has no columns
127
+ * (virtual/FTS-table fallback).
128
+ *
129
+ * @param srcDb - Source database handle.
130
+ * @param srcTable - Physical table name in the source DB.
131
+ * @param tgtDb - Target database handle.
132
+ * @param tgtTable - Physical table name in the target DB.
133
+ */
134
+ function sharedColumnsSorted(srcDb, srcTable, tgtDb, tgtTable) {
135
+ try {
136
+ const srcCols = srcDb.prepare(`PRAGMA table_info("${srcTable}")`).all().map((r) => r.name);
137
+ const tgtColSet = new Set(tgtDb.prepare(`PRAGMA table_info("${tgtTable}")`).all().map((r) => r.name));
138
+ if (srcCols.length === 0 || tgtColSet.size === 0)
139
+ return null;
140
+ return srcCols.filter((c) => tgtColSet.has(c)).sort();
141
+ }
142
+ catch {
143
+ return null;
144
+ }
145
+ }
146
+ /**
147
+ * List user tables in a DB (excluding SQLite internals + Drizzle journal).
148
+ */
149
+ function listTables(db) {
150
+ const rows = db
151
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE '__drizzle_%' ORDER BY name")
152
+ .all();
153
+ return rows.map((r) => r.name);
154
+ }
155
+ /**
156
+ * Return `true` if `tableName` exists in `db`. Used to route an FK-orphan row to
157
+ * the scope DB that actually declares its child table (T11572).
158
+ */
159
+ function tableExists(db, tableName) {
160
+ try {
161
+ const escaped = tableName.replace(/'/g, "''");
162
+ return (db.prepare(`SELECT 1 FROM sqlite_master WHERE type='table' AND name='${escaped}'`).get() !==
163
+ undefined);
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ }
169
+ // ---------------------------------------------------------------------------
170
+ // Enum/type-drift detection
171
+ // ---------------------------------------------------------------------------
172
+ /**
173
+ * Regex that extracts a single-column `IN (...)` CHECK enum from a table's DDL.
174
+ *
175
+ * Matches the canonical Drizzle-generated form:
176
+ * `CHECK ("col" IN ('a', 'b', 'c'))`
177
+ * and the NULL-tolerant variant:
178
+ * `CHECK ("col" IS NULL OR "col" IN ('a', 'b'))`
179
+ *
180
+ * Capture group 1 is the column name; group 2 is the raw `'a', 'b', …` list.
181
+ * The regex is intentionally conservative — it only recognises the
182
+ * string-literal `IN` enum shape (the one that drops rows on drift), not GLOB
183
+ * or arithmetic CHECKs.
184
+ */
185
+ const CHECK_ENUM_REGEX = /CHECK\s*\(\s*"([^"]+)"\s+(?:IS\s+NULL\s+OR\s+"[^"]+"\s+)?IN\s*\(([^)]*)\)\s*\)/gi;
186
+ /**
187
+ * Parse the `'a', 'b', 'c'` body of an `IN (...)` clause into the set of
188
+ * canonical enum members (single-quoted SQL string literals, `''` un-escaped).
189
+ */
190
+ function parseEnumMembers(body) {
191
+ const members = [];
192
+ // Match single-quoted literals, handling the SQL `''` escape for a quote.
193
+ for (const m of body.matchAll(/'((?:[^']|'')*)'/g)) {
194
+ members.push(m[1].replace(/''/g, "'"));
195
+ }
196
+ return members;
197
+ }
198
+ /**
199
+ * Read a target table's DDL and return a map of `column → allowed enum members`
200
+ * for every single-column string-literal CHECK enum on that table.
201
+ *
202
+ * @param db - Target DB with the consolidated schema.
203
+ * @param tableName - Physical consolidated table name.
204
+ * @returns Map from column name to its allowed enum members. Empty when the
205
+ * table declares no recognised CHECK enums.
206
+ */
207
+ function detectCheckEnums(db, tableName) {
208
+ const escaped = tableName.replace(/'/g, "''");
209
+ const row = db
210
+ .prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='${escaped}'`)
211
+ .get();
212
+ const out = new Map();
213
+ if (!row?.sql)
214
+ return out;
215
+ CHECK_ENUM_REGEX.lastIndex = 0;
216
+ for (const match of row.sql.matchAll(CHECK_ENUM_REGEX)) {
217
+ const col = match[1];
218
+ const members = parseEnumMembers(match[2]);
219
+ if (members.length > 0)
220
+ out.set(col, members);
221
+ }
222
+ return out;
223
+ }
224
+ /**
225
+ * Detect enum/type drift for one source→target table pair: source values in an
226
+ * enum-constrained column that are NOT members of the target CHECK enum.
227
+ *
228
+ * Reads the DISTINCT non-null values of each enum column from the source table
229
+ * and compares them against the target's allowed members. Only columns present
230
+ * in BOTH source and target are inspected. The check is purely diagnostic — it
231
+ * reports raw source drift; the migration layer is responsible for normalising
232
+ * known aliases before insert.
233
+ *
234
+ * @param srcDb - Source DB handle.
235
+ * @param srcTable - Physical source table name.
236
+ * @param tgtDb - Target DB handle.
237
+ * @param tgtTable - Physical consolidated target table name.
238
+ * @returns Drift findings for this table (empty when fully canonical).
239
+ */
240
+ function detectTableEnumDrift(srcDb, srcTable, tgtDb, tgtTable) {
241
+ const enums = detectCheckEnums(tgtDb, tgtTable);
242
+ if (enums.size === 0)
243
+ return [];
244
+ let srcCols;
245
+ try {
246
+ srcCols = new Set(srcDb.prepare(`PRAGMA table_info("${srcTable}")`).all().map((r) => r.name));
247
+ }
248
+ catch {
249
+ return [];
250
+ }
251
+ const findings = [];
252
+ for (const [col, allowed] of enums) {
253
+ if (!srcCols.has(col))
254
+ continue;
255
+ const allowedSet = new Set(allowed);
256
+ let rows;
257
+ try {
258
+ rows = srcDb
259
+ .prepare(`SELECT "${col}" AS v, COUNT(*) AS c FROM "${srcTable}" WHERE "${col}" IS NOT NULL GROUP BY "${col}"`)
260
+ .all();
261
+ }
262
+ catch {
263
+ continue;
264
+ }
265
+ const offending = [];
266
+ let driftCount = 0;
267
+ for (const r of rows) {
268
+ const value = String(r.v);
269
+ if (!allowedSet.has(value)) {
270
+ driftCount += r.c;
271
+ if (offending.length < MIGRATION_ENUM_DRIFT_SAMPLE_LIMIT)
272
+ offending.push(value);
273
+ }
274
+ }
275
+ if (driftCount > 0) {
276
+ findings.push({
277
+ targetTable: tgtTable,
278
+ column: col,
279
+ offendingValues: offending,
280
+ allowedValues: allowed,
281
+ driftCount,
282
+ });
283
+ }
284
+ }
285
+ return findings;
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Foreign-key integrity
289
+ // ---------------------------------------------------------------------------
290
+ /**
291
+ * Run `PRAGMA foreign_key_check` on a target DB and return any orphan rows.
292
+ *
293
+ * @param db - Target DB handle (consolidated cleo.db).
294
+ * @param scope - Scope label, attached to log context only.
295
+ * @returns The list of FK violations (empty when referential integrity holds).
296
+ */
297
+ function foreignKeyCheck(db, scope) {
298
+ try {
299
+ const rows = db.prepare('PRAGMA foreign_key_check').all();
300
+ if (rows.length > 0) {
301
+ log.warn({ scope, count: rows.length, sample: rows.slice(0, 5) }, `verifyMigration: PRAGMA foreign_key_check found ${rows.length} orphan row(s)`);
302
+ }
303
+ return rows.map((r) => ({
304
+ table: r.table,
305
+ rowid: r.rowid ?? null,
306
+ parent: r.parent,
307
+ fkid: r.fkid,
308
+ }));
309
+ }
310
+ catch (err) {
311
+ log.warn({ scope, err }, 'verifyMigration: PRAGMA foreign_key_check failed (non-fatal)');
312
+ return [];
313
+ }
314
+ }
315
+ /**
316
+ * Compute a **migration-stable, name-mapping-stable signature** for one FK
317
+ * orphan so the same dangling row can be matched between the legacy SOURCE and
318
+ * the consolidated TARGET — despite (a) a different `rowid` after the copy AND
319
+ * (b) the legacy→consolidated table RENAME (`task_relations`→`tasks_task_relations`,
320
+ * parent `tasks`→`tasks_tasks`).
321
+ *
322
+ * `PRAGMA foreign_key_check` returns `{ table, rowid, parent, fkid }`. We key the
323
+ * orphan on:
324
+ * - the CONSOLIDATED child-table name (source names are mapped via
325
+ * {@link resolveConsolidatedTableName} so both sides agree),
326
+ * - the CONSOLIDATED parent-table name (same mapping),
327
+ * - the actual VALUES of the foreign-key child columns for that row (read via
328
+ * `PRAGMA foreign_key_list` + the row at `rowid`) — these travel with the row
329
+ * unchanged, so the dangling reference is identical on both sides.
330
+ *
331
+ * `fkid` is intentionally EXCLUDED — the consolidated table may declare its FKs
332
+ * in a different order than the legacy one, so the per-table fkid is not stable.
333
+ * The (consolidated child, consolidated parent, dangling FK column values) triple
334
+ * uniquely identifies the orphan reference.
335
+ *
336
+ * Falls back to a column-name-only shape if the child columns can't be read
337
+ * (best-effort — a fallback only ever makes two orphans compare as *different*,
338
+ * which biases toward treating an orphan as "introduced", the SAFE/strict
339
+ * direction).
340
+ *
341
+ * @param db - DB handle the orphan was found in.
342
+ * @param v - One `PRAGMA foreign_key_check` row.
343
+ * @param sourceName - When set, the orphan is on the SOURCE side and its
344
+ * `table`/`parent` names are mapped to their consolidated equivalents so the
345
+ * signature matches the target side. Omit for the already-consolidated target.
346
+ * @returns A stable string signature.
347
+ */
348
+ function orphanSignature(db, v, sourceName) {
349
+ // Map both child + parent table names to their CONSOLIDATED form so the source
350
+ // and target signatures agree across the legacy→consolidated rename.
351
+ const mapName = (name) => {
352
+ if (sourceName === undefined)
353
+ return name; // already consolidated (target side)
354
+ const res = resolveConsolidatedTableName(sourceName, name);
355
+ return res.kind === 'skip' ? name : res.targetName;
356
+ };
357
+ const childTable = mapName(v.table);
358
+ const parentTable = mapName(v.parent);
359
+ // Resolve the child→parent column mapping for this specific FK (matched by
360
+ // fkid via PRAGMA foreign_key_list ordering).
361
+ let childCols = [];
362
+ try {
363
+ const fkList = db.prepare(`PRAGMA foreign_key_list("${v.table}")`).all();
364
+ childCols = fkList.filter((r) => r.id === v.fkid).map((r) => r.from);
365
+ }
366
+ catch {
367
+ // ignore — fall through to rowid-based fallback
368
+ }
369
+ if (v.rowid !== null && childCols.length > 0) {
370
+ try {
371
+ const sel = childCols.map((c) => `"${c}"`).join(', ');
372
+ const row = db.prepare(`SELECT ${sel} FROM "${v.table}" WHERE rowid = ?`).get(v.rowid);
373
+ if (row) {
374
+ // Order the FK column values deterministically by column name.
375
+ const vals = childCols
376
+ .slice()
377
+ .sort()
378
+ .map((c) => `${c}=${JSON.stringify(row[c])}`)
379
+ .join('&');
380
+ return `${childTable}|${parentTable}|${vals}`;
381
+ }
382
+ }
383
+ catch {
384
+ // ignore — fall through to rowid-based fallback
385
+ }
386
+ }
387
+ // Fallback: rowid-qualified signature (only collides with itself).
388
+ return `${childTable}|${parentTable}|rowid:${v.rowid ?? '?'}`;
389
+ }
390
+ /**
391
+ * Collect the set of {@link orphanSignature}s for every FK orphan in a SOURCE DB.
392
+ *
393
+ * Used to compute SOURCE-side orphan signatures so the parity gate can subtract
394
+ * pre-existing orphans from the target's orphan set and fail only on the orphans
395
+ * the migration INTRODUCED (T11572). The signatures are mapped to consolidated
396
+ * table names so they compare equal to the target-side signatures.
397
+ *
398
+ * @param db - SOURCE DB handle to scan.
399
+ * @param sourceName - `LegacyDbDescriptor.name` (for table-name mapping).
400
+ * @param scope - Scope label for diagnostics.
401
+ * @returns A set of name-mapping-stable orphan signatures.
402
+ */
403
+ function sourceOrphanSignatures(db, sourceName, scope) {
404
+ const sigs = new Set();
405
+ try {
406
+ const rows = db.prepare('PRAGMA foreign_key_check').all();
407
+ for (const r of rows)
408
+ sigs.add(orphanSignature(db, r, sourceName));
409
+ if (rows.length > 0) {
410
+ log.warn({ scope, count: rows.length, sample: rows.slice(0, 5) }, `verifyMigration: source already has ${rows.length} pre-existing FK orphan(s) — these are tolerated (carried forward losslessly, flagged for data-hygiene)`);
411
+ }
412
+ }
413
+ catch (err) {
414
+ log.warn({ scope, err }, 'verifyMigration: source PRAGMA foreign_key_check failed (non-fatal)');
415
+ }
416
+ return sigs;
417
+ }
418
+ // ---------------------------------------------------------------------------
419
+ // Public primitive
420
+ // ---------------------------------------------------------------------------
421
+ /**
422
+ * Verify that a source→target SQLite migration preserved every row, referential
423
+ * integrity, content, and enum validity.
424
+ *
425
+ * Opens all source DBs and the consolidated target DBs **read-only**, then for
426
+ * each legacy source table:
427
+ *
428
+ * 1. Resolves the consolidated target name via {@link resolveConsolidatedTableName}.
429
+ * 2. Compares row counts (parity gate).
430
+ * 3. Computes a column-intersection content digest on both sides.
431
+ * 4. Records any enum/type drift (source values outside the target CHECK enum).
432
+ *
433
+ * After all tables, it runs `PRAGMA foreign_key_check` on each distinct target
434
+ * DB and folds the orphan rows into the result.
435
+ *
436
+ * @param sources - Legacy source descriptors (from `buildExodusPlan()`).
437
+ * @param projectDbPath - Absolute path to the consolidated project `cleo.db`.
438
+ * @param globalDbPath - Absolute path to the consolidated global `cleo.db`.
439
+ * @param onProgress - Optional progress callback.
440
+ *
441
+ * @returns A {@link VerifyMigrationResult}. `ok === false` (with `error`
442
+ * populated) on any count mismatch, content mismatch, FK orphan, or enum
443
+ * drift.
444
+ *
445
+ * @task T11551 (DHQ-045 — exodus zero-loss durable guard · AC1)
446
+ */
447
+ export function verifyMigration(sources, projectDbPath, globalDbPath, onProgress) {
448
+ const tables = [];
449
+ const enumDrift = [];
450
+ const foreignKeyViolations = [];
451
+ const introducedForeignKeyViolations = [];
452
+ const preExistingForeignKeyViolations = [];
453
+ const failureLines = [];
454
+ /**
455
+ * Signatures of FK orphans ALREADY present in the legacy SOURCE DBs (T11572).
456
+ * Target orphans whose signature is in this set are pre-existing — carried
457
+ * forward losslessly — and do NOT fail the parity gate.
458
+ */
459
+ const sourceOrphanSigs = new Set();
460
+ if (!existsSync(projectDbPath)) {
461
+ return {
462
+ ok: false,
463
+ tables: [],
464
+ foreignKeyViolations: [],
465
+ introducedForeignKeyViolations: [],
466
+ preExistingForeignKeyViolations: [],
467
+ enumDrift: [],
468
+ error: `Consolidated project cleo.db not found at ${projectDbPath}. Run 'cleo exodus migrate' first.`,
469
+ };
470
+ }
471
+ if (!existsSync(globalDbPath)) {
472
+ return {
473
+ ok: false,
474
+ tables: [],
475
+ foreignKeyViolations: [],
476
+ introducedForeignKeyViolations: [],
477
+ preExistingForeignKeyViolations: [],
478
+ enumDrift: [],
479
+ error: `Consolidated global cleo.db not found at ${globalDbPath}. Run 'cleo exodus migrate' first.`,
480
+ };
481
+ }
482
+ const projectSnap = openCleoDbSnapshot(projectDbPath, { readOnly: true });
483
+ const globalSnap = openCleoDbSnapshot(globalDbPath, { readOnly: true });
484
+ try {
485
+ for (const src of sources) {
486
+ if (!existsSync(src.path)) {
487
+ onProgress?.(`Skipping ${src.name} (not present)`);
488
+ continue;
489
+ }
490
+ const srcSnap = openCleoDbSnapshot(src.path, { readOnly: true });
491
+ try {
492
+ // T11572: record FK orphans that already exist in THIS source DB so the
493
+ // gate can distinguish pre-existing orphans (tolerated, zero-loss) from
494
+ // orphans the migration introduces (genuine loss → abort). Done while the
495
+ // source snapshot is open; signatures are migration-stable (content, not
496
+ // rowid). FK enforcement on the source is irrelevant — foreign_key_check
497
+ // scans regardless.
498
+ for (const sig of sourceOrphanSignatures(srcSnap.db, src.name, `source:${src.name}`)) {
499
+ sourceOrphanSigs.add(sig);
500
+ }
501
+ const sourceTables = listTables(srcSnap.db);
502
+ // Pre-compute the table set for each consolidated scope once; the
503
+ // per-table scope override (ADR-090 nexus graph residency, T11539) means
504
+ // a single source can verify against BOTH scope DBs.
505
+ const projectTables = new Set(listTables(projectSnap.db));
506
+ const globalTables = new Set(listTables(globalSnap.db));
507
+ for (const legacyTableName of sourceTables) {
508
+ onProgress?.(`Verifying ${src.name}.${legacyTableName}…`);
509
+ const resolution = resolveConsolidatedTableName(src.name, legacyTableName);
510
+ if (resolution.kind === 'skip') {
511
+ onProgress?.(` [skip] ${src.name}.${legacyTableName} — ${resolution.reason}`);
512
+ continue;
513
+ }
514
+ const targetTableName = resolution.targetName;
515
+ // Per-table scope override (ADR-090 · T11539): the four nexus graph
516
+ // tables come from the GLOBAL `nexus.db` source but land in PROJECT
517
+ // scope. Pick the verify target DB by the effective per-table scope.
518
+ const scope = resolveTableTargetScope(src.name, legacyTableName, src.targetScope);
519
+ const targetSnap = scope === 'project' ? projectSnap : globalSnap;
520
+ const targetTables = scope === 'project' ? projectTables : globalTables;
521
+ // --- Enum/type-drift report (diagnostic, only when target exists) ---
522
+ if (targetTables.has(targetTableName)) {
523
+ const drift = detectTableEnumDrift(srcSnap.db, legacyTableName, targetSnap.db, targetTableName);
524
+ if (drift.length > 0) {
525
+ enumDrift.push(...drift);
526
+ for (const d of drift) {
527
+ failureLines.push(`[${scope}] ${targetTableName}.${d.column}: ${d.driftCount} row(s) with value(s) ` +
528
+ `outside enum {${d.allowedValues.join(', ')}} — e.g. ${d.offendingValues
529
+ .map((v) => `'${v}'`)
530
+ .join(', ')}`);
531
+ }
532
+ }
533
+ }
534
+ // --- Row-count + content-checksum parity ---
535
+ if (!targetTables.has(targetTableName)) {
536
+ const srcResult = computeTableDigest(srcSnap.db, legacyTableName, null);
537
+ const countMatch = srcResult.count === 0;
538
+ tables.push({
539
+ sourceTable: legacyTableName,
540
+ targetTable: targetTableName,
541
+ scope,
542
+ sourceCount: srcResult.count,
543
+ targetCount: 0,
544
+ sourceHash: srcResult.hash,
545
+ targetHash: '',
546
+ hashMatch: countMatch,
547
+ countMatch,
548
+ });
549
+ if (!countMatch) {
550
+ failureLines.push(`[${scope}] ${src.name}.${legacyTableName} → ${targetTableName}: ` +
551
+ `missing from target (source has ${srcResult.count} rows)`);
552
+ }
553
+ continue;
554
+ }
555
+ const cols = sharedColumnsSorted(srcSnap.db, legacyTableName, targetSnap.db, targetTableName);
556
+ const srcDigest = computeTableDigest(srcSnap.db, legacyTableName, cols);
557
+ const tgtDigest = computeTableDigest(targetSnap.db, targetTableName, cols);
558
+ const countMatch = srcDigest.count === tgtDigest.count;
559
+ const hashMatch = srcDigest.hash === tgtDigest.hash;
560
+ // T11577: only a row DEFICIT (target < source) is genuine data loss.
561
+ // A SURPLUS (target > source) — e.g. nexus_audit_log gaining the
562
+ // migration's OWN audit writes during the migrating open — is NOT loss
563
+ // and must not fail the gate. When a surplus exists the content digest
564
+ // necessarily differs (more rows), so the hash difference is expected
565
+ // and is NOT counted as a failure. Surplus is logged as a WARN so the
566
+ // table + delta stay visible (a surplus on a non-append table could
567
+ // hint at a double-copy worth an operator's attention).
568
+ if (tgtDigest.count < srcDigest.count) {
569
+ failureLines.push(`[${scope}] ${src.name}.${legacyTableName} → ${targetTableName}: ` +
570
+ `DEFICIT — source=${srcDigest.count} rows, target=${tgtDigest.count} rows (${srcDigest.count - tgtDigest.count} missing), hashMatch=${hashMatch}`);
571
+ }
572
+ else if (tgtDigest.count > srcDigest.count) {
573
+ log.warn({
574
+ scope,
575
+ source: src.name,
576
+ table: targetTableName,
577
+ sourceCount: srcDigest.count,
578
+ targetCount: tgtDigest.count,
579
+ delta: tgtDigest.count - srcDigest.count,
580
+ }, `verifyMigration: ${targetTableName} has ${tgtDigest.count - srcDigest.count} MORE row(s) in target than source (surplus — NOT data loss, tolerated; ` +
581
+ `e.g. migration-time audit writes). Verify it is not an unexpected double-copy.`);
582
+ }
583
+ else if (!hashMatch) {
584
+ // Exact count parity but content drift — a genuine corruption class.
585
+ failureLines.push(`[${scope}] ${src.name}.${legacyTableName} → ${targetTableName}: ` +
586
+ `source=${srcDigest.count} rows, target=${tgtDigest.count} rows, hashMatch=${hashMatch}`);
587
+ }
588
+ tables.push({
589
+ sourceTable: legacyTableName,
590
+ targetTable: targetTableName,
591
+ scope,
592
+ sourceCount: srcDigest.count,
593
+ targetCount: tgtDigest.count,
594
+ sourceHash: srcDigest.hash,
595
+ targetHash: tgtDigest.hash,
596
+ hashMatch,
597
+ countMatch,
598
+ });
599
+ }
600
+ }
601
+ finally {
602
+ srcSnap.close();
603
+ }
604
+ }
605
+ // --- Foreign-key integrity on each distinct target DB ---
606
+ // Collect ALL target orphans, then partition into pre-existing (already
607
+ // orphaned in the source — tolerated, zero-loss) vs migration-introduced
608
+ // (genuine loss → gate failure). Match by migration-stable signature so a
609
+ // faithfully-copied pre-existing orphan is recognised despite a new rowid.
610
+ const targetOrphans = [];
611
+ targetOrphans.push(...foreignKeyCheck(projectSnap.db, 'project'));
612
+ targetOrphans.push(...foreignKeyCheck(globalSnap.db, 'global'));
613
+ foreignKeyViolations.push(...targetOrphans);
614
+ for (const fk of targetOrphans) {
615
+ // Recompute the orphan signature on the TARGET side (same content key as
616
+ // the source side) to test membership in the pre-existing source set. The
617
+ // orphan lives in whichever scope DB declares the child table.
618
+ const orphanDb = tableExists(projectSnap.db, fk.table) ? projectSnap.db : globalSnap.db;
619
+ const sig = orphanSignature(orphanDb, fk);
620
+ const preExisting = sourceOrphanSigs.has(sig);
621
+ if (preExisting) {
622
+ preExistingForeignKeyViolations.push(fk);
623
+ }
624
+ else {
625
+ introducedForeignKeyViolations.push(fk);
626
+ // ONLY migration-INTRODUCED orphans fail the gate (T11572).
627
+ failureLines.push(`[fk] ${fk.table}.rowid=${fk.rowid ?? '?'} references missing ${fk.parent} (fkid=${fk.fkid}) — INTRODUCED by migration`);
628
+ }
629
+ }
630
+ if (preExistingForeignKeyViolations.length > 0) {
631
+ log.warn({
632
+ count: preExistingForeignKeyViolations.length,
633
+ sample: preExistingForeignKeyViolations.slice(0, 5),
634
+ }, `verifyMigration: ${preExistingForeignKeyViolations.length} pre-existing source FK orphan(s) carried forward losslessly — tolerated (flag for data-hygiene follow-up, NOT a migration failure)`);
635
+ }
636
+ }
637
+ catch (err) {
638
+ const error = err instanceof Error ? err.message : String(err);
639
+ log.error({ err }, 'verifyMigration failed');
640
+ return {
641
+ ok: false,
642
+ tables,
643
+ foreignKeyViolations,
644
+ introducedForeignKeyViolations,
645
+ preExistingForeignKeyViolations,
646
+ enumDrift,
647
+ error,
648
+ };
649
+ }
650
+ finally {
651
+ projectSnap.close();
652
+ globalSnap.close();
653
+ }
654
+ if (failureLines.length > 0) {
655
+ const error = `verifyMigration FAILED: ${failureLines.length} issue(s):\n${failureLines
656
+ .map((l) => ` • ${l}`)
657
+ .join('\n')}`;
658
+ log.error({ failureCount: failureLines.length }, error);
659
+ return {
660
+ ok: false,
661
+ tables,
662
+ foreignKeyViolations,
663
+ introducedForeignKeyViolations,
664
+ preExistingForeignKeyViolations,
665
+ enumDrift,
666
+ error,
667
+ };
668
+ }
669
+ return {
670
+ ok: true,
671
+ tables,
672
+ foreignKeyViolations,
673
+ introducedForeignKeyViolations,
674
+ preExistingForeignKeyViolations,
675
+ enumDrift,
676
+ };
677
+ }
678
+ //# sourceMappingURL=verify-migration.js.map