@cleocode/core 2026.9.8 → 2026.9.10

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 (569) hide show
  1. package/dist/audit/reconstruct.d.ts +13 -43
  2. package/dist/audit/reconstruct.d.ts.map +1 -1
  3. package/dist/audit/reconstruct.js +295 -290
  4. package/dist/audit/reconstruct.js.map +1 -1
  5. package/dist/bootstrap.d.ts.map +1 -1
  6. package/dist/bootstrap.js +8 -2
  7. package/dist/bootstrap.js.map +1 -1
  8. package/dist/compliance/protocol-rules.d.ts.map +1 -1
  9. package/dist/compliance/protocol-rules.js +3 -1
  10. package/dist/compliance/protocol-rules.js.map +1 -1
  11. package/dist/dispatch/mutate-projection.d.ts.map +1 -1
  12. package/dist/dispatch/mutate-projection.js +12 -0
  13. package/dist/dispatch/mutate-projection.js.map +1 -1
  14. package/dist/dispatch/mvi-projection.d.ts +29 -6
  15. package/dist/dispatch/mvi-projection.d.ts.map +1 -1
  16. package/dist/dispatch/mvi-projection.js +109 -139
  17. package/dist/dispatch/mvi-projection.js.map +1 -1
  18. package/dist/docs/docs-read-model.d.ts +3 -2
  19. package/dist/docs/docs-read-model.d.ts.map +1 -1
  20. package/dist/docs/docs-read-model.js +4 -3
  21. package/dist/docs/docs-read-model.js.map +1 -1
  22. package/dist/docs/export-document.js +5129 -2297
  23. package/dist/docs/export-document.js.map +3 -3
  24. package/dist/docs/projection.d.ts +67 -0
  25. package/dist/docs/projection.d.ts.map +1 -0
  26. package/dist/docs/projection.js +370 -0
  27. package/dist/docs/projection.js.map +1 -0
  28. package/dist/doctor/acceptance-drift.d.ts +6 -2
  29. package/dist/doctor/acceptance-drift.d.ts.map +1 -1
  30. package/dist/doctor/acceptance-drift.js +43 -5
  31. package/dist/doctor/acceptance-drift.js.map +1 -1
  32. package/dist/doctor/knowledge-summary.d.ts +41 -0
  33. package/dist/doctor/knowledge-summary.d.ts.map +1 -0
  34. package/dist/doctor/knowledge-summary.js +81 -0
  35. package/dist/doctor/knowledge-summary.js.map +1 -0
  36. package/dist/doctor/knowledge.d.ts +192 -0
  37. package/dist/doctor/knowledge.d.ts.map +1 -0
  38. package/dist/doctor/knowledge.js +1864 -0
  39. package/dist/doctor/knowledge.js.map +1 -0
  40. package/dist/git/work-tree.d.ts +169 -0
  41. package/dist/git/work-tree.d.ts.map +1 -0
  42. package/dist/git/work-tree.js +341 -0
  43. package/dist/git/work-tree.js.map +1 -0
  44. package/dist/hooks/handlers/task-hooks.d.ts +8 -5
  45. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  46. package/dist/hooks/handlers/task-hooks.js +15 -60
  47. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  48. package/dist/identity/cleo-identity.d.ts +13 -0
  49. package/dist/identity/cleo-identity.d.ts.map +1 -1
  50. package/dist/identity/cleo-identity.js +20 -6
  51. package/dist/identity/cleo-identity.js.map +1 -1
  52. package/dist/injection.d.ts.map +1 -1
  53. package/dist/injection.js +29 -13
  54. package/dist/injection.js.map +1 -1
  55. package/dist/internal.d.ts +3 -0
  56. package/dist/internal.d.ts.map +1 -1
  57. package/dist/internal.js +4 -0
  58. package/dist/internal.js.map +1 -1
  59. package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
  60. package/dist/lifecycle/verification/satisfies-validator.js +124 -120
  61. package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
  62. package/dist/llm/plugin-facade.js +4047 -1726
  63. package/dist/llm/plugin-facade.js.map +3 -3
  64. package/dist/memory/brain-backfill.d.ts +27 -12
  65. package/dist/memory/brain-backfill.d.ts.map +1 -1
  66. package/dist/memory/brain-backfill.js +325 -134
  67. package/dist/memory/brain-backfill.js.map +1 -1
  68. package/dist/memory/brain-doctor.d.ts +21 -0
  69. package/dist/memory/brain-doctor.d.ts.map +1 -1
  70. package/dist/memory/brain-doctor.js +111 -53
  71. package/dist/memory/brain-doctor.js.map +1 -1
  72. package/dist/memory/brain-links.d.ts.map +1 -1
  73. package/dist/memory/brain-links.js +31 -4
  74. package/dist/memory/brain-links.js.map +1 -1
  75. package/dist/memory/brain-reasoning.d.ts.map +1 -1
  76. package/dist/memory/brain-reasoning.js +28 -2
  77. package/dist/memory/brain-reasoning.js.map +1 -1
  78. package/dist/memory/brain-reconciler.d.ts +14 -19
  79. package/dist/memory/brain-reconciler.d.ts.map +1 -1
  80. package/dist/memory/brain-reconciler.js +70 -97
  81. package/dist/memory/brain-reconciler.js.map +1 -1
  82. package/dist/memory/brain-search.d.ts +2 -0
  83. package/dist/memory/brain-search.d.ts.map +1 -1
  84. package/dist/memory/brain-search.js +59 -29
  85. package/dist/memory/brain-search.js.map +1 -1
  86. package/dist/memory/brain-similarity.d.ts.map +1 -1
  87. package/dist/memory/brain-similarity.js +5 -4
  88. package/dist/memory/brain-similarity.js.map +1 -1
  89. package/dist/memory/brain-stub-prune.d.ts +31 -9
  90. package/dist/memory/brain-stub-prune.d.ts.map +1 -1
  91. package/dist/memory/brain-stub-prune.js +65 -18
  92. package/dist/memory/brain-stub-prune.js.map +1 -1
  93. package/dist/memory/brain-writer-handlers.d.ts +10 -1
  94. package/dist/memory/brain-writer-handlers.d.ts.map +1 -1
  95. package/dist/memory/brain-writer-handlers.js +23 -3
  96. package/dist/memory/brain-writer-handlers.js.map +1 -1
  97. package/dist/memory/brain-writer-thread.d.ts +11 -1
  98. package/dist/memory/brain-writer-thread.d.ts.map +1 -1
  99. package/dist/memory/brain-writer-thread.js +87 -20
  100. package/dist/memory/brain-writer-thread.js.map +1 -1
  101. package/dist/memory/brain-writer-worker.js +8 -1
  102. package/dist/memory/brain-writer-worker.js.map +1 -1
  103. package/dist/memory/decision-cross-link.d.ts +39 -0
  104. package/dist/memory/decision-cross-link.d.ts.map +1 -1
  105. package/dist/memory/decision-cross-link.js +316 -0
  106. package/dist/memory/decision-cross-link.js.map +1 -1
  107. package/dist/memory/decisions.d.ts +4 -1
  108. package/dist/memory/decisions.d.ts.map +1 -1
  109. package/dist/memory/decisions.js +7 -24
  110. package/dist/memory/decisions.js.map +1 -1
  111. package/dist/memory/dispatch-trace.d.ts +12 -5
  112. package/dist/memory/dispatch-trace.d.ts.map +1 -1
  113. package/dist/memory/dispatch-trace.js +17 -7
  114. package/dist/memory/dispatch-trace.js.map +1 -1
  115. package/dist/memory/eligibility.d.ts +51 -0
  116. package/dist/memory/eligibility.d.ts.map +1 -0
  117. package/dist/memory/eligibility.js +77 -0
  118. package/dist/memory/eligibility.js.map +1 -0
  119. package/dist/memory/engine-compat.d.ts +2 -0
  120. package/dist/memory/engine-compat.d.ts.map +1 -1
  121. package/dist/memory/engine-compat.js +10 -0
  122. package/dist/memory/engine-compat.js.map +1 -1
  123. package/dist/memory/extraction-gate.d.ts +21 -7
  124. package/dist/memory/extraction-gate.d.ts.map +1 -1
  125. package/dist/memory/extraction-gate.js +178 -216
  126. package/dist/memory/extraction-gate.js.map +1 -1
  127. package/dist/memory/graph-auto-populate.d.ts +38 -5
  128. package/dist/memory/graph-auto-populate.d.ts.map +1 -1
  129. package/dist/memory/graph-auto-populate.js +182 -60
  130. package/dist/memory/graph-auto-populate.js.map +1 -1
  131. package/dist/memory/graph-memory-bridge.d.ts +14 -1
  132. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  133. package/dist/memory/graph-memory-bridge.js +66 -28
  134. package/dist/memory/graph-memory-bridge.js.map +1 -1
  135. package/dist/memory/index.d.ts +1 -19
  136. package/dist/memory/index.d.ts.map +1 -1
  137. package/dist/memory/index.js +1 -50
  138. package/dist/memory/index.js.map +1 -1
  139. package/dist/memory/learnings.d.ts.map +1 -1
  140. package/dist/memory/learnings.js +2 -23
  141. package/dist/memory/learnings.js.map +1 -1
  142. package/dist/memory/manifest-filter.d.ts +21 -0
  143. package/dist/memory/manifest-filter.d.ts.map +1 -0
  144. package/dist/memory/manifest-filter.js +51 -0
  145. package/dist/memory/manifest-filter.js.map +1 -0
  146. package/dist/memory/manifest-ingestion.d.ts +28 -30
  147. package/dist/memory/manifest-ingestion.d.ts.map +1 -1
  148. package/dist/memory/manifest-ingestion.js +104 -235
  149. package/dist/memory/manifest-ingestion.js.map +1 -1
  150. package/dist/memory/observer-reflector.d.ts +2 -0
  151. package/dist/memory/observer-reflector.d.ts.map +1 -1
  152. package/dist/memory/observer-reflector.js +6 -49
  153. package/dist/memory/observer-reflector.js.map +1 -1
  154. package/dist/memory/patterns.d.ts +10 -0
  155. package/dist/memory/patterns.d.ts.map +1 -1
  156. package/dist/memory/patterns.js +25 -33
  157. package/dist/memory/patterns.js.map +1 -1
  158. package/dist/memory/pipeline-manifest-sqlite.d.ts +72 -9
  159. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  160. package/dist/memory/pipeline-manifest-sqlite.js +508 -412
  161. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  162. package/dist/memory/retrieval/build-retrieval-bundle.d.ts.map +1 -1
  163. package/dist/memory/retrieval/build-retrieval-bundle.js +16 -15
  164. package/dist/memory/retrieval/build-retrieval-bundle.js.map +1 -1
  165. package/dist/memory/retrieval/fetch.d.ts +7 -0
  166. package/dist/memory/retrieval/fetch.d.ts.map +1 -1
  167. package/dist/memory/retrieval/fetch.js +14 -11
  168. package/dist/memory/retrieval/fetch.js.map +1 -1
  169. package/dist/memory/retrieval/observe.d.ts +7 -1
  170. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  171. package/dist/memory/retrieval/observe.js +58 -4
  172. package/dist/memory/retrieval/observe.js.map +1 -1
  173. package/dist/memory/retrieval/search.d.ts +14 -1
  174. package/dist/memory/retrieval/search.d.ts.map +1 -1
  175. package/dist/memory/retrieval/search.js +133 -69
  176. package/dist/memory/retrieval/search.js.map +1 -1
  177. package/dist/memory/retrieval/telemetry.d.ts +31 -0
  178. package/dist/memory/retrieval/telemetry.d.ts.map +1 -0
  179. package/dist/memory/retrieval/telemetry.js +53 -0
  180. package/dist/memory/retrieval/telemetry.js.map +1 -0
  181. package/dist/nexus/analyze-orchestrator.d.ts +41 -9
  182. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  183. package/dist/nexus/analyze-orchestrator.js +257 -58
  184. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  185. package/dist/nexus/api-contracts.d.ts +2 -6
  186. package/dist/nexus/api-contracts.d.ts.map +1 -1
  187. package/dist/nexus/api-contracts.js +11 -2
  188. package/dist/nexus/api-contracts.js.map +1 -1
  189. package/dist/nexus/context.d.ts.map +1 -1
  190. package/dist/nexus/context.js +14 -37
  191. package/dist/nexus/context.js.map +1 -1
  192. package/dist/nexus/diff.d.ts.map +1 -1
  193. package/dist/nexus/diff.js +2 -1
  194. package/dist/nexus/diff.js.map +1 -1
  195. package/dist/nexus/identity.d.ts +29 -3
  196. package/dist/nexus/identity.d.ts.map +1 -1
  197. package/dist/nexus/identity.js +63 -12
  198. package/dist/nexus/identity.js.map +1 -1
  199. package/dist/nexus/impact.d.ts +21 -19
  200. package/dist/nexus/impact.d.ts.map +1 -1
  201. package/dist/nexus/impact.js +96 -192
  202. package/dist/nexus/impact.js.map +1 -1
  203. package/dist/nexus/knowledge.d.ts +80 -0
  204. package/dist/nexus/knowledge.d.ts.map +1 -0
  205. package/dist/nexus/knowledge.js +786 -0
  206. package/dist/nexus/knowledge.js.map +1 -0
  207. package/dist/nexus/living-brain.d.ts +8 -5
  208. package/dist/nexus/living-brain.d.ts.map +1 -1
  209. package/dist/nexus/living-brain.js +252 -188
  210. package/dist/nexus/living-brain.js.map +1 -1
  211. package/dist/nexus/registry.d.ts +11 -2
  212. package/dist/nexus/registry.d.ts.map +1 -1
  213. package/dist/nexus/registry.js +144 -128
  214. package/dist/nexus/registry.js.map +1 -1
  215. package/dist/nexus/source-roots.d.ts +16 -0
  216. package/dist/nexus/source-roots.d.ts.map +1 -0
  217. package/dist/nexus/source-roots.js +174 -0
  218. package/dist/nexus/source-roots.js.map +1 -0
  219. package/dist/nexus/task-evidence.d.ts +22 -0
  220. package/dist/nexus/task-evidence.d.ts.map +1 -0
  221. package/dist/nexus/task-evidence.js +210 -0
  222. package/dist/nexus/task-evidence.js.map +1 -0
  223. package/dist/nexus/tasks-bridge.d.ts +14 -7
  224. package/dist/nexus/tasks-bridge.d.ts.map +1 -1
  225. package/dist/nexus/tasks-bridge.js +81 -40
  226. package/dist/nexus/tasks-bridge.js.map +1 -1
  227. package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
  228. package/dist/orchestrate/lifecycle-ops.js +170 -120
  229. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  230. package/dist/orchestrate/query-ops.d.ts +6 -7
  231. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  232. package/dist/orchestrate/query-ops.js +509 -532
  233. package/dist/orchestrate/query-ops.js.map +1 -1
  234. package/dist/orchestration/bootstrap.d.ts +15 -1
  235. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  236. package/dist/orchestration/bootstrap.js +21 -10
  237. package/dist/orchestration/bootstrap.js.map +1 -1
  238. package/dist/orchestration/index.d.ts +35 -3
  239. package/dist/orchestration/index.d.ts.map +1 -1
  240. package/dist/orchestration/index.js +64 -35
  241. package/dist/orchestration/index.js.map +1 -1
  242. package/dist/orchestration/lead-rollup.d.ts +24 -1
  243. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  244. package/dist/orchestration/lead-rollup.js +31 -11
  245. package/dist/orchestration/lead-rollup.js.map +1 -1
  246. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  247. package/dist/orchestration/spawn-prompt.js +25 -45
  248. package/dist/orchestration/spawn-prompt.js.map +1 -1
  249. package/dist/orchestration/unblock.d.ts +15 -1
  250. package/dist/orchestration/unblock.d.ts.map +1 -1
  251. package/dist/orchestration/unblock.js +23 -12
  252. package/dist/orchestration/unblock.js.map +1 -1
  253. package/dist/orchestration/validate-spawn.d.ts.map +1 -1
  254. package/dist/orchestration/validate-spawn.js +3 -3
  255. package/dist/orchestration/validate-spawn.js.map +1 -1
  256. package/dist/orchestration/waves.d.ts +29 -13
  257. package/dist/orchestration/waves.d.ts.map +1 -1
  258. package/dist/orchestration/waves.js +43 -55
  259. package/dist/orchestration/waves.js.map +1 -1
  260. package/dist/paths.d.ts +17 -163
  261. package/dist/paths.d.ts.map +1 -1
  262. package/dist/paths.js +145 -496
  263. package/dist/paths.js.map +1 -1
  264. package/dist/project-info.d.ts +2 -11
  265. package/dist/project-info.d.ts.map +1 -1
  266. package/dist/project-info.js +3 -31
  267. package/dist/project-info.js.map +1 -1
  268. package/dist/project-scope.d.ts +239 -0
  269. package/dist/project-scope.d.ts.map +1 -0
  270. package/dist/project-scope.js +473 -0
  271. package/dist/project-scope.js.map +1 -0
  272. package/dist/release/pr-evidence.d.ts +23 -4
  273. package/dist/release/pr-evidence.d.ts.map +1 -1
  274. package/dist/release/pr-evidence.js +65 -9
  275. package/dist/release/pr-evidence.js.map +1 -1
  276. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  277. package/dist/render/nexus/graph/index.js +4 -2
  278. package/dist/render/nexus/graph/index.js.map +1 -1
  279. package/dist/render/orchestration/audit-reconstruct.d.ts +11 -0
  280. package/dist/render/orchestration/audit-reconstruct.d.ts.map +1 -1
  281. package/dist/render/orchestration/audit-reconstruct.js +21 -6
  282. package/dist/render/orchestration/audit-reconstruct.js.map +1 -1
  283. package/dist/render/tasks/show.js +2 -1
  284. package/dist/render/tasks/show.js.map +1 -1
  285. package/dist/resources/spawn-wrapper.d.ts +82 -14
  286. package/dist/resources/spawn-wrapper.d.ts.map +1 -1
  287. package/dist/resources/spawn-wrapper.js +585 -27
  288. package/dist/resources/spawn-wrapper.js.map +1 -1
  289. package/dist/selfimprove/fix-gen.js +4055 -1734
  290. package/dist/selfimprove/fix-gen.js.map +3 -3
  291. package/dist/sequence/index.d.ts.map +1 -1
  292. package/dist/sequence/index.js +76 -68
  293. package/dist/sequence/index.js.map +1 -1
  294. package/dist/session/canon-lint.d.ts +24 -3
  295. package/dist/session/canon-lint.d.ts.map +1 -1
  296. package/dist/session/canon-lint.js +72 -31
  297. package/dist/session/canon-lint.js.map +1 -1
  298. package/dist/session/engine-ops.d.ts +1 -4
  299. package/dist/session/engine-ops.d.ts.map +1 -1
  300. package/dist/session/engine-ops.js +42 -6
  301. package/dist/session/engine-ops.js.map +1 -1
  302. package/dist/sessions/briefing.d.ts +11 -1
  303. package/dist/sessions/briefing.d.ts.map +1 -1
  304. package/dist/sessions/briefing.js +76 -8
  305. package/dist/sessions/briefing.js.map +1 -1
  306. package/dist/sessions/handoff.d.ts +3 -1
  307. package/dist/sessions/handoff.d.ts.map +1 -1
  308. package/dist/sessions/handoff.js +2 -0
  309. package/dist/sessions/handoff.js.map +1 -1
  310. package/dist/shutdown-deadline.d.ts +24 -33
  311. package/dist/shutdown-deadline.d.ts.map +1 -1
  312. package/dist/shutdown-deadline.js +71 -14
  313. package/dist/shutdown-deadline.js.map +1 -1
  314. package/dist/shutdown.d.ts +21 -10
  315. package/dist/shutdown.d.ts.map +1 -1
  316. package/dist/shutdown.js +89 -42
  317. package/dist/shutdown.js.map +1 -1
  318. package/dist/skills/index.d.ts +1 -1
  319. package/dist/skills/index.d.ts.map +1 -1
  320. package/dist/skills/index.js +1 -1
  321. package/dist/skills/index.js.map +1 -1
  322. package/dist/skills/orchestrator/validator.d.ts +87 -20
  323. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  324. package/dist/skills/orchestrator/validator.js +330 -241
  325. package/dist/skills/orchestrator/validator.js.map +1 -1
  326. package/dist/store/agent-resolver.d.ts.map +1 -1
  327. package/dist/store/agent-resolver.js +16 -9
  328. package/dist/store/agent-resolver.js.map +1 -1
  329. package/dist/store/attachment-store.d.ts +4 -1
  330. package/dist/store/attachment-store.d.ts.map +1 -1
  331. package/dist/store/attachment-store.js +20 -3
  332. package/dist/store/attachment-store.js.map +1 -1
  333. package/dist/store/background-jobs.d.ts +426 -105
  334. package/dist/store/background-jobs.d.ts.map +1 -1
  335. package/dist/store/background-jobs.js +1208 -252
  336. package/dist/store/background-jobs.js.map +1 -1
  337. package/dist/store/background-ops.d.ts +145 -8
  338. package/dist/store/background-ops.d.ts.map +1 -1
  339. package/dist/store/background-ops.js +459 -15
  340. package/dist/store/background-ops.js.map +1 -1
  341. package/dist/store/backup-inspect.d.ts +48 -4
  342. package/dist/store/backup-inspect.d.ts.map +1 -1
  343. package/dist/store/backup-inspect.js +384 -4
  344. package/dist/store/backup-inspect.js.map +1 -1
  345. package/dist/store/converters.d.ts.map +1 -1
  346. package/dist/store/converters.js +19 -2
  347. package/dist/store/converters.js.map +1 -1
  348. package/dist/store/data-accessor.d.ts +9 -1
  349. package/dist/store/data-accessor.d.ts.map +1 -1
  350. package/dist/store/data-accessor.js +22 -5
  351. package/dist/store/data-accessor.js.map +1 -1
  352. package/dist/store/data-safety-central.d.ts.map +1 -1
  353. package/dist/store/data-safety-central.js +272 -232
  354. package/dist/store/data-safety-central.js.map +1 -1
  355. package/dist/store/db-helpers.d.ts +19 -3
  356. package/dist/store/db-helpers.d.ts.map +1 -1
  357. package/dist/store/db-helpers.js +42 -58
  358. package/dist/store/db-helpers.js.map +1 -1
  359. package/dist/store/dual-scope-db.d.ts +63 -4
  360. package/dist/store/dual-scope-db.d.ts.map +1 -1
  361. package/dist/store/dual-scope-db.js +166 -19
  362. package/dist/store/dual-scope-db.js.map +1 -1
  363. package/dist/store/exodus/archive.d.ts +21 -7
  364. package/dist/store/exodus/archive.d.ts.map +1 -1
  365. package/dist/store/exodus/archive.js +60 -18
  366. package/dist/store/exodus/archive.js.map +1 -1
  367. package/dist/store/exodus/migrate.d.ts.map +1 -1
  368. package/dist/store/exodus/migrate.js +27 -23
  369. package/dist/store/exodus/migrate.js.map +1 -1
  370. package/dist/store/exodus/on-open.d.ts +16 -27
  371. package/dist/store/exodus/on-open.d.ts.map +1 -1
  372. package/dist/store/exodus/on-open.js +121 -169
  373. package/dist/store/exodus/on-open.js.map +1 -1
  374. package/dist/store/exodus/recovery.d.ts +90 -0
  375. package/dist/store/exodus/recovery.d.ts.map +1 -0
  376. package/dist/store/exodus/recovery.js +434 -0
  377. package/dist/store/exodus/recovery.js.map +1 -0
  378. package/dist/store/exodus/types.d.ts +15 -0
  379. package/dist/store/exodus/types.d.ts.map +1 -1
  380. package/dist/store/memory-accessor.d.ts +52 -3
  381. package/dist/store/memory-accessor.d.ts.map +1 -1
  382. package/dist/store/memory-accessor.js +122 -7
  383. package/dist/store/memory-accessor.js.map +1 -1
  384. package/dist/store/nexus-sqlite.d.ts +24 -6
  385. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  386. package/dist/store/nexus-sqlite.js +39 -20
  387. package/dist/store/nexus-sqlite.js.map +1 -1
  388. package/dist/store/ports/domain-binding.d.ts.map +1 -1
  389. package/dist/store/ports/domain-binding.js +27 -5
  390. package/dist/store/ports/domain-binding.js.map +1 -1
  391. package/dist/store/schema/background-jobs.d.ts +181 -2
  392. package/dist/store/schema/background-jobs.d.ts.map +1 -1
  393. package/dist/store/schema/background-jobs.js +27 -3
  394. package/dist/store/schema/background-jobs.js.map +1 -1
  395. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  396. package/dist/store/schema/cleo-project/lifecycle.d.ts +2 -2
  397. package/dist/store/schema/cleo-project/runtime.d.ts +1 -1
  398. package/dist/store/schema/cleo-project/tasks-core.d.ts +1 -1
  399. package/dist/store/schema/lifecycle.d.ts +2 -2
  400. package/dist/store/schema/skills-schema.d.ts +2 -2
  401. package/dist/store/schema/tasks.d.ts +1 -1
  402. package/dist/store/session-store.d.ts +3 -1
  403. package/dist/store/session-store.d.ts.map +1 -1
  404. package/dist/store/session-store.js +252 -207
  405. package/dist/store/session-store.js.map +1 -1
  406. package/dist/store/sqlite-data-accessor.d.ts +39 -4
  407. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  408. package/dist/store/sqlite-data-accessor.js +689 -527
  409. package/dist/store/sqlite-data-accessor.js.map +1 -1
  410. package/dist/store/tasks-sqlite.d.ts +3 -1
  411. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  412. package/dist/store/tasks-sqlite.js +309 -279
  413. package/dist/store/tasks-sqlite.js.map +1 -1
  414. package/dist/store/validation-schemas.d.ts +8 -8
  415. package/dist/store/writer-lease.d.ts +80 -8
  416. package/dist/store/writer-lease.d.ts.map +1 -1
  417. package/dist/store/writer-lease.js +503 -134
  418. package/dist/store/writer-lease.js.map +1 -1
  419. package/dist/system/audit.d.ts +2 -1
  420. package/dist/system/audit.d.ts.map +1 -1
  421. package/dist/system/audit.js +118 -71
  422. package/dist/system/audit.js.map +1 -1
  423. package/dist/system/backup.d.ts.map +1 -1
  424. package/dist/system/backup.js +5 -5
  425. package/dist/system/backup.js.map +1 -1
  426. package/dist/system/inject-generate.js +1 -1
  427. package/dist/task-work/index.d.ts +3 -0
  428. package/dist/task-work/index.d.ts.map +1 -1
  429. package/dist/task-work/index.js +34 -37
  430. package/dist/task-work/index.js.map +1 -1
  431. package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
  432. package/dist/tasks/ac-coverage-gate.js +4 -0
  433. package/dist/tasks/ac-coverage-gate.js.map +1 -1
  434. package/dist/tasks/ac-immutability.d.ts +7 -4
  435. package/dist/tasks/ac-immutability.d.ts.map +1 -1
  436. package/dist/tasks/ac-immutability.js +19 -17
  437. package/dist/tasks/ac-immutability.js.map +1 -1
  438. package/dist/tasks/ac-table.d.ts +5 -5
  439. package/dist/tasks/ac-table.d.ts.map +1 -1
  440. package/dist/tasks/ac-table.js +26 -12
  441. package/dist/tasks/ac-table.js.map +1 -1
  442. package/dist/tasks/acceptance-input.d.ts +52 -0
  443. package/dist/tasks/acceptance-input.d.ts.map +1 -0
  444. package/dist/tasks/acceptance-input.js +259 -0
  445. package/dist/tasks/acceptance-input.js.map +1 -0
  446. package/dist/tasks/add.d.ts +67 -29
  447. package/dist/tasks/add.d.ts.map +1 -1
  448. package/dist/tasks/add.js +255 -97
  449. package/dist/tasks/add.js.map +1 -1
  450. package/dist/tasks/complete.d.ts +16 -1
  451. package/dist/tasks/complete.d.ts.map +1 -1
  452. package/dist/tasks/complete.js +152 -55
  453. package/dist/tasks/complete.js.map +1 -1
  454. package/dist/tasks/decompose.d.ts +103 -0
  455. package/dist/tasks/decompose.d.ts.map +1 -0
  456. package/dist/tasks/decompose.js +224 -0
  457. package/dist/tasks/decompose.js.map +1 -0
  458. package/dist/tasks/delete.d.ts +5 -8
  459. package/dist/tasks/delete.d.ts.map +1 -1
  460. package/dist/tasks/delete.js +4 -3
  461. package/dist/tasks/delete.js.map +1 -1
  462. package/dist/tasks/dependency-check.d.ts +59 -0
  463. package/dist/tasks/dependency-check.d.ts.map +1 -1
  464. package/dist/tasks/dependency-check.js +73 -0
  465. package/dist/tasks/dependency-check.js.map +1 -1
  466. package/dist/tasks/deps-ready.d.ts +13 -1
  467. package/dist/tasks/deps-ready.d.ts.map +1 -1
  468. package/dist/tasks/deps-ready.js +16 -5
  469. package/dist/tasks/deps-ready.js.map +1 -1
  470. package/dist/tasks/engine-converters.d.ts +7 -0
  471. package/dist/tasks/engine-converters.d.ts.map +1 -1
  472. package/dist/tasks/engine-converters.js +8 -1
  473. package/dist/tasks/engine-converters.js.map +1 -1
  474. package/dist/tasks/evidence.d.ts +88 -27
  475. package/dist/tasks/evidence.d.ts.map +1 -1
  476. package/dist/tasks/evidence.js +344 -43
  477. package/dist/tasks/evidence.js.map +1 -1
  478. package/dist/tasks/find.d.ts +16 -12
  479. package/dist/tasks/find.d.ts.map +1 -1
  480. package/dist/tasks/find.js +107 -93
  481. package/dist/tasks/find.js.map +1 -1
  482. package/dist/tasks/gate-preview.d.ts +73 -0
  483. package/dist/tasks/gate-preview.d.ts.map +1 -0
  484. package/dist/tasks/gate-preview.js +119 -0
  485. package/dist/tasks/gate-preview.js.map +1 -0
  486. package/dist/tasks/gate-runner.d.ts +88 -14
  487. package/dist/tasks/gate-runner.d.ts.map +1 -1
  488. package/dist/tasks/gate-runner.js +719 -250
  489. package/dist/tasks/gate-runner.js.map +1 -1
  490. package/dist/tasks/hierarchy-policy.d.ts +8 -0
  491. package/dist/tasks/hierarchy-policy.d.ts.map +1 -1
  492. package/dist/tasks/hierarchy-policy.js +9 -2
  493. package/dist/tasks/hierarchy-policy.js.map +1 -1
  494. package/dist/tasks/hierarchy.d.ts +67 -1
  495. package/dist/tasks/hierarchy.d.ts.map +1 -1
  496. package/dist/tasks/hierarchy.js +81 -1
  497. package/dist/tasks/hierarchy.js.map +1 -1
  498. package/dist/tasks/index.d.ts +3 -0
  499. package/dist/tasks/index.d.ts.map +1 -1
  500. package/dist/tasks/index.js +3 -0
  501. package/dist/tasks/index.js.map +1 -1
  502. package/dist/tasks/infer-add-params.d.ts +1 -20
  503. package/dist/tasks/infer-add-params.d.ts.map +1 -1
  504. package/dist/tasks/infer-add-params.js +2 -203
  505. package/dist/tasks/infer-add-params.js.map +1 -1
  506. package/dist/tasks/list.d.ts +7 -2
  507. package/dist/tasks/list.d.ts.map +1 -1
  508. package/dist/tasks/list.js +24 -36
  509. package/dist/tasks/list.js.map +1 -1
  510. package/dist/tasks/ops.d.ts +6 -61
  511. package/dist/tasks/ops.d.ts.map +1 -1
  512. package/dist/tasks/ops.js +5 -53
  513. package/dist/tasks/ops.js.map +1 -1
  514. package/dist/tasks/plan.d.ts +15 -1
  515. package/dist/tasks/plan.d.ts.map +1 -1
  516. package/dist/tasks/plan.js +23 -25
  517. package/dist/tasks/plan.js.map +1 -1
  518. package/dist/tasks/population.d.ts +46 -0
  519. package/dist/tasks/population.d.ts.map +1 -0
  520. package/dist/tasks/population.js +88 -0
  521. package/dist/tasks/population.js.map +1 -0
  522. package/dist/tasks/reconcile-scope.d.ts +157 -0
  523. package/dist/tasks/reconcile-scope.d.ts.map +1 -0
  524. package/dist/tasks/reconcile-scope.js +242 -0
  525. package/dist/tasks/reconcile-scope.js.map +1 -0
  526. package/dist/tasks/req.d.ts +51 -12
  527. package/dist/tasks/req.d.ts.map +1 -1
  528. package/dist/tasks/req.js +125 -69
  529. package/dist/tasks/req.js.map +1 -1
  530. package/dist/tasks/session-scope.d.ts +6 -31
  531. package/dist/tasks/session-scope.d.ts.map +1 -1
  532. package/dist/tasks/session-scope.js +3 -17
  533. package/dist/tasks/session-scope.js.map +1 -1
  534. package/dist/tasks/severity-attestation.d.ts +39 -10
  535. package/dist/tasks/severity-attestation.d.ts.map +1 -1
  536. package/dist/tasks/severity-attestation.js +75 -36
  537. package/dist/tasks/severity-attestation.js.map +1 -1
  538. package/dist/tasks/task-next.d.ts +5 -0
  539. package/dist/tasks/task-next.d.ts.map +1 -1
  540. package/dist/tasks/task-next.js +10 -9
  541. package/dist/tasks/task-next.js.map +1 -1
  542. package/dist/tasks/task-reparent.d.ts.map +1 -1
  543. package/dist/tasks/task-reparent.js +3 -13
  544. package/dist/tasks/task-reparent.js.map +1 -1
  545. package/dist/tasks/update.d.ts +20 -43
  546. package/dist/tasks/update.d.ts.map +1 -1
  547. package/dist/tasks/update.js +64 -49
  548. package/dist/tasks/update.js.map +1 -1
  549. package/dist/validation/engine-ops.d.ts +17 -1
  550. package/dist/validation/engine-ops.d.ts.map +1 -1
  551. package/dist/validation/engine-ops.js +149 -11
  552. package/dist/validation/engine-ops.js.map +1 -1
  553. package/dist/workgraph/reparent-preflight.d.ts +1 -1
  554. package/dist/workgraph/reparent-preflight.d.ts.map +1 -1
  555. package/dist/workgraph/reparent-preflight.js +6 -1
  556. package/dist/workgraph/reparent-preflight.js.map +1 -1
  557. package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
  558. package/dist/workgraph/scaffold-apply.js +81 -76
  559. package/dist/workgraph/scaffold-apply.js.map +1 -1
  560. package/dist/workgraph/structure-validation.d.ts +1 -1
  561. package/dist/workgraph/structure-validation.d.ts.map +1 -1
  562. package/dist/workgraph/structure-validation.js +6 -1
  563. package/dist/workgraph/structure-validation.js.map +1 -1
  564. package/migrations/drizzle-tasks/20260919180000_t12263-job-ownership-fences/migration.sql +34 -0
  565. package/migrations/drizzle-tasks/20260919184500_t12265-durable-pending-proposals/migration.sql +4 -0
  566. package/package.json +18 -13
  567. package/schemas/config.schema.json +2 -2
  568. package/schemas/project-context.schema.json +12 -0
  569. package/templates/CLEO-INJECTION.md +114 -101
@@ -2,7 +2,7 @@
2
2
  * Pipeline Manifest SQLite Implementation
3
3
  *
4
4
  * Reimplements all 14 pipeline manifest operations using Drizzle ORM +
5
- * SQLite (tasks.db pipeline_manifest table) instead of JSONL file I/O.
5
+ * Canonical docs_pipeline_manifest writes and provenance-aware legacy history reads.
6
6
  *
7
7
  * Provides a one-time migration function to import existing MANIFEST.jsonl
8
8
  * entries into the new table.
@@ -13,29 +13,25 @@
13
13
  import { createHash } from 'node:crypto';
14
14
  import { existsSync, readFileSync, renameSync } from 'node:fs';
15
15
  import { join } from 'node:path';
16
- import { and, count, desc, eq, gte, isNull, like, lte, or } from 'drizzle-orm';
17
- import { pipelineManifest } from '../store/tasks-schema.js';
18
- async function getDb(cwd) {
19
- const { getDb: _getDb } = await import('../store/sqlite.js');
20
- return _getDb(cwd);
16
+ import { isDeepStrictEqual } from 'node:util';
17
+ import { eq, like, or } from 'drizzle-orm';
18
+ import { z } from 'zod';
19
+ import { createDocsReadModel } from '../docs/docs-read-model.js';
20
+ import { EngineResultError } from '../engine-result.js';
21
+ import { captureProjectScope, worktreeScope } from '../project-scope.js';
22
+ import { docsPipelineManifest as pipelineManifest } from '../store/schema/cleo-project/docs.js';
23
+ import { pipelineManifest as legacyManifest } from '../store/schema/manifest.js';
24
+ function manifestScope(cwd) {
25
+ return captureProjectScope(cwd ?? getProjectRoot(), worktreeScope.getStore());
21
26
  }
22
- /**
23
- * Resolve the project's native `DatabaseSync` handle.
24
- *
25
- * T12037: `getNativeDb` is path-keyed, so the caller's `cwd` MUST be forwarded.
26
- * The bare call used to return whichever project was opened LAST in the
27
- * process — under test isolation (or any multi-project run) that silently
28
- * pointed manifest archiving at the wrong database.
29
- *
30
- * @param cwd - Project working directory.
31
- */
32
- async function getNativeDb(cwd) {
33
- const { getNativeDb: _getNativeDb } = await import('../store/sqlite.js');
34
- return _getNativeDb(cwd);
27
+ async function getBinding(cwd) {
28
+ const scope = manifestScope(cwd);
29
+ const { bindTasksDomain } = await import('../store/sqlite.js');
30
+ return worktreeScope.run(scope, () => bindTasksDomain(scope.worktreeRoot));
35
31
  }
36
32
  import { createPage } from '../pagination.js';
37
33
  import { getProjectRoot, resolveCleoDir } from '../paths.js';
38
- import { filterManifestEntries, } from './index.js';
34
+ import { filterManifestEntries } from './manifest-filter.js';
39
35
  export { filterManifestEntries };
40
36
  function normalizeLimit(limit) {
41
37
  return typeof limit === 'number' && limit > 0 ? limit : undefined;
@@ -46,37 +42,155 @@ function normalizeOffset(offset) {
46
42
  function effectivePageLimit(limit, offset) {
47
43
  return limit ?? (offset !== undefined ? 50 : undefined);
48
44
  }
49
- function buildManifestSqlFilters(filter) {
50
- const conditions = [isNull(pipelineManifest.archivedAt)];
51
- if (filter.status) {
52
- const storedStatus = filter.status === 'completed' ? 'active' : filter.status;
53
- conditions.push(eq(pipelineManifest.status, storedStatus));
45
+ // ============================================================================
46
+ // Internal helpers
47
+ // ============================================================================
48
+ function readStoredRows(binding, includeArchived = false, id) {
49
+ const { db, store } = binding;
50
+ const modern = db
51
+ .select()
52
+ .from(pipelineManifest)
53
+ .where(id ? eq(pipelineManifest.id, id) : undefined)
54
+ .all();
55
+ const legacy = db
56
+ .select()
57
+ .from(legacyManifest)
58
+ .where(id ? eq(legacyManifest.id, id) : undefined)
59
+ .all();
60
+ const rows = new Map();
61
+ for (const [table, sourceRows] of [
62
+ [pipelineManifest, modern],
63
+ [legacyManifest, legacy],
64
+ ]) {
65
+ const tableName = table === pipelineManifest ? 'docs_pipeline_manifest' : 'pipeline_manifest';
66
+ for (const row of sourceRows) {
67
+ const existing = rows.get(row.id);
68
+ if (existing) {
69
+ const { provenance, ...stored } = existing;
70
+ // Compare every persisted scalar, including raw content/metadata bytes and archival state.
71
+ // A short content hash or the lossy public projection cannot establish equality.
72
+ if (!isDeepStrictEqual(stored, row)) {
73
+ throw new EngineResultError({
74
+ code: 'E_MANIFEST_ID_CONFLICT',
75
+ message: `Manifest '${row.id}' has conflicting stored payloads; inspect both sources before repair.`,
76
+ details: {
77
+ entryId: row.id,
78
+ databasePath: store.dbPath,
79
+ candidates: [
80
+ {
81
+ table: provenance.tables[0],
82
+ payload: stored,
83
+ sha256: createHash('sha256').update(JSON.stringify(stored)).digest('hex'),
84
+ },
85
+ {
86
+ table: tableName,
87
+ payload: row,
88
+ sha256: createHash('sha256').update(JSON.stringify(row)).digest('hex'),
89
+ },
90
+ ],
91
+ },
92
+ });
93
+ }
94
+ provenance.tables.push(tableName);
95
+ }
96
+ else {
97
+ rows.set(row.id, {
98
+ ...row,
99
+ provenance: { databasePath: store.dbPath, tables: [tableName] },
100
+ });
101
+ }
102
+ }
54
103
  }
55
- if (filter.agent_type) {
56
- conditions.push(eq(pipelineManifest.type, filter.agent_type));
104
+ return [...rows.values()]
105
+ .filter((row) => includeArchived || row.archivedAt === null)
106
+ .sort((a, b) => b.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b.id));
107
+ }
108
+ async function readRows(projectRoot, includeArchived = false, id) {
109
+ const binding = await getBinding(projectRoot);
110
+ return binding.db.transaction(() => readStoredRows(binding, includeArchived, id));
111
+ }
112
+ function requireModernRows(rows) {
113
+ const legacy = rows.filter((row) => row.provenance.tables.includes('pipeline_manifest'));
114
+ if (legacy.length) {
115
+ throw new EngineResultError({
116
+ code: 'E_MANIFEST_LEGACY_REPAIR_REQUIRED',
117
+ message: 'Legacy manifest evidence requires an explicit guarded repair before mutation.',
118
+ details: { entries: legacy.map((row) => ({ entryId: row.id, provenance: row.provenance })) },
119
+ });
57
120
  }
58
- if (filter.dateAfter) {
59
- conditions.push(gte(pipelineManifest.createdAt, `${filter.dateAfter} 00:00:00`));
121
+ }
122
+ function manifestFailure(code, error) {
123
+ if (error instanceof EngineResultError) {
124
+ return {
125
+ success: false,
126
+ error: { code: error.code, message: error.message, details: error.details },
127
+ };
60
128
  }
61
- if (filter.dateBefore) {
62
- conditions.push(lte(pipelineManifest.createdAt, `${filter.dateBefore} 23:59:59`));
129
+ const causes = [];
130
+ const seen = new Set();
131
+ let cause = error;
132
+ while (!seen.has(cause)) {
133
+ seen.add(cause);
134
+ causes.push(cause.message);
135
+ if (!(cause.cause instanceof Error))
136
+ break;
137
+ cause = cause.cause;
63
138
  }
64
- return {
65
- conditions,
66
- requiresInMemoryFiltering: filter.taskId !== undefined || filter.topic !== undefined || filter.actionable !== undefined,
67
- };
139
+ return { success: false, error: { code, message: causes.join(' → ') } };
68
140
  }
69
- function applyManifestMemoryOnlyFilters(entries, filter) {
70
- const inMemoryFilter = {
71
- taskId: filter.taskId,
72
- topic: filter.topic,
73
- actionable: filter.actionable,
74
- };
75
- return filterManifestEntries(entries, inMemoryFilter);
141
+ /**
142
+ * Insert authentic prepared manifest rows in one guarded project transaction.
143
+ *
144
+ * @remarks
145
+ * Preserves caller handle ownership and both storage histories. Identical complete
146
+ * payloads are idempotent; differing identities and legacy rows never authorize
147
+ * replacement. Any batch failure rolls back all inserted rows.
148
+ * @param rows - Complete persisted payloads, including raw content and metadata.
149
+ * @param projectRoot - Explicit project identity captured before asynchronous binding.
150
+ * @param expectedDb - Caller-owned canonical task-domain handle for this project.
151
+ * @returns Number of newly inserted rows; identical stored rows are skipped.
152
+ * @throws If database identity, historical evidence, or any transactional write fails.
153
+ * @example
154
+ * ```ts
155
+ * const inserted = await insertManifestRows(preparedRows, projectRoot, db);
156
+ * ```
157
+ */
158
+ export async function insertManifestRows(rows, projectRoot, expectedDb) {
159
+ try {
160
+ const binding = await getBinding(projectRoot);
161
+ if (expectedDb !== binding.db) {
162
+ throw new EngineResultError({
163
+ code: 'E_MANIFEST_DATABASE_MISMATCH',
164
+ message: 'Supplied database is not the captured canonical project binding; ownership is unverified.',
165
+ details: { databasePath: binding.store.dbPath },
166
+ });
167
+ }
168
+ return binding.db.transaction(() => {
169
+ let inserted = 0;
170
+ for (const row of rows) {
171
+ const existing = readStoredRows(binding, true, row.id);
172
+ requireModernRows(existing);
173
+ if (existing[0]) {
174
+ const { provenance, ...stored } = existing[0];
175
+ if (!isDeepStrictEqual(stored, row)) {
176
+ throw new EngineResultError({
177
+ code: 'E_MANIFEST_ID_CONFLICT',
178
+ message: `Manifest '${row.id}' differs from the supplied payload; explicit repair is required.`,
179
+ details: { entryId: row.id, provenance, stored, incoming: row },
180
+ });
181
+ }
182
+ continue;
183
+ }
184
+ binding.db.insert(pipelineManifest).values(row).run();
185
+ inserted++;
186
+ }
187
+ return inserted;
188
+ }, { behavior: 'immediate' });
189
+ }
190
+ catch (error) {
191
+ throw new EngineResultError(manifestFailure('E_MANIFEST_INGEST', error instanceof Error ? error : new Error(String(error))).error);
192
+ }
76
193
  }
77
- // ============================================================================
78
- // Internal helpers
79
- // ============================================================================
80
194
  function now() {
81
195
  return new Date().toISOString().replace('T', ' ').slice(0, 19);
82
196
  }
@@ -86,35 +200,72 @@ function computeContentHash(content) {
86
200
  .digest('hex')
87
201
  .slice(0, 16);
88
202
  }
203
+ /** Validate only fields projected by the canonical reader; retain other provenance. */
204
+ const manifestMetadataSchema = z.looseObject({
205
+ file: z.string().optional(),
206
+ title: z.string().optional(),
207
+ topics: z.array(z.string()).optional(),
208
+ key_findings: z.array(z.string()).optional(),
209
+ actionable: z.boolean().optional(),
210
+ needs_followup: z.array(z.string()).optional(),
211
+ linked_tasks: z.array(z.string()).optional(),
212
+ confidence: z.number().optional(),
213
+ file_checksum: z.string().optional(),
214
+ duration_seconds: z.number().optional(),
215
+ });
216
+ function readRowMetadata(row) {
217
+ const details = {
218
+ entryId: row.id,
219
+ tables: row.provenance.tables,
220
+ metadataSha256: createHash('sha256')
221
+ .update(row.metadataJson ?? '')
222
+ .digest('hex'),
223
+ };
224
+ let parsed;
225
+ try {
226
+ parsed = manifestMetadataSchema.safeParse(row.metadataJson === null ? {} : JSON.parse(row.metadataJson));
227
+ }
228
+ catch (error) {
229
+ throw new EngineResultError({
230
+ code: 'E_MANIFEST_METADATA_INVALID',
231
+ message: `Manifest '${row.id}' metadata is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
232
+ details: { ...details, field: 'metadata_json' },
233
+ });
234
+ }
235
+ if (!parsed.success) {
236
+ const issues = parsed.error.issues.map((issue) => ({
237
+ field: issue.path.join('.') || 'metadata_json',
238
+ message: issue.message,
239
+ }));
240
+ throw new EngineResultError({
241
+ code: 'E_MANIFEST_METADATA_INVALID',
242
+ message: `Manifest '${row.id}' metadata violates the stored field contract`,
243
+ details: { ...details, field: issues[0]?.field ?? 'metadata_json', issues },
244
+ });
245
+ }
246
+ return parsed.data;
247
+ }
89
248
  /**
90
- * Convert a pipeline_manifest row back to ExtendedManifestEntry format
91
- * for backward-compatible output.
249
+ * Convert a validated canonical or historical row without rewriting stored bytes.
92
250
  */
93
251
  function rowToEntry(row) {
94
- let meta = {};
95
- if (row.metadataJson) {
96
- try {
97
- meta = JSON.parse(row.metadataJson);
98
- }
99
- catch {
100
- // ignore malformed JSON
101
- }
102
- }
252
+ const meta = readRowMetadata(row);
103
253
  return {
104
254
  id: row.id,
105
- file: meta['file'] ?? row.sourceFile ?? '',
106
- title: meta['title'] ?? row.type,
255
+ provenance: row.provenance,
256
+ file: meta.file ?? row.sourceFile ?? '',
257
+ title: meta.title ?? row.type,
107
258
  date: row.createdAt.slice(0, 10),
108
259
  status: (row.status === 'active' ? 'completed' : row.status),
109
260
  agent_type: row.type,
110
- topics: meta['topics'] ?? [],
111
- key_findings: meta['key_findings'] ?? [],
112
- actionable: meta['actionable'] ?? true,
113
- needs_followup: meta['needs_followup'] ?? [],
114
- linked_tasks: meta['linked_tasks'] ?? (row.taskId ? [row.taskId] : []),
115
- confidence: meta['confidence'],
116
- file_checksum: meta['file_checksum'],
117
- duration_seconds: meta['duration_seconds'],
261
+ topics: meta.topics ?? [],
262
+ key_findings: meta.key_findings ?? [],
263
+ actionable: meta.actionable ?? true,
264
+ needs_followup: meta.needs_followup ?? [],
265
+ linked_tasks: meta.linked_tasks ?? (row.taskId ? [row.taskId] : []),
266
+ confidence: meta.confidence,
267
+ file_checksum: meta.file_checksum,
268
+ duration_seconds: meta.duration_seconds,
118
269
  };
119
270
  }
120
271
  /**
@@ -159,7 +310,22 @@ function entryToRow(entry) {
159
310
  // ============================================================================
160
311
  // EngineResult-wrapped functions
161
312
  // ============================================================================
162
- /** pipeline.manifest.show - Get manifest entry details by ID */
313
+ /**
314
+ * Retrieve a manifest and resolve its local file or canonical document reference.
315
+ *
316
+ * @remarks
317
+ * Supports `cleo://docs/<reference>` where the single percent-encoded segment is
318
+ * a document slug, attachment ID, or SHA-256 accepted by the canonical docs read
319
+ * model. URI syntax establishes no authority. Unsupported URIs and failed reads
320
+ * are explicit failures; missing ordinary files retain `fileExists: false`.
321
+ * @param researchId - Exact manifest identity, including historical entries.
322
+ * @param projectRoot - Explicit project directory used for both manifest and docs.
323
+ * @returns Manifest provenance and content, or a structured resolution failure.
324
+ * @example
325
+ * ```ts
326
+ * const result = await pipelineManifestShow('T001-report', '/project');
327
+ * ```
328
+ */
163
329
  export async function pipelineManifestShow(researchId, projectRoot) {
164
330
  if (!researchId) {
165
331
  return {
@@ -168,12 +334,8 @@ export async function pipelineManifestShow(researchId, projectRoot) {
168
334
  };
169
335
  }
170
336
  try {
171
- const db = await getDb(projectRoot);
172
- const rows = await db
173
- .select()
174
- .from(pipelineManifest)
175
- .where(eq(pipelineManifest.id, researchId))
176
- .limit(1);
337
+ const scope = manifestScope(projectRoot);
338
+ const rows = await readRows(scope.worktreeRoot, true, researchId);
177
339
  if (rows.length === 0) {
178
340
  return {
179
341
  success: false,
@@ -181,16 +343,67 @@ export async function pipelineManifestShow(researchId, projectRoot) {
181
343
  };
182
344
  }
183
345
  const entry = rowToEntry(rows[0]);
184
- const root = getProjectRoot(projectRoot);
185
346
  let fileContent = null;
186
- try {
187
- const filePath = join(root, entry.file);
188
- if (existsSync(filePath)) {
189
- fileContent = readFileSync(filePath, 'utf-8');
347
+ if (/^[a-z][a-z\d+.-]*:/i.test(entry.file) && !/^[a-z]:[\\/]/i.test(entry.file)) {
348
+ const details = { entryId: researchId, reference: entry.file };
349
+ if (!entry.file.startsWith('cleo://docs/')) {
350
+ throw new EngineResultError({
351
+ code: 'E_MANIFEST_REFERENCE_UNSUPPORTED',
352
+ message: 'Only cleo://docs/<reference> document URIs are supported; no network lookup was attempted.',
353
+ details,
354
+ });
190
355
  }
356
+ const encoded = entry.file.slice('cleo://docs/'.length);
357
+ let reference;
358
+ try {
359
+ reference = decodeURIComponent(encoded);
360
+ }
361
+ catch {
362
+ throw new EngineResultError({
363
+ code: 'E_MANIFEST_REFERENCE_INVALID',
364
+ message: 'Document reference contains invalid percent encoding.',
365
+ details,
366
+ });
367
+ }
368
+ if (!reference ||
369
+ reference === '.' ||
370
+ reference === '..' ||
371
+ /[/\\?#\s\x00-\x1f]/.test(reference)) {
372
+ throw new EngineResultError({
373
+ code: 'E_MANIFEST_REFERENCE_INVALID',
374
+ message: 'Document URI requires one nonempty reference without path, query, or fragment components.',
375
+ details,
376
+ });
377
+ }
378
+ fileContent = await worktreeScope.run(scope, async () => {
379
+ const model = createDocsReadModel(scope.worktreeRoot);
380
+ const doc = (await model.resolveLatest(reference)) ?? (await model.resolveByAttachmentId(reference));
381
+ if (!doc) {
382
+ throw new EngineResultError({
383
+ code: 'E_MANIFEST_DOC_NOT_FOUND',
384
+ message: 'Document reference was not found in the selected project.',
385
+ details,
386
+ });
387
+ }
388
+ const content = await model.fetchContent(doc);
389
+ if (content === null) {
390
+ throw new EngineResultError({
391
+ code: 'E_MANIFEST_DOC_CONTENT_UNAVAILABLE',
392
+ message: 'Document metadata resolved but its content is unavailable.',
393
+ details: { ...details, attachmentId: doc.id, sha256: doc.sha256 },
394
+ });
395
+ }
396
+ return content;
397
+ });
191
398
  }
192
- catch {
193
- // File may not exist or be unreadable
399
+ else if (entry.file) {
400
+ try {
401
+ fileContent = readFileSync(join(scope.worktreeRoot, entry.file), 'utf-8');
402
+ }
403
+ catch (error) {
404
+ if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT'))
405
+ throw error;
406
+ }
194
407
  }
195
408
  return {
196
409
  success: true,
@@ -198,84 +411,35 @@ export async function pipelineManifestShow(researchId, projectRoot) {
198
411
  };
199
412
  }
200
413
  catch (error) {
201
- return {
202
- success: false,
203
- error: {
204
- code: 'E_MANIFEST_SHOW',
205
- message: error instanceof Error ? error.message : String(error),
206
- },
207
- };
414
+ return manifestFailure('E_MANIFEST_SHOW', error instanceof Error ? error : new Error(String(error)));
208
415
  }
209
416
  }
210
417
  /** pipeline.manifest.list - List manifest entries with filters */
211
418
  export async function pipelineManifestList(params, projectRoot) {
212
419
  try {
213
- const db = await getDb(projectRoot);
214
- const filter = { ...params };
215
- if (params.type) {
216
- filter.agent_type = params.type;
217
- }
420
+ const entries = (await readRows(projectRoot)).map(rowToEntry);
218
421
  const limit = normalizeLimit(params.limit);
219
422
  const offset = normalizeOffset(params.offset);
220
423
  const pageLimit = effectivePageLimit(limit, offset);
221
- const { conditions, requiresInMemoryFiltering } = buildManifestSqlFilters(filter);
222
- const whereClause = and(...conditions);
223
- const totalRow = await db
224
- .select({ count: count() })
225
- .from(pipelineManifest)
226
- .where(isNull(pipelineManifest.archivedAt))
227
- .get();
228
- const total = totalRow?.count ?? 0;
229
- if (!requiresInMemoryFiltering) {
230
- const filteredRow = await db
231
- .select({ count: count() })
232
- .from(pipelineManifest)
233
- .where(whereClause)
234
- .get();
235
- const filtered = filteredRow?.count ?? 0;
236
- let query = db
237
- .select()
238
- .from(pipelineManifest)
239
- .where(whereClause)
240
- .orderBy(desc(pipelineManifest.createdAt));
241
- if (pageLimit !== undefined) {
242
- query = query.limit(pageLimit);
243
- }
244
- if (offset !== undefined) {
245
- query = query.offset(offset);
246
- }
247
- const rows = await query;
248
- return {
249
- success: true,
250
- data: { entries: rows.map(rowToEntry), total, filtered },
251
- page: createPage({ total: filtered, limit: pageLimit, offset }),
252
- };
253
- }
254
- const rows = await db
255
- .select()
256
- .from(pipelineManifest)
257
- .where(whereClause)
258
- .orderBy(desc(pipelineManifest.createdAt));
259
- const filteredEntries = applyManifestMemoryOnlyFilters(rows.map(rowToEntry), filter);
260
- const filtered = filteredEntries.length;
424
+ const filtered = filterManifestEntries(entries, {
425
+ ...params,
426
+ agent_type: params.type ?? params.agent_type,
427
+ limit: undefined,
428
+ offset: undefined,
429
+ });
261
430
  const start = offset ?? 0;
262
- const pagedEntries = pageLimit !== undefined
263
- ? filteredEntries.slice(start, start + pageLimit)
264
- : filteredEntries.slice(start);
265
431
  return {
266
432
  success: true,
267
- data: { entries: pagedEntries, total, filtered },
268
- page: createPage({ total: filtered, limit: pageLimit, offset }),
433
+ data: {
434
+ entries: filtered.slice(start, pageLimit === undefined ? undefined : start + pageLimit),
435
+ total: entries.length,
436
+ filtered: filtered.length,
437
+ },
438
+ page: createPage({ total: filtered.length, limit: pageLimit, offset }),
269
439
  };
270
440
  }
271
441
  catch (error) {
272
- return {
273
- success: false,
274
- error: {
275
- code: 'E_MANIFEST_LIST',
276
- message: error instanceof Error ? error.message : String(error),
277
- },
278
- };
442
+ return manifestFailure('E_MANIFEST_LIST', error instanceof Error ? error : new Error(String(error)));
279
443
  }
280
444
  }
281
445
  /** pipeline.manifest.find - Find manifest entries by text (LIKE search on content + type) */
@@ -284,13 +448,23 @@ export async function pipelineManifestFind(query, options, projectRoot) {
284
448
  return { success: false, error: { code: 'E_INVALID_INPUT', message: 'query is required' } };
285
449
  }
286
450
  try {
287
- const db = await getDb(projectRoot);
288
- const likePattern = `%${query}%`;
289
- const rows = await db
290
- .select()
291
- .from(pipelineManifest)
292
- .where(and(isNull(pipelineManifest.archivedAt), or(like(pipelineManifest.content, likePattern), like(pipelineManifest.type, likePattern))))
293
- .orderBy(desc(pipelineManifest.createdAt));
451
+ const binding = await getBinding(projectRoot);
452
+ const rows = binding.db.transaction(() => {
453
+ const merged = readStoredRows(binding);
454
+ const ids = new Set([
455
+ ...binding.db
456
+ .select({ id: pipelineManifest.id })
457
+ .from(pipelineManifest)
458
+ .where(or(like(pipelineManifest.content, `%${query}%`), like(pipelineManifest.type, `%${query}%`)))
459
+ .all(),
460
+ ...binding.db
461
+ .select({ id: legacyManifest.id })
462
+ .from(legacyManifest)
463
+ .where(or(like(legacyManifest.content, `%${query}%`), like(legacyManifest.type, `%${query}%`)))
464
+ .all(),
465
+ ].map((row) => row.id));
466
+ return merged.filter((row) => ids.has(row.id));
467
+ });
294
468
  const queryLower = query.toLowerCase();
295
469
  const entries = rows.map(rowToEntry);
296
470
  const scored = entries.map((entry) => {
@@ -323,24 +497,13 @@ export async function pipelineManifestFind(query, options, projectRoot) {
323
497
  };
324
498
  }
325
499
  catch (error) {
326
- return {
327
- success: false,
328
- error: {
329
- code: 'E_MANIFEST_FIND',
330
- message: error instanceof Error ? error.message : String(error),
331
- },
332
- };
500
+ return manifestFailure('E_MANIFEST_FIND', error instanceof Error ? error : new Error(String(error)));
333
501
  }
334
502
  }
335
503
  /** pipeline.manifest.pending - Get pending manifest items */
336
504
  export async function pipelineManifestPending(epicId, projectRoot) {
337
505
  try {
338
- const db = await getDb(projectRoot);
339
- const rows = await db
340
- .select()
341
- .from(pipelineManifest)
342
- .where(isNull(pipelineManifest.archivedAt))
343
- .orderBy(desc(pipelineManifest.createdAt));
506
+ const rows = await readRows(projectRoot);
344
507
  const entries = rows.map(rowToEntry);
345
508
  let pending = entries.filter((e) => e.status === 'partial' ||
346
509
  e.status === 'blocked' ||
@@ -363,23 +526,13 @@ export async function pipelineManifestPending(epicId, projectRoot) {
363
526
  };
364
527
  }
365
528
  catch (error) {
366
- return {
367
- success: false,
368
- error: {
369
- code: 'E_MANIFEST_PENDING',
370
- message: error instanceof Error ? error.message : String(error),
371
- },
372
- };
529
+ return manifestFailure('E_MANIFEST_PENDING', error instanceof Error ? error : new Error(String(error)));
373
530
  }
374
531
  }
375
532
  /** pipeline.manifest.stats - Manifest statistics */
376
533
  export async function pipelineManifestStats(epicId, projectRoot) {
377
534
  try {
378
- const db = await getDb(projectRoot);
379
- const rows = await db
380
- .select()
381
- .from(pipelineManifest)
382
- .where(isNull(pipelineManifest.archivedAt));
535
+ const rows = await readRows(projectRoot);
383
536
  const entries = rows.map(rowToEntry);
384
537
  let filtered = entries;
385
538
  if (epicId) {
@@ -413,24 +566,13 @@ export async function pipelineManifestStats(epicId, projectRoot) {
413
566
  };
414
567
  }
415
568
  catch (error) {
416
- return {
417
- success: false,
418
- error: {
419
- code: 'E_MANIFEST_STATS',
420
- message: error instanceof Error ? error.message : String(error),
421
- },
422
- };
569
+ return manifestFailure('E_MANIFEST_STATS', error instanceof Error ? error : new Error(String(error)));
423
570
  }
424
571
  }
425
572
  /** pipeline.manifest.read - Read manifest entries with optional filter */
426
573
  export async function pipelineManifestRead(filter, projectRoot) {
427
574
  try {
428
- const db = await getDb(projectRoot);
429
- const rows = await db
430
- .select()
431
- .from(pipelineManifest)
432
- .where(isNull(pipelineManifest.archivedAt))
433
- .orderBy(desc(pipelineManifest.createdAt));
575
+ const rows = await readRows(projectRoot);
434
576
  const entries = rows.map(rowToEntry);
435
577
  const filtered = filter ? filterManifestEntries(entries, filter) : entries;
436
578
  return {
@@ -439,16 +581,10 @@ export async function pipelineManifestRead(filter, projectRoot) {
439
581
  };
440
582
  }
441
583
  catch (error) {
442
- return {
443
- success: false,
444
- error: {
445
- code: 'E_MANIFEST_READ',
446
- message: error instanceof Error ? error.message : String(error),
447
- },
448
- };
584
+ return manifestFailure('E_MANIFEST_READ', error instanceof Error ? error : new Error(String(error)));
449
585
  }
450
586
  }
451
- /** pipeline.manifest.append - Append entry to pipeline_manifest table */
587
+ /** Append to canonical manifest storage after checking both histories for unresolved identities. */
452
588
  export async function pipelineManifestAppend(entry, projectRoot) {
453
589
  if (!entry) {
454
590
  return { success: false, error: { code: 'E_INVALID_INPUT', message: 'entry is required' } };
@@ -480,32 +616,30 @@ export async function pipelineManifestAppend(entry, projectRoot) {
480
616
  };
481
617
  }
482
618
  try {
483
- const db = await getDb(projectRoot);
619
+ const binding = await getBinding(projectRoot);
484
620
  const row = entryToRow(entry);
485
- await db
486
- .insert(pipelineManifest)
487
- .values(row)
488
- .onConflictDoUpdate({
489
- target: pipelineManifest.id,
490
- set: {
491
- content: row.content,
492
- contentHash: row.contentHash,
493
- status: row.status,
494
- metadataJson: row.metadataJson,
495
- sourceFile: row.sourceFile,
496
- taskId: row.taskId,
497
- },
498
- });
621
+ binding.db.transaction(() => {
622
+ requireModernRows(readStoredRows(binding, true, entry.id));
623
+ binding.db
624
+ .insert(pipelineManifest)
625
+ .values(row)
626
+ .onConflictDoUpdate({
627
+ target: pipelineManifest.id,
628
+ set: {
629
+ content: row.content,
630
+ contentHash: row.contentHash,
631
+ status: row.status,
632
+ metadataJson: row.metadataJson,
633
+ sourceFile: row.sourceFile,
634
+ taskId: row.taskId,
635
+ },
636
+ })
637
+ .run();
638
+ }, { behavior: 'immediate' });
499
639
  return { success: true, data: { appended: true, entryId: entry.id } };
500
640
  }
501
641
  catch (error) {
502
- return {
503
- success: false,
504
- error: {
505
- code: 'E_MANIFEST_APPEND',
506
- message: error instanceof Error ? error.message : String(error),
507
- },
508
- };
642
+ return manifestFailure('E_MANIFEST_APPEND', error instanceof Error ? error : new Error(String(error)));
509
643
  }
510
644
  }
511
645
  /** pipeline.manifest.archive - Archive old manifest entries by date */
@@ -520,118 +654,103 @@ export async function pipelineManifestArchive(beforeDate, projectRoot) {
520
654
  };
521
655
  }
522
656
  try {
523
- const db = await getDb(projectRoot);
524
- const nativeDb = await getNativeDb(projectRoot);
525
- if (!nativeDb) {
526
- return {
527
- success: false,
528
- error: { code: 'E_DB_NOT_INITIALIZED', message: 'Database not initialized' },
529
- };
530
- }
531
- // Find entries to archive (before date, not already archived)
532
- const rows = await db
533
- .select()
534
- .from(pipelineManifest)
535
- .where(isNull(pipelineManifest.archivedAt));
536
- const toArchive = rows.filter((r) => r.createdAt.slice(0, 10) < beforeDate);
537
- if (toArchive.length === 0) {
538
- const remaining = rows.length;
657
+ const binding = await getBinding(projectRoot);
658
+ return binding.db.transaction(() => {
659
+ const rows = readStoredRows(binding);
660
+ const toArchive = rows.filter((row) => row.createdAt.slice(0, 10) < beforeDate);
661
+ requireModernRows(toArchive);
662
+ const archivedAt = now();
663
+ for (const row of toArchive) {
664
+ binding.db
665
+ .update(pipelineManifest)
666
+ .set({ archivedAt })
667
+ .where(eq(pipelineManifest.id, row.id))
668
+ .run();
669
+ }
539
670
  return {
540
671
  success: true,
541
- data: { archived: 0, remaining, message: 'No entries found before the specified date' },
672
+ data: { archived: toArchive.length, remaining: rows.length - toArchive.length },
542
673
  };
543
- }
544
- const archivedAt = now();
545
- for (const row of toArchive) {
546
- await db.update(pipelineManifest).set({ archivedAt }).where(eq(pipelineManifest.id, row.id));
547
- }
548
- const remaining = rows.length - toArchive.length;
549
- return { success: true, data: { archived: toArchive.length, remaining } };
674
+ }, { behavior: 'immediate' });
550
675
  }
551
676
  catch (error) {
552
- return {
553
- success: false,
554
- error: {
555
- code: 'E_MANIFEST_ARCHIVE',
556
- message: error instanceof Error ? error.message : String(error),
557
- },
558
- };
677
+ return manifestFailure('E_MANIFEST_ARCHIVE', error instanceof Error ? error : new Error(String(error)));
559
678
  }
560
679
  }
561
680
  /** pipeline.manifest.compact - Dedup by contentHash (keep newest by createdAt) */
562
681
  export async function pipelineManifestCompact(projectRoot) {
563
682
  try {
564
- const db = await getDb(projectRoot);
565
- const rows = await db
566
- .select()
567
- .from(pipelineManifest)
568
- .where(isNull(pipelineManifest.archivedAt))
569
- .orderBy(desc(pipelineManifest.createdAt));
570
- const originalCount = rows.length;
571
- if (originalCount === 0) {
572
- return { success: true, data: { compacted: false, message: 'No entries found' } };
573
- }
574
- // Dedup by contentHash — keep newest (first seen due to DESC order)
575
- const seenHashes = new Set();
576
- const seenIds = new Set();
577
- const toDelete = [];
578
- for (const row of rows) {
579
- const hash = row.contentHash ?? computeContentHash(row.content);
580
- if (seenHashes.has(hash) || seenIds.has(row.id)) {
581
- toDelete.push(row.id);
683
+ const binding = await getBinding(projectRoot);
684
+ return binding.db.transaction(() => {
685
+ const rows = readStoredRows(binding);
686
+ requireModernRows(rows);
687
+ if (!rows.length)
688
+ return { success: true, data: { compacted: false, message: 'No entries found' } };
689
+ // Hashes can collide; only the full stored content establishes duplicate payloads.
690
+ const seen = new Set();
691
+ const toDelete = [];
692
+ for (const row of rows) {
693
+ if (seen.has(row.content))
694
+ toDelete.push(row.id);
695
+ else
696
+ seen.add(row.content);
582
697
  }
583
- else {
584
- seenHashes.add(hash);
585
- seenIds.add(row.id);
586
- }
587
- }
588
- for (const id of toDelete) {
589
- await db.delete(pipelineManifest).where(eq(pipelineManifest.id, id));
590
- }
591
- return {
592
- success: true,
593
- data: {
594
- compacted: true,
595
- originalLines: originalCount,
596
- malformedRemoved: 0,
597
- duplicatesRemoved: toDelete.length,
598
- remainingEntries: originalCount - toDelete.length,
599
- },
600
- };
698
+ for (const id of toDelete)
699
+ binding.db.delete(pipelineManifest).where(eq(pipelineManifest.id, id)).run();
700
+ return {
701
+ success: true,
702
+ data: {
703
+ compacted: true,
704
+ originalLines: rows.length,
705
+ malformedRemoved: 0,
706
+ duplicatesRemoved: toDelete.length,
707
+ remainingEntries: rows.length - toDelete.length,
708
+ },
709
+ };
710
+ }, { behavior: 'immediate' });
601
711
  }
602
712
  catch (error) {
603
- return {
604
- success: false,
605
- error: {
606
- code: 'E_COMPACT_FAILED',
607
- message: error instanceof Error ? error.message : String(error),
608
- },
609
- };
713
+ return manifestFailure('E_COMPACT_FAILED', error instanceof Error ? error : new Error(String(error)));
610
714
  }
611
715
  }
612
- /** pipeline.manifest.validate - Validate manifest entries for a task */
716
+ /**
717
+ * Validate available manifest evidence explicitly linked to one task.
718
+ *
719
+ * @remarks
720
+ * This exported SDK helper is not a registered CLI operation. Selection uses
721
+ * exact linked-task membership; manifest ID wording establishes no ownership.
722
+ * Absent evidence, missing output, and blank output invalidate the assessment.
723
+ * Canonical document/read failures retain their structured diagnostics. Content
724
+ * availability does not establish implementation, testing, review, or authority.
725
+ * @param taskId - Exact task identity whose linked evidence is assessed.
726
+ * @param projectRoot - Project captured before any asynchronous store access.
727
+ * @returns Field and content assessment, or a structured diagnostic failure.
728
+ * @example
729
+ * ```ts
730
+ * const result = await pipelineManifestValidate('T001', '/project');
731
+ * ```
732
+ */
613
733
  export async function pipelineManifestValidate(taskId, projectRoot) {
614
734
  if (!taskId) {
615
735
  return { success: false, error: { code: 'E_INVALID_INPUT', message: 'taskId is required' } };
616
736
  }
617
737
  try {
618
- const db = await getDb(projectRoot);
619
- const root = getProjectRoot(projectRoot);
620
- const rows = await db
621
- .select()
622
- .from(pipelineManifest)
623
- .where(isNull(pipelineManifest.archivedAt));
624
- const entries = rows.map(rowToEntry);
625
- const linked = entries.filter((e) => e.id.startsWith(taskId) || e.linked_tasks?.includes(taskId));
738
+ const root = manifestScope(projectRoot).worktreeRoot;
739
+ const entries = await readManifestEntries(root);
740
+ const linked = entries.filter((entry) => entry.linked_tasks?.includes(taskId));
626
741
  if (linked.length === 0) {
627
742
  return {
628
743
  success: true,
629
744
  data: {
630
745
  taskId,
631
- valid: true,
746
+ valid: false,
632
747
  entriesFound: 0,
633
748
  message: `No research entries found for task ${taskId}`,
634
- issues: [],
749
+ issues: [
750
+ { entryId: taskId, issue: 'No explicitly linked evidence found', severity: 'error' },
751
+ ],
752
+ errorCount: 1,
753
+ warningCount: 0,
635
754
  },
636
755
  };
637
756
  }
@@ -657,12 +776,34 @@ export async function pipelineManifestValidate(taskId, projectRoot) {
657
776
  });
658
777
  }
659
778
  if (entry.file) {
660
- const filePath = join(root, entry.file);
661
- if (!existsSync(filePath)) {
779
+ const output = await pipelineManifestShow(entry.id, root);
780
+ if (!output.success)
781
+ return output;
782
+ const data = output.data;
783
+ if (!data ||
784
+ typeof data !== 'object' ||
785
+ !('fileExists' in data) ||
786
+ typeof data.fileExists !== 'boolean' ||
787
+ !('fileContent' in data) ||
788
+ (data.fileExists ? typeof data.fileContent !== 'string' : data.fileContent !== null)) {
789
+ throw new EngineResultError({
790
+ code: 'E_MANIFEST_RESULT_INVALID',
791
+ message: 'Canonical manifest show did not disclose consistent output availability',
792
+ details: { entryId: entry.id },
793
+ });
794
+ }
795
+ if (!data.fileExists) {
662
796
  issues.push({
663
797
  entryId: entry.id,
664
798
  issue: `Output file not found: ${entry.file}`,
665
- severity: 'warning',
799
+ severity: 'error',
800
+ });
801
+ }
802
+ else if (typeof data.fileContent === 'string' && data.fileContent.trim().length === 0) {
803
+ issues.push({
804
+ entryId: entry.id,
805
+ issue: `Output content is empty: ${entry.file}`,
806
+ severity: 'error',
666
807
  });
667
808
  }
668
809
  }
@@ -688,23 +829,13 @@ export async function pipelineManifestValidate(taskId, projectRoot) {
688
829
  };
689
830
  }
690
831
  catch (error) {
691
- return {
692
- success: false,
693
- error: {
694
- code: 'E_MANIFEST_VALIDATE',
695
- message: error instanceof Error ? error.message : String(error),
696
- },
697
- };
832
+ return manifestFailure('E_MANIFEST_VALIDATE', error instanceof Error ? error : new Error(String(error)));
698
833
  }
699
834
  }
700
835
  /** pipeline.manifest.contradictions - Find entries with overlapping topics but conflicting key_findings */
701
836
  export async function pipelineManifestContradictions(projectRoot, params) {
702
837
  try {
703
- const db = await getDb(projectRoot);
704
- const rows = await db
705
- .select()
706
- .from(pipelineManifest)
707
- .where(isNull(pipelineManifest.archivedAt));
838
+ const rows = await readRows(projectRoot);
708
839
  const entries = rows.map(rowToEntry);
709
840
  // In-memory negation pattern matching (same logic as compat layer)
710
841
  const byTopic = new Map();
@@ -766,23 +897,13 @@ export async function pipelineManifestContradictions(projectRoot, params) {
766
897
  return { success: true, data: { contradictions } };
767
898
  }
768
899
  catch (error) {
769
- return {
770
- success: false,
771
- error: {
772
- code: 'E_MANIFEST_CONTRADICTIONS',
773
- message: error instanceof Error ? error.message : String(error),
774
- },
775
- };
900
+ return manifestFailure('E_MANIFEST_CONTRADICTIONS', error instanceof Error ? error : new Error(String(error)));
776
901
  }
777
902
  }
778
903
  /** pipeline.manifest.superseded - Identify entries replaced by newer work on same topic */
779
904
  export async function pipelineManifestSuperseded(projectRoot, params) {
780
905
  try {
781
- const db = await getDb(projectRoot);
782
- const rows = await db
783
- .select()
784
- .from(pipelineManifest)
785
- .where(isNull(pipelineManifest.archivedAt));
906
+ const rows = await readRows(projectRoot);
786
907
  const entries = rows.map(rowToEntry);
787
908
  const byTopicAndType = new Map();
788
909
  for (const entry of entries) {
@@ -813,13 +934,7 @@ export async function pipelineManifestSuperseded(projectRoot, params) {
813
934
  return { success: true, data: { superseded } };
814
935
  }
815
936
  catch (error) {
816
- return {
817
- success: false,
818
- error: {
819
- code: 'E_MANIFEST_SUPERSEDED',
820
- message: error instanceof Error ? error.message : String(error),
821
- },
822
- };
937
+ return manifestFailure('E_MANIFEST_SUPERSEDED', error instanceof Error ? error : new Error(String(error)));
823
938
  }
824
939
  }
825
940
  /** pipeline.manifest.link - Link manifest entry to a task */
@@ -831,72 +946,58 @@ export async function pipelineManifestLink(taskId, researchId, notes, projectRoo
831
946
  };
832
947
  }
833
948
  try {
834
- const db = await getDb(projectRoot);
835
- const rows = await db
836
- .select()
837
- .from(pipelineManifest)
838
- .where(eq(pipelineManifest.id, researchId))
839
- .limit(1);
840
- if (rows.length === 0) {
841
- return {
842
- success: false,
843
- error: { code: 'E_NOT_FOUND', message: `Research entry '${researchId}' not found` },
844
- };
845
- }
846
- const row = rows[0];
847
- const entry = rowToEntry(row);
848
- if (entry.linked_tasks?.includes(taskId)) {
849
- return { success: true, data: { taskId, researchId, linked: true, alreadyLinked: true } };
850
- }
851
- // Update linked_tasks in metadataJson
852
- const updatedLinkedTasks = [...(entry.linked_tasks ?? []), taskId];
853
- let meta = {};
854
- try {
855
- meta = row.metadataJson ? JSON.parse(row.metadataJson) : {};
856
- }
857
- catch {
858
- // ignore
859
- }
860
- meta['linked_tasks'] = updatedLinkedTasks;
861
- await db
862
- .update(pipelineManifest)
863
- .set({
864
- taskId: row.taskId ?? taskId,
865
- metadataJson: JSON.stringify(meta),
866
- })
867
- .where(eq(pipelineManifest.id, researchId));
868
- return { success: true, data: { taskId, researchId, linked: true, notes: notes || null } };
949
+ const binding = await getBinding(projectRoot);
950
+ return binding.db.transaction(() => {
951
+ const rows = readStoredRows(binding, true, researchId);
952
+ if (!rows.length)
953
+ throw new EngineResultError({
954
+ code: 'E_NOT_FOUND',
955
+ message: `Research entry '${researchId}' not found`,
956
+ });
957
+ requireModernRows(rows);
958
+ const row = rows[0];
959
+ const entry = rowToEntry(row);
960
+ if (entry.linked_tasks?.includes(taskId)) {
961
+ return { success: true, data: { taskId, researchId, linked: true, alreadyLinked: true } };
962
+ }
963
+ // Update linked_tasks in metadataJson
964
+ const updatedLinkedTasks = [...(entry.linked_tasks ?? []), taskId];
965
+ const meta = readRowMetadata(row);
966
+ meta['linked_tasks'] = updatedLinkedTasks;
967
+ binding.db
968
+ .update(pipelineManifest)
969
+ .set({
970
+ taskId: row.taskId ?? taskId,
971
+ metadataJson: JSON.stringify(meta),
972
+ })
973
+ .where(eq(pipelineManifest.id, researchId))
974
+ .run();
975
+ return { success: true, data: { taskId, researchId, linked: true, notes: notes || null } };
976
+ }, { behavior: 'immediate' });
869
977
  }
870
978
  catch (error) {
871
- return {
872
- success: false,
873
- error: {
874
- code: 'E_MANIFEST_LINK',
875
- message: error instanceof Error ? error.message : String(error),
876
- },
877
- };
979
+ return manifestFailure('E_MANIFEST_LINK', error instanceof Error ? error : new Error(String(error)));
878
980
  }
879
981
  }
880
982
  // ============================================================================
881
983
  // Helper exported for compat consumers
882
984
  // ============================================================================
883
985
  /**
884
- * Read all manifest entries from the pipeline_manifest table.
885
- * Replaces readManifestEntries() from pipeline-manifest-compat.
986
+ * Read unarchived entries from both manifest histories with physical provenance.
987
+ * @param projectRoot - Explicit project root; takes priority over ambient project pins.
988
+ * @returns Entries retaining the existing fields and observed source tables/database path.
989
+ * @throws EngineResultError when the same identity has conflicting persisted payloads.
990
+ * @throws Error when storage reads fail; failure is never represented as an empty history.
991
+ * @remarks Identical rows are deduplicated only after comparing every stored scalar.
992
+ * Legacy-only evidence remains readable and is never implicitly migrated or rewritten.
993
+ * @example
994
+ * ```ts
995
+ * const entries = await readManifestEntries('/project');
996
+ * const sources = entries.map((entry) => entry.provenance.tables);
997
+ * ```
886
998
  */
887
999
  export async function readManifestEntries(projectRoot) {
888
- try {
889
- const db = await getDb(projectRoot);
890
- const rows = await db
891
- .select()
892
- .from(pipelineManifest)
893
- .where(isNull(pipelineManifest.archivedAt))
894
- .orderBy(desc(pipelineManifest.createdAt));
895
- return rows.map(rowToEntry);
896
- }
897
- catch {
898
- return [];
899
- }
1000
+ return (await readRows(projectRoot)).map(rowToEntry);
900
1001
  }
901
1002
  /**
902
1003
  * Filter manifest entries by criteria (alias for backward compatibility).
@@ -924,7 +1025,7 @@ export async function distillManifestEntry(_entryId, _projectRoot) {
924
1025
  * @returns Count of migrated and skipped entries.
925
1026
  */
926
1027
  export async function migrateManifestJsonlToSqlite(projectRoot) {
927
- const root = getProjectRoot(projectRoot);
1028
+ const root = manifestScope(projectRoot).worktreeRoot;
928
1029
  const manifestPath = join(resolveCleoDir(root), 'MANIFEST.jsonl');
929
1030
  if (!existsSync(manifestPath)) {
930
1031
  return { migrated: 0, skipped: 0 };
@@ -946,7 +1047,8 @@ export async function migrateManifestJsonlToSqlite(projectRoot) {
946
1047
  if (entries.length === 0) {
947
1048
  return { migrated: 0, skipped: 0 };
948
1049
  }
949
- const db = await getDb(projectRoot);
1050
+ const binding = await getBinding(projectRoot);
1051
+ const db = binding.db;
950
1052
  let migrated = 0;
951
1053
  let skipped = 0;
952
1054
  for (const entry of entries) {
@@ -954,24 +1056,18 @@ export async function migrateManifestJsonlToSqlite(projectRoot) {
954
1056
  skipped++;
955
1057
  continue;
956
1058
  }
957
- // Check if already exists
958
- const existing = await db
959
- .select({ id: pipelineManifest.id })
960
- .from(pipelineManifest)
961
- .where(eq(pipelineManifest.id, entry.id))
962
- .limit(1);
963
- if (existing.length > 0) {
964
- skipped++;
965
- continue;
966
- }
967
- try {
968
- const row = entryToRow(entry);
969
- await db.insert(pipelineManifest).values(row);
1059
+ const inserted = db.transaction(() => {
1060
+ const existing = readStoredRows(binding, true, entry.id);
1061
+ requireModernRows(existing);
1062
+ if (existing.length)
1063
+ return false;
1064
+ db.insert(pipelineManifest).values(entryToRow(entry)).run();
1065
+ return true;
1066
+ }, { behavior: 'immediate' });
1067
+ if (inserted)
970
1068
  migrated++;
971
- }
972
- catch {
1069
+ else
973
1070
  skipped++;
974
- }
975
1071
  }
976
1072
  // Rename MANIFEST.jsonl to MANIFEST.jsonl.migrated
977
1073
  try {