@cleocode/core 2026.9.23 → 2026.9.25

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 (865) hide show
  1. package/dist/admin/import-tasks.d.ts.map +1 -1
  2. package/dist/admin/import-tasks.js +35 -6
  3. package/dist/admin/import-tasks.js.map +1 -1
  4. package/dist/admin/import.d.ts.map +1 -1
  5. package/dist/admin/import.js +25 -6
  6. package/dist/admin/import.js.map +1 -1
  7. package/dist/audit-prune.d.ts +32 -0
  8. package/dist/audit-prune.d.ts.map +1 -1
  9. package/dist/audit-prune.js +37 -3
  10. package/dist/audit-prune.js.map +1 -1
  11. package/dist/build-provenance.json +2 -2
  12. package/dist/cloud/crypto.d.ts +1 -2
  13. package/dist/cloud/crypto.d.ts.map +1 -1
  14. package/dist/cloud/crypto.js +1 -11
  15. package/dist/cloud/crypto.js.map +1 -1
  16. package/dist/cloud/http.d.ts +8 -0
  17. package/dist/cloud/http.d.ts.map +1 -1
  18. package/dist/cloud/http.js +8 -1
  19. package/dist/cloud/http.js.map +1 -1
  20. package/dist/cloud/index.d.ts +6 -1
  21. package/dist/cloud/index.d.ts.map +1 -1
  22. package/dist/cloud/index.js +6 -1
  23. package/dist/cloud/index.js.map +1 -1
  24. package/dist/cloud/nexus-auth.d.ts +169 -0
  25. package/dist/cloud/nexus-auth.d.ts.map +1 -0
  26. package/dist/cloud/nexus-auth.js +372 -0
  27. package/dist/cloud/nexus-auth.js.map +1 -0
  28. package/dist/cloud/nexus-credentials.d.ts +188 -0
  29. package/dist/cloud/nexus-credentials.d.ts.map +1 -0
  30. package/dist/cloud/nexus-credentials.js +323 -0
  31. package/dist/cloud/nexus-credentials.js.map +1 -0
  32. package/dist/cloud/nexus-link.d.ts +85 -0
  33. package/dist/cloud/nexus-link.d.ts.map +1 -0
  34. package/dist/cloud/nexus-link.js +226 -0
  35. package/dist/cloud/nexus-link.js.map +1 -0
  36. package/dist/cloud/presence.d.ts +88 -0
  37. package/dist/cloud/presence.d.ts.map +1 -0
  38. package/dist/cloud/presence.js +137 -0
  39. package/dist/cloud/presence.js.map +1 -0
  40. package/dist/cloud/projects.d.ts +3 -1
  41. package/dist/cloud/projects.d.ts.map +1 -1
  42. package/dist/cloud/projects.js +4 -2
  43. package/dist/cloud/projects.js.map +1 -1
  44. package/dist/cloud/uuidv7.d.ts +9 -0
  45. package/dist/cloud/uuidv7.d.ts.map +1 -0
  46. package/dist/cloud/uuidv7.js +19 -0
  47. package/dist/cloud/uuidv7.js.map +1 -0
  48. package/dist/crypto/credentials.d.ts +14 -4
  49. package/dist/crypto/credentials.d.ts.map +1 -1
  50. package/dist/crypto/credentials.js +15 -1
  51. package/dist/crypto/credentials.js.map +1 -1
  52. package/dist/decide/bench/dataset.d.ts +125 -0
  53. package/dist/decide/bench/dataset.d.ts.map +1 -0
  54. package/dist/decide/bench/dataset.js +457 -0
  55. package/dist/decide/bench/dataset.js.map +1 -0
  56. package/dist/decide/bench/index.d.ts +23 -0
  57. package/dist/decide/bench/index.d.ts.map +1 -0
  58. package/dist/decide/bench/index.js +23 -0
  59. package/dist/decide/bench/index.js.map +1 -0
  60. package/dist/decide/bench/metrics.d.ts +55 -0
  61. package/dist/decide/bench/metrics.d.ts.map +1 -0
  62. package/dist/decide/bench/metrics.js +100 -0
  63. package/dist/decide/bench/metrics.js.map +1 -0
  64. package/dist/decide/bench/operation.d.ts +119 -0
  65. package/dist/decide/bench/operation.d.ts.map +1 -0
  66. package/dist/decide/bench/operation.js +171 -0
  67. package/dist/decide/bench/operation.js.map +1 -0
  68. package/dist/decide/bench/profiles.d.ts +102 -0
  69. package/dist/decide/bench/profiles.d.ts.map +1 -0
  70. package/dist/decide/bench/profiles.js +175 -0
  71. package/dist/decide/bench/profiles.js.map +1 -0
  72. package/dist/decide/bench/questions.d.ts +40 -0
  73. package/dist/decide/bench/questions.d.ts.map +1 -0
  74. package/dist/decide/bench/questions.js +107 -0
  75. package/dist/decide/bench/questions.js.map +1 -0
  76. package/dist/decide/bench/report.d.ts +21 -0
  77. package/dist/decide/bench/report.d.ts.map +1 -0
  78. package/dist/decide/bench/report.js +125 -0
  79. package/dist/decide/bench/report.js.map +1 -0
  80. package/dist/decide/bench/runner.d.ts +208 -0
  81. package/dist/decide/bench/runner.d.ts.map +1 -0
  82. package/dist/decide/bench/runner.js +336 -0
  83. package/dist/decide/bench/runner.js.map +1 -0
  84. package/dist/decide/bench/source.d.ts +21 -0
  85. package/dist/decide/bench/source.d.ts.map +1 -0
  86. package/dist/decide/bench/source.js +67 -0
  87. package/dist/decide/bench/source.js.map +1 -0
  88. package/dist/decide/bench/spot-check.d.ts +117 -0
  89. package/dist/decide/bench/spot-check.d.ts.map +1 -0
  90. package/dist/decide/bench/spot-check.js +221 -0
  91. package/dist/decide/bench/spot-check.js.map +1 -0
  92. package/dist/decide/bench/stats.d.ts +57 -0
  93. package/dist/decide/bench/stats.d.ts.map +1 -0
  94. package/dist/decide/bench/stats.js +82 -0
  95. package/dist/decide/bench/stats.js.map +1 -0
  96. package/dist/decide/bench/types.d.ts +216 -0
  97. package/dist/decide/bench/types.d.ts.map +1 -0
  98. package/dist/decide/bench/types.js +104 -0
  99. package/dist/decide/bench/types.js.map +1 -0
  100. package/dist/decide/client.d.ts +35 -1
  101. package/dist/decide/client.d.ts.map +1 -1
  102. package/dist/decide/client.js +135 -35
  103. package/dist/decide/client.js.map +1 -1
  104. package/dist/decide/credentials.d.ts +177 -17
  105. package/dist/decide/credentials.d.ts.map +1 -1
  106. package/dist/decide/credentials.js +505 -41
  107. package/dist/decide/credentials.js.map +1 -1
  108. package/dist/decide/index.d.ts +8 -8
  109. package/dist/decide/index.d.ts.map +1 -1
  110. package/dist/decide/index.js +8 -8
  111. package/dist/decide/index.js.map +1 -1
  112. package/dist/decide/jev-wire.d.ts +55 -19
  113. package/dist/decide/jev-wire.d.ts.map +1 -1
  114. package/dist/decide/jev-wire.js +116 -37
  115. package/dist/decide/jev-wire.js.map +1 -1
  116. package/dist/decide/operations.d.ts +63 -12
  117. package/dist/decide/operations.d.ts.map +1 -1
  118. package/dist/decide/operations.js +116 -58
  119. package/dist/decide/operations.js.map +1 -1
  120. package/dist/decide/provider-state.d.ts +85 -12
  121. package/dist/decide/provider-state.d.ts.map +1 -1
  122. package/dist/decide/provider-state.js +154 -21
  123. package/dist/decide/provider-state.js.map +1 -1
  124. package/dist/decide/provider.d.ts +5 -0
  125. package/dist/decide/provider.d.ts.map +1 -1
  126. package/dist/decide/provider.js.map +1 -1
  127. package/dist/decide/providers.d.ts +15 -2
  128. package/dist/decide/providers.d.ts.map +1 -1
  129. package/dist/decide/providers.js +22 -6
  130. package/dist/decide/providers.js.map +1 -1
  131. package/dist/decide/sites/registry.d.ts +22 -0
  132. package/dist/decide/sites/registry.d.ts.map +1 -1
  133. package/dist/decide/sites/registry.js +23 -0
  134. package/dist/decide/sites/registry.js.map +1 -1
  135. package/dist/decide/wizard.d.ts +12 -4
  136. package/dist/decide/wizard.d.ts.map +1 -1
  137. package/dist/decide/wizard.js +79 -26
  138. package/dist/decide/wizard.js.map +1 -1
  139. package/dist/dispatch/mvi-projection.d.ts +15 -2
  140. package/dist/dispatch/mvi-projection.d.ts.map +1 -1
  141. package/dist/dispatch/mvi-projection.js +73 -12
  142. package/dist/dispatch/mvi-projection.js.map +1 -1
  143. package/dist/docs/adr-allocator.d.ts +2 -2
  144. package/dist/docs/adr-allocator.d.ts.map +1 -1
  145. package/dist/docs/adr-allocator.js +17 -4
  146. package/dist/docs/adr-allocator.js.map +1 -1
  147. package/dist/docs/blob-consolidation.js +1 -1
  148. package/dist/docs/blob-consolidation.js.map +1 -1
  149. package/dist/docs/display-alias.d.ts +1 -1
  150. package/dist/docs/display-alias.d.ts.map +1 -1
  151. package/dist/docs/display-alias.js +7 -4
  152. package/dist/docs/display-alias.js.map +1 -1
  153. package/dist/docs/docs-inconsistency-detector.js +1 -1
  154. package/dist/docs/docs-inconsistency-detector.js.map +1 -1
  155. package/dist/docs/docs-update.d.ts.map +1 -1
  156. package/dist/docs/docs-update.js +6 -1
  157. package/dist/docs/docs-update.js.map +1 -1
  158. package/dist/docs/export-document.js +18058 -14538
  159. package/dist/docs/export-document.js.map +3 -3
  160. package/dist/docs/numbering.js +1 -1
  161. package/dist/docs/numbering.js.map +1 -1
  162. package/dist/docs/supersede.d.ts.map +1 -1
  163. package/dist/docs/supersede.js +6 -3
  164. package/dist/docs/supersede.js.map +1 -1
  165. package/dist/docs/version-ssot.js +1 -1
  166. package/dist/docs/version-ssot.js.map +1 -1
  167. package/dist/doctor/db-substrate.d.ts.map +1 -1
  168. package/dist/doctor/db-substrate.js +39 -24
  169. package/dist/doctor/db-substrate.js.map +1 -1
  170. package/dist/doctor/knowledge-summary.d.ts +10 -3
  171. package/dist/doctor/knowledge-summary.d.ts.map +1 -1
  172. package/dist/doctor/knowledge-summary.js +10 -3
  173. package/dist/doctor/knowledge-summary.js.map +1 -1
  174. package/dist/doctor/orphan-ac-bindings.d.ts +64 -0
  175. package/dist/doctor/orphan-ac-bindings.d.ts.map +1 -0
  176. package/dist/doctor/orphan-ac-bindings.js +59 -0
  177. package/dist/doctor/orphan-ac-bindings.js.map +1 -0
  178. package/dist/doctor/project-identity.d.ts +128 -37
  179. package/dist/doctor/project-identity.d.ts.map +1 -1
  180. package/dist/doctor/project-identity.js +476 -63
  181. package/dist/doctor/project-identity.js.map +1 -1
  182. package/dist/doctor/projects.d.ts.map +1 -1
  183. package/dist/doctor/projects.js +43 -29
  184. package/dist/doctor/projects.js.map +1 -1
  185. package/dist/doctor/row-identity.d.ts +31 -0
  186. package/dist/doctor/row-identity.d.ts.map +1 -0
  187. package/dist/doctor/row-identity.js +93 -0
  188. package/dist/doctor/row-identity.js.map +1 -0
  189. package/dist/doctor/twin-collapse.d.ts +108 -2
  190. package/dist/doctor/twin-collapse.d.ts.map +1 -1
  191. package/dist/doctor/twin-collapse.js +309 -7
  192. package/dist/doctor/twin-collapse.js.map +1 -1
  193. package/dist/error-catalog.js +2 -2
  194. package/dist/error-catalog.js.map +1 -1
  195. package/dist/error-registry.js +1 -1
  196. package/dist/error-registry.js.map +1 -1
  197. package/dist/gateway-client/generated/types.gen.d.ts +22 -2
  198. package/dist/gateway-client/generated/types.gen.d.ts.map +1 -1
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +1 -1
  202. package/dist/index.js.map +1 -1
  203. package/dist/init.d.ts.map +1 -1
  204. package/dist/init.js +20 -11
  205. package/dist/init.js.map +1 -1
  206. package/dist/inject/index.d.ts.map +1 -1
  207. package/dist/inject/index.js +2 -3
  208. package/dist/inject/index.js.map +1 -1
  209. package/dist/internal.d.ts +5 -4
  210. package/dist/internal.d.ts.map +1 -1
  211. package/dist/internal.js +6 -4
  212. package/dist/internal.js.map +1 -1
  213. package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
  214. package/dist/lifecycle/verification/satisfies-validator.js +10 -0
  215. package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
  216. package/dist/llm/credential-remove-entry.d.ts +59 -0
  217. package/dist/llm/credential-remove-entry.d.ts.map +1 -0
  218. package/dist/llm/credential-remove-entry.js +101 -0
  219. package/dist/llm/credential-remove-entry.js.map +1 -0
  220. package/dist/llm/oauth/device-code.d.ts +26 -6
  221. package/dist/llm/oauth/device-code.d.ts.map +1 -1
  222. package/dist/llm/oauth/device-code.js +44 -12
  223. package/dist/llm/oauth/device-code.js.map +1 -1
  224. package/dist/llm/plugin-facade.js +18202 -14682
  225. package/dist/llm/plugin-facade.js.map +3 -3
  226. package/dist/memory/attention.d.ts.map +1 -1
  227. package/dist/memory/attention.js +5 -3
  228. package/dist/memory/attention.js.map +1 -1
  229. package/dist/memory/decisions.d.ts +48 -3
  230. package/dist/memory/decisions.d.ts.map +1 -1
  231. package/dist/memory/decisions.js +98 -14
  232. package/dist/memory/decisions.js.map +1 -1
  233. package/dist/memory/index.d.ts.map +1 -1
  234. package/dist/memory/index.js +19 -10
  235. package/dist/memory/index.js.map +1 -1
  236. package/dist/memory/learnings.d.ts +6 -6
  237. package/dist/memory/manifest-identity.d.ts +171 -0
  238. package/dist/memory/manifest-identity.d.ts.map +1 -0
  239. package/dist/memory/manifest-identity.js +345 -0
  240. package/dist/memory/manifest-identity.js.map +1 -0
  241. package/dist/memory/mental-model-queue.d.ts +14 -4
  242. package/dist/memory/mental-model-queue.d.ts.map +1 -1
  243. package/dist/memory/mental-model-queue.js +64 -35
  244. package/dist/memory/mental-model-queue.js.map +1 -1
  245. package/dist/memory/patterns.d.ts +4 -4
  246. package/dist/memory/pipeline-manifest-sqlite.d.ts +47 -5
  247. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  248. package/dist/memory/pipeline-manifest-sqlite.js +130 -14
  249. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  250. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  251. package/dist/memory/retrieval/observe.js +2 -0
  252. package/dist/memory/retrieval/observe.js.map +1 -1
  253. package/dist/memory/transcript-scanner.js +1 -1
  254. package/dist/migration/manual/T10165-backfill-adr-index.d.ts.map +1 -1
  255. package/dist/migration/manual/T10165-backfill-adr-index.js +5 -1
  256. package/dist/migration/manual/T10165-backfill-adr-index.js.map +1 -1
  257. package/dist/nexus/deps.d.ts.map +1 -1
  258. package/dist/nexus/deps.js +7 -14
  259. package/dist/nexus/deps.js.map +1 -1
  260. package/dist/nexus/discover.d.ts.map +1 -1
  261. package/dist/nexus/discover.js +6 -9
  262. package/dist/nexus/discover.js.map +1 -1
  263. package/dist/nexus/fleet-status.d.ts +83 -0
  264. package/dist/nexus/fleet-status.d.ts.map +1 -0
  265. package/dist/nexus/fleet-status.js +414 -0
  266. package/dist/nexus/fleet-status.js.map +1 -0
  267. package/dist/nexus/git-state.d.ts +15 -0
  268. package/dist/nexus/git-state.d.ts.map +1 -1
  269. package/dist/nexus/git-state.js +77 -3
  270. package/dist/nexus/git-state.js.map +1 -1
  271. package/dist/nexus/identity.d.ts.map +1 -1
  272. package/dist/nexus/identity.js +4 -0
  273. package/dist/nexus/identity.js.map +1 -1
  274. package/dist/nexus/index.d.ts +4 -1
  275. package/dist/nexus/index.d.ts.map +1 -1
  276. package/dist/nexus/index.js +7 -1
  277. package/dist/nexus/index.js.map +1 -1
  278. package/dist/nexus/migrate-json-to-sqlite.d.ts +3 -2
  279. package/dist/nexus/migrate-json-to-sqlite.d.ts.map +1 -1
  280. package/dist/nexus/migrate-json-to-sqlite.js +9 -17
  281. package/dist/nexus/migrate-json-to-sqlite.js.map +1 -1
  282. package/dist/nexus/ops.d.ts +1 -0
  283. package/dist/nexus/ops.d.ts.map +1 -1
  284. package/dist/nexus/project-activity.d.ts +104 -0
  285. package/dist/nexus/project-activity.d.ts.map +1 -0
  286. package/dist/nexus/project-activity.js +150 -0
  287. package/dist/nexus/project-activity.js.map +1 -0
  288. package/dist/nexus/projects-clean.d.ts.map +1 -1
  289. package/dist/nexus/projects-clean.js +22 -11
  290. package/dist/nexus/projects-clean.js.map +1 -1
  291. package/dist/nexus/projects-scan.d.ts.map +1 -1
  292. package/dist/nexus/projects-scan.js +8 -13
  293. package/dist/nexus/projects-scan.js.map +1 -1
  294. package/dist/nexus/query.d.ts +2 -2
  295. package/dist/nexus/query.d.ts.map +1 -1
  296. package/dist/nexus/query.js +8 -31
  297. package/dist/nexus/query.js.map +1 -1
  298. package/dist/nexus/registry-errors.d.ts +61 -0
  299. package/dist/nexus/registry-errors.d.ts.map +1 -0
  300. package/dist/nexus/registry-errors.js +85 -0
  301. package/dist/nexus/registry-errors.js.map +1 -0
  302. package/dist/nexus/registry-roots.d.ts +5 -2
  303. package/dist/nexus/registry-roots.d.ts.map +1 -1
  304. package/dist/nexus/registry-roots.js +8 -10
  305. package/dist/nexus/registry-roots.js.map +1 -1
  306. package/dist/nexus/registry.d.ts +48 -5
  307. package/dist/nexus/registry.d.ts.map +1 -1
  308. package/dist/nexus/registry.js +151 -85
  309. package/dist/nexus/registry.js.map +1 -1
  310. package/dist/orchestrate/pivot.d.ts +4 -0
  311. package/dist/orchestrate/pivot.d.ts.map +1 -1
  312. package/dist/orchestrate/pivot.js +75 -12
  313. package/dist/orchestrate/pivot.js.map +1 -1
  314. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  315. package/dist/orchestrate/query-ops.js +29 -27
  316. package/dist/orchestrate/query-ops.js.map +1 -1
  317. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  318. package/dist/orchestrate/spawn-ops.js +29 -3
  319. package/dist/orchestrate/spawn-ops.js.map +1 -1
  320. package/dist/orchestrate/worktree-complete.d.ts.map +1 -1
  321. package/dist/orchestrate/worktree-complete.js +40 -2
  322. package/dist/orchestrate/worktree-complete.js.map +1 -1
  323. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  324. package/dist/orchestration/bootstrap.js +20 -14
  325. package/dist/orchestration/bootstrap.js.map +1 -1
  326. package/dist/orchestration/index.d.ts +15 -1
  327. package/dist/orchestration/index.d.ts.map +1 -1
  328. package/dist/orchestration/index.js +25 -6
  329. package/dist/orchestration/index.js.map +1 -1
  330. package/dist/orchestration/lead-rollup.d.ts +7 -1
  331. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  332. package/dist/orchestration/lead-rollup.js +6 -3
  333. package/dist/orchestration/lead-rollup.js.map +1 -1
  334. package/dist/orchestration/spawn-prompt.d.ts +26 -0
  335. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  336. package/dist/orchestration/spawn-prompt.js +63 -92
  337. package/dist/orchestration/spawn-prompt.js.map +1 -1
  338. package/dist/orchestration/waves.d.ts +21 -10
  339. package/dist/orchestration/waves.d.ts.map +1 -1
  340. package/dist/orchestration/waves.js +38 -35
  341. package/dist/orchestration/waves.js.map +1 -1
  342. package/dist/paths.d.ts +9 -2
  343. package/dist/paths.d.ts.map +1 -1
  344. package/dist/paths.js +30 -13
  345. package/dist/paths.js.map +1 -1
  346. package/dist/phases/index.d.ts +1 -1
  347. package/dist/phases/index.d.ts.map +1 -1
  348. package/dist/phases/index.js +3 -4
  349. package/dist/phases/index.js.map +1 -1
  350. package/dist/project-info.d.ts +40 -3
  351. package/dist/project-info.d.ts.map +1 -1
  352. package/dist/project-info.js +74 -6
  353. package/dist/project-info.js.map +1 -1
  354. package/dist/project-lifecycle.d.ts +28 -7
  355. package/dist/project-lifecycle.d.ts.map +1 -1
  356. package/dist/project-lifecycle.js +114 -47
  357. package/dist/project-lifecycle.js.map +1 -1
  358. package/dist/project-scope.d.ts +70 -3
  359. package/dist/project-scope.d.ts.map +1 -1
  360. package/dist/project-scope.js +154 -15
  361. package/dist/project-scope.js.map +1 -1
  362. package/dist/release/ci-evidence.d.ts +190 -0
  363. package/dist/release/ci-evidence.d.ts.map +1 -1
  364. package/dist/release/ci-evidence.js +436 -4
  365. package/dist/release/ci-evidence.js.map +1 -1
  366. package/dist/release/open.d.ts +12 -2
  367. package/dist/release/open.d.ts.map +1 -1
  368. package/dist/release/open.js +32 -3
  369. package/dist/release/open.js.map +1 -1
  370. package/dist/release/preflight-skip.d.ts +73 -0
  371. package/dist/release/preflight-skip.d.ts.map +1 -0
  372. package/dist/release/preflight-skip.js +254 -0
  373. package/dist/release/preflight-skip.js.map +1 -0
  374. package/dist/render/decide/index.d.ts +51 -0
  375. package/dist/render/decide/index.d.ts.map +1 -0
  376. package/dist/render/decide/index.js +289 -0
  377. package/dist/render/decide/index.js.map +1 -0
  378. package/dist/render/index.d.ts +1 -0
  379. package/dist/render/index.d.ts.map +1 -1
  380. package/dist/render/index.js +1 -0
  381. package/dist/render/index.js.map +1 -1
  382. package/dist/render/nexus/graph/index.d.ts +5 -0
  383. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  384. package/dist/render/nexus/graph/index.js +53 -0
  385. package/dist/render/nexus/graph/index.js.map +1 -1
  386. package/dist/scaffold/ensure-config.d.ts +14 -6
  387. package/dist/scaffold/ensure-config.d.ts.map +1 -1
  388. package/dist/scaffold/ensure-config.js +39 -17
  389. package/dist/scaffold/ensure-config.js.map +1 -1
  390. package/dist/scaffold/project-identity.d.ts +115 -23
  391. package/dist/scaffold/project-identity.d.ts.map +1 -1
  392. package/dist/scaffold/project-identity.js +196 -44
  393. package/dist/scaffold/project-identity.js.map +1 -1
  394. package/dist/sdk/validator-ac-pull.d.ts.map +1 -1
  395. package/dist/sdk/validator-ac-pull.js +2 -1
  396. package/dist/sdk/validator-ac-pull.js.map +1 -1
  397. package/dist/selfimprove/fix-gen.js +18221 -14701
  398. package/dist/selfimprove/fix-gen.js.map +3 -3
  399. package/dist/sentient/cross-project-hygiene.d.ts +17 -6
  400. package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
  401. package/dist/sentient/cross-project-hygiene.js +22 -11
  402. package/dist/sentient/cross-project-hygiene.js.map +1 -1
  403. package/dist/sentient/propose-tick.d.ts.map +1 -1
  404. package/dist/sentient/propose-tick.js +2 -3
  405. package/dist/sentient/propose-tick.js.map +1 -1
  406. package/dist/sentient/stage-drift-tick.d.ts.map +1 -1
  407. package/dist/sentient/stage-drift-tick.js +2 -3
  408. package/dist/sentient/stage-drift-tick.js.map +1 -1
  409. package/dist/session/engine-ops.d.ts +13 -4
  410. package/dist/session/engine-ops.d.ts.map +1 -1
  411. package/dist/session/engine-ops.js +38 -45
  412. package/dist/session/engine-ops.js.map +1 -1
  413. package/dist/sessions/briefing.d.ts +7 -3
  414. package/dist/sessions/briefing.d.ts.map +1 -1
  415. package/dist/sessions/briefing.js +10 -10
  416. package/dist/sessions/briefing.js.map +1 -1
  417. package/dist/sessions/drift-watchdog.d.ts.map +1 -1
  418. package/dist/sessions/drift-watchdog.js +11 -19
  419. package/dist/sessions/drift-watchdog.js.map +1 -1
  420. package/dist/sessions/focus-state-store.d.ts +103 -26
  421. package/dist/sessions/focus-state-store.d.ts.map +1 -1
  422. package/dist/sessions/focus-state-store.js +166 -37
  423. package/dist/sessions/focus-state-store.js.map +1 -1
  424. package/dist/sessions/handoff.d.ts.map +1 -1
  425. package/dist/sessions/handoff.js +9 -18
  426. package/dist/sessions/handoff.js.map +1 -1
  427. package/dist/sessions/index.d.ts +4 -2
  428. package/dist/sessions/index.d.ts.map +1 -1
  429. package/dist/sessions/index.js +35 -6
  430. package/dist/sessions/index.js.map +1 -1
  431. package/dist/sessions/session-drift.d.ts.map +1 -1
  432. package/dist/sessions/session-drift.js +4 -2
  433. package/dist/sessions/session-drift.js.map +1 -1
  434. package/dist/sessions/session-view.d.ts +8 -1
  435. package/dist/sessions/session-view.d.ts.map +1 -1
  436. package/dist/sessions/session-view.js +9 -2
  437. package/dist/sessions/session-view.js.map +1 -1
  438. package/dist/setup/config-json-merge.d.ts.map +1 -1
  439. package/dist/setup/config-json-merge.js +1 -0
  440. package/dist/setup/config-json-merge.js.map +1 -1
  441. package/dist/setup/index.d.ts +4 -2
  442. package/dist/setup/index.d.ts.map +1 -1
  443. package/dist/setup/index.js +6 -2
  444. package/dist/setup/index.js.map +1 -1
  445. package/dist/setup/sections/nexus-account.d.ts +32 -0
  446. package/dist/setup/sections/nexus-account.d.ts.map +1 -0
  447. package/dist/setup/sections/nexus-account.js +64 -0
  448. package/dist/setup/sections/nexus-account.js.map +1 -0
  449. package/dist/setup/wizard.d.ts +1 -1
  450. package/dist/setup/wizard.d.ts.map +1 -1
  451. package/dist/setup/wizard.js.map +1 -1
  452. package/dist/skills/manifests/research.js +2 -0
  453. package/dist/skills/manifests/research.js.map +1 -1
  454. package/dist/skills/orchestrator/startup.d.ts.map +1 -1
  455. package/dist/skills/orchestrator/startup.js +18 -31
  456. package/dist/skills/orchestrator/startup.js.map +1 -1
  457. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  458. package/dist/skills/orchestrator/validator.js +9 -2
  459. package/dist/skills/orchestrator/validator.js.map +1 -1
  460. package/dist/skills/validation.d.ts +4 -1
  461. package/dist/skills/validation.d.ts.map +1 -1
  462. package/dist/skills/validation.js +11 -3
  463. package/dist/skills/validation.js.map +1 -1
  464. package/dist/snapshot/index.d.ts.map +1 -1
  465. package/dist/snapshot/index.js +60 -53
  466. package/dist/snapshot/index.js.map +1 -1
  467. package/dist/spawn/agent-identity.d.ts +33 -1
  468. package/dist/spawn/agent-identity.d.ts.map +1 -1
  469. package/dist/spawn/agent-identity.js +53 -1
  470. package/dist/spawn/agent-identity.js.map +1 -1
  471. package/dist/spawn/branch-lock.d.ts +111 -7
  472. package/dist/spawn/branch-lock.d.ts.map +1 -1
  473. package/dist/spawn/branch-lock.js +296 -8
  474. package/dist/spawn/branch-lock.js.map +1 -1
  475. package/dist/spawn/index.d.ts +1 -1
  476. package/dist/spawn/index.d.ts.map +1 -1
  477. package/dist/spawn/index.js +1 -1
  478. package/dist/spawn/index.js.map +1 -1
  479. package/dist/stats/index.d.ts.map +1 -1
  480. package/dist/stats/index.js +3 -4
  481. package/dist/stats/index.js.map +1 -1
  482. package/dist/status/index.d.ts +12 -3
  483. package/dist/status/index.d.ts.map +1 -1
  484. package/dist/status/index.js +47 -5
  485. package/dist/status/index.js.map +1 -1
  486. package/dist/store/ac-binding-prune.d.ts +144 -0
  487. package/dist/store/ac-binding-prune.d.ts.map +1 -0
  488. package/dist/store/ac-binding-prune.js +293 -0
  489. package/dist/store/ac-binding-prune.js.map +1 -0
  490. package/dist/store/agent-registry-store.d.ts.map +1 -1
  491. package/dist/store/agent-registry-store.js +3 -2
  492. package/dist/store/agent-registry-store.js.map +1 -1
  493. package/dist/store/attachment-repair.d.ts.map +1 -1
  494. package/dist/store/attachment-repair.js +42 -3
  495. package/dist/store/attachment-repair.js.map +1 -1
  496. package/dist/store/attachment-store.d.ts.map +1 -1
  497. package/dist/store/attachment-store.js +30 -46
  498. package/dist/store/attachment-store.js.map +1 -1
  499. package/dist/store/backup-recover-brain.d.ts +4 -0
  500. package/dist/store/backup-recover-brain.d.ts.map +1 -1
  501. package/dist/store/backup-recover-brain.js +2 -0
  502. package/dist/store/backup-recover-brain.js.map +1 -1
  503. package/dist/store/backup-recover.d.ts +9 -0
  504. package/dist/store/backup-recover.d.ts.map +1 -1
  505. package/dist/store/backup-recover.js +28 -1
  506. package/dist/store/backup-recover.js.map +1 -1
  507. package/dist/store/backup-sidecar.d.ts +115 -2
  508. package/dist/store/backup-sidecar.d.ts.map +1 -1
  509. package/dist/store/backup-sidecar.js +263 -3
  510. package/dist/store/backup-sidecar.js.map +1 -1
  511. package/dist/store/blob-keep.d.ts +135 -0
  512. package/dist/store/blob-keep.d.ts.map +1 -0
  513. package/dist/store/blob-keep.js +283 -0
  514. package/dist/store/blob-keep.js.map +1 -0
  515. package/dist/store/conduit-sqlite.d.ts.map +1 -1
  516. package/dist/store/conduit-sqlite.js +3 -2
  517. package/dist/store/conduit-sqlite.js.map +1 -1
  518. package/dist/store/converters.d.ts.map +1 -1
  519. package/dist/store/converters.js +11 -0
  520. package/dist/store/converters.js.map +1 -1
  521. package/dist/store/credential-transfer.d.ts +37 -5
  522. package/dist/store/credential-transfer.d.ts.map +1 -1
  523. package/dist/store/credential-transfer.js +76 -18
  524. package/dist/store/credential-transfer.js.map +1 -1
  525. package/dist/store/data-accessor.d.ts +1 -1
  526. package/dist/store/data-accessor.d.ts.map +1 -1
  527. package/dist/store/data-accessor.js.map +1 -1
  528. package/dist/store/db-helpers.d.ts +35 -11
  529. package/dist/store/db-helpers.d.ts.map +1 -1
  530. package/dist/store/db-helpers.js +107 -38
  531. package/dist/store/db-helpers.js.map +1 -1
  532. package/dist/store/display-id-alias.d.ts +529 -0
  533. package/dist/store/display-id-alias.d.ts.map +1 -0
  534. package/dist/store/display-id-alias.js +1063 -0
  535. package/dist/store/display-id-alias.js.map +1 -0
  536. package/dist/store/dual-scope-db.d.ts.map +1 -1
  537. package/dist/store/dual-scope-db.js +21 -0
  538. package/dist/store/dual-scope-db.js.map +1 -1
  539. package/dist/store/exodus/on-open.d.ts.map +1 -1
  540. package/dist/store/exodus/on-open.js +35 -0
  541. package/dist/store/exodus/on-open.js.map +1 -1
  542. package/dist/store/exodus/reconcile.d.ts.map +1 -1
  543. package/dist/store/exodus/reconcile.js +7 -2
  544. package/dist/store/exodus/reconcile.js.map +1 -1
  545. package/dist/store/exodus/recovery.d.ts.map +1 -1
  546. package/dist/store/exodus/recovery.js +20 -1
  547. package/dist/store/exodus/recovery.js.map +1 -1
  548. package/dist/store/exodus/runtime-targets.d.ts +3 -3
  549. package/dist/store/exodus/runtime-targets.js +3 -3
  550. package/dist/store/import-remap.d.ts +12 -1
  551. package/dist/store/import-remap.d.ts.map +1 -1
  552. package/dist/store/import-remap.js +14 -0
  553. package/dist/store/import-remap.js.map +1 -1
  554. package/dist/store/legacy-tasks-lineage.d.ts +3 -1
  555. package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
  556. package/dist/store/legacy-tasks-lineage.js +22 -3
  557. package/dist/store/legacy-tasks-lineage.js.map +1 -1
  558. package/dist/store/memory-accessor.js +1 -1
  559. package/dist/store/memory-accessor.js.map +1 -1
  560. package/dist/store/migration-manager.d.ts +61 -0
  561. package/dist/store/migration-manager.d.ts.map +1 -1
  562. package/dist/store/migration-manager.js +102 -4
  563. package/dist/store/migration-manager.js.map +1 -1
  564. package/dist/store/nexus-validation-schemas.d.ts +64 -0
  565. package/dist/store/nexus-validation-schemas.d.ts.map +1 -1
  566. package/dist/store/portable-bundle-import.d.ts +8 -0
  567. package/dist/store/portable-bundle-import.d.ts.map +1 -1
  568. package/dist/store/portable-bundle-import.js +10 -0
  569. package/dist/store/portable-bundle-import.js.map +1 -1
  570. package/dist/store/portable-bundle-scan.d.ts.map +1 -1
  571. package/dist/store/portable-bundle-scan.js +1 -0
  572. package/dist/store/portable-bundle-scan.js.map +1 -1
  573. package/dist/store/portable-bundle.d.ts.map +1 -1
  574. package/dist/store/portable-bundle.js +15 -14
  575. package/dist/store/portable-bundle.js.map +1 -1
  576. package/dist/store/pre-repair-snapshot.d.ts +4 -1
  577. package/dist/store/pre-repair-snapshot.d.ts.map +1 -1
  578. package/dist/store/pre-repair-snapshot.js +5 -1
  579. package/dist/store/pre-repair-snapshot.js.map +1 -1
  580. package/dist/store/regenerators.d.ts +4 -2
  581. package/dist/store/regenerators.d.ts.map +1 -1
  582. package/dist/store/regenerators.js +7 -3
  583. package/dist/store/regenerators.js.map +1 -1
  584. package/dist/store/repair-malformed-dbs.d.ts +4 -0
  585. package/dist/store/repair-malformed-dbs.d.ts.map +1 -1
  586. package/dist/store/repair-malformed-dbs.js +3 -0
  587. package/dist/store/repair-malformed-dbs.js.map +1 -1
  588. package/dist/store/row-identity-flag.d.ts +26 -0
  589. package/dist/store/row-identity-flag.d.ts.map +1 -0
  590. package/dist/store/row-identity-flag.js +31 -0
  591. package/dist/store/row-identity-flag.js.map +1 -0
  592. package/dist/store/row-identity-registry.d.ts +61 -0
  593. package/dist/store/row-identity-registry.d.ts.map +1 -0
  594. package/dist/store/row-identity-registry.js +198 -0
  595. package/dist/store/row-identity-registry.js.map +1 -0
  596. package/dist/store/row-identity.d.ts +390 -0
  597. package/dist/store/row-identity.d.ts.map +1 -0
  598. package/dist/store/row-identity.js +1240 -0
  599. package/dist/store/row-identity.js.map +1 -0
  600. package/dist/store/safety-data-accessor.d.ts +10 -3
  601. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  602. package/dist/store/safety-data-accessor.js +15 -4
  603. package/dist/store/safety-data-accessor.js.map +1 -1
  604. package/dist/store/schema/attachments.d.ts +1 -1
  605. package/dist/store/schema/audit.d.ts +4 -4
  606. package/dist/store/schema/background-jobs.d.ts +1 -1
  607. package/dist/store/schema/cleo-global/nexus.d.ts +49 -1
  608. package/dist/store/schema/cleo-global/nexus.d.ts.map +1 -1
  609. package/dist/store/schema/cleo-global/nexus.js +17 -0
  610. package/dist/store/schema/cleo-global/nexus.js.map +1 -1
  611. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  612. package/dist/store/schema/cleo-project/audit.d.ts +4 -4
  613. package/dist/store/schema/cleo-project/docs.d.ts +17 -1
  614. package/dist/store/schema/cleo-project/docs.d.ts.map +1 -1
  615. package/dist/store/schema/cleo-project/docs.js +10 -0
  616. package/dist/store/schema/cleo-project/docs.js.map +1 -1
  617. package/dist/store/schema/cleo-project/lifecycle.d.ts +4 -4
  618. package/dist/store/schema/cleo-project/nexus-graph.d.ts +3 -3
  619. package/dist/store/schema/cleo-project/provenance-commits.d.ts +2 -2
  620. package/dist/store/schema/cleo-project/provenance-rest.d.ts +3 -3
  621. package/dist/store/schema/cleo-project/runtime.d.ts +3 -3
  622. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts +87 -1
  623. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts.map +1 -1
  624. package/dist/store/schema/cleo-project/tasks-core-batch2.js +35 -0
  625. package/dist/store/schema/cleo-project/tasks-core-batch2.js.map +1 -1
  626. package/dist/store/schema/cleo-project/tasks-core.d.ts +263 -7
  627. package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
  628. package/dist/store/schema/cleo-project/tasks-core.js +77 -2
  629. package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
  630. package/dist/store/schema/cleo-shared/brain.d.ts +7 -7
  631. package/dist/store/schema/lifecycle.d.ts +4 -4
  632. package/dist/store/schema/manifest.d.ts +1 -1
  633. package/dist/store/schema/memory-schema.d.ts +6 -6
  634. package/dist/store/schema/nexus-schema.d.ts +51 -3
  635. package/dist/store/schema/nexus-schema.d.ts.map +1 -1
  636. package/dist/store/schema/nexus-schema.js +28 -7
  637. package/dist/store/schema/nexus-schema.js.map +1 -1
  638. package/dist/store/schema/provenance/releases.d.ts +1 -1
  639. package/dist/store/schema/skills-schema.d.ts +2 -2
  640. package/dist/store/schema/tasks.d.ts +6 -6
  641. package/dist/store/session-store.d.ts +65 -0
  642. package/dist/store/session-store.d.ts.map +1 -1
  643. package/dist/store/session-store.js +108 -7
  644. package/dist/store/session-store.js.map +1 -1
  645. package/dist/store/split-brain-import.d.ts +2 -14
  646. package/dist/store/split-brain-import.d.ts.map +1 -1
  647. package/dist/store/split-brain-import.js +4 -19
  648. package/dist/store/split-brain-import.js.map +1 -1
  649. package/dist/store/sqlite-data-accessor.d.ts +279 -2
  650. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  651. package/dist/store/sqlite-data-accessor.js +789 -91
  652. package/dist/store/sqlite-data-accessor.js.map +1 -1
  653. package/dist/store/sqlite.d.ts +15 -3
  654. package/dist/store/sqlite.d.ts.map +1 -1
  655. package/dist/store/sqlite.js +52 -20
  656. package/dist/store/sqlite.js.map +1 -1
  657. package/dist/store/store-write-guard.d.ts +9 -3
  658. package/dist/store/store-write-guard.d.ts.map +1 -1
  659. package/dist/store/store-write-guard.js +25 -4
  660. package/dist/store/store-write-guard.js.map +1 -1
  661. package/dist/store/sync/clock-store.d.ts +67 -0
  662. package/dist/store/sync/clock-store.d.ts.map +1 -0
  663. package/dist/store/sync/clock-store.js +117 -0
  664. package/dist/store/sync/clock-store.js.map +1 -0
  665. package/dist/store/sync/flags.d.ts +51 -0
  666. package/dist/store/sync/flags.d.ts.map +1 -0
  667. package/dist/store/sync/flags.js +81 -0
  668. package/dist/store/sync/flags.js.map +1 -0
  669. package/dist/store/sync/hlc.d.ts +115 -0
  670. package/dist/store/sync/hlc.d.ts.map +1 -0
  671. package/dist/store/sync/hlc.js +172 -0
  672. package/dist/store/sync/hlc.js.map +1 -0
  673. package/dist/store/sync/index.d.ts +20 -0
  674. package/dist/store/sync/index.d.ts.map +1 -0
  675. package/dist/store/sync/index.js +20 -0
  676. package/dist/store/sync/index.js.map +1 -0
  677. package/dist/store/sync/replica-registry.d.ts +85 -0
  678. package/dist/store/sync/replica-registry.d.ts.map +1 -0
  679. package/dist/store/sync/replica-registry.js +147 -0
  680. package/dist/store/sync/replica-registry.js.map +1 -0
  681. package/dist/store/sync/replica.d.ts +181 -0
  682. package/dist/store/sync/replica.d.ts.map +1 -0
  683. package/dist/store/sync/replica.js +305 -0
  684. package/dist/store/sync/replica.js.map +1 -0
  685. package/dist/store/sync/schema.d.ts +68 -0
  686. package/dist/store/sync/schema.d.ts.map +1 -0
  687. package/dist/store/sync/schema.js +130 -0
  688. package/dist/store/sync/schema.js.map +1 -0
  689. package/dist/store/sync/skew-hold.d.ts +71 -0
  690. package/dist/store/sync/skew-hold.d.ts.map +1 -0
  691. package/dist/store/sync/skew-hold.js +89 -0
  692. package/dist/store/sync/skew-hold.js.map +1 -0
  693. package/dist/store/table-classification.d.ts +11 -9
  694. package/dist/store/table-classification.d.ts.map +1 -1
  695. package/dist/store/table-classification.js +127 -33
  696. package/dist/store/table-classification.js.map +1 -1
  697. package/dist/store/task-claim.d.ts +144 -0
  698. package/dist/store/task-claim.d.ts.map +1 -0
  699. package/dist/store/task-claim.js +195 -0
  700. package/dist/store/task-claim.js.map +1 -0
  701. package/dist/store/task-version.d.ts +43 -5
  702. package/dist/store/task-version.d.ts.map +1 -1
  703. package/dist/store/task-version.js +113 -17
  704. package/dist/store/task-version.js.map +1 -1
  705. package/dist/store/tasks-schema.d.ts +2 -0
  706. package/dist/store/tasks-schema.d.ts.map +1 -1
  707. package/dist/store/tasks-schema.js +1 -0
  708. package/dist/store/tasks-schema.js.map +1 -1
  709. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  710. package/dist/store/tasks-sqlite.js +10 -2
  711. package/dist/store/tasks-sqlite.js.map +1 -1
  712. package/dist/store/twin-collapse.d.ts +450 -22
  713. package/dist/store/twin-collapse.d.ts.map +1 -1
  714. package/dist/store/twin-collapse.js +1552 -49
  715. package/dist/store/twin-collapse.js.map +1 -1
  716. package/dist/store/umbrella-data-accessor.d.ts +10 -3
  717. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  718. package/dist/store/umbrella-data-accessor.js +14 -4
  719. package/dist/store/umbrella-data-accessor.js.map +1 -1
  720. package/dist/store/validation-schemas.d.ts +402 -50
  721. package/dist/store/validation-schemas.d.ts.map +1 -1
  722. package/dist/store/with-retry.d.ts +36 -0
  723. package/dist/store/with-retry.d.ts.map +1 -1
  724. package/dist/store/with-retry.js +51 -0
  725. package/dist/store/with-retry.js.map +1 -1
  726. package/dist/store/worktree-build-guard.d.ts +13 -4
  727. package/dist/store/worktree-build-guard.d.ts.map +1 -1
  728. package/dist/store/worktree-build-guard.js +21 -10
  729. package/dist/store/worktree-build-guard.js.map +1 -1
  730. package/dist/store/worktree-isolation-guard.d.ts +121 -10
  731. package/dist/store/worktree-isolation-guard.d.ts.map +1 -1
  732. package/dist/store/worktree-isolation-guard.js +155 -34
  733. package/dist/store/worktree-isolation-guard.js.map +1 -1
  734. package/dist/system/backup.d.ts +7 -0
  735. package/dist/system/backup.d.ts.map +1 -1
  736. package/dist/system/backup.js +5 -0
  737. package/dist/system/backup.js.map +1 -1
  738. package/dist/system/health.d.ts.map +1 -1
  739. package/dist/system/health.js +6 -1
  740. package/dist/system/health.js.map +1 -1
  741. package/dist/system/inject-generate.d.ts.map +1 -1
  742. package/dist/system/inject-generate.js +23 -10
  743. package/dist/system/inject-generate.js.map +1 -1
  744. package/dist/system/project-health.d.ts +17 -2
  745. package/dist/system/project-health.d.ts.map +1 -1
  746. package/dist/system/project-health.js +19 -6
  747. package/dist/system/project-health.js.map +1 -1
  748. package/dist/task-tools/index.d.ts +1 -1
  749. package/dist/task-tools/index.d.ts.map +1 -1
  750. package/dist/task-tools/index.js +1 -1
  751. package/dist/task-tools/index.js.map +1 -1
  752. package/dist/task-tools/score-task-priority.d.ts +38 -0
  753. package/dist/task-tools/score-task-priority.d.ts.map +1 -1
  754. package/dist/task-tools/score-task-priority.js +51 -0
  755. package/dist/task-tools/score-task-priority.js.map +1 -1
  756. package/dist/task-work/claims.d.ts +215 -0
  757. package/dist/task-work/claims.d.ts.map +1 -0
  758. package/dist/task-work/claims.js +272 -0
  759. package/dist/task-work/claims.js.map +1 -0
  760. package/dist/task-work/index.d.ts +47 -3
  761. package/dist/task-work/index.d.ts.map +1 -1
  762. package/dist/task-work/index.js +74 -41
  763. package/dist/task-work/index.js.map +1 -1
  764. package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
  765. package/dist/tasks/ac-coverage-gate.js +3 -0
  766. package/dist/tasks/ac-coverage-gate.js.map +1 -1
  767. package/dist/tasks/ac-table.d.ts +35 -7
  768. package/dist/tasks/ac-table.d.ts.map +1 -1
  769. package/dist/tasks/ac-table.js +119 -14
  770. package/dist/tasks/ac-table.js.map +1 -1
  771. package/dist/tasks/add.d.ts.map +1 -1
  772. package/dist/tasks/add.js +51 -4
  773. package/dist/tasks/add.js.map +1 -1
  774. package/dist/tasks/analyze.d.ts.map +1 -1
  775. package/dist/tasks/analyze.js +3 -4
  776. package/dist/tasks/analyze.js.map +1 -1
  777. package/dist/tasks/backfill-child-projections.js +47 -6
  778. package/dist/tasks/backfill-child-projections.js.map +1 -1
  779. package/dist/tasks/change-set.d.ts +5 -0
  780. package/dist/tasks/change-set.d.ts.map +1 -1
  781. package/dist/tasks/change-set.js +59 -3
  782. package/dist/tasks/change-set.js.map +1 -1
  783. package/dist/tasks/complete.d.ts +16 -0
  784. package/dist/tasks/complete.d.ts.map +1 -1
  785. package/dist/tasks/complete.js +33 -8
  786. package/dist/tasks/complete.js.map +1 -1
  787. package/dist/tasks/completion-evaluation.d.ts.map +1 -1
  788. package/dist/tasks/completion-evaluation.js +3 -0
  789. package/dist/tasks/completion-evaluation.js.map +1 -1
  790. package/dist/tasks/component-pr.d.ts +162 -1
  791. package/dist/tasks/component-pr.d.ts.map +1 -1
  792. package/dist/tasks/component-pr.js +560 -59
  793. package/dist/tasks/component-pr.js.map +1 -1
  794. package/dist/tasks/done-record.d.ts +14 -1
  795. package/dist/tasks/done-record.d.ts.map +1 -1
  796. package/dist/tasks/done-record.js +37 -0
  797. package/dist/tasks/done-record.js.map +1 -1
  798. package/dist/tasks/duplicate-detector.d.ts +20 -1
  799. package/dist/tasks/duplicate-detector.d.ts.map +1 -1
  800. package/dist/tasks/duplicate-detector.js +10 -2
  801. package/dist/tasks/duplicate-detector.js.map +1 -1
  802. package/dist/tasks/engine-wrap-ops.d.ts +19 -10
  803. package/dist/tasks/engine-wrap-ops.d.ts.map +1 -1
  804. package/dist/tasks/engine-wrap-ops.js +38 -10
  805. package/dist/tasks/engine-wrap-ops.js.map +1 -1
  806. package/dist/tasks/evidence.d.ts.map +1 -1
  807. package/dist/tasks/evidence.js +14 -3
  808. package/dist/tasks/evidence.js.map +1 -1
  809. package/dist/tasks/graph-ops.d.ts +9 -2
  810. package/dist/tasks/graph-ops.d.ts.map +1 -1
  811. package/dist/tasks/graph-ops.js +24 -32
  812. package/dist/tasks/graph-ops.js.map +1 -1
  813. package/dist/tasks/plan.d.ts.map +1 -1
  814. package/dist/tasks/plan.js +16 -60
  815. package/dist/tasks/plan.js.map +1 -1
  816. package/dist/tasks/task-context.d.ts.map +1 -1
  817. package/dist/tasks/task-context.js +13 -0
  818. package/dist/tasks/task-context.js.map +1 -1
  819. package/dist/tasks/task-import.d.ts.map +1 -1
  820. package/dist/tasks/task-import.js +21 -12
  821. package/dist/tasks/task-import.js.map +1 -1
  822. package/dist/tasks/task-next.d.ts +25 -2
  823. package/dist/tasks/task-next.d.ts.map +1 -1
  824. package/dist/tasks/task-next.js +32 -13
  825. package/dist/tasks/task-next.js.map +1 -1
  826. package/dist/tasks/update.d.ts.map +1 -1
  827. package/dist/tasks/update.js +7 -5
  828. package/dist/tasks/update.js.map +1 -1
  829. package/dist/upgrade.d.ts +1 -1
  830. package/dist/upgrade.d.ts.map +1 -1
  831. package/dist/upgrade.js +48 -9
  832. package/dist/upgrade.js.map +1 -1
  833. package/dist/validation/compliance.d.ts +5 -1
  834. package/dist/validation/compliance.d.ts.map +1 -1
  835. package/dist/validation/compliance.js +24 -3
  836. package/dist/validation/compliance.js.map +1 -1
  837. package/dist/validation/doctor/checks.d.ts +20 -6
  838. package/dist/validation/doctor/checks.d.ts.map +1 -1
  839. package/dist/validation/doctor/checks.js +51 -8
  840. package/dist/validation/doctor/checks.js.map +1 -1
  841. package/dist/validation/index.d.ts +1 -1
  842. package/dist/validation/index.d.ts.map +1 -1
  843. package/dist/validation/index.js +1 -1
  844. package/dist/validation/index.js.map +1 -1
  845. package/dist/validation/protocol-common.d.ts +47 -2
  846. package/dist/validation/protocol-common.d.ts.map +1 -1
  847. package/dist/validation/protocol-common.js +86 -21
  848. package/dist/validation/protocol-common.js.map +1 -1
  849. package/dist/validation/validate-ops.d.ts.map +1 -1
  850. package/dist/validation/validate-ops.js +2 -3
  851. package/dist/validation/validate-ops.js.map +1 -1
  852. package/migrations/README.md +12 -0
  853. package/migrations/drizzle-cleo-global/20260929010000_t12512-registry-probed-opened/migration.sql +35 -0
  854. package/migrations/drizzle-cleo-global/20260929020000_t12721-git-state-head-committed-at/migration.sql +25 -0
  855. package/migrations/drizzle-cleo-project/20260928120000_t12341-row-uids/migration.sql +169 -0
  856. package/migrations/drizzle-cleo-project/20260929000000_t12535-docs-attachments-union-shape/migration.sql +21 -0
  857. package/migrations/drizzle-cleo-project/20260929120000_t12502-task-claim-leases/migration.sql +77 -0
  858. package/migrations/drizzle-cleo-project/20260929130000_t12736-claim-lease-iso-repair/migration.sql +37 -0
  859. package/migrations/sync-journal/20260929140000_t12342-sync-clock/migration.sql +42 -0
  860. package/package.json +23 -13
  861. package/schemas/project-info.schema.json +10 -4
  862. package/templates/CLEO-INJECTION.md +1 -1
  863. package/templates/CLEO-REFERENCE.md +7 -3
  864. package/templates/cleo-gitignore +11 -0
  865. package/templates/workflows/release-prepare.yml.tmpl +156 -10
@@ -12,21 +12,26 @@
12
12
  */
13
13
  import { AsyncLocalStorage } from 'node:async_hooks';
14
14
  import { resolve } from 'node:path';
15
- import { ARCHIVE_REASON_TOMBSTONE, } from '@cleocode/contracts';
16
- import { and, eq, getTableColumns, inArray, isNull, like, ne, notInArray, or, sql, } from 'drizzle-orm';
15
+ import { ARCHIVE_REASON_TOMBSTONE, ExitCode, } from '@cleocode/contracts';
16
+ import { and, eq, getTableColumns, inArray, isNull, like, lte, ne, notInArray, or, sql, } from 'drizzle-orm';
17
+ import { CleoError } from '../errors.js';
17
18
  import { captureProjectScope as captureTaskAccessorScope, getProjectRoot, worktreeScope, } from '../project-scope.js';
19
+ import { acTextHash, buildAcRowId } from '../tasks/ac-table.js';
20
+ import { generateAuditLogId, pruneAcBindingsForAcIds, pruneAcBindingsForTask, pruneOrphanAcBindings, selectOrphanAcBindings, } from './ac-binding-prune.js';
18
21
  import { withBackgroundOpCommitBoundary } from './background-ops.js';
19
22
  import { archivedTaskToRow, rowToSession, rowToTask, taskToRow } from './converters.js';
20
23
  import { cleanupBrainRefsOnSessionDelete } from './cross-db-cleanup.js';
21
- import { batchUpdateDependencies, loadDependenciesForTasks, loadRelationsForTasks, parseLabels, updateDependencies, updateTaskLabels, upsertSession, upsertTask, } from './db-helpers.js';
24
+ import { batchUpdateDependencies, insertNewTask, loadDependenciesForTasks, loadRelationsForTasks, parseLabels, updateDependencies, updateTaskLabels, upsertSession, upsertTask, } from './db-helpers.js';
25
+ import { registerRowIdentityWriters } from './row-identity.js';
22
26
  import { tasksAuditLog } from './schema/cleo-project/audit.js';
23
27
  import { resolveCurrentSession } from './session-store.js';
24
28
  import { closeDb, getDb, getNativeTasksDb } from './sqlite.js';
25
29
  import { TERMINAL_TASK_STATUSES } from './status-registry.js';
26
- import { assertTaskVersion, nextTaskVersion } from './task-version.js';
30
+ import { claimAllows, claimColumnsOf, claimFromColumns, isClaimExpired, leaseExpiresAtFrom, taskClaimedError, taskClaimLeaseMs, } from './task-claim.js';
31
+ import { nextTaskVersion, taskConflictError, taskVersion } from './task-version.js';
27
32
  import * as schema from './tasks-schema.js';
28
33
  import { assertTwinCollapseWritable, bareCounterOf, mirrorCounterToBare } from './twin-collapse.js';
29
- import { withWriteRetry } from './with-retry.js';
34
+ import { runHeartbeatWrite, withWriteRetry } from './with-retry.js';
30
35
  /**
31
36
  * Per-process monotonic counter for unique nested SAVEPOINT names (T9814).
32
37
  * Only used when DataAccessor.transaction() is called from within an
@@ -35,13 +40,67 @@ import { withWriteRetry } from './with-retry.js';
35
40
  */
36
41
  let _txSavepointCounter = 0;
37
42
  /**
38
- * Generate a unique audit log entry ID.
39
- * @task T4837
43
+ * Evidence bindings for a set of CURRENT AC ids (T12341).
44
+ *
45
+ * A binding is matched through the criterion's uid (`ac_uid`), which survives
46
+ * an AC edit, and falls back to `ac_id` for a binding whose uid is not filled.
47
+ * A binding recorded against an older text of a criterion is reported under
48
+ * the criterion's current id, so callers keyed by AC id keep working, and is
49
+ * marked `stale` when the text hash it recorded (`ac_text_hash`) differs from
50
+ * the criterion's current text: evidence for different text never satisfies a
51
+ * gate (spec §8.2).
40
52
  */
41
- function generateAuditLogId() {
42
- const epoch = Math.floor(Date.now() / 1000);
43
- const rand = Math.random().toString(36).slice(2, 8);
44
- return `log-${epoch}-${rand}`;
53
+ async function selectAcBindings(db, acIds) {
54
+ if (acIds.length === 0)
55
+ return [];
56
+ const b = schema.evidenceAcBindings;
57
+ const ac = schema.taskAcceptanceCriteria;
58
+ const ids = acIds;
59
+ const columns = {
60
+ id: b.id,
61
+ evidenceAtomId: b.evidenceAtomId,
62
+ acId: b.acId,
63
+ currentAcId: ac.id,
64
+ currentAcText: ac.text,
65
+ recordedTextHash: b.acTextHash,
66
+ bindingType: b.bindingType,
67
+ createdAt: b.createdAt,
68
+ };
69
+ // Two indexed lookups rather than one OR across the join: by the current
70
+ // criterion's uid, then by the recorded ac_id.
71
+ const byUid = await db
72
+ .select(columns)
73
+ .from(b)
74
+ .innerJoin(ac, eq(ac.uid, b.acUid))
75
+ .where(inArray(ac.id, ids))
76
+ .all();
77
+ const byId = await db
78
+ .select(columns)
79
+ .from(b)
80
+ .leftJoin(ac, eq(ac.uid, b.acUid))
81
+ .where(inArray(b.acId, ids))
82
+ .all();
83
+ const rows = [...byUid, ...byId];
84
+ const wanted = new Set(ids);
85
+ const seen = new Set();
86
+ const out = [];
87
+ for (const r of rows) {
88
+ if (seen.has(r.id))
89
+ continue;
90
+ seen.add(r.id);
91
+ const stale = r.recordedTextHash !== null &&
92
+ r.currentAcText !== null &&
93
+ acTextHash(r.currentAcText) !== r.recordedTextHash;
94
+ out.push({
95
+ id: r.id,
96
+ evidenceAtomId: r.evidenceAtomId,
97
+ acId: r.currentAcId && wanted.has(r.currentAcId) ? r.currentAcId : r.acId,
98
+ bindingType: r.bindingType,
99
+ createdAt: r.createdAt,
100
+ ...(stale ? { stale: true } : {}),
101
+ });
102
+ }
103
+ return out;
45
104
  }
46
105
  // ---- Schema meta helpers ----
47
106
  /** Read a JSON blob from the schema_meta table by key. */
@@ -70,7 +129,7 @@ export async function setMetaValue(cwd, key, value) {
70
129
  async function writeMetaValue(cwd, key, value) {
71
130
  const db = await getDb(cwd);
72
131
  // T12535: fail fast on a store degraded by a failed twin collapse.
73
- assertTwinCollapseWritable(getNativeTasksDb(cwd));
132
+ assertTwinCollapseWritable(getNativeTasksDb(cwd), 'schema_meta');
74
133
  const json = JSON.stringify(value);
75
134
  await db
76
135
  .insert(schema.schemaMeta)
@@ -105,7 +164,7 @@ async function writeMetaValue(cwd, key, value) {
105
164
  * @task T12535
106
165
  */
107
166
  export function advanceTaskIdSequence(nativeDb, floor) {
108
- assertTwinCollapseWritable(nativeDb);
167
+ assertTwinCollapseWritable(nativeDb, 'schema_meta');
109
168
  // T12535: an id the older build reserved in the bare counter is taken too.
110
169
  const lowest = Math.max(floor, bareCounterOf(nativeDb, 'task_id_sequence'));
111
170
  nativeDb
@@ -130,6 +189,398 @@ export function advanceTaskIdSequence(nativeDb, floor) {
130
189
  .get();
131
190
  return row?.counter;
132
191
  }
192
+ /**
193
+ * Give the task with `uid` the display id `toId`: a compare-and-set on the
194
+ * stored version AND claim lease that advances the version (so a stale
195
+ * `--if-match` writer fails, #1698), with the claim columns carried unchanged
196
+ * (#1701), then every local reference rewritten. Runs in the caller's
197
+ * transaction with foreign keys deferred to its commit.
198
+ *
199
+ * A collision re-mint is a system write: it passes no claim guard and never
200
+ * takes or drops a lease, but the version bump makes the lease holder's next
201
+ * guarded write re-read. A caller acting for a session (a manual rename)
202
+ * passes `guard`: `expectedUpdatedAt` fails with `E_CONFLICT` when the task
203
+ * moved on, `claim` fails with `E_TASK_CLAIMED` when another session holds it.
204
+ *
205
+ * @param nativeDb - The project `cleo.db` handle holding the transaction.
206
+ * @param uid - Uid of the task to rename.
207
+ * @param toId - Its new display id.
208
+ * @param refs - Columns that hold task display ids.
209
+ * @param guard - Optional version / claim guard.
210
+ * @returns The id it had and the rows rewritten per `table.column`.
211
+ * @task T12341
212
+ * @task T12748
213
+ */
214
+ export function renameTaskDisplayIdNative(nativeDb, uid, toId, refs, guard = {}) {
215
+ const current = nativeDb
216
+ .prepare(`SELECT id, updated_at AS updatedAt, created_at AS createdAt,
217
+ claimed_by_session AS claimedBySession, claimed_by_agent AS claimedByAgent,
218
+ claimed_at AS claimedAt, lease_expires_at AS leaseExpiresAt
219
+ FROM tasks_tasks WHERE uid = ?`)
220
+ .get(uid);
221
+ if (!current)
222
+ throw new Error(`No task with uid ${uid}`);
223
+ if (guard.expectedUpdatedAt !== undefined && guard.expectedUpdatedAt !== taskVersion(current)) {
224
+ throw taskConflictError(current.id, guard.expectedUpdatedAt, current);
225
+ }
226
+ if (guard.claim)
227
+ assertClaimAllowed(current.id, current, guard.claim, []);
228
+ nativeDb.exec('PRAGMA defer_foreign_keys = ON');
229
+ const changed = nativeDb
230
+ .prepare(`UPDATE tasks_tasks SET id = ?, updated_at = ?
231
+ WHERE uid = ? AND id = ? AND updated_at IS ? AND claimed_by_session IS ?
232
+ AND lease_expires_at IS ?`)
233
+ .run(toId, nextTaskVersion(current), uid, current.id, current.updatedAt, current.claimedBySession, current.leaseExpiresAt).changes;
234
+ if (Number(changed) !== 1) {
235
+ throw taskConflictError(current.id, taskVersion(current), null);
236
+ }
237
+ const rewritten = {};
238
+ const q = (name) => `"${name.replaceAll('"', '""')}"`;
239
+ for (const ref of refs) {
240
+ const table = `main.${q(ref.table)}`;
241
+ const col = q(ref.column);
242
+ const n = ref.jsonArray
243
+ ? nativeDb
244
+ .prepare(`UPDATE ${table} SET ${col} = (
245
+ SELECT json_group_array(CASE WHEN j.value = ? THEN ? ELSE j.value END)
246
+ FROM json_each(${table}.${col}) j)
247
+ WHERE json_valid(${col}) AND EXISTS (
248
+ SELECT 1 FROM json_each(${table}.${col}) j WHERE j.value = ?)`)
249
+ .run(current.id, toId, current.id).changes
250
+ : nativeDb.prepare(`UPDATE ${table} SET ${col} = ? WHERE ${col} = ?`).run(toId, current.id)
251
+ .changes;
252
+ if (Number(n) > 0)
253
+ rewritten[`${ref.table}.${ref.column}`] = Number(n);
254
+ }
255
+ for (const [key, n] of Object.entries(rederiveAcIdsNative(nativeDb, current.id, toId))) {
256
+ if (n > 0)
257
+ rewritten[key] = n;
258
+ }
259
+ return { fromId: current.id, rewritten };
260
+ }
261
+ /**
262
+ * After a task's display id changed from `fromId` to `toId`, re-derive the
263
+ * ids of the acceptance criteria derived from it (`buildAcRowId(taskId,
264
+ * identity)`): the task's own criteria, and a parent's child-projection
265
+ * criteria (`child:<id>`, whose source key is rewritten too). The binding and
266
+ * history rows that point at a re-derived id follow. A criterion whose id was
267
+ * not derived from the old id (an explicit id) keeps it. Without this, two
268
+ * tasks that once shared a display id keep identical ids for same-text
269
+ * criteria ("tests pass") and collide on every merge (T12799).
270
+ *
271
+ * @param nativeDb - The project `cleo.db` handle, inside the rename's transaction.
272
+ * @param fromId - The task's old display id.
273
+ * @param toId - Its new display id (the task row already carries it).
274
+ * @returns Rows rewritten per `table.column`.
275
+ * @task T12799
276
+ */
277
+ export function rederiveAcIdsNative(nativeDb, fromId, toId) {
278
+ const count = {};
279
+ const bump = (key, n) => {
280
+ count[key] = (count[key] ?? 0) + Number(n);
281
+ };
282
+ const has = (table) => nativeDb
283
+ .prepare("SELECT 1 AS x FROM sqlite_master WHERE type = 'table' AND name = ?")
284
+ .get(table) !== undefined;
285
+ if (!has('tasks_task_acceptance_criteria'))
286
+ return count;
287
+ const oldChild = `child:${fromId}`;
288
+ const rows = nativeDb
289
+ .prepare(`SELECT id, task_id AS taskId, kind, text, source_key AS sourceKey
290
+ FROM tasks_task_acceptance_criteria WHERE task_id = ? OR source_key = ?`)
291
+ .all(toId, oldChild);
292
+ const followers = ['tasks_evidence_ac_bindings', 'tasks_task_acceptance_criteria_history'].filter(has);
293
+ for (const row of rows) {
294
+ const ownerBefore = row.taskId === toId ? fromId : row.taskId;
295
+ const sourceAfter = row.sourceKey === oldChild ? `child:${toId}` : row.sourceKey;
296
+ const identity = (source) => (row.kind === 'text' ? row.text : (source ?? ''));
297
+ const derived = row.id === buildAcRowId(ownerBefore, identity(row.sourceKey));
298
+ const newId = derived ? buildAcRowId(row.taskId, identity(sourceAfter)) : row.id;
299
+ if (newId === row.id && sourceAfter === row.sourceKey)
300
+ continue;
301
+ bump('tasks_task_acceptance_criteria.id', nativeDb
302
+ .prepare('UPDATE tasks_task_acceptance_criteria SET id = ?, source_key = ? WHERE id = ?')
303
+ .run(newId, sourceAfter, row.id).changes);
304
+ if (newId === row.id)
305
+ continue;
306
+ for (const table of followers) {
307
+ bump(`${table}.ac_id`, nativeDb.prepare(`UPDATE ${table} SET ac_id = ? WHERE ac_id = ?`).run(newId, row.id)
308
+ .changes);
309
+ }
310
+ }
311
+ return count;
312
+ }
313
+ /**
314
+ * Insert a display-id alias row (idempotent on its uid).
315
+ *
316
+ * @param nativeDb - The project `cleo.db` handle.
317
+ * @param row - The alias.
318
+ * @task T12341
319
+ */
320
+ export function insertDisplayIdAliasNative(nativeDb, row) {
321
+ nativeDb
322
+ .prepare(`INSERT OR IGNORE INTO tasks_display_id_aliases
323
+ (uid, entity_table, display_id, entity_uid, reason, origin, displaced_hlc, created_at,
324
+ entity_birth_fp)
325
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
326
+ .run(row.uid, row.entityTable, row.displayId, row.entityUid, row.reason, row.origin, row.displacedHlc, row.createdAt, row.entityBirthFp);
327
+ }
328
+ /**
329
+ * Delete one display-id alias row (a local alias whose entity was re-keyed is
330
+ * re-inserted under its new entity uid by the caller).
331
+ *
332
+ * @param nativeDb - The project `cleo.db` handle.
333
+ * @param uid - The alias row's uid.
334
+ * @task T12341
335
+ */
336
+ export function deleteDisplayIdAliasNative(nativeDb, uid) {
337
+ nativeDb.prepare('DELETE FROM tasks_display_id_aliases WHERE uid = ?').run(uid);
338
+ }
339
+ /**
340
+ * Insert a uid re-key alias row (idempotent on its uid).
341
+ *
342
+ * @param nativeDb - The project `cleo.db` handle.
343
+ * @param row - The alias.
344
+ * @task T12341
345
+ */
346
+ export function insertUidAliasNative(nativeDb, row) {
347
+ nativeDb
348
+ .prepare(`INSERT OR IGNORE INTO tasks_uid_aliases
349
+ (uid, entity_table, old_uid, old_birth_fp, new_uid, origin, displaced_hlc, created_at)
350
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
351
+ .run(row.uid, row.entityTable, row.oldUid, row.oldBirthFp, row.newUid, row.origin, row.displacedHlc, row.createdAt);
352
+ }
353
+ /**
354
+ * Hold an incoming row the merge cannot place yet (replacing an older hold of
355
+ * the same row).
356
+ *
357
+ * @param nativeDb - The project `cleo.db` handle.
358
+ * @param row - The held row.
359
+ * @task T12341
360
+ */
361
+ export function insertQuarantineNative(nativeDb, row) {
362
+ nativeDb
363
+ .prepare(`INSERT INTO tasks_identity_quarantine
364
+ (entity_table, uid, birth_fp, reason, contested_id, row_json, received_hlc, created_at)
365
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
366
+ ON CONFLICT(entity_table, uid, birth_fp) DO UPDATE SET
367
+ reason = excluded.reason, contested_id = excluded.contested_id,
368
+ row_json = excluded.row_json, received_hlc = excluded.received_hlc,
369
+ created_at = excluded.created_at`)
370
+ .run(row.entityTable, row.uid, row.birthFp, row.reason, row.contestedId, row.rowJson, row.receivedHlc, row.createdAt);
371
+ }
372
+ /**
373
+ * Drop a held row (released or superseded).
374
+ *
375
+ * @param nativeDb - The project `cleo.db` handle.
376
+ * @param key - The held row's table, uid and birth fingerprint.
377
+ * @task T12341
378
+ */
379
+ export function deleteQuarantineNative(nativeDb, key) {
380
+ nativeDb
381
+ .prepare('DELETE FROM tasks_identity_quarantine WHERE entity_table = ? AND uid = ? AND birth_fp = ?')
382
+ .run(key.entityTable, key.uid, key.birthFp);
383
+ }
384
+ /**
385
+ * Write a row-identity meta value (the recipe marker, a re-mint record).
386
+ *
387
+ * @param nativeDb - The project `cleo.db` handle.
388
+ * @param key - Meta key.
389
+ * @param value - Meta value.
390
+ * @task T12341
391
+ */
392
+ export function writeRowIdentityMetaNative(nativeDb, key, value) {
393
+ nativeDb
394
+ .prepare(`INSERT INTO tasks_row_identity_meta (key, value) VALUES (?, ?)
395
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value`)
396
+ .run(key, value);
397
+ }
398
+ /**
399
+ * Hand a criterion back the uid its deleted predecessor carried (AC uid
400
+ * graveyard re-link, spec §6.5), with that predecessor's birth fingerprint.
401
+ *
402
+ * @param nativeDb - The project `cleo.db` handle.
403
+ * @param acId - The criterion to re-link (its uid is NULL).
404
+ * @param uid - The uid to hand back.
405
+ * @param birthFp - The fingerprint that goes with it, when recorded.
406
+ * @returns Rows changed (0 or 1).
407
+ * @task T12341
408
+ */
409
+ export function relinkAcUidNative(nativeDb, acId, uid, birthFp) {
410
+ return Number(nativeDb
411
+ .prepare('UPDATE tasks_task_acceptance_criteria SET uid = ?, birth_fp = COALESCE(?, birth_fp) WHERE id = ? AND uid IS NULL')
412
+ .run(uid, birthFp, acId).changes);
413
+ }
414
+ /**
415
+ * Empty the AC uid graveyard (after the open pass consumed it).
416
+ *
417
+ * @param nativeDb - The project `cleo.db` handle.
418
+ * @task T12341
419
+ */
420
+ export function clearAcUidGraveyardNative(nativeDb) {
421
+ nativeDb.exec('DELETE FROM tasks_ac_uid_graveyard');
422
+ }
423
+ /** Quote an identifier for the dynamic row-identity writes below. */
424
+ function quoteIdent(name) {
425
+ return `"${name.replaceAll('"', '""')}"`;
426
+ }
427
+ /**
428
+ * Fill a NULL identity column (`uid`, `birth_fp`, a stored reference uid) of a
429
+ * declared table from its recipe SQL (the row-uid open pass, spec §6.1).
430
+ *
431
+ * @param nativeDb - The `cleo.db` handle holding the cold-open lease.
432
+ * @param table - Declared table.
433
+ * @param column - Identity column.
434
+ * @param valueSql - Recipe expression over `main."<table>"` columns.
435
+ * @param rowid - One row only (the clash fallback); all NULL rows otherwise.
436
+ * @returns Rows written.
437
+ * @task T12341
438
+ */
439
+ export function fillIdentityColumnNative(nativeDb, table, column, valueSql, rowid) {
440
+ const col = quoteIdent(column);
441
+ const sql = `UPDATE main.${quoteIdent(table)} SET ${col} = ${valueSql} WHERE ${col} IS NULL`;
442
+ const changes = rowid === undefined
443
+ ? nativeDb.prepare(sql).run().changes
444
+ : nativeDb.prepare(`${sql} AND rowid = ?`).run(rowid).changes;
445
+ return Number(changes);
446
+ }
447
+ /**
448
+ * Clear one pre-release birth fingerprint so the fill re-derives it (spec §12.1).
449
+ *
450
+ * @param nativeDb - The `cleo.db` handle holding the cold-open lease.
451
+ * @param table - Declared minted table.
452
+ * @param rowid - The row.
453
+ * @task T12341
454
+ */
455
+ export function clearBirthFpNative(nativeDb, table, rowid) {
456
+ nativeDb
457
+ .prepare(`UPDATE main.${quoteIdent(table)} SET birth_fp = NULL WHERE rowid = ?`)
458
+ .run(rowid);
459
+ }
460
+ /**
461
+ * Insert one row into a declared identity table, with the columns the row
462
+ * carries that the table has (a row released from the identity quarantine).
463
+ *
464
+ * @param nativeDb - The project `cleo.db` handle.
465
+ * @param table - Declared table.
466
+ * @param row - Column → value.
467
+ * @task T12341
468
+ */
469
+ export function insertIdentityRowNative(nativeDb, table, row) {
470
+ const have = new Set(nativeDb.prepare('SELECT name FROM pragma_table_info(?)').all(table).map((c) => c.name));
471
+ const cols = Object.keys(row).filter((c) => have.has(c));
472
+ nativeDb
473
+ .prepare(`INSERT INTO main.${quoteIdent(table)} (${cols.map(quoteIdent).join(', ')}) VALUES (${cols
474
+ .map(() => '?')
475
+ .join(', ')})`)
476
+ .run(...cols.map((c) => row[c] ?? null));
477
+ }
478
+ /**
479
+ * Give the row of `table` identified by (`oldUid`, `birthFp`) the uid
480
+ * `newUid` (a uid re-key; the birth fingerprint never changes).
481
+ *
482
+ * @param nativeDb - The project `cleo.db` handle.
483
+ * @param table - Declared minted table.
484
+ * @param oldUid - The colliding uid.
485
+ * @param birthFp - The row's birth fingerprint.
486
+ * @param newUid - Its new uid.
487
+ * @returns Rows changed (0 or 1).
488
+ * @task T12341
489
+ */
490
+ export function setRowUidNative(nativeDb, table, oldUid, birthFp, newUid) {
491
+ return Number(nativeDb
492
+ .prepare(`UPDATE main.${quoteIdent(table)} SET uid = ? WHERE uid = ? AND birth_fp = ?`)
493
+ .run(newUid, oldUid, birthFp).changes);
494
+ }
495
+ /**
496
+ * Point a stored reference uid column (`ac_uid`) of the rows that reference
497
+ * the re-keyed row by key at its new uid. Scoped by the key column, so a row
498
+ * referencing the OTHER holder of a colliding uid is never touched.
499
+ *
500
+ * @param nativeDb - The project `cleo.db` handle.
501
+ * @param table - Table holding the column.
502
+ * @param column - The stored reference uid column.
503
+ * @param fromColumn - The column that references the row by key (`ac_id`).
504
+ * @param key - The re-keyed row's local key.
505
+ * @param oldUid - Old referenced uid.
506
+ * @param newUid - New referenced uid.
507
+ * @returns Rows changed.
508
+ * @task T12341
509
+ */
510
+ export function rewriteStoredRefUidNative(nativeDb, table, column, fromColumn, key, oldUid, newUid) {
511
+ const col = quoteIdent(column);
512
+ return Number(nativeDb
513
+ .prepare(`UPDATE main.${quoteIdent(table)} SET ${col} = ? WHERE ${col} = ? AND ${quoteIdent(fromColumn)} = ?`)
514
+ .run(newUid, oldUid, key).changes);
515
+ }
516
+ /**
517
+ * Clear one row's uid so the natural recipe re-derives it (a uid re-key
518
+ * changed an endpoint's uid).
519
+ *
520
+ * @param nativeDb - The project `cleo.db` handle.
521
+ * @param table - Declared natural table.
522
+ * @param rowid - The row.
523
+ * @task T12341
524
+ */
525
+ export function clearRowUidNative(nativeDb, table, rowid) {
526
+ nativeDb.prepare(`UPDATE main.${quoteIdent(table)} SET uid = NULL WHERE rowid = ?`).run(rowid);
527
+ }
528
+ /**
529
+ * Delete a row-identity meta value (a re-mint record that moved with a re-key).
530
+ *
531
+ * @param nativeDb - The project `cleo.db` handle.
532
+ * @param key - Meta key.
533
+ * @task T12341
534
+ */
535
+ export function deleteRowIdentityMetaNative(nativeDb, key) {
536
+ nativeDb.prepare('DELETE FROM tasks_row_identity_meta WHERE key = ?').run(key);
537
+ }
538
+ /**
539
+ * Set a natural row's uid by its current uid (a re-key re-derives the natural
540
+ * uids keyed by the re-keyed row; a receiver applies the published values).
541
+ *
542
+ * @param nativeDb - The project `cleo.db` handle.
543
+ * @param table - Declared natural table.
544
+ * @param oldUid - Current uid.
545
+ * @param newUid - New uid.
546
+ * @returns Rows changed.
547
+ * @task T12341
548
+ */
549
+ export function setNaturalUidNative(nativeDb, table, oldUid, newUid) {
550
+ return Number(nativeDb
551
+ .prepare(`UPDATE main.${quoteIdent(table)} SET uid = ? WHERE uid = ?`)
552
+ .run(newUid, oldUid).changes);
553
+ }
554
+ /**
555
+ * Rewrite a held row (identity quarantine) under a new uid: a uid re-key of a
556
+ * row this replica holds but has not placed.
557
+ *
558
+ * @param nativeDb - The project `cleo.db` handle.
559
+ * @param key - The held row's table, uid and birth fingerprint.
560
+ * @param newUid - Its new uid.
561
+ * @param rowJson - Its wire form with the new uid.
562
+ * @task T12341
563
+ */
564
+ export function rekeyQuarantineNative(nativeDb, key, newUid, rowJson) {
565
+ nativeDb
566
+ .prepare(`UPDATE tasks_identity_quarantine SET uid = ?, row_json = ?
567
+ WHERE entity_table = ? AND uid = ? AND birth_fp = ?`)
568
+ .run(newUid, rowJson, key.entityTable, key.uid, key.birthFp);
569
+ }
570
+ /**
571
+ * Add labels to a task's label junction (idempotent), for writers that
572
+ * insert a task with raw SQL (the sentient proposal ticks).
573
+ *
574
+ * @param nativeDb - The project `cleo.db` handle.
575
+ * @param taskId - The task.
576
+ * @param labels - Labels to add.
577
+ * @task T12341
578
+ */
579
+ export function addTaskLabelsNative(nativeDb, taskId, labels) {
580
+ const stmt = nativeDb.prepare('INSERT OR IGNORE INTO tasks_task_labels (task_id, label) VALUES (?, ?)');
581
+ for (const label of labels)
582
+ stmt.run(taskId, label);
583
+ }
133
584
  // One queue per shared native handle, independent of accessor identity. These
134
585
  // hold coordination state only; the ProjectStore remains the owner of handles.
135
586
  const taskTransactionQueue = new WeakMap();
@@ -189,6 +640,87 @@ async function scheduleTaskBackground(native, work) {
189
640
  * ```
190
641
  */
191
642
  export { captureProjectScope as captureTaskAccessorScope } from '../project-scope.js';
643
+ /** The claim lease columns, selected alongside a row's version (T12502). */
644
+ const CLAIM_COLUMNS = {
645
+ claimedBySession: schema.tasks.claimedBySession,
646
+ claimedByAgent: schema.tasks.claimedByAgent,
647
+ claimedAt: schema.tasks.claimedAt,
648
+ leaseExpiresAt: schema.tasks.leaseExpiresAt,
649
+ };
650
+ /**
651
+ * The claim compare-and-set predicate for an UPDATE's WHERE clause (T12502).
652
+ * The SQL mirror of `claimAllows`; `force` adds no predicate.
653
+ *
654
+ * @param guard - The claim guard.
655
+ * @param allowedHolders - Holders `acquire` / `take-over` may replace even
656
+ * while live (hand-off source, spawn-edge parent and children).
657
+ */
658
+ function claimPredicate(guard, allowedHolders) {
659
+ const holder = schema.tasks.claimedBySession;
660
+ if (guard.mode === 'force')
661
+ return undefined;
662
+ const mine = guard.sessionId === null ? undefined : eq(holder, guard.sessionId);
663
+ if (guard.mode === 'renew' || guard.mode === 'release')
664
+ return mine ?? sql `0`;
665
+ const related = allowedHolders.length > 0 ? inArray(holder, [...allowedHolders]) : undefined;
666
+ const expired = guard.mode === 'take-over'
667
+ ? or(isNull(schema.tasks.leaseExpiresAt), lte(schema.tasks.leaseExpiresAt, guard.now))
668
+ : undefined;
669
+ return or(isNull(holder), mine, related, expired);
670
+ }
671
+ /** Throw `E_TASK_CLAIMED` when the stored holder refuses this claim write. */
672
+ function assertClaimAllowed(taskId, row, guard, allowedHolders) {
673
+ const stored = claimFromColumns(row);
674
+ if (claimAllows(stored, guard.mode, guard.sessionId, guard.now, allowedHolders))
675
+ return;
676
+ if (!stored) {
677
+ throw new CleoError(ExitCode.NOT_FOUND, `Task ${taskId} has no claim held by session ${guard.sessionId ?? '(unbound)'} to ${guard.mode}`, { fix: `Take the claim first: cleo claim ${taskId}` });
678
+ }
679
+ throw taskClaimedError(taskId, stored, { sessionId: guard.sessionId, agentId: null }, guard.now);
680
+ }
681
+ /**
682
+ * The holders an `acquire` / `take-over` claim write may replace even while
683
+ * their lease is live (T12502): the explicit hand-off source, plus the
684
+ * caller's claim family — the session that spawned it and the sessions it
685
+ * spawned (`tasks_sessions.spawned_by_session_id`, written only by the spawn
686
+ * itself). The self-declared `parent_session_id` (from
687
+ * `CLEO_PARENT_SESSION_ID` at `session start`) is NOT trusted here: any
688
+ * process can name any parent, so honouring it would let a forged child take
689
+ * a live lease silently. A spawned worker whose calls
690
+ * resolve to its orchestrator's session, or an orchestrator taking a task
691
+ * back from its own worker, is a hand-off, not a conflict.
692
+ *
693
+ * @param db - The project DB handle (inside the write transaction).
694
+ * @param guard - The claim guard.
695
+ * @returns Distinct session ids other than the caller's.
696
+ */
697
+ async function claimAllowedHolders(db, guard) {
698
+ if (guard.mode !== 'acquire' && guard.mode !== 'take-over')
699
+ return [];
700
+ const holders = new Set();
701
+ if (guard.handoffFrom)
702
+ holders.add(guard.handoffFrom);
703
+ const sessionId = guard.sessionId;
704
+ if (sessionId) {
705
+ const [self] = await db
706
+ .select({ parent: schema.sessions.spawnedBySessionId })
707
+ .from(schema.sessions)
708
+ .where(eq(schema.sessions.id, sessionId))
709
+ .limit(1)
710
+ .all();
711
+ if (self?.parent)
712
+ holders.add(self.parent);
713
+ const children = await db
714
+ .select({ id: schema.sessions.id })
715
+ .from(schema.sessions)
716
+ .where(eq(schema.sessions.spawnedBySessionId, sessionId))
717
+ .all();
718
+ for (const child of children)
719
+ holders.add(child.id);
720
+ holders.delete(sessionId);
721
+ }
722
+ return [...holders];
723
+ }
192
724
  /**
193
725
  * Bind all asynchronous accessor methods, including transaction ports, to one project.
194
726
  * @typeParam T - Concrete accessor contract retained by the scoped wrapper.
@@ -445,6 +977,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
445
977
  async upsertSingleTask(task) {
446
978
  await accessor.transaction((tx) => tx.upsertSingleTask(task));
447
979
  },
980
+ async insertNewTask(task) {
981
+ await accessor.transaction((tx) => tx.insertNewTask(task));
982
+ },
448
983
  async addRelation(taskId, relatedTo, relationType, reason) {
449
984
  return accessor.transaction(async () => {
450
985
  const db = await getDb(cwd);
@@ -521,6 +1056,8 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
521
1056
  createdAt: schema.taskAcceptanceCriteria.createdAt,
522
1057
  updatedAt: schema.taskAcceptanceCriteria.updatedAt,
523
1058
  contentHash: schema.taskAcceptanceCriteria.contentHash,
1059
+ uid: schema.taskAcceptanceCriteria.uid,
1060
+ birthFp: schema.taskAcceptanceCriteria.birthFp,
524
1061
  })
525
1062
  .from(schema.taskAcceptanceCriteria)
526
1063
  .where(eq(schema.taskAcceptanceCriteria.taskId, taskId))
@@ -538,31 +1075,20 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
538
1075
  createdAt: r.createdAt,
539
1076
  updatedAt: r.updatedAt ?? null,
540
1077
  contentHash: r.contentHash ?? null,
1078
+ uid: r.uid ?? null,
1079
+ birthFp: r.birthFp ?? null,
541
1080
  }));
542
1081
  },
543
1082
  // ---- AC bindings (T10509 — AC-coverage gate) ----
544
1083
  async getAcBindings(acIds) {
545
1084
  if (acIds.length === 0)
546
1085
  return [];
1086
+ return selectAcBindings(await getDb(cwd), acIds);
1087
+ },
1088
+ // ---- AC bindings — orphan scan (T12790) ----
1089
+ async findOrphanAcBindings() {
547
1090
  const db = await getDb(cwd);
548
- const rows = await db
549
- .select({
550
- id: schema.evidenceAcBindings.id,
551
- evidenceAtomId: schema.evidenceAcBindings.evidenceAtomId,
552
- acId: schema.evidenceAcBindings.acId,
553
- bindingType: schema.evidenceAcBindings.bindingType,
554
- createdAt: schema.evidenceAcBindings.createdAt,
555
- })
556
- .from(schema.evidenceAcBindings)
557
- .where(inArray(schema.evidenceAcBindings.acId, acIds))
558
- .all();
559
- return rows.map((r) => ({
560
- id: r.id,
561
- evidenceAtomId: r.evidenceAtomId,
562
- acId: r.acId,
563
- bindingType: r.bindingType,
564
- createdAt: r.createdAt,
565
- }));
1091
+ return selectOrphanAcBindings(db);
566
1092
  },
567
1093
  async archiveSingleTask(taskId, fields) {
568
1094
  return accessor.transaction(async () => {
@@ -606,6 +1132,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
606
1132
  .delete(schema.taskDependencies)
607
1133
  .where(eq(schema.taskDependencies.dependsOn, taskId))
608
1134
  .run();
1135
+ // T12790: the bindings table has no FK to the AC rows that cascade
1136
+ // from tasks_tasks — remove (and audit) them explicitly.
1137
+ await pruneAcBindingsForTask(db, taskId);
609
1138
  // Delete the task itself
610
1139
  await db.delete(schema.tasks).where(eq(schema.tasks.id, taskId)).run();
611
1140
  });
@@ -1018,24 +1547,54 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1018
1547
  // E_CONFLICT, and advance the version strictly so a same-millisecond
1019
1548
  // write can never reproduce a version a stale reader already holds.
1020
1549
  const [current] = await db
1021
- .select({ updatedAt: schema.tasks.updatedAt, createdAt: schema.tasks.createdAt })
1550
+ .select({
1551
+ updatedAt: schema.tasks.updatedAt,
1552
+ createdAt: schema.tasks.createdAt,
1553
+ ...CLAIM_COLUMNS,
1554
+ })
1022
1555
  .from(schema.tasks)
1023
1556
  .where(eq(schema.tasks.id, taskId))
1024
1557
  .limit(1)
1025
1558
  .all();
1026
1559
  if (!current)
1027
1560
  throw new Error(`Task not found: ${taskId}`);
1028
- assertTaskVersion(taskId, current, guard?.expectedUpdatedAt);
1561
+ // T12502: refuse a claim write the stored holder does not allow before
1562
+ // touching anything, with the holder named. The WHERE clause below
1563
+ // repeats the predicate, so the write itself is the compare-and-set.
1564
+ const claimGuard = guard?.claim;
1565
+ const allowedHolders = claimGuard ? await claimAllowedHolders(db, claimGuard) : [];
1566
+ if (claimGuard)
1567
+ assertClaimAllowed(taskId, current, claimGuard, allowedHolders);
1568
+ const expected = guard?.expectedUpdatedAt;
1569
+ if (expected !== undefined && taskVersion(current) !== expected) {
1570
+ throw taskConflictError(taskId, expected, (await accessor.loadSingleTask(taskId)) ?? current, guard?.baseline);
1571
+ }
1029
1572
  const updateRow = {
1030
1573
  ...fields,
1031
- updatedAt: fields.updatedAt ?? nextTaskVersion(current),
1574
+ updatedAt: fields.updatedAt ?? (guard?.keepVersion ? current.updatedAt : nextTaskVersion(current)),
1032
1575
  };
1576
+ // T12503: a guarded write is a compare-and-set in SQL — the UPDATE
1577
+ // matches only while the stored version is still the expected one, so
1578
+ // the check and the write are one statement, not a read-then-write.
1579
+ const versionMatch = expected === undefined
1580
+ ? undefined
1581
+ : current.updatedAt === null
1582
+ ? isNull(schema.tasks.updatedAt)
1583
+ : eq(schema.tasks.updatedAt, current.updatedAt);
1584
+ const where = and(eq(schema.tasks.id, taskId), versionMatch, claimGuard ? claimPredicate(claimGuard, allowedHolders) : undefined);
1033
1585
  // gh#391: this is the chokepoint for `cleo update <id> --add-labels`.
1034
1586
  // Parallel invocations from a single shell used to lose ~50% of writes
1035
1587
  // to SQLITE_BUSY; withWriteRetry recovers them.
1036
- const result = await withWriteRetry(() => db.update(schema.tasks).set(updateRow).where(eq(schema.tasks.id, taskId)).run());
1037
- if (Number(result.changes) !== 1)
1038
- throw new Error(`Task not found: ${taskId}`);
1588
+ const result = await withWriteRetry(() => db.update(schema.tasks).set(updateRow).where(where).run());
1589
+ if (Number(result.changes) !== 1) {
1590
+ const stored = await accessor.loadSingleTask(taskId);
1591
+ if (!stored)
1592
+ throw new Error(`Task not found: ${taskId}`);
1593
+ if (claimGuard) {
1594
+ assertClaimAllowed(taskId, claimColumnsOf(stored.claim), claimGuard, allowedHolders);
1595
+ }
1596
+ throw taskConflictError(taskId, expected ?? taskVersion(current), stored, guard?.baseline);
1597
+ }
1039
1598
  if (fields.labelsJson !== undefined) {
1040
1599
  await updateTaskLabels(db, taskId, parseLabels(fields.labelsJson));
1041
1600
  }
@@ -1089,6 +1648,14 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1089
1648
  await updateDependencies(db, task.id, task.depends ?? []);
1090
1649
  });
1091
1650
  },
1651
+ async insertNewTask(task) {
1652
+ scope.assertActive();
1653
+ return accessor.transaction(async () => {
1654
+ scope.assertActive();
1655
+ await insertNewTask(db, taskToRow(task));
1656
+ await updateDependencies(db, task.id, task.depends ?? []);
1657
+ });
1658
+ },
1092
1659
  async archiveSingleTask(taskId, fields) {
1093
1660
  scope.assertActive();
1094
1661
  return accessor.transaction(async () => {
@@ -1118,6 +1685,8 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1118
1685
  .delete(schema.taskDependencies)
1119
1686
  .where(eq(schema.taskDependencies.dependsOn, taskId))
1120
1687
  .run();
1688
+ // T12790: bindings of the cascading AC rows (no FK).
1689
+ await pruneAcBindingsForTask(db, taskId);
1121
1690
  await db.delete(schema.tasks).where(eq(schema.tasks.id, taskId)).run();
1122
1691
  });
1123
1692
  },
@@ -1197,6 +1766,9 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1197
1766
  projection: r.projection ?? 'legacy',
1198
1767
  text: r.text,
1199
1768
  contentHash: r.contentHash ?? null,
1769
+ // A kept criterion keeps its uid (T12341); else one is minted.
1770
+ ...(r.uid ? { uid: r.uid } : {}),
1771
+ ...(r.uid && r.birthFp ? { birthFp: r.birthFp } : {}),
1200
1772
  })))
1201
1773
  .run();
1202
1774
  });
@@ -1216,6 +1788,8 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1216
1788
  createdAt: schema.taskAcceptanceCriteria.createdAt,
1217
1789
  updatedAt: schema.taskAcceptanceCriteria.updatedAt,
1218
1790
  contentHash: schema.taskAcceptanceCriteria.contentHash,
1791
+ uid: schema.taskAcceptanceCriteria.uid,
1792
+ birthFp: schema.taskAcceptanceCriteria.birthFp,
1219
1793
  })
1220
1794
  .from(schema.taskAcceptanceCriteria)
1221
1795
  .where(eq(schema.taskAcceptanceCriteria.taskId, taskId))
@@ -1233,18 +1807,70 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1233
1807
  createdAt: r.createdAt,
1234
1808
  updatedAt: r.updatedAt ?? null,
1235
1809
  contentHash: r.contentHash ?? null,
1810
+ uid: r.uid ?? null,
1811
+ birthFp: r.birthFp ?? null,
1236
1812
  }));
1237
1813
  },
1238
1814
  async deleteAcRowsForTask(taskId) {
1239
1815
  scope.assertActive();
1240
1816
  return accessor.transaction(async () => {
1241
1817
  scope.assertActive();
1818
+ // T12790: remove (and audit) the departing rows' bindings.
1819
+ await pruneAcBindingsForTask(db, taskId, 'ac-removed');
1242
1820
  await db
1243
1821
  .delete(schema.taskAcceptanceCriteria)
1244
1822
  .where(eq(schema.taskAcceptanceCriteria.taskId, taskId))
1245
1823
  .run();
1246
1824
  });
1247
1825
  },
1826
+ async deleteAcRowsByIds(taskId, ids, keepBindingsForUids = []) {
1827
+ scope.assertActive();
1828
+ if (ids.length === 0)
1829
+ return;
1830
+ return accessor.transaction(async () => {
1831
+ scope.assertActive();
1832
+ // T12790: only ids this task actually owns leave the set —
1833
+ // prune (and audit) exactly their bindings.
1834
+ const owned = await db
1835
+ .select({ id: schema.taskAcceptanceCriteria.id })
1836
+ .from(schema.taskAcceptanceCriteria)
1837
+ .where(and(eq(schema.taskAcceptanceCriteria.taskId, taskId), inArray(schema.taskAcceptanceCriteria.id, ids)))
1838
+ .all();
1839
+ await pruneAcBindingsForAcIds(db, taskId, owned.map((r) => r.id), 'ac-removed', keepBindingsForUids);
1840
+ await db
1841
+ .delete(schema.taskAcceptanceCriteria)
1842
+ .where(and(eq(schema.taskAcceptanceCriteria.taskId, taskId), inArray(schema.taskAcceptanceCriteria.id, ids)))
1843
+ .run();
1844
+ });
1845
+ },
1846
+ async updateAcRows(rows) {
1847
+ scope.assertActive();
1848
+ if (rows.length === 0)
1849
+ return;
1850
+ return accessor.transaction(async () => {
1851
+ scope.assertActive();
1852
+ const updatedAt = new Date().toISOString();
1853
+ for (const r of rows) {
1854
+ const result = await db
1855
+ .update(schema.taskAcceptanceCriteria)
1856
+ .set({
1857
+ ordinal: r.ordinal,
1858
+ kind: r.kind ?? 'text',
1859
+ sourceKey: r.sourceKey ?? `text:${r.ordinal}`,
1860
+ targetTaskId: r.targetTaskId ?? null,
1861
+ projection: r.projection ?? 'legacy',
1862
+ text: r.text,
1863
+ contentHash: r.contentHash ?? null,
1864
+ updatedAt,
1865
+ })
1866
+ .where(and(eq(schema.taskAcceptanceCriteria.id, r.id), eq(schema.taskAcceptanceCriteria.taskId, r.taskId)))
1867
+ .run();
1868
+ if (Number(result.changes) === 0) {
1869
+ throw new CleoError(ExitCode.VALIDATION_ERROR, `Acceptance criterion ${r.id} does not exist on task ${r.taskId}; refusing to update it`);
1870
+ }
1871
+ }
1872
+ });
1873
+ },
1248
1874
  async appendAcHistory(rows) {
1249
1875
  scope.assertActive();
1250
1876
  return accessor.transaction(async () => {
@@ -1257,6 +1883,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1257
1883
  acId: r.acId,
1258
1884
  previousText: r.previousText,
1259
1885
  reason: r.reason,
1886
+ ...(r.acUid ? { acUid: r.acUid } : {}),
1260
1887
  })))
1261
1888
  .run();
1262
1889
  });
@@ -1264,26 +1891,7 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1264
1891
  // ---- AC bindings (T10509 — AC-coverage gate) ----
1265
1892
  async getAcBindings(acIds) {
1266
1893
  scope.assertActive();
1267
- if (acIds.length === 0)
1268
- return [];
1269
- const out = await db
1270
- .select({
1271
- id: schema.evidenceAcBindings.id,
1272
- evidenceAtomId: schema.evidenceAcBindings.evidenceAtomId,
1273
- acId: schema.evidenceAcBindings.acId,
1274
- bindingType: schema.evidenceAcBindings.bindingType,
1275
- createdAt: schema.evidenceAcBindings.createdAt,
1276
- })
1277
- .from(schema.evidenceAcBindings)
1278
- .where(inArray(schema.evidenceAcBindings.acId, acIds))
1279
- .all();
1280
- return out.map((r) => ({
1281
- id: r.id,
1282
- evidenceAtomId: r.evidenceAtomId,
1283
- acId: r.acId,
1284
- bindingType: r.bindingType,
1285
- createdAt: r.createdAt,
1286
- }));
1894
+ return selectAcBindings(db, acIds);
1287
1895
  },
1288
1896
  // ---- AC bindings — writer (T10511, Validator SDK tools) ----
1289
1897
  async insertAcBindings(rows) {
@@ -1312,6 +1920,14 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1312
1920
  .run();
1313
1921
  });
1314
1922
  },
1923
+ // ---- AC bindings — orphan repair (T12790) ----
1924
+ async pruneOrphanAcBindings() {
1925
+ scope.assertActive();
1926
+ return accessor.transaction(async () => {
1927
+ scope.assertActive();
1928
+ return pruneOrphanAcBindings(db);
1929
+ });
1930
+ },
1315
1931
  };
1316
1932
  const result = await fn(bindTaskAccessorScope(tx, accessorScope));
1317
1933
  await scope.pending;
@@ -1378,52 +1994,134 @@ async function createOwnedSqliteDataAccessor(cwd, accessorScope) {
1378
1994
  const { getAgentInstance: getAgent } = await import('../agents/registry.js');
1379
1995
  return getAgent(agentId, cwd);
1380
1996
  },
1381
- // ---- Agent task claiming ----
1382
- async claimTask(taskId, agentId) {
1997
+ // ---- Agent task claiming (leased, T12502) ----
1998
+ async claimTask(taskId, request) {
1999
+ const now = request.now ?? new Date().toISOString();
2000
+ const guard = {
2001
+ sessionId: request.sessionId,
2002
+ mode: request.mode,
2003
+ now,
2004
+ handoffFrom: request.handoffFrom ?? null,
2005
+ };
1383
2006
  return accessor.transaction(async () => {
1384
- const nativeDb = await requireNativeDb();
1385
- if (!nativeDb) {
1386
- throw new Error('Native database not initialized');
1387
- }
1388
- // Verify the task exists first
1389
- const existsRow = nativeDb
1390
- .prepare('SELECT assignee FROM tasks_tasks WHERE id = ?')
1391
- .get(taskId);
1392
- if (!existsRow) {
2007
+ const task = await accessor.loadSingleTask(taskId);
2008
+ if (!task)
1393
2009
  throw new Error(`Task not found: ${taskId}`);
2010
+ const before = task.claim;
2011
+ if (request.sessionId === null) {
2012
+ // An override names who takes the task; an unbound caller has no
2013
+ // session to record, so it is refused rather than silently ignored.
2014
+ if (request.mode === 'take-over' || request.mode === 'force') {
2015
+ const flag = request.mode === 'force' ? '--force-claim' : '--take-over';
2016
+ throw new CleoError(ExitCode.SESSION_UNBOUND, `Cannot ${flag} task ${taskId}: this caller is not bound to a session, so there is no session to hand the claim to.`, {
2017
+ fix: `Bind a session first (cleo session start --scope global --name "<work>", cleo session resume <id>, or export CLEO_SESSION_ID=<id>), then retry with ${flag}.`,
2018
+ });
2019
+ }
2020
+ // An unbound caller holds no lease; the guarded no-op write still
2021
+ // proves, under the write lock, that no other session holds it.
2022
+ await accessor.updateTaskFields(taskId, {}, { claim: guard, keepVersion: true });
2023
+ return null;
1394
2024
  }
1395
- // Atomic claim: only succeeds if assignee IS NULL or already claimed by this agent.
1396
- // This prevents race conditions between concurrent agents.
1397
- const result = nativeDb
1398
- .prepare('UPDATE tasks_tasks SET assignee = ?, updated_at = ? WHERE id = ? AND (assignee IS NULL OR assignee = ?)')
1399
- .run(agentId, new Date().toISOString(), taskId, agentId);
1400
- if (result.changes === 0) {
1401
- // Row was not updated — task is claimed by a different agent
1402
- const currentRow = nativeDb
1403
- .prepare('SELECT assignee FROM tasks_tasks WHERE id = ?')
1404
- .get(taskId);
1405
- throw new Error(`Task ${taskId} is already claimed by agent: ${currentRow?.assignee ?? 'unknown'}`);
2025
+ const renewing = before?.sessionId === request.sessionId;
2026
+ const lease = {
2027
+ sessionId: request.sessionId,
2028
+ agentId: request.agentId ?? (renewing ? (before?.agentId ?? null) : null),
2029
+ claimedAt: renewing && before ? before.claimedAt : now,
2030
+ leaseExpiresAt: leaseExpiresAtFrom(now, request.leaseMs ?? taskClaimLeaseMs()),
2031
+ };
2032
+ await accessor.updateTaskFields(taskId, {
2033
+ claimedBySession: lease.sessionId,
2034
+ claimedByAgent: lease.agentId,
2035
+ claimedAt: lease.claimedAt,
2036
+ leaseExpiresAt: lease.leaseExpiresAt,
2037
+ },
2038
+ // Renewing one's own lease is bookkeeping, not an edit: it must not
2039
+ // move the version another writer holds for --if-match.
2040
+ { claim: guard, keepVersion: renewing });
2041
+ const replaced = before && before.sessionId !== request.sessionId ? before : undefined;
2042
+ if (replaced) {
2043
+ // A write the predicate allowed over a LIVE lease without `force` is
2044
+ // a claim-family hand-off (spawn source, spawn-edge parent or child).
2045
+ const handoff = request.mode !== 'force' && !isClaimExpired(replaced, now);
2046
+ await accessor.appendLog({
2047
+ action: handoff
2048
+ ? 'task_claim_handoff'
2049
+ : request.mode === 'force'
2050
+ ? 'task_claim_force'
2051
+ : 'task_claim_takeover',
2052
+ taskId,
2053
+ actor: request.agentId ?? request.sessionId,
2054
+ sessionId: request.sessionId,
2055
+ timestamp: now,
2056
+ details: {
2057
+ mode: request.mode,
2058
+ leaseExpired: replaced.leaseExpiresAt <= now,
2059
+ },
2060
+ before: replaced,
2061
+ after: lease,
2062
+ });
1406
2063
  }
2064
+ return lease;
1407
2065
  });
1408
2066
  },
1409
- async unclaimTask(taskId) {
2067
+ async unclaimTask(taskId, release) {
2068
+ const now = new Date().toISOString();
1410
2069
  return accessor.transaction(async () => {
1411
- const nativeDb = await requireNativeDb();
1412
- if (!nativeDb) {
1413
- throw new Error('Native database not initialized');
1414
- }
1415
- // Verify the task exists
1416
- const existsRow = nativeDb.prepare('SELECT id FROM tasks_tasks WHERE id = ?').get(taskId);
1417
- if (!existsRow) {
2070
+ const task = await accessor.loadSingleTask(taskId);
2071
+ if (!task)
1418
2072
  throw new Error(`Task not found: ${taskId}`);
2073
+ const held = task.claim;
2074
+ if (!held)
2075
+ return false;
2076
+ await accessor.updateTaskFields(taskId, { claimedBySession: null, claimedByAgent: null, claimedAt: null, leaseExpiresAt: null }, {
2077
+ claim: { sessionId: release.sessionId, mode: release.force ? 'force' : 'release', now },
2078
+ keepVersion: true,
2079
+ });
2080
+ if (held.sessionId !== release.sessionId) {
2081
+ await accessor.appendLog({
2082
+ action: 'task_claim_force_release',
2083
+ taskId,
2084
+ actor: release.sessionId ?? 'unbound',
2085
+ sessionId: release.sessionId,
2086
+ timestamp: now,
2087
+ details: { mode: 'force', leaseExpired: held.leaseExpiresAt <= now },
2088
+ before: held,
2089
+ });
1419
2090
  }
1420
- // Clear the assignee — no-op if already null
1421
- nativeDb
1422
- .prepare('UPDATE tasks_tasks SET assignee = NULL, updated_at = ? WHERE id = ?')
1423
- .run(new Date().toISOString(), taskId);
2091
+ return true;
1424
2092
  });
1425
2093
  },
2094
+ async renewSessionClaims(sessionId, leaseExpiresAt) {
2095
+ // The heartbeat follows EVERY mutation of a bound session, and almost no
2096
+ // session holds a lease. Probe the claimed_by_session index first and
2097
+ // write only when there is a lease to extend, so the common case costs
2098
+ // one indexed read and no lock.
2099
+ const db = await getDb(cwd);
2100
+ const [held] = await db
2101
+ .select({ id: schema.tasks.id })
2102
+ .from(schema.tasks)
2103
+ .where(eq(schema.tasks.claimedBySession, sessionId))
2104
+ .limit(1)
2105
+ .all();
2106
+ if (!held)
2107
+ return 0;
2108
+ // Bounded lock wait, skipped on SQLITE_BUSY or inside another caller's
2109
+ // transaction — see runHeartbeatWrite. The next mutation renews.
2110
+ return (runHeartbeatWrite(db, getNativeTasksDb(cwd), () => Number(db
2111
+ .update(schema.tasks)
2112
+ .set({ leaseExpiresAt })
2113
+ .where(eq(schema.tasks.claimedBySession, sessionId))
2114
+ .run().changes)) ?? 0);
2115
+ },
1426
2116
  };
1427
2117
  return accessor;
1428
2118
  }
2119
+ // T12341: the row-identity open pass writes through these chokepoint helpers.
2120
+ registerRowIdentityWriters({
2121
+ relinkAcUidNative,
2122
+ clearAcUidGraveyardNative,
2123
+ writeRowIdentityMetaNative,
2124
+ fillIdentityColumnNative,
2125
+ clearBirthFpNative,
2126
+ });
1429
2127
  //# sourceMappingURL=sqlite-data-accessor.js.map