@cleocode/core 2026.9.20 → 2026.9.22

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 (961) hide show
  1. package/dist/adapters/discovery.d.ts.map +1 -1
  2. package/dist/adapters/discovery.js +3 -10
  3. package/dist/adapters/discovery.js.map +1 -1
  4. package/dist/adrs/link-pipeline.js +2 -2
  5. package/dist/adrs/link-pipeline.js.map +1 -1
  6. package/dist/adrs/parse.js +3 -3
  7. package/dist/adrs/parse.js.map +1 -1
  8. package/dist/agents/invoke-meta-agent.d.ts.map +1 -1
  9. package/dist/agents/invoke-meta-agent.js +8 -4
  10. package/dist/agents/invoke-meta-agent.js.map +1 -1
  11. package/dist/agents/scaffold.d.ts.map +1 -1
  12. package/dist/agents/scaffold.js +0 -1
  13. package/dist/agents/scaffold.js.map +1 -1
  14. package/dist/bootstrap.d.ts +5 -1
  15. package/dist/bootstrap.d.ts.map +1 -1
  16. package/dist/bootstrap.js +45 -21
  17. package/dist/bootstrap.js.map +1 -1
  18. package/dist/cloud/crypto.d.ts +47 -0
  19. package/dist/cloud/crypto.d.ts.map +1 -0
  20. package/dist/cloud/crypto.js +223 -0
  21. package/dist/cloud/crypto.js.map +1 -0
  22. package/dist/cloud/http.d.ts +52 -0
  23. package/dist/cloud/http.d.ts.map +1 -0
  24. package/dist/cloud/http.js +98 -0
  25. package/dist/cloud/http.js.map +1 -0
  26. package/dist/cloud/index.d.ts +19 -0
  27. package/dist/cloud/index.d.ts.map +1 -0
  28. package/dist/cloud/index.js +19 -0
  29. package/dist/cloud/index.js.map +1 -0
  30. package/dist/cloud/journal.d.ts +169 -0
  31. package/dist/cloud/journal.d.ts.map +1 -0
  32. package/dist/cloud/journal.js +428 -0
  33. package/dist/cloud/journal.js.map +1 -0
  34. package/dist/cloud/keys.d.ts +213 -0
  35. package/dist/cloud/keys.d.ts.map +1 -0
  36. package/dist/cloud/keys.js +362 -0
  37. package/dist/cloud/keys.js.map +1 -0
  38. package/dist/cloud/manifest-check.d.ts +36 -0
  39. package/dist/cloud/manifest-check.d.ts.map +1 -0
  40. package/dist/cloud/manifest-check.js +70 -0
  41. package/dist/cloud/manifest-check.js.map +1 -0
  42. package/dist/cloud/projects.d.ts +13 -0
  43. package/dist/cloud/projects.d.ts.map +1 -0
  44. package/dist/cloud/projects.js +11 -0
  45. package/dist/cloud/projects.js.map +1 -0
  46. package/dist/cloud/signing.d.ts +105 -0
  47. package/dist/cloud/signing.d.ts.map +1 -0
  48. package/dist/cloud/signing.js +117 -0
  49. package/dist/cloud/signing.js.map +1 -0
  50. package/dist/cloud/streams.d.ts +6 -0
  51. package/dist/cloud/streams.d.ts.map +1 -0
  52. package/dist/cloud/streams.js +5 -0
  53. package/dist/cloud/streams.js.map +1 -0
  54. package/dist/decide/audit.d.ts +131 -0
  55. package/dist/decide/audit.d.ts.map +1 -0
  56. package/dist/decide/audit.js +98 -0
  57. package/dist/decide/audit.js.map +1 -0
  58. package/dist/decide/budget.d.ts +91 -0
  59. package/dist/decide/budget.d.ts.map +1 -0
  60. package/dist/decide/budget.js +194 -0
  61. package/dist/decide/budget.js.map +1 -0
  62. package/dist/decide/cache.d.ts +49 -0
  63. package/dist/decide/cache.d.ts.map +1 -0
  64. package/dist/decide/cache.js +87 -0
  65. package/dist/decide/cache.js.map +1 -0
  66. package/dist/decide/client.d.ts +103 -0
  67. package/dist/decide/client.d.ts.map +1 -0
  68. package/dist/decide/client.js +262 -0
  69. package/dist/decide/client.js.map +1 -0
  70. package/dist/decide/credentials.d.ts +159 -0
  71. package/dist/decide/credentials.d.ts.map +1 -0
  72. package/dist/decide/credentials.js +383 -0
  73. package/dist/decide/credentials.js.map +1 -0
  74. package/dist/decide/index.d.ts +18 -0
  75. package/dist/decide/index.d.ts.map +1 -0
  76. package/dist/decide/index.js +18 -0
  77. package/dist/decide/index.js.map +1 -0
  78. package/dist/decide/jev-wire.d.ts +155 -0
  79. package/dist/decide/jev-wire.d.ts.map +1 -0
  80. package/dist/decide/jev-wire.js +420 -0
  81. package/dist/decide/jev-wire.js.map +1 -0
  82. package/dist/decide/operations.d.ts +152 -0
  83. package/dist/decide/operations.d.ts.map +1 -0
  84. package/dist/decide/operations.js +199 -0
  85. package/dist/decide/operations.js.map +1 -0
  86. package/dist/decide/provider.d.ts +90 -0
  87. package/dist/decide/provider.d.ts.map +1 -0
  88. package/dist/decide/provider.js +43 -0
  89. package/dist/decide/provider.js.map +1 -0
  90. package/dist/decide/site.d.ts +148 -0
  91. package/dist/decide/site.d.ts.map +1 -0
  92. package/dist/decide/site.js +181 -0
  93. package/dist/decide/site.js.map +1 -0
  94. package/dist/decide/transport.d.ts +67 -0
  95. package/dist/decide/transport.d.ts.map +1 -0
  96. package/dist/decide/transport.js +350 -0
  97. package/dist/decide/transport.js.map +1 -0
  98. package/dist/dispatch/mutate-projection.d.ts.map +1 -1
  99. package/dist/dispatch/mutate-projection.js +5 -0
  100. package/dist/dispatch/mutate-projection.js.map +1 -1
  101. package/dist/docs/docs-update.d.ts.map +1 -1
  102. package/dist/docs/docs-update.js +25 -9
  103. package/dist/docs/docs-update.js.map +1 -1
  104. package/dist/docs/export-document.js +5963 -2406
  105. package/dist/docs/export-document.js.map +3 -3
  106. package/dist/docs/index.d.ts +2 -2
  107. package/dist/docs/index.d.ts.map +1 -1
  108. package/dist/docs/index.js +1 -1
  109. package/dist/docs/index.js.map +1 -1
  110. package/dist/docs/projection.d.ts.map +1 -1
  111. package/dist/docs/projection.js +2 -3
  112. package/dist/docs/projection.js.map +1 -1
  113. package/dist/docs/publish-pr.d.ts +69 -1
  114. package/dist/docs/publish-pr.d.ts.map +1 -1
  115. package/dist/docs/publish-pr.js +112 -10
  116. package/dist/docs/publish-pr.js.map +1 -1
  117. package/dist/doctor/db-substrate.d.ts +13 -8
  118. package/dist/doctor/db-substrate.d.ts.map +1 -1
  119. package/dist/doctor/db-substrate.js +39 -26
  120. package/dist/doctor/db-substrate.js.map +1 -1
  121. package/dist/doctor/index.d.ts +2 -0
  122. package/dist/doctor/index.d.ts.map +1 -1
  123. package/dist/doctor/index.js +1 -0
  124. package/dist/doctor/index.js.map +1 -1
  125. package/dist/doctor/knowledge.d.ts +16 -1
  126. package/dist/doctor/knowledge.d.ts.map +1 -1
  127. package/dist/doctor/knowledge.js +58 -32
  128. package/dist/doctor/knowledge.js.map +1 -1
  129. package/dist/doctor/nexus-schema-residency.d.ts +1 -1
  130. package/dist/doctor/nexus-schema-residency.d.ts.map +1 -1
  131. package/dist/doctor/nexus-schema-residency.js +3 -0
  132. package/dist/doctor/nexus-schema-residency.js.map +1 -1
  133. package/dist/doctor/project-identity.d.ts +44 -1
  134. package/dist/doctor/project-identity.d.ts.map +1 -1
  135. package/dist/doctor/project-identity.js +237 -10
  136. package/dist/doctor/project-identity.js.map +1 -1
  137. package/dist/doctor/projects.d.ts +170 -0
  138. package/dist/doctor/projects.d.ts.map +1 -0
  139. package/dist/doctor/projects.js +1075 -0
  140. package/dist/doctor/projects.js.map +1 -0
  141. package/dist/doctor/twin-collapse.d.ts +97 -0
  142. package/dist/doctor/twin-collapse.d.ts.map +1 -0
  143. package/dist/doctor/twin-collapse.js +168 -0
  144. package/dist/doctor/twin-collapse.js.map +1 -0
  145. package/dist/doctor/worktree-orphans.d.ts.map +1 -1
  146. package/dist/doctor/worktree-orphans.js +13 -29
  147. package/dist/doctor/worktree-orphans.js.map +1 -1
  148. package/dist/doctor/worktree-stores.d.ts +128 -0
  149. package/dist/doctor/worktree-stores.d.ts.map +1 -0
  150. package/dist/doctor/worktree-stores.js +374 -0
  151. package/dist/doctor/worktree-stores.js.map +1 -0
  152. package/dist/engine/engine-ops.d.ts +36 -6
  153. package/dist/engine/engine-ops.d.ts.map +1 -1
  154. package/dist/engine/engine-ops.js +115 -14
  155. package/dist/engine/engine-ops.js.map +1 -1
  156. package/dist/error-catalog.d.ts.map +1 -1
  157. package/dist/error-catalog.js +21 -0
  158. package/dist/error-catalog.js.map +1 -1
  159. package/dist/error-registry.d.ts.map +1 -1
  160. package/dist/error-registry.js +40 -0
  161. package/dist/error-registry.js.map +1 -1
  162. package/dist/gateway-client/generated/types.gen.d.ts +1 -1
  163. package/dist/gc/cleanup.d.ts.map +1 -1
  164. package/dist/gc/cleanup.js +32 -19
  165. package/dist/gc/cleanup.js.map +1 -1
  166. package/dist/git/bounded-git.d.ts +170 -0
  167. package/dist/git/bounded-git.d.ts.map +1 -0
  168. package/dist/git/bounded-git.js +371 -0
  169. package/dist/git/bounded-git.js.map +1 -0
  170. package/dist/git/work-tree.d.ts +20 -0
  171. package/dist/git/work-tree.d.ts.map +1 -1
  172. package/dist/git/work-tree.js +20 -2
  173. package/dist/git/work-tree.js.map +1 -1
  174. package/dist/hooks/handlers/session-hooks.d.ts +11 -26
  175. package/dist/hooks/handlers/session-hooks.d.ts.map +1 -1
  176. package/dist/hooks/handlers/session-hooks.js +18 -47
  177. package/dist/hooks/handlers/session-hooks.js.map +1 -1
  178. package/dist/hooks/payload-schemas.d.ts +2 -2
  179. package/dist/index.d.ts +8 -5
  180. package/dist/index.d.ts.map +1 -1
  181. package/dist/index.js +6 -3
  182. package/dist/index.js.map +1 -1
  183. package/dist/init/engine-ops.d.ts.map +1 -1
  184. package/dist/init/engine-ops.js +23 -1
  185. package/dist/init/engine-ops.js.map +1 -1
  186. package/dist/init.d.ts +158 -1
  187. package/dist/init.d.ts.map +1 -1
  188. package/dist/init.js +578 -53
  189. package/dist/init.js.map +1 -1
  190. package/dist/inject/index.d.ts.map +1 -1
  191. package/dist/inject/index.js +8 -3
  192. package/dist/inject/index.js.map +1 -1
  193. package/dist/injection.d.ts +55 -0
  194. package/dist/injection.d.ts.map +1 -1
  195. package/dist/injection.js +102 -6
  196. package/dist/injection.js.map +1 -1
  197. package/dist/internal.d.ts +11 -7
  198. package/dist/internal.d.ts.map +1 -1
  199. package/dist/internal.js +9 -5
  200. package/dist/internal.js.map +1 -1
  201. package/dist/issue/diagnostics.d.ts.map +1 -1
  202. package/dist/issue/diagnostics.js +2 -1
  203. package/dist/issue/diagnostics.js.map +1 -1
  204. package/dist/lib/concurrency.d.ts +25 -0
  205. package/dist/lib/concurrency.d.ts.map +1 -0
  206. package/dist/lib/concurrency.js +43 -0
  207. package/dist/lib/concurrency.js.map +1 -0
  208. package/dist/lib/index.d.ts +1 -0
  209. package/dist/lib/index.d.ts.map +1 -1
  210. package/dist/lib/index.js +1 -0
  211. package/dist/lib/index.js.map +1 -1
  212. package/dist/lifecycle/engine-ops.d.ts.map +1 -1
  213. package/dist/lifecycle/engine-ops.js +4 -2
  214. package/dist/lifecycle/engine-ops.js.map +1 -1
  215. package/dist/lifecycle/stage-guidance.d.ts +5 -0
  216. package/dist/lifecycle/stage-guidance.d.ts.map +1 -1
  217. package/dist/lifecycle/stage-guidance.js +14 -4
  218. package/dist/lifecycle/stage-guidance.js.map +1 -1
  219. package/dist/llm/catalog-cache.d.ts +3 -2
  220. package/dist/llm/catalog-cache.d.ts.map +1 -1
  221. package/dist/llm/catalog-cache.js +5 -5
  222. package/dist/llm/catalog-cache.js.map +1 -1
  223. package/dist/llm/credentials.d.ts +4 -4
  224. package/dist/llm/credentials.js +6 -6
  225. package/dist/llm/credentials.js.map +1 -1
  226. package/dist/llm/plugin-facade.js +4400 -1801
  227. package/dist/llm/plugin-facade.js.map +3 -3
  228. package/dist/llm/stable-device-id.d.ts.map +1 -1
  229. package/dist/llm/stable-device-id.js +3 -5
  230. package/dist/llm/stable-device-id.js.map +1 -1
  231. package/dist/memory/attention.js +31 -31
  232. package/dist/memory/attention.js.map +1 -1
  233. package/dist/memory/decision-contradiction.d.ts +152 -0
  234. package/dist/memory/decision-contradiction.d.ts.map +1 -0
  235. package/dist/memory/decision-contradiction.js +273 -0
  236. package/dist/memory/decision-contradiction.js.map +1 -0
  237. package/dist/memory/decisions.d.ts +42 -11
  238. package/dist/memory/decisions.d.ts.map +1 -1
  239. package/dist/memory/decisions.js +153 -56
  240. package/dist/memory/decisions.js.map +1 -1
  241. package/dist/memory/dialectic-evaluator.d.ts +7 -0
  242. package/dist/memory/dialectic-evaluator.d.ts.map +1 -1
  243. package/dist/memory/dialectic-evaluator.js +23 -8
  244. package/dist/memory/dialectic-evaluator.js.map +1 -1
  245. package/dist/memory/dispatch-trace-format.d.ts +39 -0
  246. package/dist/memory/dispatch-trace-format.d.ts.map +1 -0
  247. package/dist/memory/dispatch-trace-format.js +54 -0
  248. package/dist/memory/dispatch-trace-format.js.map +1 -0
  249. package/dist/memory/dispatch-trace.d.ts.map +1 -1
  250. package/dist/memory/dispatch-trace.js +1 -27
  251. package/dist/memory/dispatch-trace.js.map +1 -1
  252. package/dist/memory/engine-compat.d.ts +2 -0
  253. package/dist/memory/engine-compat.d.ts.map +1 -1
  254. package/dist/memory/engine-compat.js +1 -0
  255. package/dist/memory/engine-compat.js.map +1 -1
  256. package/dist/memory/import-from-provider.js +3 -3
  257. package/dist/memory/import-from-provider.js.map +1 -1
  258. package/dist/memory/learnings.d.ts +2 -2
  259. package/dist/memory/observation-type-decision.d.ts +96 -0
  260. package/dist/memory/observation-type-decision.d.ts.map +1 -0
  261. package/dist/memory/observation-type-decision.js +218 -0
  262. package/dist/memory/observation-type-decision.js.map +1 -0
  263. package/dist/memory/redaction.js +2 -0
  264. package/dist/memory/redaction.js.map +1 -1
  265. package/dist/memory/retrieval/build-retrieval-bundle.d.ts +9 -2
  266. package/dist/memory/retrieval/build-retrieval-bundle.d.ts.map +1 -1
  267. package/dist/memory/retrieval/build-retrieval-bundle.js +42 -11
  268. package/dist/memory/retrieval/build-retrieval-bundle.js.map +1 -1
  269. package/dist/memory/retrieval/get-current-session-id.d.ts +5 -0
  270. package/dist/memory/retrieval/get-current-session-id.d.ts.map +1 -1
  271. package/dist/memory/retrieval/get-current-session-id.js +7 -2
  272. package/dist/memory/retrieval/get-current-session-id.js.map +1 -1
  273. package/dist/memory/retrieval/observe.d.ts.map +1 -1
  274. package/dist/memory/retrieval/observe.js +30 -29
  275. package/dist/memory/retrieval/observe.js.map +1 -1
  276. package/dist/nexus/analyze-orchestrator.d.ts +38 -0
  277. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  278. package/dist/nexus/analyze-orchestrator.js +136 -48
  279. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  280. package/dist/nexus/assessment-projection.d.ts +76 -0
  281. package/dist/nexus/assessment-projection.d.ts.map +1 -0
  282. package/dist/nexus/assessment-projection.js +143 -0
  283. package/dist/nexus/assessment-projection.js.map +1 -0
  284. package/dist/nexus/assessment-store.d.ts +14 -2
  285. package/dist/nexus/assessment-store.d.ts.map +1 -1
  286. package/dist/nexus/assessment-store.js +21 -3
  287. package/dist/nexus/assessment-store.js.map +1 -1
  288. package/dist/nexus/checkout-nonce.d.ts +48 -0
  289. package/dist/nexus/checkout-nonce.d.ts.map +1 -0
  290. package/dist/nexus/checkout-nonce.js +84 -0
  291. package/dist/nexus/checkout-nonce.js.map +1 -0
  292. package/dist/nexus/devices.d.ts +93 -0
  293. package/dist/nexus/devices.d.ts.map +1 -0
  294. package/dist/nexus/devices.js +141 -0
  295. package/dist/nexus/devices.js.map +1 -0
  296. package/dist/nexus/freshness.d.ts.map +1 -1
  297. package/dist/nexus/freshness.js +25 -6
  298. package/dist/nexus/freshness.js.map +1 -1
  299. package/dist/nexus/git-state.d.ts +225 -0
  300. package/dist/nexus/git-state.d.ts.map +1 -0
  301. package/dist/nexus/git-state.js +677 -0
  302. package/dist/nexus/git-state.js.map +1 -0
  303. package/dist/nexus/graph-manifest.d.ts +20 -4
  304. package/dist/nexus/graph-manifest.d.ts.map +1 -1
  305. package/dist/nexus/graph-manifest.js +40 -5
  306. package/dist/nexus/graph-manifest.js.map +1 -1
  307. package/dist/nexus/identity.d.ts +68 -23
  308. package/dist/nexus/identity.d.ts.map +1 -1
  309. package/dist/nexus/identity.js +99 -22
  310. package/dist/nexus/identity.js.map +1 -1
  311. package/dist/nexus/index.d.ts +5 -2
  312. package/dist/nexus/index.d.ts.map +1 -1
  313. package/dist/nexus/index.js +10 -4
  314. package/dist/nexus/index.js.map +1 -1
  315. package/dist/nexus/knowledge.d.ts +5 -0
  316. package/dist/nexus/knowledge.d.ts.map +1 -1
  317. package/dist/nexus/knowledge.js +40 -5
  318. package/dist/nexus/knowledge.js.map +1 -1
  319. package/dist/nexus/legacy-alias.d.ts +60 -0
  320. package/dist/nexus/legacy-alias.d.ts.map +1 -0
  321. package/dist/nexus/legacy-alias.js +68 -0
  322. package/dist/nexus/legacy-alias.js.map +1 -0
  323. package/dist/nexus/migrate-json-to-sqlite.js +2 -2
  324. package/dist/nexus/migrate-json-to-sqlite.js.map +1 -1
  325. package/dist/nexus/ops.d.ts +1 -0
  326. package/dist/nexus/ops.d.ts.map +1 -1
  327. package/dist/nexus/path-map.d.ts +264 -20
  328. package/dist/nexus/path-map.d.ts.map +1 -1
  329. package/dist/nexus/path-map.js +580 -44
  330. package/dist/nexus/path-map.js.map +1 -1
  331. package/dist/nexus/projects-clean.d.ts +9 -1
  332. package/dist/nexus/projects-clean.d.ts.map +1 -1
  333. package/dist/nexus/projects-clean.js +126 -14
  334. package/dist/nexus/projects-clean.js.map +1 -1
  335. package/dist/nexus/projects-scan.d.ts +56 -1
  336. package/dist/nexus/projects-scan.d.ts.map +1 -1
  337. package/dist/nexus/projects-scan.js +144 -3
  338. package/dist/nexus/projects-scan.js.map +1 -1
  339. package/dist/nexus/registry-hygiene.d.ts +18 -2
  340. package/dist/nexus/registry-hygiene.d.ts.map +1 -1
  341. package/dist/nexus/registry-hygiene.js +37 -11
  342. package/dist/nexus/registry-hygiene.js.map +1 -1
  343. package/dist/nexus/registry-roots.d.ts +47 -0
  344. package/dist/nexus/registry-roots.d.ts.map +1 -0
  345. package/dist/nexus/registry-roots.js +79 -0
  346. package/dist/nexus/registry-roots.js.map +1 -0
  347. package/dist/nexus/registry.d.ts +50 -9
  348. package/dist/nexus/registry.d.ts.map +1 -1
  349. package/dist/nexus/registry.js +311 -156
  350. package/dist/nexus/registry.js.map +1 -1
  351. package/dist/nexus/stored-roots.d.ts +171 -0
  352. package/dist/nexus/stored-roots.d.ts.map +1 -0
  353. package/dist/nexus/stored-roots.js +253 -0
  354. package/dist/nexus/stored-roots.js.map +1 -0
  355. package/dist/nexus/transfer.d.ts.map +1 -1
  356. package/dist/nexus/transfer.js +3 -0
  357. package/dist/nexus/transfer.js.map +1 -1
  358. package/dist/nexus/user-profile-hygiene.d.ts +168 -0
  359. package/dist/nexus/user-profile-hygiene.d.ts.map +1 -0
  360. package/dist/nexus/user-profile-hygiene.js +305 -0
  361. package/dist/nexus/user-profile-hygiene.js.map +1 -0
  362. package/dist/nexus/user-profile.d.ts +53 -2
  363. package/dist/nexus/user-profile.d.ts.map +1 -1
  364. package/dist/nexus/user-profile.js +106 -4
  365. package/dist/nexus/user-profile.js.map +1 -1
  366. package/dist/orchestrate/lifecycle-ops.d.ts.map +1 -1
  367. package/dist/orchestrate/lifecycle-ops.js +4 -1
  368. package/dist/orchestrate/lifecycle-ops.js.map +1 -1
  369. package/dist/orchestrate/pivot.d.ts.map +1 -1
  370. package/dist/orchestrate/pivot.js +5 -1
  371. package/dist/orchestrate/pivot.js.map +1 -1
  372. package/dist/orchestrate/plan.d.ts.map +1 -1
  373. package/dist/orchestrate/plan.js +5 -2
  374. package/dist/orchestrate/plan.js.map +1 -1
  375. package/dist/orchestrate/query-ops.d.ts +7 -2
  376. package/dist/orchestrate/query-ops.d.ts.map +1 -1
  377. package/dist/orchestrate/query-ops.js +17 -6
  378. package/dist/orchestrate/query-ops.js.map +1 -1
  379. package/dist/orchestrate/spawn-ops.d.ts +12 -0
  380. package/dist/orchestrate/spawn-ops.d.ts.map +1 -1
  381. package/dist/orchestrate/spawn-ops.js +157 -71
  382. package/dist/orchestrate/spawn-ops.js.map +1 -1
  383. package/dist/orchestration/bootstrap.d.ts.map +1 -1
  384. package/dist/orchestration/bootstrap.js +4 -2
  385. package/dist/orchestration/bootstrap.js.map +1 -1
  386. package/dist/orchestration/classify-readiness.d.ts +37 -1
  387. package/dist/orchestration/classify-readiness.d.ts.map +1 -1
  388. package/dist/orchestration/classify-readiness.js +48 -19
  389. package/dist/orchestration/classify-readiness.js.map +1 -1
  390. package/dist/orchestration/index.d.ts +4 -2
  391. package/dist/orchestration/index.d.ts.map +1 -1
  392. package/dist/orchestration/index.js +6 -4
  393. package/dist/orchestration/index.js.map +1 -1
  394. package/dist/orchestration/lead-rollup.d.ts +8 -5
  395. package/dist/orchestration/lead-rollup.d.ts.map +1 -1
  396. package/dist/orchestration/lead-rollup.js +32 -15
  397. package/dist/orchestration/lead-rollup.js.map +1 -1
  398. package/dist/orchestration/owner-decision-readiness.d.ts +88 -0
  399. package/dist/orchestration/owner-decision-readiness.d.ts.map +1 -0
  400. package/dist/orchestration/owner-decision-readiness.js +152 -0
  401. package/dist/orchestration/owner-decision-readiness.js.map +1 -0
  402. package/dist/orchestration/parallel.d.ts.map +1 -1
  403. package/dist/orchestration/parallel.js +10 -17
  404. package/dist/orchestration/parallel.js.map +1 -1
  405. package/dist/orchestration/psyche-memory-budget.d.ts +105 -0
  406. package/dist/orchestration/psyche-memory-budget.d.ts.map +1 -0
  407. package/dist/orchestration/psyche-memory-budget.js +383 -0
  408. package/dist/orchestration/psyche-memory-budget.js.map +1 -0
  409. package/dist/orchestration/spawn-prompt.d.ts +16 -2
  410. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  411. package/dist/orchestration/spawn-prompt.js +144 -181
  412. package/dist/orchestration/spawn-prompt.js.map +1 -1
  413. package/dist/orchestration/spawn.d.ts +7 -0
  414. package/dist/orchestration/spawn.d.ts.map +1 -1
  415. package/dist/orchestration/spawn.js +1 -0
  416. package/dist/orchestration/spawn.js.map +1 -1
  417. package/dist/orchestration/status.d.ts +8 -3
  418. package/dist/orchestration/status.d.ts.map +1 -1
  419. package/dist/orchestration/status.js +9 -6
  420. package/dist/orchestration/status.js.map +1 -1
  421. package/dist/orchestration/wave-topic.d.ts +54 -0
  422. package/dist/orchestration/wave-topic.d.ts.map +1 -0
  423. package/dist/orchestration/wave-topic.js +68 -0
  424. package/dist/orchestration/wave-topic.js.map +1 -0
  425. package/dist/orchestration/waves.d.ts +47 -8
  426. package/dist/orchestration/waves.d.ts.map +1 -1
  427. package/dist/orchestration/waves.js +152 -43
  428. package/dist/orchestration/waves.js.map +1 -1
  429. package/dist/paths.d.ts +24 -8
  430. package/dist/paths.d.ts.map +1 -1
  431. package/dist/paths.js +135 -71
  432. package/dist/paths.js.map +1 -1
  433. package/dist/phases/index.d.ts.map +1 -1
  434. package/dist/phases/index.js +6 -2
  435. package/dist/phases/index.js.map +1 -1
  436. package/dist/platform.d.ts +6 -1
  437. package/dist/platform.d.ts.map +1 -1
  438. package/dist/platform.js +8 -19
  439. package/dist/platform.js.map +1 -1
  440. package/dist/project-info.d.ts +18 -0
  441. package/dist/project-info.d.ts.map +1 -1
  442. package/dist/project-info.js +29 -1
  443. package/dist/project-info.js.map +1 -1
  444. package/dist/project-lifecycle.d.ts +91 -32
  445. package/dist/project-lifecycle.d.ts.map +1 -1
  446. package/dist/project-lifecycle.js +639 -75
  447. package/dist/project-lifecycle.js.map +1 -1
  448. package/dist/project-scope.d.ts +104 -4
  449. package/dist/project-scope.d.ts.map +1 -1
  450. package/dist/project-scope.js +263 -13
  451. package/dist/project-scope.js.map +1 -1
  452. package/dist/project-tombstone.d.ts +111 -0
  453. package/dist/project-tombstone.d.ts.map +1 -0
  454. package/dist/project-tombstone.js +220 -0
  455. package/dist/project-tombstone.js.map +1 -0
  456. package/dist/release/artifacts.d.ts.map +1 -1
  457. package/dist/release/artifacts.js +14 -9
  458. package/dist/release/artifacts.js.map +1 -1
  459. package/dist/release/ci-evidence.d.ts +233 -0
  460. package/dist/release/ci-evidence.d.ts.map +1 -0
  461. package/dist/release/ci-evidence.js +668 -0
  462. package/dist/release/ci-evidence.js.map +1 -0
  463. package/dist/release/engine-ops.d.ts.map +1 -1
  464. package/dist/release/engine-ops.js +3 -3
  465. package/dist/release/engine-ops.js.map +1 -1
  466. package/dist/release/github-pr.d.ts +30 -0
  467. package/dist/release/github-pr.d.ts.map +1 -1
  468. package/dist/release/github-pr.js +40 -0
  469. package/dist/release/github-pr.js.map +1 -1
  470. package/dist/release/plan.d.ts.map +1 -1
  471. package/dist/release/plan.js +11 -7
  472. package/dist/release/plan.js.map +1 -1
  473. package/dist/release/pr-evidence.d.ts +38 -0
  474. package/dist/release/pr-evidence.d.ts.map +1 -1
  475. package/dist/release/pr-evidence.js +79 -15
  476. package/dist/release/pr-evidence.js.map +1 -1
  477. package/dist/release/reconcile.d.ts.map +1 -1
  478. package/dist/release/reconcile.js +3 -2
  479. package/dist/release/reconcile.js.map +1 -1
  480. package/dist/release/release-manifest.d.ts +2 -1
  481. package/dist/release/release-manifest.d.ts.map +1 -1
  482. package/dist/release/release-manifest.js +6 -5
  483. package/dist/release/release-manifest.js.map +1 -1
  484. package/dist/render/nexus/graph/index.d.ts +4 -0
  485. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  486. package/dist/render/nexus/graph/index.js +57 -0
  487. package/dist/render/nexus/graph/index.js.map +1 -1
  488. package/dist/resources/spawn-wrapper.d.ts +8 -1
  489. package/dist/resources/spawn-wrapper.d.ts.map +1 -1
  490. package/dist/resources/spawn-wrapper.js +42 -5
  491. package/dist/resources/spawn-wrapper.js.map +1 -1
  492. package/dist/routing/build-command-groups.d.ts.map +1 -1
  493. package/dist/routing/build-command-groups.js +1 -0
  494. package/dist/routing/build-command-groups.js.map +1 -1
  495. package/dist/sagas/index.d.ts +1 -1
  496. package/dist/sagas/index.d.ts.map +1 -1
  497. package/dist/sagas/index.js +1 -1
  498. package/dist/sagas/index.js.map +1 -1
  499. package/dist/sagas/reconcile.d.ts +24 -4
  500. package/dist/sagas/reconcile.d.ts.map +1 -1
  501. package/dist/sagas/reconcile.js +226 -100
  502. package/dist/sagas/reconcile.js.map +1 -1
  503. package/dist/scaffold/ensure-config.d.ts.map +1 -1
  504. package/dist/scaffold/ensure-config.js +31 -1
  505. package/dist/scaffold/ensure-config.js.map +1 -1
  506. package/dist/scaffold/project-identity.d.ts +2 -8
  507. package/dist/scaffold/project-identity.d.ts.map +1 -1
  508. package/dist/scaffold/project-identity.js +5 -21
  509. package/dist/scaffold/project-identity.js.map +1 -1
  510. package/dist/security/input-sanitization.d.ts +9 -1
  511. package/dist/security/input-sanitization.d.ts.map +1 -1
  512. package/dist/security/input-sanitization.js +20 -3
  513. package/dist/security/input-sanitization.js.map +1 -1
  514. package/dist/selfimprove/fix-gen.js +4409 -1810
  515. package/dist/selfimprove/fix-gen.js.map +3 -3
  516. package/dist/sentient/propose-tick.d.ts.map +1 -1
  517. package/dist/sentient/propose-tick.js +4 -2
  518. package/dist/sentient/propose-tick.js.map +1 -1
  519. package/dist/sequence/index.d.ts.map +1 -1
  520. package/dist/sequence/index.js +6 -23
  521. package/dist/sequence/index.js.map +1 -1
  522. package/dist/session/engine-ops.d.ts +15 -0
  523. package/dist/session/engine-ops.d.ts.map +1 -1
  524. package/dist/session/engine-ops.js +146 -22
  525. package/dist/session/engine-ops.js.map +1 -1
  526. package/dist/sessions/assumptions.d.ts.map +1 -1
  527. package/dist/sessions/assumptions.js +7 -4
  528. package/dist/sessions/assumptions.js.map +1 -1
  529. package/dist/sessions/briefing.d.ts +23 -0
  530. package/dist/sessions/briefing.d.ts.map +1 -1
  531. package/dist/sessions/briefing.js +59 -9
  532. package/dist/sessions/briefing.js.map +1 -1
  533. package/dist/sessions/decisions.d.ts +38 -3
  534. package/dist/sessions/decisions.d.ts.map +1 -1
  535. package/dist/sessions/decisions.js +235 -21
  536. package/dist/sessions/decisions.js.map +1 -1
  537. package/dist/sessions/drift-watchdog.d.ts.map +1 -1
  538. package/dist/sessions/drift-watchdog.js +8 -5
  539. package/dist/sessions/drift-watchdog.js.map +1 -1
  540. package/dist/sessions/focus-state-store.d.ts +89 -1
  541. package/dist/sessions/focus-state-store.d.ts.map +1 -1
  542. package/dist/sessions/focus-state-store.js +97 -1
  543. package/dist/sessions/focus-state-store.js.map +1 -1
  544. package/dist/sessions/index.d.ts +2 -2
  545. package/dist/sessions/index.d.ts.map +1 -1
  546. package/dist/sessions/index.js +34 -5
  547. package/dist/sessions/index.js.map +1 -1
  548. package/dist/sessions/session-drift.d.ts.map +1 -1
  549. package/dist/sessions/session-drift.js +4 -3
  550. package/dist/sessions/session-drift.js.map +1 -1
  551. package/dist/sessions/session-end-snapshot-entry.d.ts +26 -0
  552. package/dist/sessions/session-end-snapshot-entry.d.ts.map +1 -0
  553. package/dist/sessions/session-end-snapshot-entry.js +59 -0
  554. package/dist/sessions/session-end-snapshot-entry.js.map +1 -0
  555. package/dist/sessions/session-end-snapshot.d.ts +114 -0
  556. package/dist/sessions/session-end-snapshot.d.ts.map +1 -0
  557. package/dist/sessions/session-end-snapshot.js +446 -0
  558. package/dist/sessions/session-end-snapshot.js.map +1 -0
  559. package/dist/sessions/session-manifest-mirror.d.ts.map +1 -1
  560. package/dist/sessions/session-manifest-mirror.js +10 -17
  561. package/dist/sessions/session-manifest-mirror.js.map +1 -1
  562. package/dist/sessions/session-switch.d.ts.map +1 -1
  563. package/dist/sessions/session-switch.js +5 -3
  564. package/dist/sessions/session-switch.js.map +1 -1
  565. package/dist/sessions/snapshot.d.ts.map +1 -1
  566. package/dist/sessions/snapshot.js +5 -4
  567. package/dist/sessions/snapshot.js.map +1 -1
  568. package/dist/sessions/terminal-identity.d.ts +169 -0
  569. package/dist/sessions/terminal-identity.d.ts.map +1 -0
  570. package/dist/sessions/terminal-identity.js +273 -0
  571. package/dist/sessions/terminal-identity.js.map +1 -0
  572. package/dist/setup/sections/verification.d.ts +1 -1
  573. package/dist/setup/sections/verification.d.ts.map +1 -1
  574. package/dist/setup/sections/verification.js +11 -15
  575. package/dist/setup/sections/verification.js.map +1 -1
  576. package/dist/skills/discovery.d.ts +20 -3
  577. package/dist/skills/discovery.d.ts.map +1 -1
  578. package/dist/skills/discovery.js +41 -4
  579. package/dist/skills/discovery.js.map +1 -1
  580. package/dist/skills/dispatch.d.ts +5 -2
  581. package/dist/skills/dispatch.d.ts.map +1 -1
  582. package/dist/skills/dispatch.js +5 -2
  583. package/dist/skills/dispatch.js.map +1 -1
  584. package/dist/skills/doctor.d.ts.map +1 -1
  585. package/dist/skills/doctor.js +5 -1
  586. package/dist/skills/doctor.js.map +1 -1
  587. package/dist/skills/federated-search.js +2 -2
  588. package/dist/skills/federated-search.js.map +1 -1
  589. package/dist/skills/index.d.ts +3 -3
  590. package/dist/skills/index.d.ts.map +1 -1
  591. package/dist/skills/index.js +1 -1
  592. package/dist/skills/index.js.map +1 -1
  593. package/dist/skills/migration.d.ts +5 -5
  594. package/dist/skills/migration.d.ts.map +1 -1
  595. package/dist/skills/migration.js +7 -9
  596. package/dist/skills/migration.js.map +1 -1
  597. package/dist/skills/orchestrator/startup.d.ts.map +1 -1
  598. package/dist/skills/orchestrator/startup.js +14 -7
  599. package/dist/skills/orchestrator/startup.js.map +1 -1
  600. package/dist/skills/prune-bundled.d.ts +267 -0
  601. package/dist/skills/prune-bundled.d.ts.map +1 -0
  602. package/dist/skills/prune-bundled.js +536 -0
  603. package/dist/skills/prune-bundled.js.map +1 -0
  604. package/dist/skills/skill-paths.d.ts +30 -3
  605. package/dist/skills/skill-paths.d.ts.map +1 -1
  606. package/dist/skills/skill-paths.js +28 -9
  607. package/dist/skills/skill-paths.js.map +1 -1
  608. package/dist/skills/skill-root.d.ts +60 -11
  609. package/dist/skills/skill-root.d.ts.map +1 -1
  610. package/dist/skills/skill-root.js +100 -14
  611. package/dist/skills/skill-root.js.map +1 -1
  612. package/dist/skills/skills-guard.js +5 -5
  613. package/dist/skills/skills-guard.js.map +1 -1
  614. package/dist/skills/types.d.ts +32 -1
  615. package/dist/skills/types.d.ts.map +1 -1
  616. package/dist/skills/types.js +17 -34
  617. package/dist/skills/types.js.map +1 -1
  618. package/dist/spawn/agent-identity.d.ts +51 -2
  619. package/dist/spawn/agent-identity.d.ts.map +1 -1
  620. package/dist/spawn/agent-identity.js +89 -26
  621. package/dist/spawn/agent-identity.js.map +1 -1
  622. package/dist/spawn/branch-lock.d.ts.map +1 -1
  623. package/dist/spawn/branch-lock.js +80 -79
  624. package/dist/spawn/branch-lock.js.map +1 -1
  625. package/dist/spawn/index.d.ts +2 -2
  626. package/dist/spawn/index.d.ts.map +1 -1
  627. package/dist/spawn/index.js +1 -1
  628. package/dist/spawn/index.js.map +1 -1
  629. package/dist/spawn/worktree-lock-holder.d.ts +37 -0
  630. package/dist/spawn/worktree-lock-holder.d.ts.map +1 -0
  631. package/dist/spawn/worktree-lock-holder.js +41 -0
  632. package/dist/spawn/worktree-lock-holder.js.map +1 -0
  633. package/dist/stats/index.d.ts.map +1 -1
  634. package/dist/stats/index.js +4 -2
  635. package/dist/stats/index.js.map +1 -1
  636. package/dist/sticky/convert.d.ts.map +1 -1
  637. package/dist/sticky/convert.js +16 -4
  638. package/dist/sticky/convert.js.map +1 -1
  639. package/dist/store/attachment-store.d.ts +14 -0
  640. package/dist/store/attachment-store.d.ts.map +1 -1
  641. package/dist/store/attachment-store.js +11 -1
  642. package/dist/store/attachment-store.js.map +1 -1
  643. package/dist/store/backup-inspect.d.ts +7 -3
  644. package/dist/store/backup-inspect.d.ts.map +1 -1
  645. package/dist/store/backup-inspect.js +18 -7
  646. package/dist/store/backup-inspect.js.map +1 -1
  647. package/dist/store/backup-sidecar.d.ts +60 -0
  648. package/dist/store/backup-sidecar.d.ts.map +1 -0
  649. package/dist/store/backup-sidecar.js +96 -0
  650. package/dist/store/backup-sidecar.js.map +1 -0
  651. package/dist/store/data-accessor.d.ts +1 -1
  652. package/dist/store/data-accessor.d.ts.map +1 -1
  653. package/dist/store/data-accessor.js +6 -6
  654. package/dist/store/data-accessor.js.map +1 -1
  655. package/dist/store/data-safety-central.d.ts +13 -4
  656. package/dist/store/data-safety-central.d.ts.map +1 -1
  657. package/dist/store/data-safety-central.js +31 -4
  658. package/dist/store/data-safety-central.js.map +1 -1
  659. package/dist/store/dual-scope-db.d.ts.map +1 -1
  660. package/dist/store/dual-scope-db.js +10 -0
  661. package/dist/store/dual-scope-db.js.map +1 -1
  662. package/dist/store/exodus/__fixtures__/representative-fixture.d.ts.map +1 -1
  663. package/dist/store/exodus/__fixtures__/representative-fixture.js +4 -0
  664. package/dist/store/exodus/__fixtures__/representative-fixture.js.map +1 -1
  665. package/dist/store/exodus/migrate.js +1 -1
  666. package/dist/store/exodus/migrate.js.map +1 -1
  667. package/dist/store/exodus/reconcile.js +1 -1
  668. package/dist/store/exodus/reconcile.js.map +1 -1
  669. package/dist/store/exodus/runtime-targets.d.ts +4 -3
  670. package/dist/store/exodus/runtime-targets.d.ts.map +1 -1
  671. package/dist/store/exodus/runtime-targets.js +4 -3
  672. package/dist/store/exodus/runtime-targets.js.map +1 -1
  673. package/dist/store/import-logging.d.ts.map +1 -1
  674. package/dist/store/import-logging.js +5 -4
  675. package/dist/store/import-logging.js.map +1 -1
  676. package/dist/store/legacy-tasks-lineage.d.ts.map +1 -1
  677. package/dist/store/legacy-tasks-lineage.js +2 -7
  678. package/dist/store/legacy-tasks-lineage.js.map +1 -1
  679. package/dist/store/lock.d.ts +1 -0
  680. package/dist/store/lock.d.ts.map +1 -1
  681. package/dist/store/lock.js +1 -0
  682. package/dist/store/lock.js.map +1 -1
  683. package/dist/store/memory-accessor.d.ts +8 -3
  684. package/dist/store/memory-accessor.d.ts.map +1 -1
  685. package/dist/store/memory-accessor.js +29 -13
  686. package/dist/store/memory-accessor.js.map +1 -1
  687. package/dist/store/memory-sqlite.d.ts.map +1 -1
  688. package/dist/store/memory-sqlite.js +5 -0
  689. package/dist/store/memory-sqlite.js.map +1 -1
  690. package/dist/store/open-cleo-db.d.ts.map +1 -1
  691. package/dist/store/open-cleo-db.js +11 -6
  692. package/dist/store/open-cleo-db.js.map +1 -1
  693. package/dist/store/portable-bundle-relocate.d.ts +13 -8
  694. package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
  695. package/dist/store/portable-bundle-relocate.js +75 -31
  696. package/dist/store/portable-bundle-relocate.js.map +1 -1
  697. package/dist/store/portable-bundle-scan.d.ts.map +1 -1
  698. package/dist/store/portable-bundle-scan.js +2 -1
  699. package/dist/store/portable-bundle-scan.js.map +1 -1
  700. package/dist/store/portable-bundle.d.ts.map +1 -1
  701. package/dist/store/portable-bundle.js +7 -3
  702. package/dist/store/portable-bundle.js.map +1 -1
  703. package/dist/store/pre-repair-snapshot.d.ts +77 -0
  704. package/dist/store/pre-repair-snapshot.d.ts.map +1 -0
  705. package/dist/store/pre-repair-snapshot.js +122 -0
  706. package/dist/store/pre-repair-snapshot.js.map +1 -0
  707. package/dist/store/regenerators.d.ts +2 -1
  708. package/dist/store/regenerators.d.ts.map +1 -1
  709. package/dist/store/regenerators.js +17 -3
  710. package/dist/store/regenerators.js.map +1 -1
  711. package/dist/store/relocated-store-guard.d.ts +71 -0
  712. package/dist/store/relocated-store-guard.d.ts.map +1 -0
  713. package/dist/store/relocated-store-guard.js +138 -0
  714. package/dist/store/relocated-store-guard.js.map +1 -0
  715. package/dist/store/safety-data-accessor.d.ts +2 -2
  716. package/dist/store/safety-data-accessor.d.ts.map +1 -1
  717. package/dist/store/safety-data-accessor.js +2 -2
  718. package/dist/store/safety-data-accessor.js.map +1 -1
  719. package/dist/store/schema/attachments.d.ts +2 -2
  720. package/dist/store/schema/audit.d.ts +5 -5
  721. package/dist/store/schema/background-jobs.d.ts +1 -1
  722. package/dist/store/schema/cleo-global/models-catalog.d.ts +1 -1
  723. package/dist/store/schema/cleo-global/nexus.d.ts +686 -0
  724. package/dist/store/schema/cleo-global/nexus.d.ts.map +1 -1
  725. package/dist/store/schema/cleo-global/nexus.js +175 -7
  726. package/dist/store/schema/cleo-global/nexus.js.map +1 -1
  727. package/dist/store/schema/cleo-global/skills.d.ts +2 -2
  728. package/dist/store/schema/cleo-project/audit.d.ts +5 -5
  729. package/dist/store/schema/cleo-project/docs.d.ts +3 -3
  730. package/dist/store/schema/cleo-project/lifecycle.d.ts +3 -3
  731. package/dist/store/schema/cleo-project/provenance-commits.d.ts +2 -2
  732. package/dist/store/schema/cleo-project/provenance-rest.d.ts +3 -3
  733. package/dist/store/schema/cleo-project/tasks-core-batch2.d.ts +1 -1
  734. package/dist/store/schema/cleo-project/tasks-core.d.ts +6 -6
  735. package/dist/store/schema/cleo-shared/brain.d.ts +26 -26
  736. package/dist/store/schema/lifecycle.d.ts +3 -3
  737. package/dist/store/schema/manifest.d.ts +1 -1
  738. package/dist/store/schema/memory-schema.d.ts +26 -26
  739. package/dist/store/schema/nexus-schema.d.ts +696 -2
  740. package/dist/store/schema/nexus-schema.d.ts.map +1 -1
  741. package/dist/store/schema/nexus-schema.js +175 -19
  742. package/dist/store/schema/nexus-schema.js.map +1 -1
  743. package/dist/store/schema/provenance/releases.d.ts +1 -1
  744. package/dist/store/schema/skills-schema.d.ts +2 -2
  745. package/dist/store/schema/tasks.d.ts +5 -5
  746. package/dist/store/session-binding-schema.d.ts +132 -0
  747. package/dist/store/session-binding-schema.d.ts.map +1 -0
  748. package/dist/store/session-binding-schema.js +53 -0
  749. package/dist/store/session-binding-schema.js.map +1 -0
  750. package/dist/store/session-store.d.ts +262 -4
  751. package/dist/store/session-store.d.ts.map +1 -1
  752. package/dist/store/session-store.js +486 -26
  753. package/dist/store/session-store.js.map +1 -1
  754. package/dist/store/skills-db.d.ts +17 -0
  755. package/dist/store/skills-db.d.ts.map +1 -1
  756. package/dist/store/skills-db.js +30 -0
  757. package/dist/store/skills-db.js.map +1 -1
  758. package/dist/store/snapshot-gate.d.ts +239 -0
  759. package/dist/store/snapshot-gate.d.ts.map +1 -0
  760. package/dist/store/snapshot-gate.js +401 -0
  761. package/dist/store/snapshot-gate.js.map +1 -0
  762. package/dist/store/split-brain-import.js +2 -2
  763. package/dist/store/split-brain-import.js.map +1 -1
  764. package/dist/store/sqlite-backup.d.ts +55 -13
  765. package/dist/store/sqlite-backup.d.ts.map +1 -1
  766. package/dist/store/sqlite-backup.js +414 -106
  767. package/dist/store/sqlite-backup.js.map +1 -1
  768. package/dist/store/sqlite-data-accessor.d.ts +15 -0
  769. package/dist/store/sqlite-data-accessor.d.ts.map +1 -1
  770. package/dist/store/sqlite-data-accessor.js +73 -4
  771. package/dist/store/sqlite-data-accessor.js.map +1 -1
  772. package/dist/store/sqlite.d.ts +15 -1
  773. package/dist/store/sqlite.d.ts.map +1 -1
  774. package/dist/store/sqlite.js +75 -5
  775. package/dist/store/sqlite.js.map +1 -1
  776. package/dist/store/store-write-guard.d.ts +28 -0
  777. package/dist/store/store-write-guard.d.ts.map +1 -0
  778. package/dist/store/store-write-guard.js +50 -0
  779. package/dist/store/store-write-guard.js.map +1 -0
  780. package/dist/store/table-classification.d.ts +143 -0
  781. package/dist/store/table-classification.d.ts.map +1 -0
  782. package/dist/store/table-classification.js +1866 -0
  783. package/dist/store/table-classification.js.map +1 -0
  784. package/dist/store/task-version.d.ts +72 -0
  785. package/dist/store/task-version.d.ts.map +1 -0
  786. package/dist/store/task-version.js +93 -0
  787. package/dist/store/task-version.js.map +1 -0
  788. package/dist/store/tasks-schema.d.ts +1 -0
  789. package/dist/store/tasks-schema.d.ts.map +1 -1
  790. package/dist/store/tasks-schema.js +13 -0
  791. package/dist/store/tasks-schema.js.map +1 -1
  792. package/dist/store/tasks-sqlite.d.ts +10 -3
  793. package/dist/store/tasks-sqlite.d.ts.map +1 -1
  794. package/dist/store/tasks-sqlite.js +12 -3
  795. package/dist/store/tasks-sqlite.js.map +1 -1
  796. package/dist/store/twin-collapse.d.ts +320 -0
  797. package/dist/store/twin-collapse.d.ts.map +1 -0
  798. package/dist/store/twin-collapse.js +931 -0
  799. package/dist/store/twin-collapse.js.map +1 -0
  800. package/dist/store/umbrella-data-accessor.d.ts +2 -2
  801. package/dist/store/umbrella-data-accessor.d.ts.map +1 -1
  802. package/dist/store/umbrella-data-accessor.js +2 -2
  803. package/dist/store/umbrella-data-accessor.js.map +1 -1
  804. package/dist/store/validation-schemas.d.ts +63 -63
  805. package/dist/store/worktree-isolation-guard.d.ts +46 -24
  806. package/dist/store/worktree-isolation-guard.d.ts.map +1 -1
  807. package/dist/store/worktree-isolation-guard.js +71 -50
  808. package/dist/store/worktree-isolation-guard.js.map +1 -1
  809. package/dist/system/backup.d.ts.map +1 -1
  810. package/dist/system/backup.js +3 -67
  811. package/dist/system/backup.js.map +1 -1
  812. package/dist/system/cleo-link.d.ts +163 -0
  813. package/dist/system/cleo-link.d.ts.map +1 -0
  814. package/dist/system/cleo-link.js +246 -0
  815. package/dist/system/cleo-link.js.map +1 -0
  816. package/dist/system/dependencies.d.ts.map +1 -1
  817. package/dist/system/dependencies.js +3 -6
  818. package/dist/system/dependencies.js.map +1 -1
  819. package/dist/system/global-delivery.d.ts +205 -0
  820. package/dist/system/global-delivery.d.ts.map +1 -0
  821. package/dist/system/global-delivery.js +320 -0
  822. package/dist/system/global-delivery.js.map +1 -0
  823. package/dist/system/health.d.ts.map +1 -1
  824. package/dist/system/health.js +29 -6
  825. package/dist/system/health.js.map +1 -1
  826. package/dist/system/inject-generate.d.ts.map +1 -1
  827. package/dist/system/inject-generate.js +4 -4
  828. package/dist/system/inject-generate.js.map +1 -1
  829. package/dist/system/project-health.d.ts.map +1 -1
  830. package/dist/system/project-health.js +1 -20
  831. package/dist/system/project-health.js.map +1 -1
  832. package/dist/system/runtime.d.ts.map +1 -1
  833. package/dist/system/runtime.js +2 -12
  834. package/dist/system/runtime.js.map +1 -1
  835. package/dist/system/safestop.d.ts.map +1 -1
  836. package/dist/system/safestop.js +5 -2
  837. package/dist/system/safestop.js.map +1 -1
  838. package/dist/system/skill-fixtures.d.ts +200 -0
  839. package/dist/system/skill-fixtures.d.ts.map +1 -0
  840. package/dist/system/skill-fixtures.js +331 -0
  841. package/dist/system/skill-fixtures.js.map +1 -0
  842. package/dist/task-work/index.d.ts +6 -0
  843. package/dist/task-work/index.d.ts.map +1 -1
  844. package/dist/task-work/index.js +6 -3
  845. package/dist/task-work/index.js.map +1 -1
  846. package/dist/tasks/add.d.ts.map +1 -1
  847. package/dist/tasks/add.js +4 -2
  848. package/dist/tasks/add.js.map +1 -1
  849. package/dist/tasks/affected-packages.d.ts +218 -0
  850. package/dist/tasks/affected-packages.d.ts.map +1 -0
  851. package/dist/tasks/affected-packages.js +496 -0
  852. package/dist/tasks/affected-packages.js.map +1 -0
  853. package/dist/tasks/affected-scope.d.ts +59 -0
  854. package/dist/tasks/affected-scope.d.ts.map +1 -0
  855. package/dist/tasks/affected-scope.js +81 -0
  856. package/dist/tasks/affected-scope.js.map +1 -0
  857. package/dist/tasks/analyze.d.ts.map +1 -1
  858. package/dist/tasks/analyze.js +7 -2
  859. package/dist/tasks/analyze.js.map +1 -1
  860. package/dist/tasks/change-set.d.ts +175 -0
  861. package/dist/tasks/change-set.d.ts.map +1 -0
  862. package/dist/tasks/change-set.js +753 -0
  863. package/dist/tasks/change-set.js.map +1 -0
  864. package/dist/tasks/complete.d.ts +10 -0
  865. package/dist/tasks/complete.d.ts.map +1 -1
  866. package/dist/tasks/complete.js +59 -5
  867. package/dist/tasks/complete.js.map +1 -1
  868. package/dist/tasks/component-pr.d.ts +106 -0
  869. package/dist/tasks/component-pr.d.ts.map +1 -0
  870. package/dist/tasks/component-pr.js +190 -0
  871. package/dist/tasks/component-pr.js.map +1 -0
  872. package/dist/tasks/done-plan.d.ts +123 -0
  873. package/dist/tasks/done-plan.d.ts.map +1 -0
  874. package/dist/tasks/done-plan.js +696 -0
  875. package/dist/tasks/done-plan.js.map +1 -0
  876. package/dist/tasks/done-record.d.ts +127 -0
  877. package/dist/tasks/done-record.d.ts.map +1 -0
  878. package/dist/tasks/done-record.js +302 -0
  879. package/dist/tasks/done-record.js.map +1 -0
  880. package/dist/tasks/duplicate-detector.d.ts +68 -11
  881. package/dist/tasks/duplicate-detector.d.ts.map +1 -1
  882. package/dist/tasks/duplicate-detector.js +314 -58
  883. package/dist/tasks/duplicate-detector.js.map +1 -1
  884. package/dist/tasks/evidence-paths.d.ts +78 -0
  885. package/dist/tasks/evidence-paths.d.ts.map +1 -0
  886. package/dist/tasks/evidence-paths.js +150 -0
  887. package/dist/tasks/evidence-paths.js.map +1 -0
  888. package/dist/tasks/evidence.d.ts +101 -1
  889. package/dist/tasks/evidence.d.ts.map +1 -1
  890. package/dist/tasks/evidence.js +278 -31
  891. package/dist/tasks/evidence.js.map +1 -1
  892. package/dist/tasks/gate-preview.d.ts +5 -0
  893. package/dist/tasks/gate-preview.d.ts.map +1 -1
  894. package/dist/tasks/gate-preview.js +25 -21
  895. package/dist/tasks/gate-preview.js.map +1 -1
  896. package/dist/tasks/gate-result-cache.d.ts +205 -0
  897. package/dist/tasks/gate-result-cache.d.ts.map +1 -0
  898. package/dist/tasks/gate-result-cache.js +285 -0
  899. package/dist/tasks/gate-result-cache.js.map +1 -0
  900. package/dist/tasks/gate-runner.d.ts +126 -3
  901. package/dist/tasks/gate-runner.d.ts.map +1 -1
  902. package/dist/tasks/gate-runner.js +483 -28
  903. package/dist/tasks/gate-runner.js.map +1 -1
  904. package/dist/tasks/session-scope.d.ts +3 -1
  905. package/dist/tasks/session-scope.d.ts.map +1 -1
  906. package/dist/tasks/session-scope.js +18 -3
  907. package/dist/tasks/session-scope.js.map +1 -1
  908. package/dist/tasks/task-next.d.ts +4 -0
  909. package/dist/tasks/task-next.d.ts.map +1 -1
  910. package/dist/tasks/task-next.js +32 -28
  911. package/dist/tasks/task-next.js.map +1 -1
  912. package/dist/tasks/tool-resolver.d.ts +23 -6
  913. package/dist/tasks/tool-resolver.d.ts.map +1 -1
  914. package/dist/tasks/tool-resolver.js +146 -8
  915. package/dist/tasks/tool-resolver.js.map +1 -1
  916. package/dist/tasks/tool-vacuity.d.ts +71 -0
  917. package/dist/tasks/tool-vacuity.d.ts.map +1 -0
  918. package/dist/tasks/tool-vacuity.js +334 -0
  919. package/dist/tasks/tool-vacuity.js.map +1 -0
  920. package/dist/tasks/update.d.ts +8 -0
  921. package/dist/tasks/update.d.ts.map +1 -1
  922. package/dist/tasks/update.js +159 -78
  923. package/dist/tasks/update.js.map +1 -1
  924. package/dist/upgrade.d.ts.map +1 -1
  925. package/dist/upgrade.js +18 -2
  926. package/dist/upgrade.js.map +1 -1
  927. package/dist/validation/doctor/checks.d.ts +20 -2
  928. package/dist/validation/doctor/checks.d.ts.map +1 -1
  929. package/dist/validation/doctor/checks.js +64 -4
  930. package/dist/validation/doctor/checks.js.map +1 -1
  931. package/dist/validation/doctor/index.d.ts +1 -1
  932. package/dist/validation/doctor/index.d.ts.map +1 -1
  933. package/dist/validation/doctor/index.js +1 -1
  934. package/dist/validation/doctor/index.js.map +1 -1
  935. package/dist/validation/doctor/utils.d.ts.map +1 -1
  936. package/dist/validation/doctor/utils.js +7 -2
  937. package/dist/validation/doctor/utils.js.map +1 -1
  938. package/dist/validation/engine-ops.d.ts +24 -1
  939. package/dist/validation/engine-ops.d.ts.map +1 -1
  940. package/dist/validation/engine-ops.js +272 -98
  941. package/dist/validation/engine-ops.js.map +1 -1
  942. package/dist/validation/validate-ops.d.ts.map +1 -1
  943. package/dist/validation/validate-ops.js +9 -3
  944. package/dist/validation/validate-ops.js.map +1 -1
  945. package/dist/worktree/worktree-adopt.d.ts.map +1 -1
  946. package/dist/worktree/worktree-adopt.js +5 -2
  947. package/dist/worktree/worktree-adopt.js.map +1 -1
  948. package/migrations/drizzle-cleo-global/20260927000000_t12469-project-locations/migration.sql +121 -0
  949. package/migrations/drizzle-cleo-global/20260927010000_t12543-user-profile-project-scope/migration.sql +23 -0
  950. package/migrations/drizzle-cleo-global/20260928010000_t12470-location-candidates/migration.sql +72 -0
  951. package/migrations/drizzle-cleo-global/20260928020000_t12510-nexus-devices/migration.sql +34 -0
  952. package/migrations/drizzle-cleo-global/20260928030000_t12511-project-git-state/migration.sql +62 -0
  953. package/migrations/drizzle-cleo-project/20260927000000_t12499-session-terminal-bindings/migration.sql +34 -0
  954. package/migrations/drizzle-cleo-project/20260928000000_t12500-binding-provider-flag/migration.sql +15 -0
  955. package/package.json +23 -13
  956. package/schemas/config.schema.json +54 -0
  957. package/schemas/project-context.schema.json +51 -3
  958. package/schemas/project-info.schema.json +28 -1
  959. package/templates/CLEO-INJECTION.md +40 -332
  960. package/templates/CLEO-REFERENCE.md +303 -0
  961. package/templates/workflows/README.md +36 -14
@@ -0,0 +1,931 @@
1
+ /**
2
+ * Twin collapses (T12535): keep a prefixed twin in step with its BARE legacy
3
+ * table, which stays authoritative while an older CLEO build still writes it.
4
+ *
5
+ * ## Why
6
+ *
7
+ * The project `cleo.db` carries legacy bare tables beside their prefixed (E6)
8
+ * twins. For `schema_meta` and `sticky_tags` the runtime wrote the bare table
9
+ * while the twin held a frozen exodus copy. This build reads and writes only
10
+ * the twin. The release before it (2026.9.20) is still installed on machines
11
+ * that share project stores and keeps writing the bare tables, so the collapse
12
+ * runs at every open:
13
+ *
14
+ * - **Initial collapse** (no marker yet): check the free space, snapshot the
15
+ * store, then fold the bare table into the twin, bare-authoritative.
16
+ * - **Incremental re-merge** (marker present): carry over only the bare keys
17
+ * (sticky ids) whose hash changed since the last merge. No snapshot. An
18
+ * unchanged bare table costs one read of it and no write.
19
+ *
20
+ * A later release removes the incremental re-merge once no supported build
21
+ * writes the bare tables; slice 3 then drops them after a backup.
22
+ *
23
+ * ## State and provenance
24
+ *
25
+ * The marker row `twin_collapse:<bare table>` in the twin's key/value table
26
+ * holds, per key (`schema_meta`) or per sticky id (`sticky_tags`), a sha256
27
+ * of the BARE value and of the TWIN value as of the last merge. A bare hash
28
+ * that moved means the older build wrote it; a twin hash that moved means this
29
+ * build wrote it.
30
+ *
31
+ * ## Rules
32
+ *
33
+ * The bare row is authoritative for every key. A monotonic counter FIELD is
34
+ * merged on its own: the result is the bare value with that field set to
35
+ * max(bare, twin). A whole twin value never replaces a bare one
36
+ * ({@link mergeSchemaMetaValue}).
37
+ *
38
+ * | `schema_meta` key | Counter field |
39
+ * |---|---|
40
+ * | `task_id_sequence` (`{counter,lastId,checksum}` from `sequence/index.ts`, or a plain number) | `counter` (a plain number takes the max of the two numbers) |
41
+ * | `sqlite_snapshot_gate` (`{generation,prefixes}`, `snapshot-gate.ts`) | `generation` |
42
+ * | `file_meta` (`FileMeta`; `session/engine-ops.ts` bumps `generation` on session start/end/resume) | `generation` |
43
+ * | `backfill:*` (the two `t877` guard keys) | not carried: the lineage re-inserts them into every bare table and nothing reads them |
44
+ * | `twin_collapse*` | not carried: collapse state and failures live only in the twin |
45
+ * | every other key (`schemaVersion`, `version`, `focus_state`, `focus_state:<session>`, `project_meta`, `project`, `parallel_state`, `activeSession`, `reconcile.<task>.release`, any unknown key) | none: the bare value |
46
+ *
47
+ * - **Initial collapse**, when the bare table holds at least one carried key:
48
+ * every bare key is carried under the rules, and a key only the twin holds
49
+ * is a frozen copy and is DROPPED (listed in the receipt, marker and log).
50
+ * The exceptions are `task_id_sequence` and `sqlite_snapshot_gate` (a
51
+ * counter must not move back) and the collapse keys. `file_meta` is dropped
52
+ * only when the bare table lacks it; when both have it the field rule
53
+ * applies. When the bare table holds no carried key (a fresh lineage, e.g.
54
+ * after exodus landed legacy rows in the twin), nothing is dropped.
55
+ * - **Incremental re-merge**, per bare key whose hash changed since the last
56
+ * merge:
57
+ * - twin unchanged since the last merge → the bare value (counter fields
58
+ * maxed);
59
+ * - twin ALSO changed (this build wrote it too) → CONFLICT: the TWIN value
60
+ * wins, recorded in the marker and reported by `cleo doctor` as a warning.
61
+ * A counter key is never a conflict: the twin value is kept with its
62
+ * counter field maxed against the bare one.
63
+ * A key the older build deleted is deleted from the twin unless the twin
64
+ * changed it too (conflict) or it is `task_id_sequence` /
65
+ * `sqlite_snapshot_gate`. A key the bare table never changed is never
66
+ * touched.
67
+ *
68
+ * `sticky_tags` → `brain_sticky_tags` (rows are `(sticky_id, tag)`, both the
69
+ * key, so a collision is two identical rows and one is kept):
70
+ *
71
+ * - Initial collapse, when the bare table has rows: the twin is made equal to
72
+ * the bare set; frozen twin-only rows are dropped and listed. A bare tag whose
73
+ * note no longer exists is not carried (`skipped`; it stays in the bare table).
74
+ * - Incremental re-merge, per sticky id whose bare tag-set hash changed: if
75
+ * the twin's set for that id is unchanged since the last merge, the twin
76
+ * set is made equal to the bare set (additions AND removals propagate);
77
+ * if the twin set changed too, the twin wins and a conflict is recorded.
78
+ * - After every merge the junction is recomputed from each note's
79
+ * `tags_json` ({@link syncStickyJunction}). Both builds write `tags_json`
80
+ * (on the shared `brain_sticky_notes` row) together with their own junction,
81
+ * so it is the one value both see; the junction is derived from it, and the
82
+ * tag filter can never disagree with the displayed tags. A conflict is still
83
+ * recorded for `cleo doctor`.
84
+ *
85
+ * ## Contract
86
+ *
87
+ * 1. **Snapshot first** (initial collapse only, only when the merge changes
88
+ * the twin). The free space is checked before the `VACUUM INTO`. One
89
+ * snapshot covers every pair collapsing in this open, registered as a
90
+ * `migration` backup (`cleo backup list`, rotation).
91
+ * 2. **Atomic.** Each pair merges, verifies and writes its marker in one
92
+ * `BEGIN IMMEDIATE` transaction, the marker re-read under the write lock.
93
+ * Any failure rolls back: both tables byte-identical.
94
+ * 3. **Verified.** Every row the merge decided is re-read and compared before
95
+ * the marker is written; a mismatch rolls back.
96
+ * 4. **The bare table is never written**, with one sanctioned exception:
97
+ * {@link mirrorCounterToBare}. When this build writes a counter key
98
+ * (`task_id_sequence`, `sqlite_snapshot_gate`, `file_meta`) it raises the
99
+ * bare row's counter field to the twin's in the same transaction, and the
100
+ * allocation floors on the bare counter ({@link bareCounterOf}). The
101
+ * 2026.9.20 build still allocates ids from the bare counter; without the
102
+ * mirror, an id one build reserved but had not stored yet could be issued
103
+ * by the other.
104
+ * 5. **Never locked out** (inside a domain bind, `onFailure: 'degrade'`). A
105
+ * failed or impossible collapse does not fail the bind. The failure is
106
+ * recorded (`twin_collapse_failed:<table>`), and the connection is put in a
107
+ * READ-ONLY-FOR-USERS mode: the merged view the collapse would have
108
+ * committed is computed in memory and served from TEMP shadow tables of the
109
+ * same names (unqualified SQL resolves `temp` before `main`), so reads see
110
+ * bare-authoritative data while `main` stays untouched. Mutating operations
111
+ * are refused with `E_TWIN_COLLAPSE_FAILED` by the dispatch write guard
112
+ * ({@link twinCollapseFailureOf}), and the shadows carry TEMP triggers that
113
+ * abort any write into them ({@link SHADOW_WRITE_REFUSED}), so a direct SDK
114
+ * write fails instead of being lost. `cleo doctor twin-collapse --retry`
115
+ * runs the collapse with `onFailure: 'throw'`; on success the shadows and
116
+ * their triggers are dropped.
117
+ *
118
+ * ## Gate 28
119
+ *
120
+ * This module is a sanctioned writer (`scripts/lint-no-raw-table-writes.mjs`
121
+ * SANCTIONED): it runs on the chokepoint handle inside the domain bind, and the
122
+ * accessors import the modules that call it.
123
+ *
124
+ * @module
125
+ * @task T12535
126
+ */
127
+ import { createHash } from 'node:crypto';
128
+ import { ExitCode } from '@cleocode/contracts';
129
+ import { CleoError } from '../errors.js';
130
+ import { getLogger } from '../logger.js';
131
+ import { planMigrationSnapshot, writeMigrationSnapshot } from './pre-repair-snapshot.js';
132
+ const log = getLogger('twin-collapse');
133
+ /** Prefix of the marker key holding a pair's collapse state. */
134
+ export const TWIN_COLLAPSE_MARKER_PREFIX = 'twin_collapse:';
135
+ /** Prefix of the key recording a pair's last failed collapse. */
136
+ export const TWIN_COLLAPSE_FAILURE_PREFIX = 'twin_collapse_failed:';
137
+ /**
138
+ * The snapshot gate's key (`SNAPSHOT_GATE_META_KEY` in `snapshot-gate.ts`),
139
+ * spelled out: `snapshot-gate.ts` imports this module to mirror its counter,
140
+ * so importing it back would be a cycle.
141
+ */
142
+ const SNAPSHOT_GATE_KEY = 'sqlite_snapshot_gate';
143
+ /** `schema_meta` keys whose named field is a monotonic counter (merged as max). */
144
+ export const SCHEMA_META_COUNTER_FIELDS = {
145
+ task_id_sequence: 'counter',
146
+ [SNAPSHOT_GATE_KEY]: 'generation',
147
+ file_meta: 'generation',
148
+ };
149
+ /** `schema_meta` keys never deleted from the twin (a counter never moves back). */
150
+ export const SCHEMA_META_NEVER_DELETED = new Set([
151
+ 'task_id_sequence',
152
+ SNAPSHOT_GATE_KEY,
153
+ ]);
154
+ /** Most conflicts kept in the marker (the doctor warning lists them). */
155
+ const MAX_CONFLICTS = 50;
156
+ const sha = (value) => createHash('sha256').update(value).digest('hex');
157
+ /** Hash of an absent value (distinct from any real value's hash). */
158
+ const ABSENT = sha('\u0000absent');
159
+ function hasMainTable(db, name) {
160
+ return (db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = 'table' AND name = ?").get(name) !==
161
+ undefined);
162
+ }
163
+ function readKv(db, kvTable, key) {
164
+ return db.prepare(`SELECT value FROM main.${kvTable} WHERE key = ?`).get(key)?.value;
165
+ }
166
+ function writeKv(db, kvTable, key, value) {
167
+ db.prepare(`INSERT INTO main.${kvTable} (key, value) VALUES (?, ?) ` +
168
+ 'ON CONFLICT(key) DO UPDATE SET value = excluded.value').run(key, value);
169
+ }
170
+ function sameHashes(a, b) {
171
+ const ka = Object.keys(a);
172
+ return ka.length === Object.keys(b).length && ka.every((k) => a[k] === b[k]);
173
+ }
174
+ /** Parse a marker row; a pre-release marker (no hashes) yields `hashes: null`. */
175
+ function readState(db, pair) {
176
+ const raw = readKv(db, pair.kvTable, `${TWIN_COLLAPSE_MARKER_PREFIX}${pair.table}`);
177
+ if (raw === undefined)
178
+ return undefined;
179
+ let parsed = {};
180
+ try {
181
+ parsed = JSON.parse(raw);
182
+ }
183
+ catch {
184
+ parsed = {};
185
+ }
186
+ const str = (v) => (typeof v === 'string' ? v : '');
187
+ return {
188
+ version: 3,
189
+ task: 'T12535',
190
+ collapsedAt: str(parsed.collapsedAt),
191
+ lastMergedAt: str(parsed.lastMergedAt),
192
+ snapshot: typeof parsed.snapshot === 'string' ? parsed.snapshot : null,
193
+ hashes: parsed.version === 3 && parsed.hashes ? parsed.hashes : null,
194
+ dropped: Array.isArray(parsed.dropped) ? parsed.dropped : [],
195
+ conflicts: Array.isArray(parsed.conflicts) ? parsed.conflicts : [],
196
+ conflictsAt: typeof parsed.conflictsAt === 'string' ? parsed.conflictsAt : null,
197
+ };
198
+ }
199
+ /** Whether the bare side moved since the stored hashes (or no usable state exists). */
200
+ function bareChanged(db, pair, state) {
201
+ return !state?.hashes || !sameHashes(state.hashes.bare, pair.bareHashes(db));
202
+ }
203
+ /** Hashes of the last merge; a pre-release marker treats the current twin as unchanged. */
204
+ function lastHashes(db, pair, state) {
205
+ return state.hashes ?? { bare: {}, twin: pair.twinHashes(db) };
206
+ }
207
+ // ── schema_meta ──────────────────────────────────────────────────────────────
208
+ function parseJson(value) {
209
+ try {
210
+ return JSON.parse(value);
211
+ }
212
+ catch {
213
+ return undefined;
214
+ }
215
+ }
216
+ /** A counter field's value, whether the whole value is a number or an object holding it. */
217
+ function counterOf(value, field) {
218
+ const parsed = parseJson(value);
219
+ if (typeof parsed === 'number' && Number.isFinite(parsed))
220
+ return parsed;
221
+ if (parsed === null || typeof parsed !== 'object')
222
+ return undefined;
223
+ const n = parsed[field];
224
+ return typeof n === 'number' && Number.isFinite(n) ? n : undefined;
225
+ }
226
+ /**
227
+ * `base` with its counter field raised to the other value's counter when that
228
+ * is larger. `base` is returned verbatim otherwise, and when it has no
229
+ * counter to raise (not a number, not an object holding the field).
230
+ */
231
+ function withMaxCounter(base, other, field) {
232
+ if (other === undefined)
233
+ return base;
234
+ const b = counterOf(base, field);
235
+ const o = counterOf(other, field);
236
+ if (b === undefined || o === undefined || o <= b)
237
+ return base;
238
+ const parsed = parseJson(base);
239
+ if (typeof parsed === 'number')
240
+ return String(o);
241
+ return JSON.stringify({ ...parsed, [field]: o });
242
+ }
243
+ /** Whether a `schema_meta` key is carried at all. */
244
+ function carried(key) {
245
+ return !key.startsWith('backfill:') && !key.startsWith('twin_collapse');
246
+ }
247
+ /**
248
+ * The value a `schema_meta` key gets when the bare side is authoritative (the
249
+ * rule table is in the module comment).
250
+ *
251
+ * @param key - The key.
252
+ * @param bare - Its value in the bare table.
253
+ * @param twin - Its value in the twin, or `undefined` when absent.
254
+ * @returns The value to keep, or `null` when the key is not carried.
255
+ * @task T12535
256
+ */
257
+ export function mergeSchemaMetaValue(key, bare, twin) {
258
+ if (!carried(key))
259
+ return null;
260
+ const field = SCHEMA_META_COUNTER_FIELDS[key];
261
+ return field === undefined ? bare : withMaxCounter(bare, twin, field);
262
+ }
263
+ /**
264
+ * Raise the BARE `schema_meta` row of a counter key to the twin's counter,
265
+ * right after this build wrote the twin row, on the same connection (so inside
266
+ * the writer's transaction).
267
+ *
268
+ * The one sanctioned write to a bare table (T12535): the 2026.9.20 build still
269
+ * allocates task ids from the bare `task_id_sequence` and reads the bare
270
+ * snapshot-gate and `file_meta` generations. Without this, an id this build
271
+ * reserved but has not stored yet (the counter is advanced before the task
272
+ * row is inserted) could be issued again by the older build. Only the counter
273
+ * field moves (the bare row keeps its other fields, see
274
+ * {@link mergeSchemaMetaValue}); a missing bare row gets the twin value. A
275
+ * non-counter key, or a store without the bare table, is left alone. The
276
+ * collapse treats the resulting bare change like any other: a counter key is
277
+ * never a conflict.
278
+ *
279
+ * @param db - The project `cleo.db` connection that wrote the twin row.
280
+ * @param key - The `schema_meta` key just written.
281
+ * @task T12535
282
+ */
283
+ export function mirrorCounterToBare(db, key) {
284
+ if (SCHEMA_META_COUNTER_FIELDS[key] === undefined)
285
+ return;
286
+ if (!hasMainTable(db, 'schema_meta'))
287
+ return;
288
+ const twin = readKv(db, 'tasks_schema_meta', key);
289
+ if (twin === undefined)
290
+ return;
291
+ const bare = readKv(db, 'schema_meta', key);
292
+ const next = bare === undefined ? twin : mergeSchemaMetaValue(key, bare, twin);
293
+ if (next === null || next === bare)
294
+ return;
295
+ writeKv(db, 'schema_meta', key, next);
296
+ }
297
+ /**
298
+ * The counter of a key's BARE `schema_meta` row (the older build's), or 0.
299
+ * This build's allocation floors on it, so an id the older build reserved but
300
+ * has not stored yet is never issued here either.
301
+ *
302
+ * @param db - The project `cleo.db` connection.
303
+ * @param key - A counter key.
304
+ * @returns The bare counter field, or 0 when absent.
305
+ * @task T12535
306
+ */
307
+ export function bareCounterOf(db, key) {
308
+ const name = SCHEMA_META_COUNTER_FIELDS[key];
309
+ if (name === undefined || !hasMainTable(db, 'schema_meta'))
310
+ return 0;
311
+ const bare = readKv(db, 'schema_meta', key);
312
+ return (bare === undefined ? undefined : counterOf(bare, name)) ?? 0;
313
+ }
314
+ function kvRows(db, table, schema = 'main') {
315
+ const rows = db.prepare(`SELECT key, value FROM ${schema}.${table}`).all();
316
+ return new Map(rows.map((r) => [r.key, r.value]));
317
+ }
318
+ /** Carried rows of a `schema_meta` table. */
319
+ function carriedRows(db, table) {
320
+ const all = kvRows(db, table);
321
+ for (const key of [...all.keys()])
322
+ if (!carried(key))
323
+ all.delete(key);
324
+ return all;
325
+ }
326
+ const hashMap = (m) => Object.fromEntries([...m].map(([k, v]) => [k, sha(v)]));
327
+ const emptyPlan = () => ({ set: new Map(), del: [], dropped: [], conflicts: [], skipped: 0 });
328
+ function planSchemaMeta(db, state) {
329
+ const plan = emptyPlan();
330
+ const bare = carriedRows(db, 'schema_meta');
331
+ const twin = carriedRows(db, 'tasks_schema_meta');
332
+ const want = (key, value) => {
333
+ if (value !== null && value !== twin.get(key))
334
+ plan.set.set(key, value);
335
+ };
336
+ if (state === undefined) {
337
+ if (bare.size === 0)
338
+ return plan;
339
+ for (const [key, value] of bare)
340
+ want(key, mergeSchemaMetaValue(key, value, twin.get(key)));
341
+ for (const key of [...twin.keys()].sort()) {
342
+ if (!bare.has(key) && !SCHEMA_META_NEVER_DELETED.has(key)) {
343
+ plan.del.push(key);
344
+ plan.dropped.push(key);
345
+ }
346
+ }
347
+ return plan;
348
+ }
349
+ const last = lastHashes(db, SCHEMA_META, state);
350
+ const twinMoved = (key) => {
351
+ const now = twin.has(key) ? sha(twin.get(key)) : ABSENT;
352
+ return now !== (last.twin[key] ?? ABSENT);
353
+ };
354
+ for (const key of [...bare.keys()].sort()) {
355
+ const value = bare.get(key);
356
+ if (last.bare[key] === sha(value))
357
+ continue;
358
+ const field = SCHEMA_META_COUNTER_FIELDS[key];
359
+ const current = twin.get(key);
360
+ if (field !== undefined) {
361
+ // A counter is never a conflict: keep whichever side is authoritative
362
+ // for the rest of the value, and max the counter field against the other.
363
+ const base = twinMoved(key) && current !== undefined ? current : value;
364
+ want(key, withMaxCounter(base, base === value ? current : value, field));
365
+ }
366
+ else if (twinMoved(key)) {
367
+ plan.conflicts.push(key);
368
+ }
369
+ else {
370
+ want(key, value);
371
+ }
372
+ }
373
+ for (const key of Object.keys(last.bare).sort()) {
374
+ if (bare.has(key) || SCHEMA_META_NEVER_DELETED.has(key) || !twin.has(key))
375
+ continue;
376
+ if (twinMoved(key))
377
+ plan.conflicts.push(key);
378
+ else
379
+ plan.del.push(key);
380
+ }
381
+ return plan;
382
+ }
383
+ function applyKv(db, schema, table, plan) {
384
+ const before = kvRows(db, table, schema);
385
+ const upsert = db.prepare(`INSERT INTO ${schema}.${table} (key, value) VALUES (?, ?) ` +
386
+ 'ON CONFLICT(key) DO UPDATE SET value = excluded.value');
387
+ const del = db.prepare(`DELETE FROM ${schema}.${table} WHERE key = ?`);
388
+ let inserted = 0;
389
+ let replaced = 0;
390
+ let deleted = 0;
391
+ for (const [key, value] of plan.set) {
392
+ upsert.run(key, value);
393
+ if (before.has(key))
394
+ replaced++;
395
+ else
396
+ inserted++;
397
+ }
398
+ for (const key of plan.del)
399
+ deleted += Number(del.run(key).changes);
400
+ return { inserted, replaced, deleted };
401
+ }
402
+ const SCHEMA_META = {
403
+ table: 'schema_meta',
404
+ twin: 'tasks_schema_meta',
405
+ kvTable: 'tasks_schema_meta',
406
+ tables: ['schema_meta', 'tasks_schema_meta'],
407
+ bareHashes: (db) => hashMap(carriedRows(db, 'schema_meta')),
408
+ twinHashes: (db) => hashMap(carriedRows(db, 'tasks_schema_meta')),
409
+ plan: planSchemaMeta,
410
+ apply(db, plan) {
411
+ const counts = applyKv(db, 'main', 'tasks_schema_meta', plan);
412
+ for (const [key, value] of plan.set) {
413
+ if (readKv(db, 'tasks_schema_meta', key) !== value)
414
+ throw new Error(`schema_meta collapse did not verify for key ${JSON.stringify(key)}`);
415
+ }
416
+ for (const key of plan.del) {
417
+ if (readKv(db, 'tasks_schema_meta', key) !== undefined)
418
+ throw new Error(`schema_meta collapse did not verify the removal of ${JSON.stringify(key)}`);
419
+ }
420
+ return counts;
421
+ },
422
+ shadow(db, plan) {
423
+ db.exec('CREATE TEMP TABLE IF NOT EXISTS tasks_schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)');
424
+ db.exec('DELETE FROM temp.tasks_schema_meta');
425
+ db.exec('INSERT INTO temp.tasks_schema_meta (key, value) SELECT key, value FROM main.tasks_schema_meta');
426
+ applyKv(db, 'temp', 'tasks_schema_meta', plan);
427
+ },
428
+ };
429
+ // ── sticky_tags ──────────────────────────────────────────────────────────────
430
+ /** Tag sets by sticky id (tags sorted). */
431
+ function stickySets(db, table) {
432
+ const rows = db
433
+ .prepare(`SELECT sticky_id, tag FROM main.${table} ORDER BY sticky_id, tag`)
434
+ .all();
435
+ const out = new Map();
436
+ for (const r of rows) {
437
+ const tags = out.get(r.sticky_id) ?? [];
438
+ tags.push(r.tag);
439
+ out.set(r.sticky_id, tags);
440
+ }
441
+ return out;
442
+ }
443
+ const hashSets = (m) => Object.fromEntries([...m].map(([k, tags]) => [k, sha(JSON.stringify(tags))]));
444
+ const EMPTY_SET = sha(JSON.stringify([]));
445
+ function planSticky(db, state) {
446
+ const plan = emptyPlan();
447
+ const bare = stickySets(db, 'sticky_tags');
448
+ const twin = stickySets(db, 'brain_sticky_tags');
449
+ const noteExists = db.prepare('SELECT 1 FROM main.brain_sticky_notes WHERE id = ?');
450
+ /** Make the twin's set for `id` equal the bare set. */
451
+ const mirror = (id, dropping) => {
452
+ const b = new Set(bare.get(id) ?? []);
453
+ const t = new Set(twin.get(id) ?? []);
454
+ const alive = b.size === 0 || noteExists.get(id) !== undefined;
455
+ for (const tag of b) {
456
+ if (!alive)
457
+ plan.skipped++;
458
+ else if (!t.has(tag))
459
+ plan.set.set(`${id}\t${tag}`, '');
460
+ }
461
+ for (const tag of t) {
462
+ if (b.has(tag))
463
+ continue;
464
+ plan.del.push(`${id}\t${tag}`);
465
+ if (dropping)
466
+ plan.dropped.push(`${id}\t${tag}`);
467
+ }
468
+ };
469
+ if (state === undefined) {
470
+ if (bare.size === 0)
471
+ return plan;
472
+ for (const id of [...new Set([...bare.keys(), ...twin.keys()])].sort())
473
+ mirror(id, true);
474
+ return plan;
475
+ }
476
+ const last = lastHashes(db, STICKY_TAGS, state);
477
+ const ids = new Set([...bare.keys(), ...Object.keys(last.bare)]);
478
+ for (const id of [...ids].sort()) {
479
+ const bareNow = bare.has(id) ? sha(JSON.stringify(bare.get(id))) : EMPTY_SET;
480
+ if (bareNow === (last.bare[id] ?? EMPTY_SET))
481
+ continue;
482
+ const twinNow = twin.has(id) ? sha(JSON.stringify(twin.get(id))) : EMPTY_SET;
483
+ if (twinNow !== (last.twin[id] ?? EMPTY_SET))
484
+ plan.conflicts.push(id);
485
+ else
486
+ mirror(id, false);
487
+ }
488
+ return plan;
489
+ }
490
+ function applyStickyRows(db, schema, plan) {
491
+ const insert = db.prepare(`INSERT OR IGNORE INTO ${schema}.brain_sticky_tags (sticky_id, tag) VALUES (?, ?)`);
492
+ const del = db.prepare(`DELETE FROM ${schema}.brain_sticky_tags WHERE sticky_id = ? AND tag = ?`);
493
+ let inserted = 0;
494
+ let deleted = 0;
495
+ for (const row of plan.set.keys()) {
496
+ const [id, tag] = row.split('\t');
497
+ inserted += Number(insert.run(id, tag).changes);
498
+ }
499
+ for (const row of plan.del) {
500
+ const [id, tag] = row.split('\t');
501
+ deleted += Number(del.run(id, tag).changes);
502
+ }
503
+ return { inserted, replaced: 0, deleted };
504
+ }
505
+ /** A note's tags as the accessor reads `tags_json` (strings, non-empty, deduplicated). */
506
+ function tagsOf(tagsJson) {
507
+ if (!tagsJson)
508
+ return [];
509
+ try {
510
+ const parsed = JSON.parse(tagsJson);
511
+ if (!Array.isArray(parsed))
512
+ return [];
513
+ return [...new Set(parsed.filter((t) => typeof t === 'string' && t.length > 0))];
514
+ }
515
+ catch {
516
+ return [];
517
+ }
518
+ }
519
+ /**
520
+ * Make the junction in `schema` equal every note's `tags_json`.
521
+ *
522
+ * `tags_json` lives on the shared `brain_sticky_notes` row, which both builds
523
+ * write together with their own junction; the junction is derived from it.
524
+ * Recomputing it after every merge keeps the tag filter (the junction) and the
525
+ * displayed tags (`tags_json`) from disagreeing when both builds retag one
526
+ * note (the merge's twin-wins rule would otherwise keep a stale set).
527
+ *
528
+ * @returns Junction rows added and removed.
529
+ */
530
+ function syncStickyJunction(db, schema) {
531
+ const notes = db.prepare('SELECT id, tags_json FROM main.brain_sticky_notes').all();
532
+ const have = new Map();
533
+ for (const r of db
534
+ .prepare(`SELECT sticky_id, tag FROM ${schema}.brain_sticky_tags`)
535
+ .all()) {
536
+ const set = have.get(r.sticky_id) ?? new Set();
537
+ set.add(r.tag);
538
+ have.set(r.sticky_id, set);
539
+ }
540
+ const insert = db.prepare(`INSERT OR IGNORE INTO ${schema}.brain_sticky_tags (sticky_id, tag) VALUES (?, ?)`);
541
+ const del = db.prepare(`DELETE FROM ${schema}.brain_sticky_tags WHERE sticky_id = ? AND tag = ?`);
542
+ let inserted = 0;
543
+ let deleted = 0;
544
+ for (const note of notes) {
545
+ const want = new Set(tagsOf(note.tags_json));
546
+ const current = have.get(note.id) ?? new Set();
547
+ for (const tag of want)
548
+ if (!current.has(tag))
549
+ inserted += Number(insert.run(note.id, tag).changes);
550
+ for (const tag of current)
551
+ if (!want.has(tag))
552
+ deleted += Number(del.run(note.id, tag).changes);
553
+ }
554
+ return { inserted, deleted };
555
+ }
556
+ const STICKY_TAGS = {
557
+ table: 'sticky_tags',
558
+ twin: 'brain_sticky_tags',
559
+ kvTable: 'brain_schema_meta',
560
+ tables: ['sticky_tags', 'brain_sticky_tags', 'brain_sticky_notes', 'brain_schema_meta'],
561
+ bareHashes: (db) => hashSets(stickySets(db, 'sticky_tags')),
562
+ twinHashes: (db) => hashSets(stickySets(db, 'brain_sticky_tags')),
563
+ plan: planSticky,
564
+ apply(db, plan) {
565
+ const counts = applyStickyRows(db, 'main', plan);
566
+ const present = db.prepare('SELECT 1 FROM main.brain_sticky_tags WHERE sticky_id = ? AND tag = ?');
567
+ const has = (row) => {
568
+ const [id, tag] = row.split('\t');
569
+ return present.get(id, tag) !== undefined;
570
+ };
571
+ const missing = [...plan.set.keys()].filter((r) => !has(r)).length;
572
+ const lingering = plan.del.filter(has).length;
573
+ if (missing > 0 || lingering > 0)
574
+ throw new Error(`sticky_tags collapse did not verify: ${missing} missing, ${lingering} not removed`);
575
+ const synced = syncStickyJunction(db, 'main');
576
+ return {
577
+ inserted: counts.inserted + synced.inserted,
578
+ replaced: 0,
579
+ deleted: counts.deleted + synced.deleted,
580
+ };
581
+ },
582
+ shadow(db, plan) {
583
+ db.exec('CREATE TEMP TABLE IF NOT EXISTS brain_sticky_tags (sticky_id TEXT NOT NULL, tag TEXT NOT NULL, PRIMARY KEY (sticky_id, tag))');
584
+ db.exec('DELETE FROM temp.brain_sticky_tags');
585
+ db.exec('INSERT INTO temp.brain_sticky_tags (sticky_id, tag) SELECT sticky_id, tag FROM main.brain_sticky_tags');
586
+ applyStickyRows(db, 'temp', plan);
587
+ syncStickyJunction(db, 'temp');
588
+ },
589
+ };
590
+ /** The pairs this build collapses, in order. */
591
+ const PAIRS = [SCHEMA_META, STICKY_TAGS];
592
+ /** Connections serving TEMP shadows because their collapse failed. */
593
+ const degraded = new WeakMap();
594
+ /**
595
+ * The failure a connection is degraded by, if any: reads on it are served from
596
+ * TEMP shadows and writes must be refused (the dispatch write guard does).
597
+ *
598
+ * @param db - A project `cleo.db` connection.
599
+ * @returns The failure, or `undefined` when the store is fully collapsed.
600
+ * @task T12535
601
+ */
602
+ export function twinCollapseFailureOf(db) {
603
+ return degraded.get(db);
604
+ }
605
+ /**
606
+ * Refuse a write before its first statement when the store is degraded by a
607
+ * failed twin collapse. The write accessors of the collapsed tables
608
+ * (`tasks_schema_meta`, and sticky notes and tags) call it at entry, so a
609
+ * degraded store never takes a partial write (e.g. a sticky's `tags_json`
610
+ * without its tag rows). The shadows' TEMP triggers stay as the backstop.
611
+ *
612
+ * @param handle - The connection the write would use (a `DatabaseSync`, or a
613
+ * drizzle instance's `$client`); anything else is not checked.
614
+ * @throws {CleoError} `E_TWIN_COLLAPSE_FAILED` when the connection is degraded.
615
+ * @task T12535
616
+ */
617
+ export function assertTwinCollapseWritable(handle) {
618
+ if (typeof handle !== 'object' || handle === null)
619
+ return;
620
+ const failure = degraded.get(handle);
621
+ if (failure)
622
+ throw twinCollapseError(failure);
623
+ }
624
+ /**
625
+ * Build the `E_TWIN_COLLAPSE_FAILED` error for a failure.
626
+ *
627
+ * @param failure - The failure.
628
+ * @param cause - The underlying error, when there is one.
629
+ * @returns The error.
630
+ * @task T12535
631
+ */
632
+ export function twinCollapseError(failure, cause) {
633
+ const where = !failure.snapshotPath
634
+ ? ''
635
+ : failure.snapshotWritten
636
+ ? ` Snapshot: ${failure.snapshotPath}.`
637
+ : ` Snapshot would be written to ${failure.snapshotPath}.`;
638
+ const space = failure.requiredBytes > 0
639
+ ? ` The snapshot needs ${failure.requiredBytes} bytes free` +
640
+ (failure.availableBytes === null ? '.' : ` (${failure.availableBytes} free).`)
641
+ : '';
642
+ return new CleoError(ExitCode.TWIN_COLLAPSE_FAILED, `Twin collapse of ${failure.tables.join(', ')} failed (both tables unchanged; reads still ` +
643
+ `work, writes are refused): ${failure.cause}.${where}${space} Run 'cleo doctor twin-collapse'.`, {
644
+ fix: "Run 'cleo doctor twin-collapse' for details, clear the cause (free the space, make " +
645
+ ".cleo/backups/sqlite writable), then 'cleo doctor twin-collapse --retry'.",
646
+ details: { field: 'twinCollapse', ...failure },
647
+ cause,
648
+ });
649
+ }
650
+ /** Record a failure outside the rolled-back transaction; best effort. */
651
+ function recordFailure(db, pairs, failure) {
652
+ for (const pair of pairs) {
653
+ try {
654
+ writeKv(db, pair.kvTable, `${TWIN_COLLAPSE_FAILURE_PREFIX}${pair.table}`, JSON.stringify(failure));
655
+ }
656
+ catch {
657
+ // The store itself may be the problem (disk full, read-only); the
658
+ // failure is still carried by the degraded state and the error.
659
+ }
660
+ }
661
+ }
662
+ /** Message a write into a sealed shadow aborts with. */
663
+ export const SHADOW_WRITE_REFUSED = 'E_TWIN_COLLAPSE_FAILED: store is read-only until the twin collapse succeeds; run cleo doctor twin-collapse';
664
+ const SHADOW_WRITE_OPS = ['INSERT', 'UPDATE', 'DELETE'];
665
+ /** Remove a shadow's write-refusing triggers (before it is rebuilt). */
666
+ function unsealShadow(db, twin) {
667
+ for (const op of SHADOW_WRITE_OPS) {
668
+ db.exec(`DROP TRIGGER IF EXISTS temp.${twin}_refuse_${op.toLowerCase()}`);
669
+ }
670
+ }
671
+ /**
672
+ * Make a shadow refuse writes. A write through the store accessors that
673
+ * bypasses the dispatch write guard (a direct SDK call) then fails with
674
+ * {@link SHADOW_WRITE_REFUSED} instead of landing in the shadow and being lost
675
+ * when the connection closes. The collapse itself writes `main.<twin>`
676
+ * (schema-qualified), which these TEMP triggers do not cover.
677
+ */
678
+ function sealShadow(db, twin) {
679
+ for (const op of SHADOW_WRITE_OPS) {
680
+ db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS ${twin}_refuse_${op.toLowerCase()} BEFORE ${op} ON temp.${twin} ` +
681
+ `BEGIN SELECT RAISE(ABORT, '${SHADOW_WRITE_REFUSED}'); END`);
682
+ }
683
+ }
684
+ /** Drop the TEMP shadows (and their triggers) of a connection that is no longer degraded. */
685
+ function clearShadows(db) {
686
+ for (const pair of PAIRS)
687
+ db.exec(`DROP TABLE IF EXISTS temp.${pair.twin}`);
688
+ degraded.delete(db);
689
+ }
690
+ function receipt(pair, status, snapshotPath) {
691
+ return {
692
+ table: pair.table,
693
+ twin: pair.twin,
694
+ status,
695
+ snapshotPath,
696
+ inserted: 0,
697
+ replaced: 0,
698
+ deleted: 0,
699
+ skipped: 0,
700
+ dropped: [],
701
+ conflicts: [],
702
+ };
703
+ }
704
+ /** Run one pair's merge in its own transaction. */
705
+ function collapsePair(db, pair, snapshotPath) {
706
+ db.exec('BEGIN IMMEDIATE');
707
+ try {
708
+ // Re-read under the write lock: another process may have merged since.
709
+ const state = readState(db, pair);
710
+ if (!bareChanged(db, pair, state)) {
711
+ db.exec('ROLLBACK');
712
+ return receipt(pair, 'unchanged', state?.snapshot ?? null);
713
+ }
714
+ const plan = pair.plan(db, state);
715
+ if (state === undefined && snapshotPath === null && (plan.set.size > 0 || plan.del.length > 0))
716
+ throw new Error(`bare ${pair.table} changed after the snapshot decision; retry the open`);
717
+ const counts = pair.apply(db, plan);
718
+ const now = new Date().toISOString();
719
+ const next = {
720
+ version: 3,
721
+ task: 'T12535',
722
+ collapsedAt: state?.collapsedAt || now,
723
+ lastMergedAt: now,
724
+ snapshot: state?.snapshot ?? snapshotPath,
725
+ hashes: { bare: pair.bareHashes(db), twin: pair.twinHashes(db) },
726
+ dropped: state === undefined ? plan.dropped : state.dropped,
727
+ conflicts: plan.conflicts.slice(0, MAX_CONFLICTS),
728
+ conflictsAt: plan.conflicts.length > 0 ? now : null,
729
+ };
730
+ writeKv(db, pair.kvTable, `${TWIN_COLLAPSE_MARKER_PREFIX}${pair.table}`, JSON.stringify(next));
731
+ db.prepare(`DELETE FROM main.${pair.kvTable} WHERE key = ?`).run(`${TWIN_COLLAPSE_FAILURE_PREFIX}${pair.table}`);
732
+ db.exec('COMMIT');
733
+ const done = {
734
+ ...receipt(pair, state === undefined ? 'initial' : 'incremental', next.snapshot),
735
+ ...counts,
736
+ skipped: plan.skipped,
737
+ dropped: plan.dropped,
738
+ conflicts: plan.conflicts,
739
+ };
740
+ if (counts.inserted + counts.replaced + counts.deleted > 0 || plan.conflicts.length > 0)
741
+ log.warn(done, `carried bare ${pair.table} into ${pair.twin} (${done.status}, T12535)`);
742
+ return done;
743
+ }
744
+ catch (error) {
745
+ if (db.isTransaction)
746
+ db.exec('ROLLBACK');
747
+ throw error;
748
+ }
749
+ }
750
+ /**
751
+ * Collapse every bare/twin pair present in the store: the initial collapse
752
+ * (snapshot first) where no marker exists yet, an incremental re-merge of
753
+ * changed bare keys where one does.
754
+ *
755
+ * @param nativeDb - The project `cleo.db` connection, outside any transaction.
756
+ * @param dbPath - Its file path (locates `.cleo/backups/sqlite/`).
757
+ * @param options - Failure handling.
758
+ * @returns One receipt per pair.
759
+ * @throws {CleoError} `E_TWIN_COLLAPSE_FAILED` with `onFailure: 'throw'`.
760
+ * @task T12535
761
+ */
762
+ export function collapseTwinTables(nativeDb, dbPath, options = {}) {
763
+ const onFailure = options.onFailure ?? 'throw';
764
+ // A bind on a connection already degraded in this process does not retry:
765
+ // the cause is outside CLEO; `cleo doctor twin-collapse --retry` retries.
766
+ if (onFailure === 'degrade' && degraded.has(nativeDb))
767
+ return PAIRS.map((p) => receipt(p, 'degraded', null));
768
+ const byTable = new Map();
769
+ const inOrder = () => PAIRS.map((p) => byTable.get(p.table)).filter((r) => r !== undefined);
770
+ const pending = [];
771
+ for (const pair of PAIRS) {
772
+ if (!pair.tables.every((t) => hasMainTable(nativeDb, t))) {
773
+ byTable.set(pair.table, receipt(pair, 'no-bare-table', null));
774
+ continue;
775
+ }
776
+ const state = readState(nativeDb, pair);
777
+ if (bareChanged(nativeDb, pair, state))
778
+ pending.push(pair);
779
+ else
780
+ byTable.set(pair.table, receipt(pair, 'unchanged', state?.snapshot ?? null));
781
+ }
782
+ if (pending.length === 0) {
783
+ if (degraded.has(nativeDb))
784
+ clearShadows(nativeDb);
785
+ return inOrder();
786
+ }
787
+ if (nativeDb.isTransaction)
788
+ throw new Error('twin collapse needs a connection outside a transaction');
789
+ const fail = (pairs, failure, cause) => {
790
+ recordFailure(nativeDb, pairs, failure);
791
+ log.error(failure, `twin collapse of ${failure.tables.join(', ')} failed (T12535)`);
792
+ if (onFailure === 'throw')
793
+ throw twinCollapseError(failure, cause);
794
+ // Read-only-for-users mode: serve the merged view from TEMP shadows. If
795
+ // even that cannot be built, reads cannot be served correctly either.
796
+ try {
797
+ for (const pair of pairs) {
798
+ unsealShadow(nativeDb, pair.twin);
799
+ pair.shadow(nativeDb, pair.plan(nativeDb, readState(nativeDb, pair)));
800
+ sealShadow(nativeDb, pair.twin);
801
+ }
802
+ }
803
+ catch (shadowError) {
804
+ throw twinCollapseError(failure, shadowError);
805
+ }
806
+ degraded.set(nativeDb, failure);
807
+ for (const pair of pairs)
808
+ byTable.set(pair.table, receipt(pair, 'degraded', failure.snapshotPath));
809
+ };
810
+ // One snapshot covers every pair whose INITIAL collapse changes its twin.
811
+ const needSnapshot = pending.filter((p) => {
812
+ if (readState(nativeDb, p) !== undefined)
813
+ return false;
814
+ const plan = p.plan(nativeDb, undefined);
815
+ return plan.set.size > 0 || plan.del.length > 0;
816
+ });
817
+ let snapshotPath = null;
818
+ if (needSnapshot.length > 0) {
819
+ const plan = planMigrationSnapshot(nativeDb, dbPath);
820
+ try {
821
+ snapshotPath = writeMigrationSnapshot(nativeDb, plan, `T12535 twin collapse of ${needSnapshot.map((p) => p.table).join(', ')} (store before the merge)`);
822
+ }
823
+ catch (error) {
824
+ fail(needSnapshot, {
825
+ tables: needSnapshot.map((p) => p.table),
826
+ cause: `snapshot not written: ${error instanceof Error ? error.message : String(error)}`,
827
+ snapshotPath: plan.snapshotPath,
828
+ snapshotWritten: false,
829
+ requiredBytes: plan.requiredBytes,
830
+ availableBytes: plan.availableBytes,
831
+ failedAt: new Date().toISOString(),
832
+ }, error);
833
+ // Pairs that need no snapshot (incremental, or an initial no-op) still run.
834
+ const rest = pending.filter((p) => !needSnapshot.includes(p));
835
+ pending.length = 0;
836
+ pending.push(...rest);
837
+ }
838
+ }
839
+ const failed = [];
840
+ let firstError;
841
+ for (const pair of pending) {
842
+ try {
843
+ byTable.set(pair.table, collapsePair(nativeDb, pair, snapshotPath));
844
+ }
845
+ catch (error) {
846
+ failed.push(pair);
847
+ firstError ??= error;
848
+ }
849
+ }
850
+ if (failed.length > 0) {
851
+ fail(failed, {
852
+ tables: failed.map((p) => p.table),
853
+ cause: firstError instanceof Error ? firstError.message : String(firstError),
854
+ snapshotPath,
855
+ snapshotWritten: snapshotPath !== null,
856
+ requiredBytes: 0,
857
+ availableBytes: null,
858
+ failedAt: new Date().toISOString(),
859
+ }, firstError);
860
+ }
861
+ else if (degraded.has(nativeDb) && byTable.size === PAIRS.length) {
862
+ if ([...byTable.values()].every((r) => r.status !== 'degraded'))
863
+ clearShadows(nativeDb);
864
+ }
865
+ return inOrder();
866
+ }
867
+ /**
868
+ * Report every pair's collapse state without writing (for `cleo doctor`).
869
+ *
870
+ * @param db - A connection on the project `cleo.db`; read-only is enough.
871
+ * @returns One status per pair.
872
+ * @task T12535
873
+ */
874
+ export function inspectTwinCollapse(db) {
875
+ return PAIRS.map((pair) => {
876
+ const empty = {
877
+ table: pair.table,
878
+ twin: pair.twin,
879
+ wouldChangeTwin: false,
880
+ snapshotPath: null,
881
+ collapsedAt: null,
882
+ lastMergedAt: null,
883
+ changedSinceMerge: 0,
884
+ conflicts: [],
885
+ conflictsAt: null,
886
+ failure: null,
887
+ };
888
+ if (!pair.tables.every((t) => hasMainTable(db, t)))
889
+ return { ...empty, state: 'no-bare-table' };
890
+ let failure = null;
891
+ try {
892
+ const raw = readKv(db, pair.kvTable, `${TWIN_COLLAPSE_FAILURE_PREFIX}${pair.table}`);
893
+ failure = raw === undefined ? null : JSON.parse(raw);
894
+ }
895
+ catch {
896
+ failure = null;
897
+ }
898
+ const state = readState(db, pair);
899
+ const now = pair.bareHashes(db);
900
+ const prev = state?.hashes?.bare ?? {};
901
+ let changed = 0;
902
+ for (const k of new Set([...Object.keys(now), ...Object.keys(prev)])) {
903
+ if (now[k] !== prev[k])
904
+ changed++;
905
+ }
906
+ let wouldChangeTwin = false;
907
+ if (state === undefined) {
908
+ const plan = pair.plan(db, undefined);
909
+ wouldChangeTwin = plan.set.size > 0 || plan.del.length > 0;
910
+ }
911
+ return {
912
+ ...empty,
913
+ state: failure !== null
914
+ ? 'failed'
915
+ : state === undefined
916
+ ? 'pending'
917
+ : changed > 0 || state.hashes === null
918
+ ? 'bare-changed'
919
+ : 'collapsed',
920
+ wouldChangeTwin,
921
+ snapshotPath: state?.snapshot ?? failure?.snapshotPath ?? null,
922
+ collapsedAt: state?.collapsedAt || null,
923
+ lastMergedAt: state?.lastMergedAt || null,
924
+ changedSinceMerge: state === undefined ? 0 : changed,
925
+ conflicts: state?.conflicts ?? [],
926
+ conflictsAt: state?.conflictsAt ?? null,
927
+ failure,
928
+ };
929
+ });
930
+ }
931
+ //# sourceMappingURL=twin-collapse.js.map