@cleocode/core 2026.9.24 → 2026.9.26

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 (481) hide show
  1. package/dist/admin/import-tasks.d.ts.map +1 -1
  2. package/dist/admin/import-tasks.js +5 -2
  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 +7 -2
  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/index.d.ts +1 -0
  17. package/dist/cloud/index.d.ts.map +1 -1
  18. package/dist/cloud/index.js +1 -0
  19. package/dist/cloud/index.js.map +1 -1
  20. package/dist/cloud/nexus-auth.d.ts +26 -1
  21. package/dist/cloud/nexus-auth.d.ts.map +1 -1
  22. package/dist/cloud/nexus-auth.js +61 -32
  23. package/dist/cloud/nexus-auth.js.map +1 -1
  24. package/dist/cloud/nexus-credentials.js +2 -2
  25. package/dist/cloud/nexus-credentials.js.map +1 -1
  26. package/dist/cloud/nexus-device.d.ts +809 -0
  27. package/dist/cloud/nexus-device.d.ts.map +1 -0
  28. package/dist/cloud/nexus-device.js +1680 -0
  29. package/dist/cloud/nexus-device.js.map +1 -0
  30. package/dist/cloud/nexus-enrol.d.ts +210 -0
  31. package/dist/cloud/nexus-enrol.d.ts.map +1 -0
  32. package/dist/cloud/nexus-enrol.js +1023 -0
  33. package/dist/cloud/nexus-enrol.js.map +1 -0
  34. package/dist/cloud/nexus-link.d.ts +3 -0
  35. package/dist/cloud/nexus-link.d.ts.map +1 -1
  36. package/dist/cloud/nexus-link.js +38 -4
  37. package/dist/cloud/nexus-link.js.map +1 -1
  38. package/dist/cloud/signing.d.ts +20 -0
  39. package/dist/cloud/signing.d.ts.map +1 -1
  40. package/dist/cloud/signing.js +14 -0
  41. package/dist/cloud/signing.js.map +1 -1
  42. package/dist/cloud/uuidv7.d.ts +9 -0
  43. package/dist/cloud/uuidv7.d.ts.map +1 -0
  44. package/dist/cloud/uuidv7.js +19 -0
  45. package/dist/cloud/uuidv7.js.map +1 -0
  46. package/dist/crypto/credentials.d.ts +61 -0
  47. package/dist/crypto/credentials.d.ts.map +1 -1
  48. package/dist/crypto/credentials.js +154 -58
  49. package/dist/crypto/credentials.js.map +1 -1
  50. package/dist/decide/bench/index.d.ts +1 -1
  51. package/dist/decide/bench/index.d.ts.map +1 -1
  52. package/dist/decide/bench/index.js +1 -1
  53. package/dist/decide/bench/index.js.map +1 -1
  54. package/dist/decide/bench/operation.d.ts +1 -1
  55. package/dist/decide/bench/operation.d.ts.map +1 -1
  56. package/dist/decide/bench/operation.js +1 -1
  57. package/dist/decide/bench/operation.js.map +1 -1
  58. package/dist/decide/bench/profiles.d.ts +50 -22
  59. package/dist/decide/bench/profiles.d.ts.map +1 -1
  60. package/dist/decide/bench/profiles.js +103 -59
  61. package/dist/decide/bench/profiles.js.map +1 -1
  62. package/dist/decide/bench/report.d.ts.map +1 -1
  63. package/dist/decide/bench/report.js +6 -1
  64. package/dist/decide/bench/report.js.map +1 -1
  65. package/dist/decide/bench/runner.d.ts +6 -1
  66. package/dist/decide/bench/runner.d.ts.map +1 -1
  67. package/dist/decide/bench/runner.js +1 -0
  68. package/dist/decide/bench/runner.js.map +1 -1
  69. package/dist/decide/client.d.ts.map +1 -1
  70. package/dist/decide/client.js +11 -5
  71. package/dist/decide/client.js.map +1 -1
  72. package/dist/decide/jev-wire.d.ts +31 -1
  73. package/dist/decide/jev-wire.d.ts.map +1 -1
  74. package/dist/decide/jev-wire.js +61 -7
  75. package/dist/decide/jev-wire.js.map +1 -1
  76. package/dist/docs/export-document.js +12907 -10622
  77. package/dist/docs/export-document.js.map +3 -3
  78. package/dist/doctor/dependency-cycles.d.ts +41 -0
  79. package/dist/doctor/dependency-cycles.d.ts.map +1 -0
  80. package/dist/doctor/dependency-cycles.js +39 -0
  81. package/dist/doctor/dependency-cycles.js.map +1 -0
  82. package/dist/doctor/index.d.ts +2 -0
  83. package/dist/doctor/index.d.ts.map +1 -1
  84. package/dist/doctor/index.js +1 -0
  85. package/dist/doctor/index.js.map +1 -1
  86. package/dist/doctor/orphan-ac-bindings.d.ts +64 -0
  87. package/dist/doctor/orphan-ac-bindings.d.ts.map +1 -0
  88. package/dist/doctor/orphan-ac-bindings.js +59 -0
  89. package/dist/doctor/orphan-ac-bindings.js.map +1 -0
  90. package/dist/doctor/projects.d.ts.map +1 -1
  91. package/dist/doctor/projects.js +43 -29
  92. package/dist/doctor/projects.js.map +1 -1
  93. package/dist/doctor/row-identity.d.ts +42 -0
  94. package/dist/doctor/row-identity.d.ts.map +1 -0
  95. package/dist/doctor/row-identity.js +151 -0
  96. package/dist/doctor/row-identity.js.map +1 -0
  97. package/dist/doctor/twin-collapse.d.ts +58 -2
  98. package/dist/doctor/twin-collapse.d.ts.map +1 -1
  99. package/dist/doctor/twin-collapse.js +212 -14
  100. package/dist/doctor/twin-collapse.js.map +1 -1
  101. package/dist/error-catalog.d.ts.map +1 -1
  102. package/dist/error-catalog.js +4 -0
  103. package/dist/error-catalog.js.map +1 -1
  104. package/dist/error-registry.d.ts.map +1 -1
  105. package/dist/error-registry.js +8 -0
  106. package/dist/error-registry.js.map +1 -1
  107. package/dist/lifecycle/verification/satisfies-validator.d.ts.map +1 -1
  108. package/dist/lifecycle/verification/satisfies-validator.js +10 -0
  109. package/dist/lifecycle/verification/satisfies-validator.js.map +1 -1
  110. package/dist/llm/plugin-facade.js +17767 -15482
  111. package/dist/llm/plugin-facade.js.map +3 -3
  112. package/dist/memory/index.d.ts.map +1 -1
  113. package/dist/memory/index.js +19 -10
  114. package/dist/memory/index.js.map +1 -1
  115. package/dist/memory/manifest-identity.d.ts +171 -0
  116. package/dist/memory/manifest-identity.d.ts.map +1 -0
  117. package/dist/memory/manifest-identity.js +345 -0
  118. package/dist/memory/manifest-identity.js.map +1 -0
  119. package/dist/memory/mental-model-queue.d.ts +14 -4
  120. package/dist/memory/mental-model-queue.d.ts.map +1 -1
  121. package/dist/memory/mental-model-queue.js +64 -35
  122. package/dist/memory/mental-model-queue.js.map +1 -1
  123. package/dist/memory/pipeline-manifest-sqlite.d.ts +47 -5
  124. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  125. package/dist/memory/pipeline-manifest-sqlite.js +130 -14
  126. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  127. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  128. package/dist/memory/retrieval/observe.js +2 -0
  129. package/dist/memory/retrieval/observe.js.map +1 -1
  130. package/dist/memory/transcript-scanner.js +1 -1
  131. package/dist/nexus/deps.d.ts.map +1 -1
  132. package/dist/nexus/deps.js +7 -14
  133. package/dist/nexus/deps.js.map +1 -1
  134. package/dist/nexus/discover.d.ts.map +1 -1
  135. package/dist/nexus/discover.js +6 -9
  136. package/dist/nexus/discover.js.map +1 -1
  137. package/dist/nexus/git-state.d.ts.map +1 -1
  138. package/dist/nexus/git-state.js +10 -1
  139. package/dist/nexus/git-state.js.map +1 -1
  140. package/dist/nexus/projects-clean.d.ts.map +1 -1
  141. package/dist/nexus/projects-clean.js +22 -11
  142. package/dist/nexus/projects-clean.js.map +1 -1
  143. package/dist/nexus/projects-scan.d.ts.map +1 -1
  144. package/dist/nexus/projects-scan.js +8 -13
  145. package/dist/nexus/projects-scan.js.map +1 -1
  146. package/dist/nexus/query.d.ts.map +1 -1
  147. package/dist/nexus/query.js +4 -12
  148. package/dist/nexus/query.js.map +1 -1
  149. package/dist/nexus/registry-roots.d.ts +5 -2
  150. package/dist/nexus/registry-roots.d.ts.map +1 -1
  151. package/dist/nexus/registry-roots.js +8 -10
  152. package/dist/nexus/registry-roots.js.map +1 -1
  153. package/dist/nexus/registry.d.ts +18 -0
  154. package/dist/nexus/registry.d.ts.map +1 -1
  155. package/dist/nexus/registry.js +37 -16
  156. package/dist/nexus/registry.js.map +1 -1
  157. package/dist/nexus/workspace.d.ts.map +1 -1
  158. package/dist/nexus/workspace.js +54 -4
  159. package/dist/nexus/workspace.js.map +1 -1
  160. package/dist/orchestrate/lifecycle-ops.js +1 -1
  161. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  162. package/dist/orchestrate/pivot.d.ts.map +1 -1
  163. package/dist/orchestrate/pivot.js +4 -2
  164. package/dist/orchestrate/pivot.js.map +1 -1
  165. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  166. package/dist/orchestrate/query-ops.js +3 -3
  167. package/dist/orchestrate/query-ops.js.map +1 -1
  168. package/dist/orchestrate/spawn-ops.js +1 -1
  169. package/dist/orchestrate/spawn-ops.js.map +1 -1
  170. package/dist/orchestrate/worktree-complete.d.ts.map +1 -1
  171. package/dist/orchestrate/worktree-complete.js +40 -2
  172. package/dist/orchestrate/worktree-complete.js.map +1 -1
  173. package/dist/orchestration/index.js +1 -1
  174. package/dist/orchestration/index.js.map +1 -1
  175. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  176. package/dist/orchestration/lead-rollup.js +3 -3
  177. package/dist/orchestration/lead-rollup.js.map +1 -1
  178. package/dist/orchestration/parallel.js +1 -1
  179. package/dist/orchestration/parallel.js.map +1 -1
  180. package/dist/orchestration/spawn-prompt.d.ts +26 -0
  181. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  182. package/dist/orchestration/spawn-prompt.js +62 -91
  183. package/dist/orchestration/spawn-prompt.js.map +1 -1
  184. package/dist/orchestration/wave-topic.d.ts +4 -2
  185. package/dist/orchestration/wave-topic.d.ts.map +1 -1
  186. package/dist/orchestration/wave-topic.js +6 -4
  187. package/dist/orchestration/wave-topic.js.map +1 -1
  188. package/dist/orchestration/waves.d.ts +2 -1
  189. package/dist/orchestration/waves.d.ts.map +1 -1
  190. package/dist/orchestration/waves.js +4 -3
  191. package/dist/orchestration/waves.js.map +1 -1
  192. package/dist/phases/index.d.ts.map +1 -1
  193. package/dist/phases/index.js +4 -2
  194. package/dist/phases/index.js.map +1 -1
  195. package/dist/release/ci-evidence.d.ts +190 -0
  196. package/dist/release/ci-evidence.d.ts.map +1 -1
  197. package/dist/release/ci-evidence.js +436 -4
  198. package/dist/release/ci-evidence.js.map +1 -1
  199. package/dist/sdk/validator-ac-pull.d.ts.map +1 -1
  200. package/dist/sdk/validator-ac-pull.js +2 -1
  201. package/dist/sdk/validator-ac-pull.js.map +1 -1
  202. package/dist/selfimprove/fix-gen.js +12807 -10522
  203. package/dist/selfimprove/fix-gen.js.map +3 -3
  204. package/dist/sentient/cross-project-hygiene.d.ts +5 -0
  205. package/dist/sentient/cross-project-hygiene.d.ts.map +1 -1
  206. package/dist/sentient/cross-project-hygiene.js +7 -1
  207. package/dist/sentient/cross-project-hygiene.js.map +1 -1
  208. package/dist/sentient/propose-tick.d.ts.map +1 -1
  209. package/dist/sentient/propose-tick.js +2 -3
  210. package/dist/sentient/propose-tick.js.map +1 -1
  211. package/dist/sentient/stage-drift-tick.d.ts.map +1 -1
  212. package/dist/sentient/stage-drift-tick.js +2 -3
  213. package/dist/sentient/stage-drift-tick.js.map +1 -1
  214. package/dist/session/engine-ops.d.ts.map +1 -1
  215. package/dist/session/engine-ops.js +77 -49
  216. package/dist/session/engine-ops.js.map +1 -1
  217. package/dist/sessions/focus-state-store.d.ts +69 -23
  218. package/dist/sessions/focus-state-store.d.ts.map +1 -1
  219. package/dist/sessions/focus-state-store.js +113 -27
  220. package/dist/sessions/focus-state-store.js.map +1 -1
  221. package/dist/sessions/handoff.js +1 -1
  222. package/dist/sessions/handoff.js.map +1 -1
  223. package/dist/sessions/index.d.ts.map +1 -1
  224. package/dist/sessions/index.js +24 -13
  225. package/dist/sessions/index.js.map +1 -1
  226. package/dist/sessions/terminal-identity.d.ts +165 -17
  227. package/dist/sessions/terminal-identity.d.ts.map +1 -1
  228. package/dist/sessions/terminal-identity.js +341 -32
  229. package/dist/sessions/terminal-identity.js.map +1 -1
  230. package/dist/skills/manifests/research.js +2 -0
  231. package/dist/skills/manifests/research.js.map +1 -1
  232. package/dist/skills/orchestrator/startup.js +2 -2
  233. package/dist/skills/orchestrator/startup.js.map +1 -1
  234. package/dist/skills/orchestrator/validator.d.ts.map +1 -1
  235. package/dist/skills/orchestrator/validator.js +9 -2
  236. package/dist/skills/orchestrator/validator.js.map +1 -1
  237. package/dist/skills/validation.d.ts +4 -1
  238. package/dist/skills/validation.d.ts.map +1 -1
  239. package/dist/skills/validation.js +11 -3
  240. package/dist/skills/validation.js.map +1 -1
  241. package/dist/snapshot/index.d.ts +4 -0
  242. package/dist/snapshot/index.d.ts.map +1 -1
  243. package/dist/snapshot/index.js +50 -3
  244. package/dist/snapshot/index.js.map +1 -1
  245. package/dist/spawn/branch-lock.d.ts +111 -7
  246. package/dist/spawn/branch-lock.d.ts.map +1 -1
  247. package/dist/spawn/branch-lock.js +296 -8
  248. package/dist/spawn/branch-lock.js.map +1 -1
  249. package/dist/store/ac-binding-prune.d.ts +144 -0
  250. package/dist/store/ac-binding-prune.d.ts.map +1 -0
  251. package/dist/store/ac-binding-prune.js +293 -0
  252. package/dist/store/ac-binding-prune.js.map +1 -0
  253. package/dist/store/agent-registry-store.d.ts.map +1 -1
  254. package/dist/store/agent-registry-store.js +3 -2
  255. package/dist/store/agent-registry-store.js.map +1 -1
  256. package/dist/store/backup-sidecar.d.ts +85 -2
  257. package/dist/store/backup-sidecar.d.ts.map +1 -1
  258. package/dist/store/backup-sidecar.js +173 -1
  259. package/dist/store/backup-sidecar.js.map +1 -1
  260. package/dist/store/conduit-sqlite.d.ts.map +1 -1
  261. package/dist/store/conduit-sqlite.js +3 -2
  262. package/dist/store/conduit-sqlite.js.map +1 -1
  263. package/dist/store/credential-transfer.d.ts.map +1 -1
  264. package/dist/store/credential-transfer.js +3 -0
  265. package/dist/store/credential-transfer.js.map +1 -1
  266. package/dist/store/db-helpers.d.ts +32 -13
  267. package/dist/store/db-helpers.d.ts.map +1 -1
  268. package/dist/store/db-helpers.js +144 -40
  269. package/dist/store/db-helpers.js.map +1 -1
  270. package/dist/store/dependency-cycles.d.ts +164 -0
  271. package/dist/store/dependency-cycles.d.ts.map +1 -0
  272. package/dist/store/dependency-cycles.js +360 -0
  273. package/dist/store/dependency-cycles.js.map +1 -0
  274. package/dist/store/display-id-alias.d.ts +585 -0
  275. package/dist/store/display-id-alias.d.ts.map +1 -0
  276. package/dist/store/display-id-alias.js +1538 -0
  277. package/dist/store/display-id-alias.js.map +1 -0
  278. package/dist/store/dual-scope-db.d.ts.map +1 -1
  279. package/dist/store/dual-scope-db.js +48 -0
  280. package/dist/store/dual-scope-db.js.map +1 -1
  281. package/dist/store/exodus/migrate.d.ts.map +1 -1
  282. package/dist/store/exodus/migrate.js +8 -1
  283. package/dist/store/exodus/migrate.js.map +1 -1
  284. package/dist/store/exodus/reconcile.d.ts.map +1 -1
  285. package/dist/store/exodus/reconcile.js +7 -2
  286. package/dist/store/exodus/reconcile.js.map +1 -1
  287. package/dist/store/exodus/recovery.d.ts.map +1 -1
  288. package/dist/store/exodus/recovery.js +20 -1
  289. package/dist/store/exodus/recovery.js.map +1 -1
  290. package/dist/store/global-salt.d.ts +35 -0
  291. package/dist/store/global-salt.d.ts.map +1 -1
  292. package/dist/store/global-salt.js +136 -16
  293. package/dist/store/global-salt.js.map +1 -1
  294. package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
  295. package/dist/store/legacy-tasks-lineage.js +19 -2
  296. package/dist/store/legacy-tasks-lineage.js.map +1 -1
  297. package/dist/store/migration-sqlite.d.ts.map +1 -1
  298. package/dist/store/migration-sqlite.js +19 -11
  299. package/dist/store/migration-sqlite.js.map +1 -1
  300. package/dist/store/portable-bundle-scan.d.ts.map +1 -1
  301. package/dist/store/portable-bundle-scan.js +6 -0
  302. package/dist/store/portable-bundle-scan.js.map +1 -1
  303. package/dist/store/row-identity-flag.d.ts +26 -0
  304. package/dist/store/row-identity-flag.d.ts.map +1 -0
  305. package/dist/store/row-identity-flag.js +31 -0
  306. package/dist/store/row-identity-flag.js.map +1 -0
  307. package/dist/store/row-identity-registry.d.ts +61 -0
  308. package/dist/store/row-identity-registry.d.ts.map +1 -0
  309. package/dist/store/row-identity-registry.js +206 -0
  310. package/dist/store/row-identity-registry.js.map +1 -0
  311. package/dist/store/row-identity.d.ts +480 -0
  312. package/dist/store/row-identity.d.ts.map +1 -0
  313. package/dist/store/row-identity.js +1509 -0
  314. package/dist/store/row-identity.js.map +1 -0
  315. package/dist/store/safety-data-accessor.d.ts +5 -2
  316. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  317. package/dist/store/safety-data-accessor.js +9 -2
  318. package/dist/store/safety-data-accessor.js.map +1 -1
  319. package/dist/store/schema/attachments.d.ts +1 -1
  320. package/dist/store/schema/audit.d.ts +4 -4
  321. package/dist/store/schema/background-jobs.d.ts +1 -1
  322. package/dist/store/schema/cleo-global/nexus.d.ts +1 -1
  323. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  324. package/dist/store/schema/cleo-project/audit.d.ts +4 -4
  325. package/dist/store/schema/cleo-project/docs.d.ts +1 -1
  326. package/dist/store/schema/cleo-project/lifecycle.d.ts +4 -4
  327. package/dist/store/schema/cleo-project/nexus-graph.d.ts +3 -3
  328. package/dist/store/schema/cleo-project/provenance-commits.d.ts +2 -2
  329. package/dist/store/schema/cleo-project/provenance-rest.d.ts +3 -3
  330. package/dist/store/schema/cleo-project/runtime.d.ts +3 -3
  331. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts +87 -1
  332. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts.map +1 -1
  333. package/dist/store/schema/cleo-project/tasks-core-batch2.js +35 -0
  334. package/dist/store/schema/cleo-project/tasks-core-batch2.js.map +1 -1
  335. package/dist/store/schema/cleo-project/tasks-core.d.ts +183 -7
  336. package/dist/store/schema/cleo-project/tasks-core.d.ts.map +1 -1
  337. package/dist/store/schema/cleo-project/tasks-core.js +52 -1
  338. package/dist/store/schema/cleo-project/tasks-core.js.map +1 -1
  339. package/dist/store/schema/cleo-shared/brain.d.ts +6 -6
  340. package/dist/store/schema/lifecycle.d.ts +4 -4
  341. package/dist/store/schema/manifest.d.ts +1 -1
  342. package/dist/store/schema/memory-schema.d.ts +5 -5
  343. package/dist/store/schema/nexus-schema.d.ts +3 -3
  344. package/dist/store/schema/provenance/releases.d.ts +1 -1
  345. package/dist/store/schema/skills-schema.d.ts +2 -2
  346. package/dist/store/schema/tasks.d.ts +6 -6
  347. package/dist/store/session-store.d.ts +63 -3
  348. package/dist/store/session-store.d.ts.map +1 -1
  349. package/dist/store/session-store.js +121 -8
  350. package/dist/store/session-store.js.map +1 -1
  351. package/dist/store/split-brain-import.d.ts +2 -14
  352. package/dist/store/split-brain-import.d.ts.map +1 -1
  353. package/dist/store/split-brain-import.js +40 -19
  354. package/dist/store/split-brain-import.js.map +1 -1
  355. package/dist/store/sqlite-data-accessor.d.ts +326 -2
  356. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  357. package/dist/store/sqlite-data-accessor.js +782 -49
  358. package/dist/store/sqlite-data-accessor.js.map +1 -1
  359. package/dist/store/sync/clock-store.d.ts +67 -0
  360. package/dist/store/sync/clock-store.d.ts.map +1 -0
  361. package/dist/store/sync/clock-store.js +117 -0
  362. package/dist/store/sync/clock-store.js.map +1 -0
  363. package/dist/store/sync/flags.d.ts +51 -0
  364. package/dist/store/sync/flags.d.ts.map +1 -0
  365. package/dist/store/sync/flags.js +81 -0
  366. package/dist/store/sync/flags.js.map +1 -0
  367. package/dist/store/sync/hlc.d.ts +115 -0
  368. package/dist/store/sync/hlc.d.ts.map +1 -0
  369. package/dist/store/sync/hlc.js +172 -0
  370. package/dist/store/sync/hlc.js.map +1 -0
  371. package/dist/store/sync/index.d.ts +20 -0
  372. package/dist/store/sync/index.d.ts.map +1 -0
  373. package/dist/store/sync/index.js +20 -0
  374. package/dist/store/sync/index.js.map +1 -0
  375. package/dist/store/sync/replica-registry.d.ts +85 -0
  376. package/dist/store/sync/replica-registry.d.ts.map +1 -0
  377. package/dist/store/sync/replica-registry.js +147 -0
  378. package/dist/store/sync/replica-registry.js.map +1 -0
  379. package/dist/store/sync/replica.d.ts +181 -0
  380. package/dist/store/sync/replica.d.ts.map +1 -0
  381. package/dist/store/sync/replica.js +305 -0
  382. package/dist/store/sync/replica.js.map +1 -0
  383. package/dist/store/sync/schema.d.ts +68 -0
  384. package/dist/store/sync/schema.d.ts.map +1 -0
  385. package/dist/store/sync/schema.js +130 -0
  386. package/dist/store/sync/schema.js.map +1 -0
  387. package/dist/store/sync/skew-hold.d.ts +71 -0
  388. package/dist/store/sync/skew-hold.d.ts.map +1 -0
  389. package/dist/store/sync/skew-hold.js +89 -0
  390. package/dist/store/sync/skew-hold.js.map +1 -0
  391. package/dist/store/table-classification.d.ts +10 -8
  392. package/dist/store/table-classification.d.ts.map +1 -1
  393. package/dist/store/table-classification.js +93 -25
  394. package/dist/store/table-classification.js.map +1 -1
  395. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  396. package/dist/store/tasks-sqlite.js +23 -3
  397. package/dist/store/tasks-sqlite.js.map +1 -1
  398. package/dist/store/twin-collapse.d.ts +113 -2
  399. package/dist/store/twin-collapse.d.ts.map +1 -1
  400. package/dist/store/twin-collapse.js +247 -19
  401. package/dist/store/twin-collapse.js.map +1 -1
  402. package/dist/store/umbrella-data-accessor.d.ts +5 -2
  403. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  404. package/dist/store/umbrella-data-accessor.js +9 -2
  405. package/dist/store/umbrella-data-accessor.js.map +1 -1
  406. package/dist/store/validation-schemas.d.ts +241 -49
  407. package/dist/store/validation-schemas.d.ts.map +1 -1
  408. package/dist/system/health.d.ts +2 -0
  409. package/dist/system/health.d.ts.map +1 -1
  410. package/dist/system/health.js +57 -0
  411. package/dist/system/health.js.map +1 -1
  412. package/dist/system/project-health.d.ts +9 -2
  413. package/dist/system/project-health.d.ts.map +1 -1
  414. package/dist/system/project-health.js +8 -3
  415. package/dist/system/project-health.js.map +1 -1
  416. package/dist/task-work/index.d.ts.map +1 -1
  417. package/dist/task-work/index.js +9 -6
  418. package/dist/task-work/index.js.map +1 -1
  419. package/dist/tasks/ac-coverage-gate.d.ts.map +1 -1
  420. package/dist/tasks/ac-coverage-gate.js +3 -0
  421. package/dist/tasks/ac-coverage-gate.js.map +1 -1
  422. package/dist/tasks/ac-table.d.ts +35 -7
  423. package/dist/tasks/ac-table.d.ts.map +1 -1
  424. package/dist/tasks/ac-table.js +119 -14
  425. package/dist/tasks/ac-table.js.map +1 -1
  426. package/dist/tasks/add.d.ts.map +1 -1
  427. package/dist/tasks/add.js +48 -2
  428. package/dist/tasks/add.js.map +1 -1
  429. package/dist/tasks/analyze.d.ts.map +1 -1
  430. package/dist/tasks/analyze.js +3 -2
  431. package/dist/tasks/analyze.js.map +1 -1
  432. package/dist/tasks/backfill-child-projections.js +47 -6
  433. package/dist/tasks/backfill-child-projections.js.map +1 -1
  434. package/dist/tasks/complete.d.ts.map +1 -1
  435. package/dist/tasks/complete.js +6 -1
  436. package/dist/tasks/complete.js.map +1 -1
  437. package/dist/tasks/completion-evaluation.d.ts.map +1 -1
  438. package/dist/tasks/completion-evaluation.js +3 -0
  439. package/dist/tasks/completion-evaluation.js.map +1 -1
  440. package/dist/tasks/evidence.d.ts +19 -1
  441. package/dist/tasks/evidence.d.ts.map +1 -1
  442. package/dist/tasks/evidence.js +93 -21
  443. package/dist/tasks/evidence.js.map +1 -1
  444. package/dist/tasks/infer-add-params.js +1 -1
  445. package/dist/tasks/infer-add-params.js.map +1 -1
  446. package/dist/tasks/task-context.d.ts.map +1 -1
  447. package/dist/tasks/task-context.js +3 -1
  448. package/dist/tasks/task-context.js.map +1 -1
  449. package/dist/tasks/task-import.d.ts.map +1 -1
  450. package/dist/tasks/task-import.js +11 -3
  451. package/dist/tasks/task-import.js.map +1 -1
  452. package/dist/tasks/task-next.d.ts +5 -1
  453. package/dist/tasks/task-next.d.ts.map +1 -1
  454. package/dist/tasks/task-next.js +7 -2
  455. package/dist/tasks/task-next.js.map +1 -1
  456. package/dist/validation/compliance.d.ts +5 -1
  457. package/dist/validation/compliance.d.ts.map +1 -1
  458. package/dist/validation/compliance.js +24 -3
  459. package/dist/validation/compliance.js.map +1 -1
  460. package/dist/validation/engine-ops.d.ts.map +1 -1
  461. package/dist/validation/engine-ops.js +3 -2
  462. package/dist/validation/engine-ops.js.map +1 -1
  463. package/dist/validation/index.d.ts +1 -1
  464. package/dist/validation/index.d.ts.map +1 -1
  465. package/dist/validation/index.js +1 -1
  466. package/dist/validation/index.js.map +1 -1
  467. package/dist/validation/protocol-common.d.ts +47 -2
  468. package/dist/validation/protocol-common.d.ts.map +1 -1
  469. package/dist/validation/protocol-common.js +86 -21
  470. package/dist/validation/protocol-common.js.map +1 -1
  471. package/dist/workgraph/scaffold-apply.d.ts.map +1 -1
  472. package/dist/workgraph/scaffold-apply.js +14 -5
  473. package/dist/workgraph/scaffold-apply.js.map +1 -1
  474. package/migrations/README.md +12 -0
  475. package/migrations/drizzle-cleo-project/20260928120000_t12341-row-uids/migration.sql +169 -0
  476. package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/migration.sql +76 -0
  477. package/migrations/drizzle-cleo-project/20260930160000_t12886-dependency-cycle-guard/revert.sql +7 -0
  478. package/migrations/sync-journal/20260929140000_t12342-sync-clock/migration.sql +42 -0
  479. package/package.json +13 -13
  480. package/templates/CLEO-INJECTION.md +2 -2
  481. package/templates/CLEO-REFERENCE.md +5 -1
@@ -179,7 +179,7 @@
179
179
  * @task T12535
180
180
  */
181
181
  import { createHash } from 'node:crypto';
182
- import { existsSync } from 'node:fs';
182
+ import { existsSync, statSync } from 'node:fs';
183
183
  import { basename, dirname } from 'node:path';
184
184
  import { fileURLToPath } from 'node:url';
185
185
  import { ExitCode } from '@cleocode/contracts';
@@ -187,7 +187,7 @@ import { z } from 'zod';
187
187
  import { CleoError } from '../errors.js';
188
188
  import { getLogger } from '../logger.js';
189
189
  import { getCleoVersion } from '../scaffold/ensure-config.js';
190
- import { isPinnedBackup, pinBackup } from './backup-sidecar.js';
190
+ import { isPinnedBackup, pinBackup, readBackupSidecar, restoreBackupSidecar, unpinBackup, } from './backup-sidecar.js';
191
191
  import { blobFileForRow, pinBlob, restoreBlob } from './blob-keep.js';
192
192
  import { planMigrationSnapshot, writeMigrationSnapshot } from './pre-repair-snapshot.js';
193
193
  const log = getLogger('twin-collapse');
@@ -1571,7 +1571,11 @@ function collapsePair(db, pair, snapshotPath, dbPath) {
1571
1571
  task: 'T12535',
1572
1572
  collapsedAt: state?.collapsedAt || now,
1573
1573
  lastMergedAt: now,
1574
- snapshot: state?.snapshot ?? snapshotPath,
1574
+ // Only an initial collapse records the snapshot it took. A later one
1575
+ // keeps what the marker holds, including `null` after an owner
1576
+ // released it (T12767): the snapshot another pair's initial collapse
1577
+ // took is not this pair's pre-collapse store.
1578
+ snapshot: state === undefined ? snapshotPath : state.snapshot,
1575
1579
  hashes: { bare: pair.bareHashes(db), twin: pair.twinHashes(db) },
1576
1580
  dropped: state === undefined ? plan.dropped : state.dropped,
1577
1581
  kept: state === undefined ? plan.kept.slice(0, MAX_CONFLICTS) : state.kept,
@@ -1924,9 +1928,10 @@ function stickySetsIfPresent(db, table) {
1924
1928
  * @returns The plan.
1925
1929
  * @task T12727
1926
1930
  */
1927
- export function planTwinCollapseRecovery(live, snapshot) {
1931
+ export function planTwinCollapseRecovery(live, snapshot, options = {}) {
1928
1932
  const state = readState(live, SCHEMA_META);
1929
- const snapshotPath = state?.snapshot ?? null;
1933
+ const recorded = state?.snapshot ?? null;
1934
+ const snapshotPath = recorded === null ? null : (options.snapshotPath ?? recorded);
1930
1935
  const liveKv = kvRows(live, 'tasks_schema_meta');
1931
1936
  const receipts = [...recoveryReceipts(live)]
1932
1937
  .filter(([, r]) => r.rolledBackAt === null)
@@ -1935,12 +1940,14 @@ export function planTwinCollapseRecovery(live, snapshot) {
1935
1940
  const empty = {
1936
1941
  snapshot: snapshotPath,
1937
1942
  snapshotExists: snapshot !== null,
1943
+ snapshotPinned: recoverySnapshotPinned(snapshotPath),
1938
1944
  archive: [],
1939
1945
  focusNotesAdded: 0,
1940
1946
  stickyArchived: [],
1941
1947
  stickyArchiveKey: STICKY_ARCHIVE_KEY,
1942
1948
  receipts,
1943
1949
  changes: false,
1950
+ movedFrom: recorded !== null && snapshotPath !== recorded ? recorded : null,
1944
1951
  };
1945
1952
  if (snapshot === null)
1946
1953
  return empty;
@@ -1959,11 +1966,25 @@ export function planTwinCollapseRecovery(live, snapshot) {
1959
1966
  continue; // not replaced
1960
1967
  const reason = sBare.has(key) ? 'replaced' : 'dropped';
1961
1968
  const done = liveKv.get(key) === twinValue || archivedValues.has(twinValue);
1962
- if (key === 'focus_state' && focusBefore !== null && !done && receipts.length === 0) {
1963
- const merged = mergeFocusState(focusBefore, twinValue);
1964
- if (merged !== focusBefore) {
1965
- focusNotesAdded = sessionNotesOf(merged).length - sessionNotesOf(focusBefore).length;
1966
- focusState = merged;
1969
+ if (key === 'focus_state' && !done && receipts.length === 0) {
1970
+ if (focusBefore !== null) {
1971
+ const merged = mergeFocusState(focusBefore, twinValue);
1972
+ if (merged !== focusBefore) {
1973
+ focusNotesAdded = sessionNotesOf(merged).length - sessionNotesOf(focusBefore).length;
1974
+ focusState = merged;
1975
+ }
1976
+ }
1977
+ else if (reason === 'dropped') {
1978
+ // Only the twin held it (the kodomeet shape) and nothing replaced the
1979
+ // legacy key since: its notes are live again. Its pointer is not:
1980
+ // bound sessions keep their focus under `focus_state:<sessionId>`
1981
+ // (T11345, T12501), and the next keyless one would adopt a live legacy
1982
+ // pointer months stale. The full value stays in the archive (T12771).
1983
+ const parsed = FocusNotesShape.safeParse(parseJson(twinValue));
1984
+ if (parsed.success) {
1985
+ focusState = JSON.stringify({ ...parsed.data, currentTask: null });
1986
+ focusNotesAdded = parsed.data.sessionNotes.length;
1987
+ }
1967
1988
  }
1968
1989
  }
1969
1990
  if (done)
@@ -2017,6 +2038,7 @@ export function planTwinCollapseRecovery(live, snapshot) {
2017
2038
  };
2018
2039
  recoveryWrites.set(plan, {
2019
2040
  snapshot,
2041
+ options,
2020
2042
  kv,
2021
2043
  focusBefore,
2022
2044
  focusState,
@@ -2042,19 +2064,36 @@ export function planTwinCollapseRecovery(live, snapshot) {
2042
2064
  * snapshot is missing (nothing is written).
2043
2065
  * @task T12727
2044
2066
  */
2045
- export function applyTwinCollapseRecovery(live, plan) {
2067
+ export function applyTwinCollapseRecovery(live, plan, onRepoint) {
2046
2068
  if (plan.snapshot === null)
2047
- return { plan, receipt: null };
2069
+ return { plan, receipt: null, repointed: null };
2048
2070
  const preview = recoveryWrites.get(plan);
2049
2071
  if (!plan.snapshotExists || preview === undefined)
2050
2072
  throw missingSnapshot(plan.snapshot);
2051
2073
  live.exec('BEGIN IMMEDIATE');
2052
2074
  try {
2053
- const fresh = planTwinCollapseRecovery(live, preview.snapshot);
2075
+ const fresh = planTwinCollapseRecovery(live, preview.snapshot, preview.options);
2054
2076
  const writes = recoveryWrites.get(fresh);
2077
+ // Only when there is something to write (T12772): a re-run on a
2078
+ // recovered store is a no-op whatever the pin. Checked before anything
2079
+ // (the re-point, its audit row) is written.
2080
+ if (fresh.changes && writes !== undefined && !fresh.snapshotPinned)
2081
+ throw unpinnedSnapshot(fresh.snapshot);
2082
+ // A moved store (T12788): the markers name the file where it lives now,
2083
+ // whether or not anything is left to recover. `onRepoint` audits it just
2084
+ // before COMMIT, so a failure that rolls the re-point back leaves no
2085
+ // audit row claiming it.
2086
+ let repointed = null;
2087
+ if (fresh.movedFrom !== null && fresh.snapshot !== null)
2088
+ repointed = repointSnapshotMarkers(live, fresh.movedFrom, fresh.snapshot);
2055
2089
  if (!fresh.changes || writes === undefined) {
2056
- live.exec('ROLLBACK');
2057
- return { plan: fresh, receipt: null };
2090
+ if (repointed === null)
2091
+ live.exec('ROLLBACK');
2092
+ else {
2093
+ onRepoint?.(repointed);
2094
+ live.exec('COMMIT');
2095
+ }
2096
+ return { plan: fresh, receipt: null, repointed };
2058
2097
  }
2059
2098
  const recoveredAt = new Date().toISOString();
2060
2099
  let id = `${TWIN_COLLAPSE_RECOVERY_PREFIX}${recoveredAt}`;
@@ -2090,8 +2129,10 @@ export function applyTwinCollapseRecovery(live, plan) {
2090
2129
  if (writes.stickyArchive !== null)
2091
2130
  writeKv(live, 'brain_schema_meta', fresh.stickyArchiveKey, writes.stickyArchive);
2092
2131
  writeKv(live, 'tasks_schema_meta', id, JSON.stringify(receipt));
2132
+ if (repointed !== null)
2133
+ onRepoint?.(repointed);
2093
2134
  live.exec('COMMIT');
2094
- return { plan: fresh, receipt };
2135
+ return { plan: fresh, receipt, repointed };
2095
2136
  }
2096
2137
  catch (error) {
2097
2138
  if (live.isTransaction)
@@ -2099,6 +2140,24 @@ export function applyTwinCollapseRecovery(live, plan) {
2099
2140
  throw error;
2100
2141
  }
2101
2142
  }
2143
+ /** Point every marker that records `from` at `to` (inside the caller's transaction). */
2144
+ function repointSnapshotMarkers(live, from, to) {
2145
+ const markers = [];
2146
+ for (const pair of PAIRS) {
2147
+ if (!hasMainTable(live, pair.kvTable))
2148
+ continue;
2149
+ const key = `${TWIN_COLLAPSE_MARKER_PREFIX}${pair.table}`;
2150
+ const raw = readKv(live, pair.kvTable, key);
2151
+ const parsed = raw === undefined ? undefined : parseJson(raw);
2152
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
2153
+ continue;
2154
+ if (parsed.snapshot !== from)
2155
+ continue;
2156
+ writeKv(live, pair.kvTable, key, JSON.stringify({ ...parsed, snapshot: to }));
2157
+ markers.push(`${pair.kvTable}:${key}`);
2158
+ }
2159
+ return { from, to, markers };
2160
+ }
2102
2161
  /** The error for a recorded snapshot that is not on disk. */
2103
2162
  export function missingSnapshot(path) {
2104
2163
  return new CleoError(ExitCode.NOT_FOUND, `${E_TWIN_COLLAPSE_RECOVER}: the pre-collapse snapshot ${path ?? '(none recorded)'} is missing; nothing was recovered`, {
@@ -2106,6 +2165,28 @@ export function missingSnapshot(path) {
2106
2165
  details: { field: 'snapshot', actual: path },
2107
2166
  });
2108
2167
  }
2168
+ /** The error for a recorded snapshot rotation could still delete. */
2169
+ export function unpinnedSnapshot(path) {
2170
+ return new CleoError(ExitCode.VALIDATION_ERROR, `${E_TWIN_COLLAPSE_RECOVER}: the pre-collapse snapshot ${path ?? '(none recorded)'} is not pinned, so backup rotation may delete it; nothing was recovered`, {
2171
+ fix: 'cleo doctor twin-collapse --recover --pin-snapshot # pins it (writes only its .meta.json sidecar), then recovers',
2172
+ details: { field: 'snapshotPinned', expected: true, actual: false },
2173
+ });
2174
+ }
2175
+ /** Whether the recorded snapshot is on disk and pinned. */
2176
+ function recoverySnapshotPinned(path) {
2177
+ return (path !== null && existsSync(path) && isPinnedBackup(dirname(path), basename(path), 'migration'));
2178
+ }
2179
+ /**
2180
+ * Pin the recorded pre-collapse snapshot before a recovery
2181
+ * (`--pin-snapshot`): writes its `.meta.json` sidecar only, never the snapshot.
2182
+ *
2183
+ * @param path - The snapshot the marker records.
2184
+ * @returns Whether it is pinned now.
2185
+ * @task T12727
2186
+ */
2187
+ export function pinRecoverySnapshot(path) {
2188
+ return pinBackup(path, 'migration', SNAPSHOT_PIN_REASON);
2189
+ }
2109
2190
  /**
2110
2191
  * Undo one recovery apply (`cleo doctor twin-collapse --rollback <id>`), in
2111
2192
  * one `BEGIN IMMEDIATE` transaction:
@@ -2152,12 +2233,16 @@ export function rollbackTwinCollapseRecovery(live, id) {
2152
2233
  }
2153
2234
  let focusState = 'none';
2154
2235
  let notesRemoved = 0;
2155
- if (receipt.after.focusState !== null && receipt.before.focusState !== null) {
2236
+ if (receipt.after.focusState !== null) {
2156
2237
  const current = readKv(live, 'tasks_schema_meta', 'focus_state');
2157
2238
  if (current !== undefined && sha(current) === receipt.after.focusState) {
2158
2239
  notesRemoved =
2159
- sessionNotesOf(current).length - sessionNotesOf(receipt.before.focusState).length;
2160
- writeKv(live, 'tasks_schema_meta', 'focus_state', receipt.before.focusState);
2240
+ sessionNotesOf(current).length -
2241
+ sessionNotesOf(receipt.before.focusState ?? undefined).length;
2242
+ if (receipt.before.focusState === null)
2243
+ live.prepare("DELETE FROM main.tasks_schema_meta WHERE key = 'focus_state'").run();
2244
+ else
2245
+ writeKv(live, 'tasks_schema_meta', 'focus_state', receipt.before.focusState);
2161
2246
  focusState = 'restored';
2162
2247
  }
2163
2248
  else if (current !== undefined) {
@@ -2203,4 +2288,147 @@ export function rollbackTwinCollapseRecovery(live, id) {
2203
2288
  throw error;
2204
2289
  }
2205
2290
  }
2291
+ // ── releasing a pre-collapse snapshot (T12767) ──────────────────────────────
2292
+ /** Error code of a snapshot release that cannot proceed; nothing was written. */
2293
+ export const E_TWIN_COLLAPSE_RELEASE = 'E_TWIN_COLLAPSE_RELEASE';
2294
+ /** Pairs whose loss the recovery (T12727) verifies; a release covers only these. */
2295
+ const RECOVERABLE_PAIRS = [SCHEMA_META, STICKY_TAGS];
2296
+ /** Whether a recorded snapshot path is the one `id` names (backup id, file name or path). */
2297
+ function namesSnapshot(path, id) {
2298
+ const want = basename(id);
2299
+ const have = basename(path);
2300
+ return have === want || have.endsWith(`.${want}`);
2301
+ }
2302
+ /**
2303
+ * Plan releasing a pre-collapse snapshot (T12767): which markers reference
2304
+ * it, how many bytes it holds, and whether it may be released. It may only
2305
+ * after a verified recovery or a no-recovery-needed check: the recovery plan
2306
+ * against it ({@link planTwinCollapseRecovery}) must find nothing left to
2307
+ * recover, and only the `schema_meta` / `sticky_tags` markers (the pairs the
2308
+ * recovery covers) may reference it.
2309
+ *
2310
+ * @param live - The project `cleo.db` connection (read-only is enough).
2311
+ * @param id - The snapshot: its backup id (`migration-<timestamp>`), file name or path.
2312
+ * @param snapshot - The snapshot opened read-only, or `null` when it is not on disk.
2313
+ * @returns The plan.
2314
+ * @task T12767
2315
+ */
2316
+ export function planSnapshotRelease(live, id, snapshot, options = {}) {
2317
+ let path = null;
2318
+ const markers = [];
2319
+ const blockers = [];
2320
+ for (const pair of PAIRS) {
2321
+ if (!hasMainTable(live, pair.kvTable))
2322
+ continue;
2323
+ const recorded = readState(live, pair)?.snapshot;
2324
+ if (typeof recorded !== 'string' || !namesSnapshot(recorded, id))
2325
+ continue;
2326
+ path ??= recorded;
2327
+ markers.push(`${pair.kvTable}:${TWIN_COLLAPSE_MARKER_PREFIX}${pair.table}`);
2328
+ if (!RECOVERABLE_PAIRS.includes(pair))
2329
+ blockers.push(`the ${pair.table} marker references it, and the recovery does not cover ${pair.table}`);
2330
+ }
2331
+ if (path === null)
2332
+ return {
2333
+ snapshot: null,
2334
+ markers,
2335
+ exists: false,
2336
+ bytes: 0,
2337
+ basis: null,
2338
+ receipts: [],
2339
+ blockers: [`no twin-collapse marker references ${id}`],
2340
+ movedFrom: null,
2341
+ };
2342
+ // A moved store (T12788): the markers name the old path; the file is local.
2343
+ const recorded = path;
2344
+ path = options.snapshotPath ?? recorded;
2345
+ const exists = existsSync(path);
2346
+ const bytes = [path, `${path}-wal`, `${path}-shm`].reduce((sum, f) => sum + (existsSync(f) ? statSync(f).size : 0), 0);
2347
+ const receipts = [...recoveryReceipts(live)]
2348
+ .filter(([, r]) => r.rolledBackAt === null && (r.snapshot === path || r.snapshot === recorded))
2349
+ .map(([k]) => k)
2350
+ .sort();
2351
+ if (!exists || snapshot === null)
2352
+ blockers.push('the snapshot is not on disk, so no recovery check can run against it');
2353
+ else {
2354
+ const recovery = planTwinCollapseRecovery(live, snapshot, { snapshotPath: path });
2355
+ if (recovery.changes)
2356
+ blockers.push(`it still holds ${recovery.archive.length} value(s), ${recovery.focusNotesAdded} session note(s) and ` +
2357
+ `${recovery.stickyArchived.length} sticky tag(s) the live store lacks: run --recover first`);
2358
+ }
2359
+ return {
2360
+ snapshot: path,
2361
+ markers,
2362
+ exists,
2363
+ bytes,
2364
+ basis: blockers.length > 0 ? null : receipts.length > 0 ? 'recovered' : 'no-recovery-needed',
2365
+ receipts,
2366
+ blockers,
2367
+ movedFrom: recorded !== path ? recorded : null,
2368
+ };
2369
+ }
2370
+ /** The release refusal for a plan with blockers. */
2371
+ export function releaseRefused(id, plan) {
2372
+ return new CleoError(ExitCode.VALIDATION_ERROR, `${E_TWIN_COLLAPSE_RELEASE}: ${id} cannot be released: ${plan.blockers.join('; ')}; nothing was changed`, {
2373
+ fix: `cleo doctor twin-collapse --recover --dry-run # then --recover, and --release-snapshot ${id} --dry-run`,
2374
+ details: { field: 'snapshot', actual: plan.snapshot, blockers: plan.blockers },
2375
+ });
2376
+ }
2377
+ /**
2378
+ * Release a pre-collapse snapshot, in one `BEGIN IMMEDIATE` transaction: the
2379
+ * plan is re-checked under the write lock, each referencing marker's
2380
+ * `snapshot` is cleared (so an open no longer pins it and rotation no longer
2381
+ * keeps it), its sidecar pin is released, and `audit` records the release
2382
+ * before the commit (a failed audit write refuses it). The snapshot file is
2383
+ * never touched; it rotates normally from then on.
2384
+ *
2385
+ * @param live - The project `cleo.db` connection, outside a transaction.
2386
+ * @param id - The snapshot: backup id, file name or path.
2387
+ * @param snapshot - The snapshot opened read-only, or `null`.
2388
+ * @param audit - Appends the audit row; throws to refuse.
2389
+ * @returns What was released.
2390
+ * @throws {CleoError} {@link E_TWIN_COLLAPSE_RELEASE} when it may not be released.
2391
+ * @task T12767
2392
+ */
2393
+ export function releaseTwinCollapseSnapshot(live, id, snapshot, audit, options = {}) {
2394
+ live.exec('BEGIN IMMEDIATE');
2395
+ let sidecarBefore;
2396
+ let path = null;
2397
+ try {
2398
+ const plan = planSnapshotRelease(live, id, snapshot, options);
2399
+ if (plan.basis === null || plan.snapshot === null)
2400
+ throw releaseRefused(id, plan);
2401
+ path = plan.snapshot;
2402
+ for (const pair of PAIRS) {
2403
+ const key = `${TWIN_COLLAPSE_MARKER_PREFIX}${pair.table}`;
2404
+ if (!plan.markers.includes(`${pair.kvTable}:${key}`))
2405
+ continue;
2406
+ const raw = readKv(live, pair.kvTable, key);
2407
+ const parsed = raw === undefined ? undefined : parseJson(raw);
2408
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
2409
+ throw releaseRefused(id, { ...plan, blockers: [`the ${pair.table} marker is unreadable`] });
2410
+ writeKv(live, pair.kvTable, key, JSON.stringify({ ...parsed, snapshot: null }));
2411
+ }
2412
+ sidecarBefore = readBackupSidecar(path, 'migration');
2413
+ const sidecar = unpinBackup(path, 'migration', `T12767: released by an owner after a ${plan.basis} check`);
2414
+ const release = {
2415
+ snapshot: path,
2416
+ markers: plan.markers,
2417
+ basis: plan.basis,
2418
+ bytes: plan.bytes,
2419
+ releasedAt: sidecar.releasedAt ?? new Date().toISOString(),
2420
+ movedFrom: plan.movedFrom,
2421
+ };
2422
+ audit({ ...release, receipts: plan.receipts });
2423
+ live.exec('COMMIT');
2424
+ return release;
2425
+ }
2426
+ catch (error) {
2427
+ if (live.isTransaction)
2428
+ live.exec('ROLLBACK');
2429
+ if (sidecarBefore !== undefined && path !== null)
2430
+ restoreBackupSidecar(path, 'migration', sidecarBefore);
2431
+ throw error;
2432
+ }
2433
+ }
2206
2434
  //# sourceMappingURL=twin-collapse.js.map