@cleocode/core 2026.10.12 → 2026.10.13

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 (255) hide show
  1. package/dist/build-provenance.json +2 -2
  2. package/dist/cloud/nexus-auth.d.ts.map +1 -1
  3. package/dist/cloud/nexus-auth.js +11 -2
  4. package/dist/cloud/nexus-auth.js.map +1 -1
  5. package/dist/cloud/nexus-cloud-status.d.ts.map +1 -1
  6. package/dist/cloud/nexus-cloud-status.js +18 -5
  7. package/dist/cloud/nexus-cloud-status.js.map +1 -1
  8. package/dist/cloud/nexus-credentials.d.ts +3 -2
  9. package/dist/cloud/nexus-credentials.d.ts.map +1 -1
  10. package/dist/cloud/nexus-credentials.js +58 -14
  11. package/dist/cloud/nexus-credentials.js.map +1 -1
  12. package/dist/cloud/nexus-logout.d.ts.map +1 -1
  13. package/dist/cloud/nexus-logout.js +12 -2
  14. package/dist/cloud/nexus-logout.js.map +1 -1
  15. package/dist/cloud/nexus-vault-state.d.ts.map +1 -1
  16. package/dist/cloud/nexus-vault-state.js +6 -26
  17. package/dist/cloud/nexus-vault-state.js.map +1 -1
  18. package/dist/config/registry.d.ts +21 -0
  19. package/dist/config/registry.d.ts.map +1 -1
  20. package/dist/config/registry.js +41 -0
  21. package/dist/config/registry.js.map +1 -1
  22. package/dist/dispatch/mvi-projection.d.ts.map +1 -1
  23. package/dist/dispatch/mvi-projection.js +2 -0
  24. package/dist/dispatch/mvi-projection.js.map +1 -1
  25. package/dist/docs/docs-ops.d.ts +15 -14
  26. package/dist/docs/docs-ops.d.ts.map +1 -1
  27. package/dist/docs/docs-ops.js +32 -96
  28. package/dist/docs/docs-ops.js.map +1 -1
  29. package/dist/docs/docs-read-model.d.ts +19 -10
  30. package/dist/docs/docs-read-model.d.ts.map +1 -1
  31. package/dist/docs/docs-read-model.js +31 -47
  32. package/dist/docs/docs-read-model.js.map +1 -1
  33. package/dist/docs/docs-update.d.ts +51 -1
  34. package/dist/docs/docs-update.d.ts.map +1 -1
  35. package/dist/docs/docs-update.js +235 -13
  36. package/dist/docs/docs-update.js.map +1 -1
  37. package/dist/docs/doctor.d.ts +26 -4
  38. package/dist/docs/doctor.d.ts.map +1 -1
  39. package/dist/docs/doctor.js +260 -102
  40. package/dist/docs/doctor.js.map +1 -1
  41. package/dist/docs/fetch-result.d.ts +30 -10
  42. package/dist/docs/fetch-result.d.ts.map +1 -1
  43. package/dist/docs/fetch-result.js +100 -15
  44. package/dist/docs/fetch-result.js.map +1 -1
  45. package/dist/docs/index.d.ts +1 -0
  46. package/dist/docs/index.d.ts.map +1 -1
  47. package/dist/docs/index.js +1 -0
  48. package/dist/docs/index.js.map +1 -1
  49. package/dist/docs/legacy-doc-migration.d.ts +182 -0
  50. package/dist/docs/legacy-doc-migration.d.ts.map +1 -0
  51. package/dist/docs/legacy-doc-migration.js +480 -0
  52. package/dist/docs/legacy-doc-migration.js.map +1 -0
  53. package/dist/docs/publications-store.d.ts +67 -0
  54. package/dist/docs/publications-store.d.ts.map +1 -0
  55. package/dist/docs/publications-store.js +193 -0
  56. package/dist/docs/publications-store.js.map +1 -0
  57. package/dist/docs/publish-pr.d.ts.map +1 -1
  58. package/dist/docs/publish-pr.js +31 -18
  59. package/dist/docs/publish-pr.js.map +1 -1
  60. package/dist/docs/section-leases.d.ts +233 -0
  61. package/dist/docs/section-leases.d.ts.map +1 -0
  62. package/dist/docs/section-leases.js +344 -0
  63. package/dist/docs/section-leases.js.map +1 -0
  64. package/dist/docs/section-merge.d.ts +159 -0
  65. package/dist/docs/section-merge.d.ts.map +1 -0
  66. package/dist/docs/section-merge.js +215 -0
  67. package/dist/docs/section-merge.js.map +1 -0
  68. package/dist/docs/section-write-path.d.ts +191 -0
  69. package/dist/docs/section-write-path.d.ts.map +1 -0
  70. package/dist/docs/section-write-path.js +423 -0
  71. package/dist/docs/section-write-path.js.map +1 -0
  72. package/dist/docs/stats.d.ts +56 -0
  73. package/dist/docs/stats.d.ts.map +1 -0
  74. package/dist/docs/stats.js +119 -0
  75. package/dist/docs/stats.js.map +1 -0
  76. package/dist/gc/cleanup.d.ts +1 -1
  77. package/dist/gc/cleanup.d.ts.map +1 -1
  78. package/dist/gc/cleanup.js +10 -1
  79. package/dist/gc/cleanup.js.map +1 -1
  80. package/dist/gc/janitor.js +1 -1
  81. package/dist/gc/janitor.js.map +1 -1
  82. package/dist/internal.d.ts +1 -1
  83. package/dist/internal.d.ts.map +1 -1
  84. package/dist/internal.js +1 -1
  85. package/dist/internal.js.map +1 -1
  86. package/dist/memory/pipeline-manifest-sqlite.d.ts +34 -0
  87. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  88. package/dist/memory/pipeline-manifest-sqlite.js +114 -0
  89. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  90. package/dist/nexus/analyze-orchestrator.d.ts +5 -1
  91. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  92. package/dist/nexus/analyze-orchestrator.js +25 -13
  93. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  94. package/dist/nexus/assessment-store.d.ts +8 -4
  95. package/dist/nexus/assessment-store.d.ts.map +1 -1
  96. package/dist/nexus/assessment-store.js +18 -27
  97. package/dist/nexus/assessment-store.js.map +1 -1
  98. package/dist/orchestration/index.d.ts.map +1 -1
  99. package/dist/orchestration/index.js +6 -0
  100. package/dist/orchestration/index.js.map +1 -1
  101. package/dist/orchestration/lean-change.d.ts +104 -5
  102. package/dist/orchestration/lean-change.d.ts.map +1 -1
  103. package/dist/orchestration/lean-change.js +162 -6
  104. package/dist/orchestration/lean-change.js.map +1 -1
  105. package/dist/orchestration/spawn-prompt.d.ts +6 -1
  106. package/dist/orchestration/spawn-prompt.d.ts.map +1 -1
  107. package/dist/orchestration/spawn-prompt.js +3 -1
  108. package/dist/orchestration/spawn-prompt.js.map +1 -1
  109. package/dist/orchestration/spawn.d.ts.map +1 -1
  110. package/dist/orchestration/spawn.js +6 -0
  111. package/dist/orchestration/spawn.js.map +1 -1
  112. package/dist/release/open.d.ts.map +1 -1
  113. package/dist/release/open.js +6 -2
  114. package/dist/release/open.js.map +1 -1
  115. package/dist/release/plan.d.ts.map +1 -1
  116. package/dist/release/plan.js +33 -2
  117. package/dist/release/plan.js.map +1 -1
  118. package/dist/resources/admission-ledger.d.ts +5 -0
  119. package/dist/resources/admission-ledger.d.ts.map +1 -1
  120. package/dist/resources/admission-ledger.js +1 -1
  121. package/dist/resources/admission-ledger.js.map +1 -1
  122. package/dist/resources/run-admission.d.ts.map +1 -1
  123. package/dist/resources/run-admission.js +4 -1
  124. package/dist/resources/run-admission.js.map +1 -1
  125. package/dist/resources/run-governed.d.ts +29 -4
  126. package/dist/resources/run-governed.d.ts.map +1 -1
  127. package/dist/resources/run-governed.js +113 -73
  128. package/dist/resources/run-governed.js.map +1 -1
  129. package/dist/sentient/worktree-dispatch.d.ts +12 -1
  130. package/dist/sentient/worktree-dispatch.d.ts.map +1 -1
  131. package/dist/sentient/worktree-dispatch.js +19 -0
  132. package/dist/sentient/worktree-dispatch.js.map +1 -1
  133. package/dist/spawn/branch-lock.d.ts +11 -1
  134. package/dist/spawn/branch-lock.d.ts.map +1 -1
  135. package/dist/spawn/branch-lock.js +54 -4
  136. package/dist/spawn/branch-lock.js.map +1 -1
  137. package/dist/sticky/archive.d.ts +1 -0
  138. package/dist/sticky/archive.d.ts.map +1 -1
  139. package/dist/sticky/archive.js +13 -0
  140. package/dist/sticky/archive.js.map +1 -1
  141. package/dist/sticky/engine-ops.d.ts.map +1 -1
  142. package/dist/sticky/engine-ops.js +7 -0
  143. package/dist/sticky/engine-ops.js.map +1 -1
  144. package/dist/store/attachment-repair.d.ts +10 -4
  145. package/dist/store/attachment-repair.d.ts.map +1 -1
  146. package/dist/store/attachment-repair.js +52 -25
  147. package/dist/store/attachment-repair.js.map +1 -1
  148. package/dist/store/attachment-store.d.ts.map +1 -1
  149. package/dist/store/attachment-store.js +27 -18
  150. package/dist/store/attachment-store.js.map +1 -1
  151. package/dist/store/blob-keep.d.ts +83 -0
  152. package/dist/store/blob-keep.d.ts.map +1 -1
  153. package/dist/store/blob-keep.js +139 -0
  154. package/dist/store/blob-keep.js.map +1 -1
  155. package/dist/store/blob-ops.d.ts +24 -0
  156. package/dist/store/blob-ops.d.ts.map +1 -1
  157. package/dist/store/blob-ops.js +47 -0
  158. package/dist/store/blob-ops.js.map +1 -1
  159. package/dist/store/conduit-doc-history.d.ts +209 -0
  160. package/dist/store/conduit-doc-history.d.ts.map +1 -1
  161. package/dist/store/conduit-doc-history.js +315 -3
  162. package/dist/store/conduit-doc-history.js.map +1 -1
  163. package/dist/store/decision-adr-links.d.ts +11 -0
  164. package/dist/store/decision-adr-links.d.ts.map +1 -1
  165. package/dist/store/decision-adr-links.js +20 -1
  166. package/dist/store/decision-adr-links.js.map +1 -1
  167. package/dist/store/display-id-alias.d.ts +8 -2
  168. package/dist/store/display-id-alias.d.ts.map +1 -1
  169. package/dist/store/display-id-alias.js +8 -3
  170. package/dist/store/display-id-alias.js.map +1 -1
  171. package/dist/store/lock.d.ts +18 -0
  172. package/dist/store/lock.d.ts.map +1 -1
  173. package/dist/store/lock.js +41 -0
  174. package/dist/store/lock.js.map +1 -1
  175. package/dist/store/row-identity-registry.d.ts.map +1 -1
  176. package/dist/store/row-identity-registry.js +17 -0
  177. package/dist/store/row-identity-registry.js.map +1 -1
  178. package/dist/store/schema/cleo-project/conduit.d.ts +16 -0
  179. package/dist/store/schema/cleo-project/conduit.d.ts.map +1 -1
  180. package/dist/store/schema/cleo-project/conduit.js +8 -0
  181. package/dist/store/schema/cleo-project/conduit.js.map +1 -1
  182. package/dist/store/schema/cleo-project/docs.d.ts +294 -0
  183. package/dist/store/schema/cleo-project/docs.d.ts.map +1 -1
  184. package/dist/store/schema/cleo-project/docs.js +82 -0
  185. package/dist/store/schema/cleo-project/docs.js.map +1 -1
  186. package/dist/store/sync/hlc.d.ts +9 -0
  187. package/dist/store/sync/hlc.d.ts.map +1 -1
  188. package/dist/store/sync/hlc.js +9 -0
  189. package/dist/store/sync/hlc.js.map +1 -1
  190. package/dist/store/sync/merge/engine.d.ts.map +1 -1
  191. package/dist/store/sync/merge/engine.js +4 -2
  192. package/dist/store/sync/merge/engine.js.map +1 -1
  193. package/dist/store/sync/merge/rules.d.ts +12 -1
  194. package/dist/store/sync/merge/rules.d.ts.map +1 -1
  195. package/dist/store/sync/merge/rules.js +76 -1
  196. package/dist/store/sync/merge/rules.js.map +1 -1
  197. package/dist/store/sync/replica-registry.d.ts +6 -2
  198. package/dist/store/sync/replica-registry.d.ts.map +1 -1
  199. package/dist/store/sync/replica-registry.js +21 -9
  200. package/dist/store/sync/replica-registry.js.map +1 -1
  201. package/dist/store/sync/timestamp-canon.d.ts.map +1 -1
  202. package/dist/store/sync/timestamp-canon.js +6 -0
  203. package/dist/store/sync/timestamp-canon.js.map +1 -1
  204. package/dist/store/table-classification.d.ts +58 -0
  205. package/dist/store/table-classification.d.ts.map +1 -1
  206. package/dist/store/table-classification.js +72 -0
  207. package/dist/store/table-classification.js.map +1 -1
  208. package/dist/store/twin-collapse.d.ts.map +1 -1
  209. package/dist/store/twin-collapse.js +4 -1
  210. package/dist/store/twin-collapse.js.map +1 -1
  211. package/dist/store/vault-manifest.d.ts +10 -1
  212. package/dist/store/vault-manifest.d.ts.map +1 -1
  213. package/dist/store/vault-manifest.js +59 -1
  214. package/dist/store/vault-manifest.js.map +1 -1
  215. package/dist/tasks/affected-scope.d.ts +11 -0
  216. package/dist/tasks/affected-scope.d.ts.map +1 -1
  217. package/dist/tasks/affected-scope.js +30 -11
  218. package/dist/tasks/affected-scope.js.map +1 -1
  219. package/dist/tasks/cancel-ops.d.ts.map +1 -1
  220. package/dist/tasks/cancel-ops.js +7 -2
  221. package/dist/tasks/cancel-ops.js.map +1 -1
  222. package/dist/tasks/change-set.d.ts +22 -0
  223. package/dist/tasks/change-set.d.ts.map +1 -1
  224. package/dist/tasks/change-set.js +119 -2
  225. package/dist/tasks/change-set.js.map +1 -1
  226. package/dist/tasks/complete.d.ts.map +1 -1
  227. package/dist/tasks/complete.js +7 -0
  228. package/dist/tasks/complete.js.map +1 -1
  229. package/dist/tasks/done-plan.d.ts +5 -0
  230. package/dist/tasks/done-plan.d.ts.map +1 -1
  231. package/dist/tasks/done-plan.js +54 -19
  232. package/dist/tasks/done-plan.js.map +1 -1
  233. package/dist/tasks/engine-wrap.d.ts +4 -0
  234. package/dist/tasks/engine-wrap.d.ts.map +1 -1
  235. package/dist/tasks/engine-wrap.js +20 -4
  236. package/dist/tasks/engine-wrap.js.map +1 -1
  237. package/dist/tasks/evidence-paths.d.ts +11 -0
  238. package/dist/tasks/evidence-paths.d.ts.map +1 -1
  239. package/dist/tasks/evidence-paths.js +12 -0
  240. package/dist/tasks/evidence-paths.js.map +1 -1
  241. package/dist/tools/fs.d.ts +7 -3
  242. package/dist/tools/fs.d.ts.map +1 -1
  243. package/dist/tools/fs.js +23 -8
  244. package/dist/tools/fs.js.map +1 -1
  245. package/dist/worktree/list.d.ts.map +1 -1
  246. package/dist/worktree/list.js +9 -0
  247. package/dist/worktree/list.js.map +1 -1
  248. package/dist/worktree/prune.d.ts.map +1 -1
  249. package/dist/worktree/prune.js +52 -1
  250. package/dist/worktree/prune.js.map +1 -1
  251. package/migrations/drizzle-cleo-project/20261013000000_t13360-migrated-doc-import/migration.sql +61 -0
  252. package/migrations/drizzle-cleo-project/20261014000000_t13362-docs-publications-ledger/migration.sql +45 -0
  253. package/package.json +13 -13
  254. package/templates/CLEO-INJECTION.md +1 -1
  255. package/templates/CLEO-REFERENCE.md +2 -2
@@ -30,6 +30,32 @@
30
30
  * @saga T13339
31
31
  */
32
32
  import { conduitAttachmentApprovals, conduitAttachmentVersions, conduitDocHeads, sectionCrdtStates } from './schema/cleo-project/conduit.js';
33
+ import type { ConduitDocMigrationLedgerRow } from './schema/cleo-project/docs.js';
34
+ /**
35
+ * Run one docs-projection write batch atomically (T13583).
36
+ *
37
+ * The section write path composes several accessors — section-state writes,
38
+ * the version append, the head upsert, the rebase and the derived
39
+ * contributors rebuild — and a failure halfway must not leave a non-head
40
+ * version behind for the next update to fork onto. The drizzle handle from
41
+ * {@link getDb} and the raw handle from {@link getNativeDb} are the same
42
+ * underlying `DatabaseSync`, so a `BEGIN IMMEDIATE` on the raw handle
43
+ * brackets every statement the accessors issue (the same pattern
44
+ * `docs-update.ts` uses for its slug transfer).
45
+ *
46
+ * Constraint (T13583): every statement inside `fn` must resolve without a
47
+ * real I/O yield — the docs projection satisfies this (sync-driver
48
+ * accessors, sync `node:fs` blob reads/writes), so no other async writer can
49
+ * interleave on this connection mid-transaction. A caller that awaits real
50
+ * I/O inside `fn` breaks that guarantee; per-handle writer serialization is
51
+ * the follow-up if such a caller appears.
52
+ *
53
+ * @param projectRoot - Absolute path to the CLEO project root.
54
+ * @param fn - The write batch; awaited between statements on this one
55
+ * connection, so no other writer can interleave inside the transaction.
56
+ * @returns What `fn` returned.
57
+ */
58
+ export declare function withConduitDocWriteTransaction<T>(projectRoot: string, fn: () => Promise<T>): Promise<T>;
33
59
  /** Row shape of `conduit_attachment_versions` as read back. */
34
60
  export type ConduitAttachmentVersionRow = typeof conduitAttachmentVersions.$inferSelect;
35
61
  /** Row shape of `conduit_attachment_approvals` as read back. */
@@ -46,6 +72,12 @@ export interface ConduitDocHeadConflict {
46
72
  readonly hlc: string;
47
73
  /** ISO-8601 instant the conflict was recorded. */
48
74
  readonly recordedAt: string;
75
+ /**
76
+ * The winning head's version uid at recording time — both sides of the
77
+ * conflict are named on the row (head `head_version_uid` + this).
78
+ * (T13595)
79
+ */
80
+ readonly winnerVersionUid?: string;
49
81
  }
50
82
  /**
51
83
  * Resolve a document slug to its immutable row uid.
@@ -59,6 +91,38 @@ export interface ConduitDocHeadConflict {
59
91
  * @returns The doc's `conduit_attachments.uid`, or `null` when unknown.
60
92
  */
61
93
  export declare function resolveConduitDocUid(projectRoot: string, slug: string): Promise<string | null>;
94
+ /**
95
+ * Adopt a document into the conduit family on first sight (T13355).
96
+ *
97
+ * The docs write path (`docs/section-write-path.ts`) projects every doc
98
+ * update through the section CRDT layer, whose history tables are keyed on
99
+ * `conduit_attachments.uid`; a doc that only exists in the legacy
100
+ * `attachments` registry has no conduit row yet, so this inserts one. The
101
+ * row is a thin identity shell: the bytes live in the blob store, so
102
+ * `content` carries an empty buffer and the sizes/hash describe nothing —
103
+ * the version rows carry the real content addressing.
104
+ *
105
+ * `conversation_id` is the NOT NULL transport owner; docs adopted here use
106
+ * the `cleodocs` sentinel (no FK — soft reference by design). Idempotent:
107
+ * an existing live row (or alias-resolved uid) is returned with
108
+ * `adopted: false`.
109
+ *
110
+ * The adopted row's uid is the schema's random UUIDv7 default — a
111
+ * single-device mint. Two devices adopting the same legacy slug concurrently
112
+ * mint two uids for one doc; deduping that is the filed follow-up (T13586).
113
+ *
114
+ * @param projectRoot - Absolute path to the CLEO project root.
115
+ * @param input - Slug, author and current full text of the doc.
116
+ * @returns The doc's immutable uid and whether this call created the row.
117
+ */
118
+ export declare function ensureConduitDoc(projectRoot: string, input: {
119
+ slug: string;
120
+ authorAgentId: string;
121
+ content: Buffer;
122
+ }): Promise<{
123
+ uid: string;
124
+ adopted: boolean;
125
+ }>;
62
126
  /**
63
127
  * Record an old-slug → doc-uid alias (append-only).
64
128
  *
@@ -118,6 +182,29 @@ export interface AppendConduitAttachmentVersionInput {
118
182
  * @returns The inserted row.
119
183
  */
120
184
  export declare function appendConduitAttachmentVersion(projectRoot: string, input: AppendConduitAttachmentVersionInput): Promise<ConduitAttachmentVersionRow>;
185
+ /**
186
+ * The set of content hashes the conduit doc-history family references.
187
+ *
188
+ * The blob sweep (`attachment-repair.ts`) only consulted the legacy
189
+ * attachments tables, the publications ledger and the blobs manifest, so a
190
+ * version/merged-text blob this family references could be garbage-collected
191
+ * as "unreferenced" (T13596). The sweep callers consult this set; it covers
192
+ * the version rows' `content_hash` (the merged-text blobs) and the adopted
193
+ * docs' `content_hash`.
194
+ *
195
+ * @param projectRoot - Absolute path to the CLEO project root.
196
+ * @returns Every `content_hash` named by `conduit_attachment_versions` or
197
+ * `conduit_attachments`.
198
+ */
199
+ export declare function listConduitHistorySha256Set(projectRoot: string): Promise<Set<string>>;
200
+ /**
201
+ * Read one version row by its wire identity (`uid`).
202
+ *
203
+ * @param projectRoot - Absolute path to the CLEO project root.
204
+ * @param versionUid - The version's `uid`.
205
+ * @returns The version row, or `null` when unknown.
206
+ */
207
+ export declare function getConduitAttachmentVersion(projectRoot: string, versionUid: string): Promise<ConduitAttachmentVersionRow | null>;
121
208
  /**
122
209
  * List a document's versions, newest display ordinal first.
123
210
  *
@@ -262,4 +349,126 @@ export declare function writeSectionCrdtState(projectRoot: string, input: {
262
349
  * @param baseVersionUid - The landed version's uid.
263
350
  */
264
351
  export declare function rebaseSectionCrdtStates(projectRoot: string, attachmentUid: string, baseVersionUid: string): Promise<void>;
352
+ /** Input for {@link importMigratedConduitDoc}. */
353
+ export interface ImportMigratedConduitDocInput {
354
+ /** Doc slug (the pre-rekey primary key; still the table PK). */
355
+ readonly slug: string;
356
+ /** Real provenance author when known; 'system:migration' when none. */
357
+ readonly fromAgentId: string;
358
+ /** Captured content bytes (stored uncompressed; sizes equal). */
359
+ readonly content: Buffer;
360
+ /** SHA-256 hex of `content`. */
361
+ readonly contentHash: string;
362
+ /** Content format tag ('markdown', 'text', …). */
363
+ readonly format: string;
364
+ /** Optional title. */
365
+ readonly title?: string;
366
+ /** Token count (measured, never invented). */
367
+ readonly tokens: number;
368
+ /** ISO-8601 doc creation instant from real provenance. */
369
+ readonly createdAt: string;
370
+ /** Imported history length (also written to the version_count columns). */
371
+ readonly versionCount: number;
372
+ }
373
+ /**
374
+ * Import one legacy doc as a `conduit_attachments` row (content-captured).
375
+ *
376
+ * The row uid is the natural identity over the slug: re-runs coalesce.
377
+ * `conversation_id` is the honest system value 'docs:migration' — migrated
378
+ * docs belong to no conduit conversation.
379
+ *
380
+ * @param projectRoot - Absolute path to the CLEO project root.
381
+ * @param input - The captured doc facts.
382
+ * @returns The doc uid and whether this call inserted the row.
383
+ * @task T13360
384
+ */
385
+ export declare function importMigratedConduitDoc(projectRoot: string, input: ImportMigratedConduitDocInput): Promise<{
386
+ uid: string;
387
+ inserted: boolean;
388
+ }>;
389
+ /** Input for {@link importMigratedConduitVersion}. */
390
+ export interface ImportMigratedConduitVersionInput {
391
+ /** Immutable doc id (`conduit_attachments.uid`). */
392
+ readonly attachmentUid: string;
393
+ /** Parent version uid in the DAG (NULL for the root import). */
394
+ readonly parentVersionUid: string | null;
395
+ /** Real provenance author (audit-log actor); 'system:migration' when none. */
396
+ readonly authorAgentId: string;
397
+ /** Content-addressed ref to the captured bytes. */
398
+ readonly storageKey: string;
399
+ /** SHA-256 hex of the version body. */
400
+ readonly contentHash: string;
401
+ /** Body size in bytes. */
402
+ readonly sizeBytes: number;
403
+ /** Measured token count. */
404
+ readonly tokens: number;
405
+ /** Display ordinal within the doc (derived from the real event order). */
406
+ readonly versionNumber: number;
407
+ /** ISO-8601 instant from real provenance (the audit event's ts). */
408
+ readonly createdAt: string;
409
+ /** Honest summary of what this row is. */
410
+ readonly changeSummary: string;
411
+ /** Pre-rekey display slug (legacy carry column). */
412
+ readonly slug: string;
413
+ }
414
+ /**
415
+ * Import one history row for a migrated doc.
416
+ *
417
+ * Every imported row carries `origin: 'migrated'` (spec §5 — no imported row
418
+ * poses as native) and a natural uid over (doc uid, content hash, event
419
+ * timestamp) — a pure function of the version's real facts (T13638). The
420
+ * derivation never touches the device-local `docs-audit.jsonl` row position,
421
+ * so two devices migrating the same synced legacy doc derive the SAME uid
422
+ * for the same content whatever their local audit logs hold, and two
423
+ * different contents (different hashes) can never collide on one uid. The
424
+ * insert is conflict-free on re-run and history can never be duplicated
425
+ * (AC4).
426
+ *
427
+ * @param projectRoot - Absolute path to the CLEO project root.
428
+ * @param input - The version facts.
429
+ * @returns The version uid and whether this call inserted the row.
430
+ * @task T13360
431
+ * @task T13638 — content-derived natural uid
432
+ */
433
+ export declare function importMigratedConduitVersion(projectRoot: string, input: ImportMigratedConduitVersionInput): Promise<{
434
+ uid: string;
435
+ inserted: boolean;
436
+ }>;
437
+ /** Input for {@link recordConduitDocMigration}. */
438
+ export interface RecordConduitDocMigrationInput {
439
+ /** The migrated doc's slug (one receipt per slug). */
440
+ readonly slug: string;
441
+ /** Captured doc uid (NULL when the doc is dangling). */
442
+ readonly docUid: string | null;
443
+ /** 'captured' or 'dangling'. */
444
+ readonly status: 'captured' | 'dangling';
445
+ /** Why (e.g. 'path-missing', 'path-ephemeral:worktree'). */
446
+ readonly reason: string;
447
+ /** Legacy pointer path when one existed. */
448
+ readonly legacyPath?: string;
449
+ /** Legacy content sha256 when known. */
450
+ readonly legacySha256?: string;
451
+ /** How many history rows the import created. */
452
+ readonly versionsImported: number;
453
+ }
454
+ /**
455
+ * Record the migration receipt for one doc (append-only, idempotent).
456
+ *
457
+ * This IS the auditable record for the dangling verdict (AC3): a dangling
458
+ * doc leaves a row with status 'dangling', the legacy pointer and the
459
+ * reason — never a silent import. The natural uid over the slug makes a
460
+ * re-run coalesce onto the same row.
461
+ *
462
+ * @param projectRoot - Absolute path to the CLEO project root.
463
+ * @param input - The receipt facts.
464
+ * @task T13360
465
+ */
466
+ export declare function recordConduitDocMigration(projectRoot: string, input: RecordConduitDocMigrationInput): Promise<{
467
+ uid: string;
468
+ inserted: boolean;
469
+ }>;
470
+ /** The migration receipt for one doc, or null when not migrated. */
471
+ export declare function findConduitDocMigration(projectRoot: string, slug: string): Promise<ConduitDocMigrationLedgerRow | null>;
472
+ /** All migration receipts, slug ascending (the audit view). */
473
+ export declare function listConduitDocMigrations(projectRoot: string): Promise<ConduitDocMigrationLedgerRow[]>;
265
474
  //# sourceMappingURL=conduit-doc-history.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conduit-doc-history.d.ts","sourceRoot":"","sources":["../../src/store/conduit-doc-history.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conduit-doc-history.d.ts","sourceRoot":"","sources":["../../src/store/conduit-doc-history.ts"],"names":[],"mappings":"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"}
@@ -29,13 +29,62 @@
29
29
  * @epic T13340
30
30
  * @saga T13339
31
31
  */
32
- import { randomUUID } from 'node:crypto';
32
+ import { createHash, randomUUID } from 'node:crypto';
33
33
  import { ExitCode } from '@cleocode/contracts/exit-codes.js';
34
- import { and, desc, eq, sql } from 'drizzle-orm';
34
+ import { and, asc, desc, eq, sql } from 'drizzle-orm';
35
35
  import { CleoError } from '../errors.js';
36
36
  import { naturalRowUid } from './row-identity.js';
37
37
  import { conduitAttachmentApprovals, conduitAttachments, conduitAttachmentVersions, conduitDocHeads, conduitDocSlugAliases, sectionCrdtStates, } from './schema/cleo-project/conduit.js';
38
- import { getDb } from './sqlite.js';
38
+ import { conduitDocMigrationLedger } from './schema/cleo-project/docs.js';
39
+ import { getDb, getNativeDb } from './sqlite.js';
40
+ /**
41
+ * Run one docs-projection write batch atomically (T13583).
42
+ *
43
+ * The section write path composes several accessors — section-state writes,
44
+ * the version append, the head upsert, the rebase and the derived
45
+ * contributors rebuild — and a failure halfway must not leave a non-head
46
+ * version behind for the next update to fork onto. The drizzle handle from
47
+ * {@link getDb} and the raw handle from {@link getNativeDb} are the same
48
+ * underlying `DatabaseSync`, so a `BEGIN IMMEDIATE` on the raw handle
49
+ * brackets every statement the accessors issue (the same pattern
50
+ * `docs-update.ts` uses for its slug transfer).
51
+ *
52
+ * Constraint (T13583): every statement inside `fn` must resolve without a
53
+ * real I/O yield — the docs projection satisfies this (sync-driver
54
+ * accessors, sync `node:fs` blob reads/writes), so no other async writer can
55
+ * interleave on this connection mid-transaction. A caller that awaits real
56
+ * I/O inside `fn` breaks that guarantee; per-handle writer serialization is
57
+ * the follow-up if such a caller appears.
58
+ *
59
+ * @param projectRoot - Absolute path to the CLEO project root.
60
+ * @param fn - The write batch; awaited between statements on this one
61
+ * connection, so no other writer can interleave inside the transaction.
62
+ * @returns What `fn` returned.
63
+ */
64
+ // @sync-invariant docs.head.max-hlc the version append, the head upsert and the rebase commit or roll back as one causal step; a half-landed projection cannot fork the next update
65
+ export async function withConduitDocWriteTransaction(projectRoot, fn) {
66
+ await getDb(projectRoot);
67
+ const native = getNativeDb(projectRoot);
68
+ if (!native) {
69
+ // @sync-invariant none:input-shape the projection requires an open project store; getDb above just opened it, so this is a broken environment, not row data — nothing was written
70
+ throw new CleoError(ExitCode.GENERAL_ERROR, 'conduit doc write transaction requires an initialised project store');
71
+ }
72
+ native.prepare('BEGIN IMMEDIATE').run();
73
+ try {
74
+ const out = await fn();
75
+ native.prepare('COMMIT').run();
76
+ return out;
77
+ }
78
+ catch (err) {
79
+ try {
80
+ native.prepare('ROLLBACK').run();
81
+ }
82
+ catch {
83
+ /* Auto-rolled back by SQLite on most errors. */
84
+ }
85
+ throw err;
86
+ }
87
+ }
39
88
  /**
40
89
  * Refuse an empty identifier at the write boundary.
41
90
  *
@@ -77,6 +126,68 @@ export async function resolveConduitDocUid(projectRoot, slug) {
77
126
  .get();
78
127
  return alias?.docUid ?? null;
79
128
  }
129
+ /**
130
+ * Adopt a document into the conduit family on first sight (T13355).
131
+ *
132
+ * The docs write path (`docs/section-write-path.ts`) projects every doc
133
+ * update through the section CRDT layer, whose history tables are keyed on
134
+ * `conduit_attachments.uid`; a doc that only exists in the legacy
135
+ * `attachments` registry has no conduit row yet, so this inserts one. The
136
+ * row is a thin identity shell: the bytes live in the blob store, so
137
+ * `content` carries an empty buffer and the sizes/hash describe nothing —
138
+ * the version rows carry the real content addressing.
139
+ *
140
+ * `conversation_id` is the NOT NULL transport owner; docs adopted here use
141
+ * the `cleodocs` sentinel (no FK — soft reference by design). Idempotent:
142
+ * an existing live row (or alias-resolved uid) is returned with
143
+ * `adopted: false`.
144
+ *
145
+ * The adopted row's uid is the schema's random UUIDv7 default — a
146
+ * single-device mint. Two devices adopting the same legacy slug concurrently
147
+ * mint two uids for one doc; deduping that is the filed follow-up (T13586).
148
+ *
149
+ * @param projectRoot - Absolute path to the CLEO project root.
150
+ * @param input - Slug, author and current full text of the doc.
151
+ * @returns The doc's immutable uid and whether this call created the row.
152
+ */
153
+ // @sync-invariant docs.doc.adopt-once the existence probe and the identity-shell insert are one causal step; the uid default makes a re-adopt conflict-free
154
+ export async function ensureConduitDoc(projectRoot, input) {
155
+ requireNonEmpty('slug', input.slug);
156
+ requireNonEmpty('authorAgentId', input.authorAgentId);
157
+ const existing = await resolveConduitDocUid(projectRoot, input.slug);
158
+ if (existing !== null)
159
+ return { uid: existing, adopted: false };
160
+ const db = await getDb(projectRoot);
161
+ await db
162
+ .insert(conduitAttachments)
163
+ .values({
164
+ slug: input.slug,
165
+ conversationId: 'cleodocs',
166
+ fromAgentId: input.authorAgentId,
167
+ content: Buffer.alloc(0),
168
+ originalSize: input.content.length,
169
+ compressedSize: input.content.length,
170
+ contentHash: createHash('sha256').update(input.content).digest('hex'),
171
+ format: 'text',
172
+ title: input.slug,
173
+ tokens: input.content
174
+ .toString('utf-8')
175
+ .split(/\s+/)
176
+ .filter((w) => w.length > 0).length,
177
+ })
178
+ .onConflictDoNothing()
179
+ .run();
180
+ const row = await db
181
+ .select({ uid: conduitAttachments.uid })
182
+ .from(conduitAttachments)
183
+ .where(eq(conduitAttachments.slug, input.slug))
184
+ .get();
185
+ if (!row?.uid) {
186
+ // @sync-invariant docs.doc.adopt-once an adopt that cannot be read back means the store lost the write; fail loudly instead of returning a phantom
187
+ throw new CleoError(ExitCode.GENERAL_ERROR, `conduit doc adopt for slug '${input.slug}' could not be read back`);
188
+ }
189
+ return { uid: row.uid, adopted: true };
190
+ }
80
191
  /**
81
192
  * Record an old-slug → doc-uid alias (append-only).
82
193
  *
@@ -165,6 +276,54 @@ export async function appendConduitAttachmentVersion(projectRoot, input) {
165
276
  }
166
277
  return row;
167
278
  }
279
+ /**
280
+ * The set of content hashes the conduit doc-history family references.
281
+ *
282
+ * The blob sweep (`attachment-repair.ts`) only consulted the legacy
283
+ * attachments tables, the publications ledger and the blobs manifest, so a
284
+ * version/merged-text blob this family references could be garbage-collected
285
+ * as "unreferenced" (T13596). The sweep callers consult this set; it covers
286
+ * the version rows' `content_hash` (the merged-text blobs) and the adopted
287
+ * docs' `content_hash`.
288
+ *
289
+ * @param projectRoot - Absolute path to the CLEO project root.
290
+ * @returns Every `content_hash` named by `conduit_attachment_versions` or
291
+ * `conduit_attachments`.
292
+ */
293
+ export async function listConduitHistorySha256Set(projectRoot) {
294
+ const db = await getDb(projectRoot);
295
+ const versionRows = await db
296
+ .select({ contentHash: conduitAttachmentVersions.contentHash })
297
+ .from(conduitAttachmentVersions)
298
+ .all();
299
+ const docRows = await db
300
+ .select({ contentHash: conduitAttachments.contentHash })
301
+ .from(conduitAttachments)
302
+ .all();
303
+ const set = new Set();
304
+ for (const row of versionRows)
305
+ set.add(row.contentHash);
306
+ for (const row of docRows)
307
+ set.add(row.contentHash);
308
+ return set;
309
+ }
310
+ /**
311
+ * Read one version row by its wire identity (`uid`).
312
+ *
313
+ * @param projectRoot - Absolute path to the CLEO project root.
314
+ * @param versionUid - The version's `uid`.
315
+ * @returns The version row, or `null` when unknown.
316
+ */
317
+ export async function getConduitAttachmentVersion(projectRoot, versionUid) {
318
+ requireNonEmpty('versionUid', versionUid);
319
+ const db = await getDb(projectRoot);
320
+ const row = await db
321
+ .select()
322
+ .from(conduitAttachmentVersions)
323
+ .where(eq(conduitAttachmentVersions.uid, versionUid))
324
+ .get();
325
+ return row ?? null;
326
+ }
168
327
  /**
169
328
  * List a document's versions, newest display ordinal first.
170
329
  *
@@ -350,6 +509,7 @@ export async function upsertConduitDocHead(projectRoot, input) {
350
509
  versionUid: input.headVersionUid,
351
510
  hlc: input.headHlc,
352
511
  recordedAt: now,
512
+ winnerVersionUid: existing.headVersionUid,
353
513
  };
354
514
  await db
355
515
  .update(conduitDocHeads)
@@ -465,4 +625,156 @@ export async function rebaseSectionCrdtStates(projectRoot, attachmentUid, baseVe
465
625
  .where(eq(sectionCrdtStates.attachmentUid, attachmentUid))
466
626
  .run();
467
627
  }
628
+ /**
629
+ * Import one legacy doc as a `conduit_attachments` row (content-captured).
630
+ *
631
+ * The row uid is the natural identity over the slug: re-runs coalesce.
632
+ * `conversation_id` is the honest system value 'docs:migration' — migrated
633
+ * docs belong to no conduit conversation.
634
+ *
635
+ * @param projectRoot - Absolute path to the CLEO project root.
636
+ * @param input - The captured doc facts.
637
+ * @returns The doc uid and whether this call inserted the row.
638
+ * @task T13360
639
+ */
640
+ // @sync-invariant docs.docs-migration.idempotent-import the natural uid over the slug makes a re-run a verified no-op via ON CONFLICT DO NOTHING; nothing is updated or deleted
641
+ export async function importMigratedConduitDoc(projectRoot, input) {
642
+ requireNonEmpty('slug', input.slug);
643
+ requireNonEmpty('fromAgentId', input.fromAgentId);
644
+ requireNonEmpty('contentHash', input.contentHash);
645
+ const uid = naturalRowUid('project', 'conduit_attachments', [input.slug]);
646
+ const db = await getDb(projectRoot);
647
+ const result = await db
648
+ .insert(conduitAttachments)
649
+ .values({
650
+ slug: input.slug,
651
+ conversationId: 'docs:migration',
652
+ fromAgentId: input.fromAgentId,
653
+ content: input.content,
654
+ originalSize: input.content.length,
655
+ compressedSize: input.content.length,
656
+ contentHash: input.contentHash,
657
+ format: input.format,
658
+ ...(input.title !== undefined ? { title: input.title } : {}),
659
+ tokens: input.tokens,
660
+ versionCount: input.versionCount,
661
+ currentVersion: input.versionCount,
662
+ createdAt: input.createdAt,
663
+ uid,
664
+ })
665
+ .onConflictDoNothing()
666
+ .run();
667
+ return { uid, inserted: (result.changes ?? 0) > 0 };
668
+ }
669
+ /**
670
+ * Import one history row for a migrated doc.
671
+ *
672
+ * Every imported row carries `origin: 'migrated'` (spec §5 — no imported row
673
+ * poses as native) and a natural uid over (doc uid, content hash, event
674
+ * timestamp) — a pure function of the version's real facts (T13638). The
675
+ * derivation never touches the device-local `docs-audit.jsonl` row position,
676
+ * so two devices migrating the same synced legacy doc derive the SAME uid
677
+ * for the same content whatever their local audit logs hold, and two
678
+ * different contents (different hashes) can never collide on one uid. The
679
+ * insert is conflict-free on re-run and history can never be duplicated
680
+ * (AC4).
681
+ *
682
+ * @param projectRoot - Absolute path to the CLEO project root.
683
+ * @param input - The version facts.
684
+ * @returns The version uid and whether this call inserted the row.
685
+ * @task T13360
686
+ * @task T13638 — content-derived natural uid
687
+ */
688
+ // @sync-invariant docs.versions.append-only the natural uid over (doc uid, content hash, event timestamp) makes a re-run a verified no-op via ON CONFLICT DO NOTHING; imported history is never updated or deleted
689
+ export async function importMigratedConduitVersion(projectRoot, input) {
690
+ requireNonEmpty('attachmentUid', input.attachmentUid);
691
+ requireNonEmpty('contentHash', input.contentHash);
692
+ requireNonEmpty('createdAt', input.createdAt);
693
+ requireNonEmpty('authorAgentId', input.authorAgentId);
694
+ const uid = naturalRowUid('project', 'conduit_attachment_versions', [
695
+ input.attachmentUid,
696
+ input.contentHash,
697
+ input.createdAt,
698
+ ]);
699
+ const db = await getDb(projectRoot);
700
+ const result = await db
701
+ .insert(conduitAttachmentVersions)
702
+ .values({
703
+ id: randomUUID(),
704
+ uid,
705
+ attachmentUid: input.attachmentUid,
706
+ parentVersionUid: input.parentVersionUid,
707
+ slug: input.slug,
708
+ versionNumber: input.versionNumber,
709
+ authorAgentId: input.authorAgentId,
710
+ changeType: 'migrated',
711
+ storageKey: input.storageKey,
712
+ contentHash: input.contentHash,
713
+ originalSize: input.sizeBytes,
714
+ compressedSize: input.sizeBytes,
715
+ tokens: input.tokens,
716
+ changeSummary: input.changeSummary,
717
+ sectionsModified: '[]',
718
+ tokensAdded: 0,
719
+ tokensRemoved: 0,
720
+ createdAt: input.createdAt,
721
+ origin: 'migrated',
722
+ })
723
+ .onConflictDoNothing()
724
+ .run();
725
+ return { uid, inserted: (result.changes ?? 0) > 0 };
726
+ }
727
+ /**
728
+ * Record the migration receipt for one doc (append-only, idempotent).
729
+ *
730
+ * This IS the auditable record for the dangling verdict (AC3): a dangling
731
+ * doc leaves a row with status 'dangling', the legacy pointer and the
732
+ * reason — never a silent import. The natural uid over the slug makes a
733
+ * re-run coalesce onto the same row.
734
+ *
735
+ * @param projectRoot - Absolute path to the CLEO project root.
736
+ * @param input - The receipt facts.
737
+ * @task T13360
738
+ */
739
+ // @sync-invariant docs.docs-migration.idempotent-import the natural uid over the slug makes a re-run a verified no-op via ON CONFLICT DO NOTHING; receipts are never updated or deleted
740
+ export async function recordConduitDocMigration(projectRoot, input) {
741
+ requireNonEmpty('slug', input.slug);
742
+ const uid = naturalRowUid('project', 'conduit_doc_migration_ledger', [input.slug]);
743
+ const db = await getDb(projectRoot);
744
+ const result = await db
745
+ .insert(conduitDocMigrationLedger)
746
+ .values({
747
+ slug: input.slug,
748
+ docUid: input.docUid,
749
+ status: input.status,
750
+ reason: input.reason,
751
+ ...(input.legacyPath !== undefined ? { legacyPath: input.legacyPath } : {}),
752
+ ...(input.legacySha256 !== undefined ? { legacySha256: input.legacySha256 } : {}),
753
+ versionsImported: input.versionsImported,
754
+ migratedAt: new Date().toISOString(),
755
+ uid,
756
+ })
757
+ .onConflictDoNothing()
758
+ .run();
759
+ return { uid, inserted: (result.changes ?? 0) > 0 };
760
+ }
761
+ /** The migration receipt for one doc, or null when not migrated. */
762
+ export async function findConduitDocMigration(projectRoot, slug) {
763
+ requireNonEmpty('slug', slug);
764
+ const db = await getDb(projectRoot);
765
+ return ((await db
766
+ .select()
767
+ .from(conduitDocMigrationLedger)
768
+ .where(eq(conduitDocMigrationLedger.slug, slug))
769
+ .get()) ?? null);
770
+ }
771
+ /** All migration receipts, slug ascending (the audit view). */
772
+ export async function listConduitDocMigrations(projectRoot) {
773
+ const db = await getDb(projectRoot);
774
+ return db
775
+ .select()
776
+ .from(conduitDocMigrationLedger)
777
+ .orderBy(asc(conduitDocMigrationLedger.slug))
778
+ .all();
779
+ }
468
780
  //# sourceMappingURL=conduit-doc-history.js.map