@cleocode/cleo 2026.10.3 → 2026.10.5-rc.ci.672

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 (352) hide show
  1. package/README.md +7 -0
  2. package/bin/cleo.js +11 -1
  3. package/dist/cli/adapter-OUQRSFZL.js +159 -0
  4. package/dist/cli/add-4SRRJL4U.js +443 -0
  5. package/dist/cli/add-batch-TSWICA5J.js +164 -0
  6. package/dist/cli/admin-L3F6CDYH.js +1428 -0
  7. package/dist/cli/admin-YMU55YCU.js +341 -0
  8. package/dist/cli/adr-XESRMFMP.js +172 -0
  9. package/dist/cli/agent-TAFPIYUU.js +2404 -0
  10. package/dist/cli/agent-outputs-HVJJIPS4.js +84 -0
  11. package/dist/cli/analyze-YQ22QVGW.js +49 -0
  12. package/dist/cli/archive-W5XX6AH7.js +65 -0
  13. package/dist/cli/archive-stats-HP2KPAJU.js +101 -0
  14. package/dist/cli/attention-7JBDCRZX.js +124 -0
  15. package/dist/cli/attention-ZXZANHKC.js +168 -0
  16. package/dist/cli/audit-ICA2SEFN.js +122 -0
  17. package/dist/cli/auth-DXIG5OG7.js +491 -0
  18. package/dist/cli/backfill-LBSYBWLR.js +156 -0
  19. package/dist/cli/backup-NUGBZ7NA.js +588 -0
  20. package/dist/cli/backup-inspect-PDRXI45A.js +26 -0
  21. package/dist/cli/backup-recover-TVKAPERB.js +29 -0
  22. package/dist/cli/blockers-ZOPCGHDW.js +55 -0
  23. package/dist/cli/brain-EJOBKL4A.js +397 -0
  24. package/dist/cli/briefing-RDQJ6WHS.js +213 -0
  25. package/dist/cli/caamp-Z3XPKEHB.js +181 -0
  26. package/dist/cli/cancel-S7EHLCJN.js +85 -0
  27. package/dist/cli/canon-NPF5RODM.js +142 -0
  28. package/dist/cli/canon-docs-2GTOLF7Y.js +26 -0
  29. package/dist/cli/cant-CHNN6O57.js +239 -0
  30. package/dist/cli/changeset-RYPHPN2B.js +246 -0
  31. package/dist/cli/check-C67YAU7W.js +759 -0
  32. package/dist/cli/check-DHMURGHC.js +924 -0
  33. package/dist/cli/checkpoint-UWDFOGYQ.js +128 -0
  34. package/dist/cli/chunk-22YPFZYB.js +91 -0
  35. package/dist/cli/chunk-2MGFDMDF.js +272 -0
  36. package/dist/cli/chunk-47JYZAMS.js +30 -0
  37. package/dist/cli/chunk-4JYHPP4C.js +76 -0
  38. package/dist/cli/chunk-4PEODTHY.js +278 -0
  39. package/dist/cli/chunk-4RGSNUUP.js +950 -0
  40. package/dist/cli/chunk-4VASFLUW.js +35 -0
  41. package/dist/cli/chunk-5PNI276X.js +124 -0
  42. package/dist/cli/chunk-6JSJNYH2.js +114 -0
  43. package/dist/cli/chunk-6N6WGLXE.js +63 -0
  44. package/dist/cli/chunk-75UH3BLS.js +210 -0
  45. package/dist/cli/chunk-7ACK4EIN.js +92 -0
  46. package/dist/cli/chunk-7NMKLVMI.js +107 -0
  47. package/dist/cli/chunk-7SINJXB6.js +110 -0
  48. package/dist/cli/chunk-7UARFJYS.js +46 -0
  49. package/dist/cli/chunk-7ZYPQV4N.js +90 -0
  50. package/dist/cli/chunk-AQCYT3L4.js +72 -0
  51. package/dist/cli/chunk-BQK6XTOH.js +57 -0
  52. package/dist/cli/chunk-C3B7C43W.js +16 -0
  53. package/dist/cli/chunk-CAPAGD5E.js +98 -0
  54. package/dist/cli/chunk-CHGEDCKG.js +77 -0
  55. package/dist/cli/chunk-COXFJ3PT.js +74 -0
  56. package/dist/cli/chunk-D7BAQNV2.js +55 -0
  57. package/dist/cli/chunk-EIUXVHNF.js +258 -0
  58. package/dist/cli/chunk-EUGB6P5V.js +173 -0
  59. package/dist/cli/chunk-EW2CKNNZ.js +304 -0
  60. package/dist/cli/chunk-FSKN4DWC.js +108 -0
  61. package/dist/cli/chunk-FVKLULL7.js +48 -0
  62. package/dist/cli/chunk-GAGUBU4Z.js +280 -0
  63. package/dist/cli/chunk-GKRFH2YG.js +171 -0
  64. package/dist/cli/chunk-GRU74UE4.js +270 -0
  65. package/dist/cli/chunk-GZFVDR44.js +320 -0
  66. package/dist/cli/chunk-HFLLZE6A.js +83 -0
  67. package/dist/cli/chunk-HXRXT3XU.js +78 -0
  68. package/dist/cli/chunk-IIOGUY3B.js +258 -0
  69. package/dist/cli/chunk-ILWWL462.js +60 -0
  70. package/dist/cli/chunk-J5USPJKZ.js +48 -0
  71. package/dist/cli/chunk-KEQS36GD.js +88 -0
  72. package/dist/cli/chunk-L7ONYSV6.js +2497 -0
  73. package/dist/cli/chunk-LVGIFMCV.js +163 -0
  74. package/dist/cli/chunk-NEFMQYLE.js +656 -0
  75. package/dist/cli/chunk-NU6CQQVB.js +4501 -0
  76. package/dist/cli/chunk-OILHT47L.js +252 -0
  77. package/dist/cli/chunk-PKKZPOOP.js +352 -0
  78. package/dist/cli/chunk-PN4WW5VX.js +66 -0
  79. package/dist/cli/chunk-PSJ33WVO.js +56 -0
  80. package/dist/cli/chunk-QA6T2LQ5.js +71 -0
  81. package/dist/cli/chunk-QJJWWCIC.js +288 -0
  82. package/dist/cli/chunk-QKMBWYAS.js +93 -0
  83. package/dist/cli/chunk-QWNKLLLG.js +84 -0
  84. package/dist/cli/chunk-QWUFFDL3.js +85 -0
  85. package/dist/cli/chunk-QY76BRUZ.js +35 -0
  86. package/dist/cli/chunk-R45KVF5Y.js +117 -0
  87. package/dist/cli/chunk-RRKP7HLU.js +66 -0
  88. package/dist/cli/chunk-SXXOC6KZ.js +209 -0
  89. package/dist/cli/chunk-T6GZJYL3.js +108 -0
  90. package/dist/cli/chunk-TLQ37HRE.js +67 -0
  91. package/dist/cli/chunk-TPTNEJZJ.js +52 -0
  92. package/dist/cli/chunk-TYC7G5LF.js +100 -0
  93. package/dist/cli/chunk-UWCZY52R.js +766 -0
  94. package/dist/cli/chunk-VB3LDPL5.js +46 -0
  95. package/dist/cli/chunk-VLEYOOPH.js +31 -0
  96. package/dist/cli/chunk-W3JLYKKY.js +140 -0
  97. package/dist/cli/chunk-WWCYZYSN.js +56 -0
  98. package/dist/cli/chunk-XA5WISNV.js +52 -0
  99. package/dist/cli/chunk-XHRZ7OYZ.js +132 -0
  100. package/dist/cli/chunk-XLPMIGJJ.js +148 -0
  101. package/dist/cli/chunk-YY66LFZF.js +29 -0
  102. package/dist/cli/chunk-ZMGDZMSJ.js +210 -0
  103. package/dist/cli/claim-IGOG2QOC.js +97 -0
  104. package/dist/cli/classify-MG4N7GMQ.js +117 -0
  105. package/dist/cli/cli-A23Q335V.js +51 -0
  106. package/dist/cli/cloud-SILYJVKO.js +731 -0
  107. package/dist/cli/cockpit-RZKLGYPN.js +790 -0
  108. package/dist/cli/code-H2FQCVMW.js +178 -0
  109. package/dist/cli/complete-JLX7NBI4.js +35 -0
  110. package/dist/cli/complexity-OKV7PVZH.js +57 -0
  111. package/dist/cli/compliance-QMGZHJNQ.js +277 -0
  112. package/dist/cli/conduit-4H32UYEA.js +308 -0
  113. package/dist/cli/conduit-EY54WTZA.js +535 -0
  114. package/dist/cli/config-TDYOC7XO.js +519 -0
  115. package/dist/cli/consensus-4XCOFPPT.js +122 -0
  116. package/dist/cli/context-FN4YTGHD.js +142 -0
  117. package/dist/cli/contribution-7RWFBJLC.js +112 -0
  118. package/dist/cli/curator-HKZJCVRL.js +139 -0
  119. package/dist/cli/current-B2NU7V3G.js +43 -0
  120. package/dist/cli/daemon-GBD4TVCD.js +452 -0
  121. package/dist/cli/dash-IGDANIE5.js +71 -0
  122. package/dist/cli/decide-26SXC2V6.js +416 -0
  123. package/dist/cli/decompose-LQ76TEZG.js +78 -0
  124. package/dist/cli/decomposition-WFRWNUSJ.js +122 -0
  125. package/dist/cli/delete-T5DUQHOX.js +69 -0
  126. package/dist/cli/deps-UTPZJBXL.js +462 -0
  127. package/dist/cli/detect-FFZSMVDT.js +46 -0
  128. package/dist/cli/detect-drift-TVCJOFYJ.js +408 -0
  129. package/dist/cli/diagnostics-GN5CVD3N.js +93 -0
  130. package/dist/cli/diagnostics-ZNBKH6GX.js +133 -0
  131. package/dist/cli/docs-CLQKEEUK.js +1710 -0
  132. package/dist/cli/docs-DPPDFTWR.js +3098 -0
  133. package/dist/cli/doctor-GPENOP4N.js +1270 -0
  134. package/dist/cli/doctor-ac-bindings-S3IOEFP4.js +26 -0
  135. package/dist/cli/doctor-acceptance-drift-VNFKPBSQ.js +26 -0
  136. package/dist/cli/doctor-credentials-A5H4JMTF.js +26 -0
  137. package/dist/cli/doctor-db-substrate-FGCISE4Z.js +27 -0
  138. package/dist/cli/doctor-dep-cycles-BKKKHHYG.js +26 -0
  139. package/dist/cli/doctor-exodus-ND2DH2KP.js +26 -0
  140. package/dist/cli/doctor-exodus-residue-4EMRYMEQ.js +26 -0
  141. package/dist/cli/doctor-fk-check-VY3RIQV3.js +26 -0
  142. package/dist/cli/doctor-global-delivery-JN6IGHUL.js +26 -0
  143. package/dist/cli/doctor-heavy-command-hook-XSN44WXU.js +26 -0
  144. package/dist/cli/doctor-legacy-backups-QAG5NHYP.js +26 -0
  145. package/dist/cli/doctor-legacy-reaper-CIRGFE6R.js +26 -0
  146. package/dist/cli/doctor-malformed-ids-WL7HT4TB.js +26 -0
  147. package/dist/cli/doctor-manifest-rows-SMQCKJ2T.js +26 -0
  148. package/dist/cli/doctor-memory-guard-LJDOJG76.js +26 -0
  149. package/dist/cli/doctor-migrations-ETQPFNUP.js +26 -0
  150. package/dist/cli/doctor-nexus-residency-A4JMKBEJ.js +26 -0
  151. package/dist/cli/doctor-project-identity-FFQJ5LNX.js +26 -0
  152. package/dist/cli/doctor-projects-MFUTKRHP.js +30 -0
  153. package/dist/cli/doctor-projects-registry-76X6VTGM.js +26 -0
  154. package/dist/cli/doctor-release-readiness-QJCOPFTK.js +26 -0
  155. package/dist/cli/doctor-repair-AU76FIKY.js +26 -0
  156. package/dist/cli/doctor-row-identity-KW6JYZQE.js +26 -0
  157. package/dist/cli/doctor-skill-fixtures-G3T7JUHS.js +26 -0
  158. package/dist/cli/doctor-split-brain-FUW6L7FS.js +26 -0
  159. package/dist/cli/doctor-superseded-store-DUHGSBLC.js +26 -0
  160. package/dist/cli/doctor-sync-journal-SXMUIKF7.js +26 -0
  161. package/dist/cli/doctor-sync-triggers-6WNJZFRM.js +26 -0
  162. package/dist/cli/doctor-tool-locks-66LSLUBN.js +26 -0
  163. package/dist/cli/doctor-twin-collapse-AYBYBFC4.js +26 -0
  164. package/dist/cli/doctor-worktree-stores-C5XEH5OG.js +26 -0
  165. package/dist/cli/done-R64XRZ32.js +196 -0
  166. package/dist/cli/dynamic-RR4HB7BB.js +29 -0
  167. package/dist/cli/entities-3JIHDIOK.js +361 -0
  168. package/dist/cli/event-45KEWV5H.js +372 -0
  169. package/dist/cli/exists-BEDZS5RI.js +65 -0
  170. package/dist/cli/exodus-DUX62344.js +401 -0
  171. package/dist/cli/export-C5PQIQ5O.js +93 -0
  172. package/dist/cli/export-tasks-CUXDZPJB.js +97 -0
  173. package/dist/cli/federation-ESM35EGG.js +145 -0
  174. package/dist/cli/find-5EUZHHQJ.js +178 -0
  175. package/dist/cli/focus-6AH4KLRO.js +368 -0
  176. package/dist/cli/focus-ANKAIRO5.js +56 -0
  177. package/dist/cli/gateway-2GW2KTK3.js +77 -0
  178. package/dist/cli/gateway-auto-start-EDK7XI6E.js +36 -0
  179. package/dist/cli/gc-CTOQLUSA.js +291 -0
  180. package/dist/cli/go-YJPNHHYT.js +206 -0
  181. package/dist/cli/goal-4GW4G77D.js +213 -0
  182. package/dist/cli/grade-25WSZH4X.js +57 -0
  183. package/dist/cli/graph-JUO3TMF3.js +879 -0
  184. package/dist/cli/history-NACNUQTC.js +138 -0
  185. package/dist/cli/hook-UF7J7R6D.js +57 -0
  186. package/dist/cli/hook-entry.js +244 -19
  187. package/dist/cli/hygiene-3QZ2NI7P.js +55 -0
  188. package/dist/cli/import-7ESGL5SS.js +89 -0
  189. package/dist/cli/import-tasks-FLE2RPBR.js +109 -0
  190. package/dist/cli/index.js +601 -94637
  191. package/dist/cli/init-AN4DZ2XO.js +40 -0
  192. package/dist/cli/inject-HQWA5GWY.js +83 -0
  193. package/dist/cli/install-global-YQV4W5OG.js +95 -0
  194. package/dist/cli/intelligence-OFFNQGHE.js +238 -0
  195. package/dist/cli/intelligence-QIC4SN4X.js +182 -0
  196. package/dist/cli/issue-P5RNMRDG.js +159 -0
  197. package/dist/cli/janitor-ZNCFQ7E3.js +111 -0
  198. package/dist/cli/labels-ORBM3T57.js +88 -0
  199. package/dist/cli/lifecycle-MHR22TVI.js +273 -0
  200. package/dist/cli/list-LB6GCYYU.js +109 -0
  201. package/dist/cli/llm-H7LZWQKX.js +130 -0
  202. package/dist/cli/llm-OTJWPMGI.js +704 -0
  203. package/dist/cli/llm-cost-MLMXEAR4.js +25 -0
  204. package/dist/cli/llm-stream-AAEUNKRP.js +27 -0
  205. package/dist/cli/log-W2A5M2NA.js +76 -0
  206. package/dist/cli/login-SIXFFZSP.js +45 -0
  207. package/dist/cli/logout-G3KVLQQM.js +74 -0
  208. package/dist/cli/manifest-G4T6EBSI.js +354 -0
  209. package/dist/cli/map-VU5M72TK.js +53 -0
  210. package/dist/cli/memory-2E27G2G5.js +1952 -0
  211. package/dist/cli/memory-IAEYKXG6.js +1895 -0
  212. package/dist/cli/migrate-agents-v2-A52QIYNJ.js +33 -0
  213. package/dist/cli/migrate-claude-mem-TPDW3R4Z.js +206 -0
  214. package/dist/cli/next-SVH4LIDY.js +57 -0
  215. package/dist/cli/nexus-FPQV2EAF.js +1059 -0
  216. package/dist/cli/nexus-XSFXN5E6.js +2924 -0
  217. package/dist/cli/ops-K6LHY5J6.js +52 -0
  218. package/dist/cli/orchestrate-CZ2J6W3L.js +1650 -0
  219. package/dist/cli/orchestrate-HURUCQFT.js +950 -0
  220. package/dist/cli/otel-JCNPVJLZ.js +188 -0
  221. package/dist/cli/phase-VDFRASSO.js +221 -0
  222. package/dist/cli/pipeline-TCZPOEDR.js +697 -0
  223. package/dist/cli/pivot-V5MSQZ7L.js +88 -0
  224. package/dist/cli/plan-SQUGCKSM.js +49 -0
  225. package/dist/cli/playbook-L47GLDQD.js +230 -0
  226. package/dist/cli/playbook-NJVO4R6P.js +33 -0
  227. package/dist/cli/project-YZEC7GYF.js +331 -0
  228. package/dist/cli/promote-FINF4HVK.js +53 -0
  229. package/dist/cli/provenance-3TUWVBFR.js +141 -0
  230. package/dist/cli/provenance-YZG33JGM.js +129 -0
  231. package/dist/cli/provider-23JVLLG3.js +213 -0
  232. package/dist/cli/reason-FHN54O7O.js +138 -0
  233. package/dist/cli/reconcile-MOM5T4AX.js +128 -0
  234. package/dist/cli/refresh-memory-3OSTRAVK.js +45 -0
  235. package/dist/cli/relates-6FWUFUS2.js +260 -0
  236. package/dist/cli/release-G2DPSG5M.js +347 -0
  237. package/dist/cli/release-URX6JHZ2.js +525 -0
  238. package/dist/cli/remote-VIULU2T5.js +279 -0
  239. package/dist/cli/renderers-TGSW77J4.js +37 -0
  240. package/dist/cli/reorder-UIPN6TQY.js +87 -0
  241. package/dist/cli/reparent-ALOWWUIU.js +59 -0
  242. package/dist/cli/req-RH2Y3H7A.js +130 -0
  243. package/dist/cli/research-G2Y72HRC.js +366 -0
  244. package/dist/cli/restore-VBR5XNML.js +470 -0
  245. package/dist/cli/revert-32LDNSGP.js +240 -0
  246. package/dist/cli/roadmap-LFU3AG7D.js +62 -0
  247. package/dist/cli/run-HXRILSR7.js +245 -0
  248. package/dist/cli/safestop-Z5UC7NGQ.js +89 -0
  249. package/dist/cli/saga-Y6FZS6AM.js +286 -0
  250. package/dist/cli/schema-OOOKLWUE.js +195 -0
  251. package/dist/cli/self-update-26SOTJMH.js +504 -0
  252. package/dist/cli/selfimprove-4SMOCLUV.js +89 -0
  253. package/dist/cli/selfimprove-EB4RQLP4.js +139 -0
  254. package/dist/cli/sentient-QPETVE53.js +254 -0
  255. package/dist/cli/sentient-RGMWR4XJ.js +1088 -0
  256. package/dist/cli/sequence-H7DSAJPF.js +94 -0
  257. package/dist/cli/service-EK5MGB2D.js +156 -0
  258. package/dist/cli/service-GLOMZWPQ.js +437 -0
  259. package/dist/cli/session-HYUXAQGC.js +708 -0
  260. package/dist/cli/session-N5ISU56W.js +568 -0
  261. package/dist/cli/setup-L3YYV53D.js +323 -0
  262. package/dist/cli/show-364V3KY2.js +123 -0
  263. package/dist/cli/skill-F2KR6HW5.js +84 -0
  264. package/dist/cli/skills-FS3DCP6E.js +929 -0
  265. package/dist/cli/smoke-provider-SKUFMZXU.js +218 -0
  266. package/dist/cli/snapshot-EGXEQ5PR.js +120 -0
  267. package/dist/cli/src-LYLXHXHH.js +80 -0
  268. package/dist/cli/start-6DXOCCKL.js +68 -0
  269. package/dist/cli/stats-UVUQEGYC.js +96 -0
  270. package/dist/cli/status-XLKYLN42.js +157 -0
  271. package/dist/cli/sticky-VSTQ2I2O.js +264 -0
  272. package/dist/cli/sticky-XZXZDCFW.js +339 -0
  273. package/dist/cli/stop-VNOAFWNB.js +43 -0
  274. package/dist/cli/sync-YYPARW3A.js +155 -0
  275. package/dist/cli/tasks-C24KHTFF.js +1118 -0
  276. package/dist/cli/tasks-LBJC7CZV.js +175 -0
  277. package/dist/cli/telemetry-CU7W5WAY.js +120 -0
  278. package/dist/cli/templates-G42JBUY4.js +609 -0
  279. package/dist/cli/testing-HSRITHEY.js +147 -0
  280. package/dist/cli/token-J74E7TSU.js +221 -0
  281. package/dist/cli/tools-BI74W7VE.js +652 -0
  282. package/dist/cli/transcript-RGK7RSGQ.js +440 -0
  283. package/dist/cli/tui-BPUFHYKK.js +51 -0
  284. package/dist/cli/update-2KQWA27S.js +478 -0
  285. package/dist/cli/update-check-entry.js +124 -0
  286. package/dist/cli/update-notice-6SQ6WPQG.js +68 -0
  287. package/dist/cli/upgrade-E2MJAPC7.js +136 -0
  288. package/dist/cli/upgrade-XRSQ4RWH.js +243 -0
  289. package/dist/cli/verify-WASRGDBA.js +191 -0
  290. package/dist/cli/web-NJ3P67EU.js +275 -0
  291. package/dist/cli/workgraph-OHJ2VKJD.js +232 -0
  292. package/dist/cli/worktree-FVQLORFY.js +371 -0
  293. package/dist/cli/worktree-ZJ6JTQNG.js +287 -0
  294. package/package.json +13 -13
  295. package/studio-dist/client/_app/immutable/chunks/{DMj27Pxj.js → AH7dIemv.js} +1 -1
  296. package/studio-dist/client/_app/immutable/chunks/{Dc2owyvE.js → BDgH40i3.js} +1 -1
  297. package/studio-dist/client/_app/immutable/chunks/BXDCSJ7U.js +1 -0
  298. package/studio-dist/client/_app/immutable/chunks/{qq3pe1aT.js → Gg4iYl59.js} +1 -1
  299. package/studio-dist/client/_app/immutable/entry/{app.CHWXLeE9.js → app.DUDNK-37.js} +2 -2
  300. package/studio-dist/client/_app/immutable/entry/start.DNmZ0pA4.js +1 -0
  301. package/studio-dist/client/_app/immutable/nodes/{0.DmKQGvFh.js → 0.DWqP3ail.js} +1 -1
  302. package/studio-dist/client/_app/immutable/nodes/{1.DqJk_REO.js → 1.CZGVUP5B.js} +1 -1
  303. package/studio-dist/client/_app/immutable/nodes/{15.GUy6kdW1.js → 15.DGaflZRS.js} +1 -1
  304. package/studio-dist/client/_app/immutable/nodes/{16.CcnKZ8f9.js → 16.uYlarGXl.js} +1 -1
  305. package/studio-dist/client/_app/immutable/nodes/{17.DAlQF3lQ.js → 17.CZMR0E47.js} +1 -1
  306. package/studio-dist/client/_app/immutable/nodes/{18.vQFr-vFj.js → 18.CBC-AKH_.js} +1 -1
  307. package/studio-dist/client/_app/immutable/nodes/{20.GVOj5j_r.js → 20.BGi43MvQ.js} +1 -1
  308. package/studio-dist/client/_app/immutable/nodes/{24.2-wC6DOh.js → 24.Dv8ftCyR.js} +1 -1
  309. package/studio-dist/client/_app/immutable/nodes/25.DQPVlTDQ.js +39 -0
  310. package/studio-dist/client/_app/immutable/nodes/{26.C3rNqzZF.js → 26.Cl800304.js} +1 -1
  311. package/studio-dist/client/_app/immutable/nodes/{3.b-7pzc3M.js → 3.D_fQKj9f.js} +1 -1
  312. package/studio-dist/client/_app/version.json +1 -1
  313. package/studio-dist/server/chunks/{0-BaCce-O1.js → 0-BpOagOst.js} +3 -3
  314. package/studio-dist/server/chunks/1-D0oRGR-C.js +9 -0
  315. package/studio-dist/server/chunks/{15-DRMOSIC9.js → 15-BcjHz7Tv.js} +3 -3
  316. package/studio-dist/server/chunks/{16-BulXhoZZ.js → 16-CXm8TUk7.js} +3 -3
  317. package/studio-dist/server/chunks/{17-DUEOCM0H.js → 17-mSgUK-cp.js} +3 -3
  318. package/studio-dist/server/chunks/{18-DP7Q8zPs.js → 18-BtfnIw1d.js} +3 -3
  319. package/studio-dist/server/chunks/{20-9ta6MI7q.js → 20-By1e4QDS.js} +3 -3
  320. package/studio-dist/server/chunks/{24-DysdL1ab.js → 24-0i2YLVxG.js} +3 -3
  321. package/studio-dist/server/chunks/{dist-CdoCt9zT.js → 25-DPsrqbrh.js} +797 -10736
  322. package/studio-dist/server/chunks/{26-Df4YXgg0.js → 26-P0XkOibm.js} +3 -3
  323. package/studio-dist/server/chunks/{3-BEhOhYpL.js → 3-WudjUK7e.js} +3 -3
  324. package/studio-dist/server/chunks/{_layout.svelte-CnLcXYG-.js → _layout.svelte-D9m81Rle.js} +4 -4
  325. package/studio-dist/server/chunks/{_page.svelte-DGhXqeRc.js → _page.svelte-2PDLOF83.js} +3 -3
  326. package/studio-dist/server/chunks/{_page.svelte-Dv8tmDEC.js → _page.svelte-BjE3jm2K.js} +3 -3
  327. package/studio-dist/server/chunks/{_page.svelte-C0qgUvzA.js → _page.svelte-Clc0vmiZ.js} +4 -4
  328. package/studio-dist/server/chunks/{_page.svelte-ui7LnWkL.js → _page.svelte-DABdRT3h.js} +3 -3
  329. package/studio-dist/server/chunks/{_page.svelte-HUqTICJR.js → _page.svelte-DG3PjiHj.js} +3 -3
  330. package/studio-dist/server/chunks/{_page.svelte-DzcZljiy.js → _page.svelte-Edy9CaE8.js} +20 -7
  331. package/studio-dist/server/chunks/{_page.svelte-DOl0DGOO.js → _page.svelte-Hrf3-ZR8.js} +3 -3
  332. package/studio-dist/server/chunks/{_page.svelte-Da4q5l93.js → _page.svelte-VB4O4Nl5.js} +3 -3
  333. package/studio-dist/server/chunks/{_page.svelte-CbyEPj2j.js → _page.svelte-d3jEgjsI.js} +3 -3
  334. package/studio-dist/server/chunks/{_server.ts-P4wVVksg.js → _server.ts-BcRFsyo3.js} +4 -5
  335. package/studio-dist/server/chunks/{_server.ts-Cr57EKWf.js → _server.ts-CEWpIFrj.js} +6 -5
  336. package/studio-dist/server/chunks/{_server.ts-CnKVmf_s.js → _server.ts-CLVdVIF9.js} +2 -2
  337. package/studio-dist/server/chunks/{_server.ts-C0evMKCk.js → _server.ts-D_j7aSy5.js} +6 -5
  338. package/studio-dist/server/chunks/{_server.ts-2BazvYRP.js → _server.ts-QEZF8h2q.js} +4 -5
  339. package/studio-dist/server/chunks/{client-CPM4LrO2.js → client-Kp1dP1od.js} +2 -2
  340. package/studio-dist/server/chunks/{error.svelte-ShcZo43D.js → error.svelte-WOCioJVX.js} +3 -3
  341. package/studio-dist/server/chunks/{hooks.server-D2qbf3Zp.js → hooks.server-DH9zkIrJ.js} +3 -1
  342. package/studio-dist/server/chunks/{http-BiQjEmVU.js → http-DT5kxaWk.js} +5 -4
  343. package/studio-dist/server/chunks/{internal-Cgsrya1j.js → internal-z0vqd5_u.js} +3 -3
  344. package/studio-dist/server/chunks/operations-registry-DdzmYzqX.js +10584 -0
  345. package/studio-dist/server/chunks/{stores-BGrpEDMK.js → stores-s2kaL315.js} +2 -2
  346. package/studio-dist/server/index.js +1 -1
  347. package/studio-dist/server/manifest.js +17 -17
  348. package/studio-dist/client/_app/immutable/chunks/Bw6J8NDM.js +0 -1
  349. package/studio-dist/client/_app/immutable/entry/start.C9bwPpvc.js +0 -1
  350. package/studio-dist/client/_app/immutable/nodes/25.D1vYaH8g.js +0 -39
  351. package/studio-dist/server/chunks/1-CVo7Nk6d.js +0 -9
  352. package/studio-dist/server/chunks/25-CYsps38R.js +0 -366
@@ -0,0 +1,1710 @@
1
+ (() => {
2
+ const _installed = Symbol.for('cleocode.cli.sqliteWarningFilter');
3
+ if (globalThis[_installed]) return;
4
+ globalThis[_installed] = true;
5
+ const _origEmitWarning = process.emitWarning;
6
+ process.emitWarning = function(warning, type, code, ctor) {
7
+ if (typeof warning === 'object' && warning.name === 'ExperimentalWarning' && typeof warning.message === 'string' && /SQLite is an experimental feature/i.test(warning.message)) {
8
+ return;
9
+ }
10
+ if (typeof warning === 'string' && /SQLite is an experimental feature/i.test(warning)) {
11
+ return;
12
+ }
13
+ return _origEmitWarning.call(process, warning, type, code, ctor);
14
+ };
15
+ })();
16
+ import {
17
+ defineTypedHandler,
18
+ lafsError,
19
+ lafsSuccess,
20
+ typedDispatch
21
+ } from "./chunk-QWNKLLLG.js";
22
+ import {
23
+ lazyOperation
24
+ } from "./chunk-TYC7G5LF.js";
25
+ import {
26
+ dispatchMeta,
27
+ handleErrorResult,
28
+ unsupportedOp
29
+ } from "./chunk-XHRZ7OYZ.js";
30
+
31
+ // packages/cleo/src/dispatch/domains/docs.ts
32
+ import { randomUUID } from "node:crypto";
33
+ import { readFile } from "node:fs/promises";
34
+ import { resolve } from "node:path";
35
+ import { DocKindRegistry } from "@cleocode/contracts/docs-taxonomy.js";
36
+ import { LLM_OUTPUT_MODES } from "@cleocode/contracts/operations/docs";
37
+ import { parseChangesetFrontmatter } from "@cleocode/core/changesets/parse-frontmatter";
38
+ import { readAuditLog, verifyAuditTrail, writeAuditEntry } from "@cleocode/core/docs/docs-audit";
39
+ import { createDocsReadModel } from "@cleocode/core/docs/docs-read-model";
40
+ import {
41
+ DOCS_UPDATE_LIFECYCLE_STATUS_LIST,
42
+ isLifecycleStatus
43
+ } from "@cleocode/core/docs/docs-update";
44
+ import { createAttachmentStoreDocsAccessor } from "@cleocode/core/docs/import/attachment-store-accessor";
45
+ import { makeClassifierForScanRoot } from "@cleocode/core/docs/import/scanner";
46
+ import { AUTO_TOKEN } from "@cleocode/core/docs/numbering";
47
+ import {
48
+ captureDocumentProjection,
49
+ projectDocumentAttachment
50
+ } from "@cleocode/core/docs/projection";
51
+ import { consumeReservedSlug, releaseReservedSlug } from "@cleocode/core/docs/slug-allocator";
52
+ import { SUPERSEDE_NOT_FOUND_CODE, SUPERSEDE_SAME_SLUG_CODE } from "@cleocode/core/docs/supersede";
53
+ import { validateDocBody } from "@cleocode/core/docs/validate-body";
54
+ import { generateProjectHash } from "@cleocode/core/nexus/hash";
55
+ import { pushWarning } from "@cleocode/core/output";
56
+ import { resolveCleoDir, worktreeScope } from "@cleocode/core/paths.js";
57
+ import { getProjectRoot } from "@cleocode/core/project-scope";
58
+ import {
59
+ createAttachmentBlobStore,
60
+ createAttachmentStore,
61
+ SlugCollisionError
62
+ } from "@cleocode/core/store/attachment-store";
63
+ var allocateAdrSlug = lazyOperation(
64
+ async () => (await import("@cleocode/core/docs/adr-allocator")).allocateAdrSlug
65
+ );
66
+ var allocateAutoSlugForDispatch = lazyOperation(
67
+ async () => (await import("@cleocode/core/docs/numbering")).allocateAutoSlugForDispatch
68
+ );
69
+ var exportDocument = lazyOperation(
70
+ async () => (await import("@cleocode/core/docs/export-document")).exportDocument
71
+ );
72
+ var findSimilarDocs = lazyOperation(
73
+ async () => (await import("@cleocode/core/docs/docs-ops")).findSimilarDocs
74
+ );
75
+ var generateDocsLlmsTxt = lazyOperation(
76
+ async () => (await import("@cleocode/core/docs/docs-generator")).generateDocsLlmsTxt
77
+ );
78
+ var listDocVersions = lazyOperation(
79
+ async () => (await import("@cleocode/core/docs/docs-ops")).listDocVersions
80
+ );
81
+ var mergeDocs = lazyOperation(
82
+ async () => (await import("@cleocode/core/docs/docs-ops")).mergeDocs
83
+ );
84
+ var publishDocs = lazyOperation(
85
+ async () => (await import("@cleocode/core/docs/docs-ops")).publishDocs
86
+ );
87
+ var publishDocsAsPr = lazyOperation(
88
+ async () => (await import("@cleocode/core/docs/publish-pr")).publishDocsAsPr
89
+ );
90
+ var rankDocs = lazyOperation(async () => (await import("@cleocode/core/docs/docs-ops")).rankDocs);
91
+ var recordPublication = lazyOperation(
92
+ async () => (await import("@cleocode/core/docs/docs-ops")).recordPublication
93
+ );
94
+ var reserveSlugForDispatch = lazyOperation(
95
+ async () => (await import("@cleocode/core/docs/slug-allocator")).reserveSlugForDispatch
96
+ );
97
+ var resolveAttachmentBackend = lazyOperation(
98
+ async () => (await import("@cleocode/core/store/attachment-store")).resolveAttachmentBackend
99
+ );
100
+ var runDocsImport = lazyOperation(
101
+ async () => (await import("@cleocode/core/docs/import/import-orchestrator")).runDocsImport
102
+ );
103
+ var searchAllProjectDocs = lazyOperation(
104
+ async () => (await import("@cleocode/core/docs/docs-ops")).searchAllProjectDocs
105
+ );
106
+ var searchDocs = lazyOperation(
107
+ async () => (await import("@cleocode/core/docs/docs-ops")).searchDocs
108
+ );
109
+ var supersedeDoc = lazyOperation(
110
+ async () => (await import("@cleocode/core/docs/supersede")).supersedeDoc
111
+ );
112
+ var syncFromGit = lazyOperation(
113
+ async () => (await import("@cleocode/core/docs/docs-ops")).syncFromGit
114
+ );
115
+ var updateDocBySlug = lazyOperation(
116
+ async () => (await import("@cleocode/core/docs/docs-update")).updateDocBySlug
117
+ );
118
+ var writeChangesetEntry = lazyOperation(
119
+ async () => (await import("@cleocode/core/changesets/writer")).writeChangesetEntry
120
+ );
121
+ var DOCS_LIST_DEFAULT_LIMIT = 50;
122
+ var SLUG_COLLISION_GUIDANCE = `slug '{slug}' is already reserved in this project. Three ways to proceed:
123
+
124
+ 1. Update the existing document: cleo docs update {slug} [--file <path> | --content <text>]
125
+ 2. Use a different slug: cleo docs add <owner> <file> --slug <alternative>
126
+ 3. Supersede with a new slug: cleo docs supersede {slug} <new-slug>
127
+
128
+ Recovery command: cleo docs update {slug} --file <your-file>`;
129
+ var _registryCache = /* @__PURE__ */ new Map();
130
+ function getDocKindRegistry() {
131
+ const root = getProjectRoot();
132
+ const cached = _registryCache.get(root);
133
+ if (cached) return cached;
134
+ try {
135
+ const registry = DocKindRegistry.load(root);
136
+ _registryCache.set(root, registry);
137
+ return registry;
138
+ } catch {
139
+ const fallback = DocKindRegistry.builtinOnly();
140
+ _registryCache.set(root, fallback);
141
+ return fallback;
142
+ }
143
+ }
144
+ function registeredKindValues() {
145
+ return getDocKindRegistry().list().map((d) => d.kind);
146
+ }
147
+ async function currentAttachmentBackend() {
148
+ return resolveAttachmentBackend();
149
+ }
150
+ function exportTaskDocument(options) {
151
+ return exportDocument(options);
152
+ }
153
+ function inferOwnerType(ownerId) {
154
+ if (/^T\d+$/i.test(ownerId)) return "task";
155
+ if (ownerId.startsWith("ses_")) return "session";
156
+ if (ownerId.startsWith("O-")) return "observation";
157
+ if (ownerId.startsWith("D-") || ownerId.startsWith("dec_")) return "decision";
158
+ if (ownerId.startsWith("L-") || ownerId.startsWith("lrn_")) return "learning";
159
+ if (ownerId.startsWith("P-") || ownerId.startsWith("pat_")) return "pattern";
160
+ return "task";
161
+ }
162
+ function parseLabels(raw) {
163
+ if (typeof raw !== "string" || !raw.trim()) return void 0;
164
+ return raw.split(",").map((l) => l.trim()).filter(Boolean);
165
+ }
166
+ function mimeFromPath(filePath) {
167
+ const lower = filePath.toLowerCase();
168
+ if (lower.endsWith(".md") || lower.endsWith(".markdown")) return "text/markdown";
169
+ if (lower.endsWith(".txt")) return "text/plain";
170
+ if (lower.endsWith(".html") || lower.endsWith(".htm")) return "text/html";
171
+ if (lower.endsWith(".json")) return "application/json";
172
+ if (lower.endsWith(".pdf")) return "application/pdf";
173
+ if (lower.endsWith(".zip")) return "application/zip";
174
+ if (lower.endsWith(".png")) return "image/png";
175
+ if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
176
+ if (lower.endsWith(".gif")) return "image/gif";
177
+ if (lower.endsWith(".svg")) return "image/svg+xml";
178
+ if (lower.endsWith(".ts") || lower.endsWith(".tsx")) return "text/plain";
179
+ if (lower.endsWith(".js")) return "text/javascript";
180
+ if (lower.endsWith(".css")) return "text/css";
181
+ return "application/octet-stream";
182
+ }
183
+ var SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
184
+ var SLUG_MAX_LEN = 80;
185
+ function validateSlug(raw) {
186
+ if (typeof raw !== "string" || raw.length === 0) {
187
+ return { valid: false, reason: "slug must be a non-empty string" };
188
+ }
189
+ if (raw.length > SLUG_MAX_LEN) {
190
+ return { valid: false, reason: `slug exceeds ${SLUG_MAX_LEN} characters` };
191
+ }
192
+ if (!SLUG_PATTERN.test(raw)) {
193
+ return {
194
+ valid: false,
195
+ reason: "slug must be lowercase kebab-case (matches /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/) \u2014 got '" + raw + "'"
196
+ };
197
+ }
198
+ return { valid: true };
199
+ }
200
+ function validateDocsType(raw) {
201
+ if (typeof raw !== "string") return false;
202
+ return getDocKindRegistry().has(raw);
203
+ }
204
+ function registeredKindList() {
205
+ return registeredKindValues().join("|");
206
+ }
207
+ function normaliseOrderBy(raw) {
208
+ if (raw === "sha" || raw === "slug" || raw === "newest") return raw;
209
+ return "newest";
210
+ }
211
+ function resolveListLimit(raw) {
212
+ if (typeof raw === "number" && Number.isFinite(raw)) {
213
+ if (raw <= 0) return Number.POSITIVE_INFINITY;
214
+ return Math.floor(raw);
215
+ }
216
+ return DOCS_LIST_DEFAULT_LIMIT;
217
+ }
218
+ function compareByOrderBy(orderBy) {
219
+ if (orderBy === "sha") return (a, b) => a.sha256.localeCompare(b.sha256);
220
+ if (orderBy === "slug") {
221
+ return (a, b) => {
222
+ const left = a.slug ?? "";
223
+ const right = b.slug ?? "";
224
+ if (!left && right) return 1;
225
+ if (left && !right) return -1;
226
+ return left.localeCompare(right);
227
+ };
228
+ }
229
+ return (a, b) => b.createdAt.localeCompare(a.createdAt);
230
+ }
231
+ var _docsTypedHandler = defineTypedHandler("docs", {
232
+ // ── docs.list ──────────────────────────────────────────────────────────────
233
+ list: async (params) => {
234
+ const ownerId = params.task ?? params.session ?? params.observation;
235
+ const explicitProject = params.project === true;
236
+ const isProjectScope = explicitProject || !ownerId;
237
+ let typeFilter;
238
+ if (params.type !== void 0) {
239
+ if (!validateDocsType(params.type)) {
240
+ return lafsError(
241
+ "E_INVALID_TYPE",
242
+ `type must be one of: ${registeredKindList()} \u2014 got '${String(params.type)}'`,
243
+ "list"
244
+ );
245
+ }
246
+ typeFilter = params.type;
247
+ }
248
+ const effectiveLimit = resolveListLimit(params.limit);
249
+ const orderBy = normaliseOrderBy(params.orderBy);
250
+ const comparator = compareByOrderBy(orderBy);
251
+ const autoPromoted = isProjectScope && !explicitProject;
252
+ const hintParts = [];
253
+ if (autoPromoted) {
254
+ hintParts.push(
255
+ "no scope set \u2014 defaulted to --project. Pass --task <id>, --session <id>, or --observation <id> for a narrower listing."
256
+ );
257
+ }
258
+ const model = createDocsReadModel();
259
+ const backend = await currentAttachmentBackend();
260
+ if (isProjectScope) {
261
+ const docs = await model.listProjectDocs({
262
+ kind: typeFilter,
263
+ limit: Number.isFinite(effectiveLimit) ? effectiveLimit : void 0
264
+ });
265
+ const totalCount = docs.length;
266
+ const projected = docs.map((doc) => ({
267
+ id: doc.id,
268
+ // Full content hash — a SHA-256 field in a machine envelope must be the
269
+ // real digest, never a display-truncated form (T11294: the per-doc
270
+ // `docs fetch` the Manual-Write-Sweep had to spawn existed solely to
271
+ // recover the full hash the list previously hid). Human/table rendering
272
+ // abbreviates for display, not the data layer.
273
+ sha256: doc.sha256,
274
+ kind: "blob",
275
+ mime: doc.mimeType ?? "\u2014",
276
+ size: doc.sizeBytes,
277
+ description: void 0,
278
+ labels: void 0,
279
+ createdAt: doc.createdAt,
280
+ // Surface the real attachment ref_count (T11572) so `docs list` agrees
281
+ // with the `docs add` response — both now read the same source of truth.
282
+ refCount: doc.refCount,
283
+ ...doc.slug ? { slug: doc.slug } : {},
284
+ ...doc.kind ? { type: doc.kind } : {},
285
+ ...doc.displayNumber !== null ? { displayNumber: doc.displayNumber } : {},
286
+ ownerId: doc.ownerId,
287
+ ownerType: doc.ownerType
288
+ }));
289
+ projected.sort(
290
+ (a, b) => comparator(
291
+ { sha256: a.sha256, slug: a.slug, createdAt: a.createdAt },
292
+ { sha256: b.sha256, slug: b.slug, createdAt: b.createdAt }
293
+ )
294
+ );
295
+ const truncated = totalCount > projected.length;
296
+ if (truncated) {
297
+ hintParts.push(
298
+ `showing ${projected.length} of ${totalCount} \u2014 pass --limit <N> to widen or page further.`
299
+ );
300
+ }
301
+ return lafsSuccess(
302
+ {
303
+ ownerId: "",
304
+ ownerType: "task",
305
+ project: true,
306
+ ...typeFilter !== void 0 ? { type: typeFilter } : {},
307
+ count: projected.length,
308
+ ...truncated ? { totalCount } : {},
309
+ limit: Number.isFinite(effectiveLimit) ? effectiveLimit : 0,
310
+ orderBy,
311
+ ...hintParts.length > 0 ? { hint: hintParts.join(" ") } : {},
312
+ attachments: projected,
313
+ attachmentBackend: backend
314
+ },
315
+ "list"
316
+ );
317
+ }
318
+ const scopedOwner = ownerId;
319
+ const ownerType = inferOwnerType(scopedOwner);
320
+ const ownerDocs = await model.resolveByOwner(scopedOwner, { ownerType, kind: typeFilter });
321
+ const projectedOwner = ownerDocs.map((doc) => ({
322
+ id: doc.id,
323
+ // Full content hash (see project-scope note above; T11294).
324
+ sha256: doc.sha256,
325
+ kind: "blob",
326
+ mime: doc.mimeType ?? "\u2014",
327
+ size: doc.sizeBytes,
328
+ description: void 0,
329
+ labels: void 0,
330
+ createdAt: doc.createdAt,
331
+ // Surface the real attachment ref_count (T11572) — see project-scope note.
332
+ refCount: doc.refCount,
333
+ ...doc.slug ? { slug: doc.slug } : {},
334
+ ...doc.kind ? { type: doc.kind } : {},
335
+ ...doc.displayNumber !== null ? { displayNumber: doc.displayNumber } : {}
336
+ }));
337
+ projectedOwner.sort(
338
+ (a, b) => comparator(
339
+ { sha256: a.sha256, slug: a.slug, createdAt: a.createdAt },
340
+ { sha256: b.sha256, slug: b.slug, createdAt: b.createdAt }
341
+ )
342
+ );
343
+ const totalCountOwner = projectedOwner.length;
344
+ const slicedOwner = Number.isFinite(effectiveLimit) ? projectedOwner.slice(0, effectiveLimit) : projectedOwner;
345
+ const truncatedOwner = totalCountOwner > slicedOwner.length;
346
+ if (truncatedOwner) {
347
+ hintParts.push(
348
+ `showing ${slicedOwner.length} of ${totalCountOwner} \u2014 pass --limit <N> to widen or page further.`
349
+ );
350
+ }
351
+ return lafsSuccess(
352
+ {
353
+ ownerId: scopedOwner,
354
+ ownerType,
355
+ ...typeFilter !== void 0 ? { type: typeFilter } : {},
356
+ count: slicedOwner.length,
357
+ ...truncatedOwner ? { totalCount: totalCountOwner } : {},
358
+ limit: Number.isFinite(effectiveLimit) ? effectiveLimit : 0,
359
+ orderBy,
360
+ ...hintParts.length > 0 ? { hint: hintParts.join(" ") } : {},
361
+ attachments: slicedOwner,
362
+ attachmentBackend: backend
363
+ },
364
+ "list"
365
+ );
366
+ },
367
+ // ── docs.generate ──────────────────────────────────────────────────────────
368
+ generate: async (params) => {
369
+ const forId = params.for;
370
+ if (!forId) {
371
+ return lafsError("E_INVALID_INPUT", "--for <taskId|epicId> is required", "generate");
372
+ }
373
+ const cwd = getProjectRoot();
374
+ const result = await generateDocsLlmsTxt({ ownerId: forId, cwd });
375
+ let attachmentId;
376
+ let attachmentSha256;
377
+ if (params.attach) {
378
+ const store = createAttachmentStore();
379
+ const ownerType = inferOwnerType(forId);
380
+ const contentBytes = Buffer.from(result.content, "utf-8");
381
+ const llmsTxtDescriptor = {
382
+ kind: "llms-txt",
383
+ source: "generated",
384
+ content: result.content,
385
+ description: `llms.txt for ${forId} (${result.attachmentCount} docs)`,
386
+ labels: ["llms-txt", "generated"]
387
+ };
388
+ const meta = await store.put(
389
+ contentBytes,
390
+ llmsTxtDescriptor,
391
+ ownerType,
392
+ forId,
393
+ "cleo-docs-generate",
394
+ cwd
395
+ );
396
+ attachmentId = meta.id;
397
+ attachmentSha256 = meta.sha256;
398
+ }
399
+ return lafsSuccess(
400
+ {
401
+ forId,
402
+ content: result.content,
403
+ attachmentCount: result.attachmentCount,
404
+ usedLlmtxtPackage: result.usedLlmtxtPackage,
405
+ ...attachmentId !== void 0 ? {
406
+ attached: true,
407
+ attachmentId,
408
+ attachmentSha256
409
+ } : { attached: false }
410
+ },
411
+ "generate"
412
+ );
413
+ },
414
+ // ── docs.llm-output (T11137) ──────────────────────────────────────────────
415
+ "llm-output": async (params) => {
416
+ const forId = params.for;
417
+ if (!forId) {
418
+ return lafsError("E_INVALID_INPUT", "--for <entityId> is required", "llm-output");
419
+ }
420
+ let mode;
421
+ if (params.mode !== void 0) {
422
+ const raw = String(params.mode);
423
+ if (!LLM_OUTPUT_MODES.includes(raw)) {
424
+ return lafsError(
425
+ "E_INVALID_INPUT",
426
+ `--mode must be one of: ${LLM_OUTPUT_MODES.join("|")}`,
427
+ "llm-output"
428
+ );
429
+ }
430
+ mode = raw;
431
+ } else {
432
+ mode = /^T\d+$/i.test(forId) ? "task-export" : "attachment-bundle";
433
+ }
434
+ const cwd = getProjectRoot();
435
+ if (mode === "task-export") {
436
+ const result2 = await exportTaskDocument({
437
+ taskId: forId,
438
+ includeAttachments: params.includeAttachments !== false,
439
+ includeMemoryRefs: params.includeMemoryRefs === true,
440
+ projectRoot: cwd
441
+ });
442
+ return lafsSuccess(
443
+ {
444
+ forId,
445
+ mode: "task-export",
446
+ content: result2.markdown,
447
+ sectionCount: result2.pages,
448
+ usedLlmtxtPackage: true
449
+ },
450
+ "llm-output"
451
+ );
452
+ }
453
+ const result = await generateDocsLlmsTxt({ ownerId: forId, cwd });
454
+ let aid, asha;
455
+ if (params.attach) {
456
+ const store = createAttachmentStore();
457
+ const desc = {
458
+ kind: "llms-txt",
459
+ source: "generated",
460
+ content: result.content,
461
+ description: `llms.txt for ${forId}`,
462
+ labels: ["llms-txt", "generated"]
463
+ };
464
+ const meta = await store.put(
465
+ Buffer.from(result.content, "utf-8"),
466
+ desc,
467
+ inferOwnerType(forId),
468
+ forId,
469
+ "cleo-docs-llm-output",
470
+ cwd
471
+ );
472
+ aid = meta.id;
473
+ asha = meta.sha256;
474
+ }
475
+ return lafsSuccess(
476
+ {
477
+ forId,
478
+ mode: "attachment-bundle",
479
+ content: result.content,
480
+ sectionCount: result.attachmentCount,
481
+ usedLlmtxtPackage: result.usedLlmtxtPackage,
482
+ ...aid ? { attached: true, attachmentId: aid, attachmentSha256: asha } : { attached: false }
483
+ },
484
+ "llm-output"
485
+ );
486
+ },
487
+ // ── docs.fetch ─────────────────────────────────────────────────────────────
488
+ fetch: async (params) => {
489
+ const ref = params.attachmentRef;
490
+ if (!ref) {
491
+ return lafsError(
492
+ "E_INVALID_INPUT",
493
+ "attachmentRef is required (attachment ID or SHA-256 hex)",
494
+ "fetch"
495
+ );
496
+ }
497
+ const model = createDocsReadModel();
498
+ const doc = await model.resolveLatest(ref) ?? await model.resolveByAttachmentId(ref);
499
+ if (!doc) {
500
+ return lafsError("E_NOT_FOUND", `Attachment not found: ${ref}`, "fetch");
501
+ }
502
+ const content = await model.fetchContent(doc);
503
+ if (content === null) {
504
+ return lafsError("E_NOT_FOUND", `Content not retrievable: ${ref}`, "fetch");
505
+ }
506
+ const cwd = getProjectRoot();
507
+ const cleoDir = resolveCleoDir(cwd);
508
+ let storagePath;
509
+ if (doc.sha256) {
510
+ const prefix = doc.sha256.slice(0, 2);
511
+ const rest = doc.sha256.slice(2);
512
+ const extMap = {
513
+ "text/markdown": ".md",
514
+ "text/plain": ".txt",
515
+ "application/json": ".json",
516
+ "application/pdf": ".pdf"
517
+ };
518
+ const ext = extMap[doc.mimeType ?? ""] ?? ".bin";
519
+ storagePath = resolve(cleoDir, "attachments", "sha256", prefix, `${rest}${ext}`);
520
+ }
521
+ const MAX_INLINE = 1024 * 1024;
522
+ const contentBytes = Buffer.from(content, "utf-8");
523
+ const bytesBase64 = contentBytes.length <= MAX_INLINE ? contentBytes.toString("base64") : void 0;
524
+ const backend = await currentAttachmentBackend();
525
+ return lafsSuccess(
526
+ {
527
+ metadata: {
528
+ id: doc.id,
529
+ sha256: doc.sha256,
530
+ kind: "blob",
531
+ mime: doc.mimeType ?? "text/plain",
532
+ size: doc.sizeBytes,
533
+ description: doc.summary ?? void 0,
534
+ labels: void 0,
535
+ createdAt: doc.createdAt,
536
+ refCount: 0,
537
+ ...doc.slug ? { slug: doc.slug } : {},
538
+ ...doc.kind ? { type: doc.kind } : {},
539
+ ...doc.displayNumber !== null ? { displayNumber: doc.displayNumber } : {}
540
+ },
541
+ path: storagePath,
542
+ sizeBytes: contentBytes.length,
543
+ ...bytesBase64 !== void 0 ? { bytesBase64 } : {},
544
+ inlined: bytesBase64 !== void 0,
545
+ attachmentBackend: backend
546
+ },
547
+ "fetch"
548
+ );
549
+ },
550
+ // ── docs.add ───────────────────────────────────────────────────────────────
551
+ add: async (params) => {
552
+ const {
553
+ ownerId,
554
+ file: filePath,
555
+ url,
556
+ content: inlineContent,
557
+ desc: description,
558
+ labels: rawLabels,
559
+ attachedBy: rawAttachedBy,
560
+ slug: rawSlug,
561
+ title: rawTitle,
562
+ type: rawType,
563
+ strict: strictMode
564
+ } = params;
565
+ if (!ownerId) {
566
+ return lafsError("E_INVALID_INPUT", "ownerId is required", "add");
567
+ }
568
+ const hasContent = typeof inlineContent === "string";
569
+ const sourceCount = (filePath ? 1 : 0) + (url ? 1 : 0) + (hasContent ? 1 : 0);
570
+ if (sourceCount === 0) {
571
+ return lafsError(
572
+ "E_INVALID_INPUT",
573
+ "Provide a file path (positional or --file), --url, or --content <text>",
574
+ "add"
575
+ );
576
+ }
577
+ if (sourceCount > 1) {
578
+ return lafsError(
579
+ "E_INVALID_INPUT",
580
+ "--file, --url, and --content are mutually exclusive \u2014 provide exactly one source",
581
+ "add",
582
+ 'Use `cleo docs add <owner> ./file.md` OR `--url <url>` OR `--content "<text>"` (not more than one).'
583
+ );
584
+ }
585
+ const projectRoot = getProjectRoot();
586
+ return worktreeScope.run(
587
+ {
588
+ ...worktreeScope.getStore(),
589
+ worktreeRoot: projectRoot,
590
+ projectHash: generateProjectHash(projectRoot)
591
+ },
592
+ async () => {
593
+ const projectionCapture = await captureDocumentProjection(
594
+ projectRoot,
595
+ rawAttachedBy ?? "cleo-docs-add",
596
+ randomUUID()
597
+ );
598
+ try {
599
+ let slug;
600
+ if (rawSlug !== void 0) {
601
+ let candidate = rawSlug;
602
+ if (typeof candidate === "string" && candidate.includes(AUTO_TOKEN)) {
603
+ const allocated = await allocateAutoSlugForDispatch(projectRoot, {
604
+ kind: typeof rawType === "string" ? rawType : "",
605
+ rawSlug: candidate
606
+ });
607
+ candidate = allocated.resolvedSlug;
608
+ }
609
+ const check = validateSlug(candidate);
610
+ if (!check.valid) {
611
+ return lafsError("E_INVALID_SLUG", check.reason, "add");
612
+ }
613
+ slug = candidate;
614
+ }
615
+ let type;
616
+ if (rawType !== void 0) {
617
+ if (!validateDocsType(rawType)) {
618
+ return lafsError(
619
+ "E_INVALID_TYPE",
620
+ `type must be one of: ${registeredKindList()} \u2014 got '${String(rawType)}'`,
621
+ "add"
622
+ );
623
+ }
624
+ type = rawType;
625
+ }
626
+ if (type === "changeset") {
627
+ if (!filePath) {
628
+ return lafsError(
629
+ "E_INVALID_INPUT",
630
+ "changeset writes require a --file path (URL attachments are not supported for changesets)",
631
+ "add"
632
+ );
633
+ }
634
+ const absPath = resolve(filePath);
635
+ let bytes;
636
+ try {
637
+ bytes = await readFile(absPath);
638
+ } catch {
639
+ return lafsError("E_FILE_ERROR", `Cannot read file: ${absPath}`, "add");
640
+ }
641
+ const parsed = parseChangesetFrontmatter(bytes.toString("utf-8"));
642
+ if (!parsed.ok) {
643
+ let message;
644
+ if (parsed.error === "missing-frontmatter") {
645
+ message = "changeset file is missing the `---`-fenced YAML frontmatter. Required fields: id, tasks, kind, summary.";
646
+ } else if (parsed.error === "missing-required") {
647
+ message = `changeset frontmatter is missing required fields: ${parsed.missing.join(", ")}.`;
648
+ } else if (parsed.error === "yaml-invalid") {
649
+ const lineHint = parsed.line !== void 0 ? ` (line ${parsed.line})` : "";
650
+ message = `changeset frontmatter YAML is invalid${lineHint}: ${parsed.parserMessage}`;
651
+ } else {
652
+ message = `changeset frontmatter failed schema validation: ${parsed.issues.join("; ")}`;
653
+ }
654
+ return {
655
+ success: false,
656
+ error: {
657
+ code: "E_REQUIRES_CHANGESET_VERB",
658
+ message,
659
+ details: {
660
+ fix: "Use `cleo changeset add --slug <id> --tasks <T####> --kind <kind> --summary <text>` for guided authoring.",
661
+ parserError: parsed.error,
662
+ ...parsed.error === "missing-required" ? { missing: parsed.missing } : {},
663
+ ...parsed.error === "schema-invalid" ? { issues: parsed.issues } : {}
664
+ }
665
+ }
666
+ };
667
+ }
668
+ if (slug !== void 0 && slug !== parsed.entry.id) {
669
+ return {
670
+ success: false,
671
+ error: {
672
+ code: "E_SLUG_MISMATCH",
673
+ message: `--slug '${slug}' does not match changeset frontmatter id '${parsed.entry.id}'. The frontmatter is canonical \u2014 drop --slug or align it.`
674
+ }
675
+ };
676
+ }
677
+ const outcome = await writeChangesetEntry(parsed.entry, {
678
+ projectRoot,
679
+ attachedBy: typeof rawAttachedBy === "string" && rawAttachedBy.length > 0 ? rawAttachedBy : "cleo-docs-add"
680
+ });
681
+ if (!outcome.ok) {
682
+ const err = outcome.error;
683
+ if (err.code === "E_SLUG_PATTERN_MISMATCH") {
684
+ const hint = err.example ? ` (example: ${err.example})` : "";
685
+ return lafsError("E_SLUG_PATTERN_MISMATCH", `${err.message}${hint}`, "add");
686
+ }
687
+ if (err.code === "E_INVALID_ENTRY") {
688
+ return lafsError("E_INVALID_INPUT", err.message, "add");
689
+ }
690
+ if (err.code === "E_FILE_WRITE_FAILED") {
691
+ return lafsError("E_FILE_ERROR", err.message, "add");
692
+ }
693
+ if (err.code === "E_SLUG_RESERVED") {
694
+ return {
695
+ success: false,
696
+ error: {
697
+ code: "E_SLUG_RESERVED",
698
+ message: err.message,
699
+ details: {
700
+ suggestions: err.suggestions,
701
+ aliases: err.aliases
702
+ }
703
+ }
704
+ };
705
+ }
706
+ return lafsError("E_SSOT_WRITE_FAILED", err.message, "add");
707
+ }
708
+ const projection = projectionCapture.status === "ready" ? await projectDocumentAttachment(projectionCapture.context, {
709
+ attachmentId: outcome.result.attachmentId,
710
+ sha256: outcome.result.sha256,
711
+ ownerId: outcome.result.ownerId,
712
+ ownerType: "task",
713
+ label: outcome.result.slug
714
+ }) : projectionCapture.outcome;
715
+ try {
716
+ writeAuditEntry(projectRoot, {
717
+ op: "docs.add",
718
+ slug: outcome.result.slug,
719
+ type: "changeset",
720
+ attachmentId: outcome.result.attachmentId,
721
+ sha256: outcome.result.sha256,
722
+ summary: `Added changeset '${outcome.result.slug}'`
723
+ });
724
+ } catch {
725
+ }
726
+ return lafsSuccess(
727
+ {
728
+ projection,
729
+ attachmentId: outcome.result.attachmentId,
730
+ sha256: outcome.result.sha256,
731
+ // writeChangesetEntry returns a freshly-minted ref so refCount is 1
732
+ // (or more if the same content was already addressed by another
733
+ // owner). The store sets the canonical value; mirroring it here
734
+ // keeps the envelope shape identical to the file/url branches.
735
+ refCount: 1,
736
+ kind: "blob",
737
+ ownerId: outcome.result.ownerId,
738
+ ownerType: "task",
739
+ // Cast: core returns 'llmtxt' (Wave C — legacy backend retired for mirror store).
740
+ attachmentBackend: await currentAttachmentBackend(),
741
+ slug: outcome.result.slug,
742
+ type: "changeset"
743
+ },
744
+ "add"
745
+ );
746
+ }
747
+ let adrNumber;
748
+ if (type === "adr" && slug === void 0) {
749
+ if (typeof rawTitle !== "string" || rawTitle.trim().length === 0) {
750
+ return lafsError(
751
+ "E_VALIDATION",
752
+ "title is required when type=adr and slug is omitted \u2014 the allocator needs a title to assemble adr-NNN-<kebab-title>",
753
+ "add"
754
+ );
755
+ }
756
+ const allocation = await allocateAdrSlug(projectRoot, { title: rawTitle });
757
+ if (!allocation.ok) {
758
+ return lafsError(allocation.code, allocation.message, "add");
759
+ }
760
+ slug = allocation.slug;
761
+ adrNumber = allocation.number;
762
+ }
763
+ if (type !== void 0 && slug !== void 0) {
764
+ const patternCheck = getDocKindRegistry().validateSlug(type, slug);
765
+ if (!patternCheck.ok) {
766
+ if (adrNumber !== void 0) releaseReservedSlug(slug);
767
+ const exampleHint = patternCheck.example ? ` (example: ${patternCheck.example})` : "";
768
+ return lafsError(
769
+ "E_SLUG_PATTERN_MISMATCH",
770
+ `${patternCheck.error}${exampleHint}`,
771
+ "add"
772
+ );
773
+ }
774
+ }
775
+ if (slug !== void 0 && adrNumber === void 0) {
776
+ const reservation = await reserveSlugForDispatch(projectRoot, {
777
+ kind: type ?? "",
778
+ slug
779
+ });
780
+ if (!reservation.ok) {
781
+ return {
782
+ success: false,
783
+ error: {
784
+ code: "E_SLUG_RESERVED",
785
+ message: SLUG_COLLISION_GUIDANCE.replaceAll("{slug}", slug ?? ""),
786
+ fix: `cleo docs update ${slug ?? "<slug>"} --file <your-file>`,
787
+ details: {
788
+ suggestions: reservation.suggestions,
789
+ aliases: ["E_SLUG_TAKEN"]
790
+ }
791
+ }
792
+ };
793
+ }
794
+ }
795
+ const extras = {};
796
+ if (slug !== void 0) extras.slug = slug;
797
+ if (type !== void 0) extras.type = type;
798
+ const labels = parseLabels(rawLabels);
799
+ const attachedBy = rawAttachedBy ?? "human";
800
+ const ownerType = inferOwnerType(ownerId);
801
+ const store = createAttachmentStore();
802
+ if (filePath) {
803
+ const absPath = resolve(filePath);
804
+ let bytes;
805
+ try {
806
+ bytes = await readFile(absPath);
807
+ } catch {
808
+ return lafsError("E_FILE_ERROR", `Cannot read file: ${absPath}`, "add");
809
+ }
810
+ if (type !== void 0) {
811
+ const bodyText = bytes.toString("utf-8");
812
+ let registry;
813
+ try {
814
+ registry = DocKindRegistry.load(projectRoot);
815
+ } catch {
816
+ registry = void 0;
817
+ }
818
+ const check = validateDocBody(type, bodyText, registry);
819
+ if (!check.ok) {
820
+ const missingList = check.missing.join(", ");
821
+ if (strictMode === true) {
822
+ return lafsError(
823
+ "E_DOC_SCHEMA_MISMATCH",
824
+ `body for kind '${type}' is missing required section(s): ${missingList}`,
825
+ "add",
826
+ `Add the missing H2 section(s) \u2014 '## ${check.missing[0] ?? ""}' \u2014 then retry. Pass --strict=false (default) to surface as an advisory warning instead of an error.`,
827
+ {
828
+ kind: type,
829
+ missing: check.missing,
830
+ strict: true
831
+ }
832
+ );
833
+ }
834
+ pushWarning({
835
+ code: "W_DOC_SCHEMA_MISMATCH",
836
+ message: `body for kind '${type}' is missing required section(s): ${missingList}. Add '--strict' to fail on schema violations.`
837
+ });
838
+ }
839
+ }
840
+ const mime = mimeFromPath(absPath);
841
+ const attachment = {
842
+ kind: "local-file",
843
+ path: absPath,
844
+ mime,
845
+ size: bytes.length,
846
+ ...description ? { description } : {},
847
+ ...labels ? { labels } : {}
848
+ };
849
+ let meta;
850
+ try {
851
+ meta = await store.put(
852
+ bytes,
853
+ attachment,
854
+ ownerType,
855
+ ownerId,
856
+ attachedBy,
857
+ projectRoot,
858
+ extras
859
+ );
860
+ } catch (err) {
861
+ if (slug !== void 0) releaseReservedSlug(slug);
862
+ if (err instanceof SlugCollisionError) {
863
+ return {
864
+ success: false,
865
+ error: {
866
+ code: "E_SLUG_RESERVED",
867
+ message: SLUG_COLLISION_GUIDANCE.replaceAll("{slug}", err.slug ?? ""),
868
+ fix: `cleo docs update ${err.slug ?? "<slug>"} --file <your-file>`,
869
+ details: {
870
+ suggestions: err.suggestions,
871
+ aliases: ["E_SLUG_TAKEN"]
872
+ }
873
+ }
874
+ };
875
+ }
876
+ throw err;
877
+ }
878
+ if (adrNumber !== void 0 && slug !== void 0) consumeReservedSlug(slug);
879
+ let backend = "llmtxt";
880
+ try {
881
+ const blobMirror = createAttachmentBlobStore(projectRoot);
882
+ const mirrorResult = await blobMirror.put(ownerId, {
883
+ name: absPath.split(/[\\/]/).pop() ?? meta.sha256.slice(0, 12),
884
+ data: new Uint8Array(bytes),
885
+ contentType: mime
886
+ });
887
+ backend = mirrorResult.backend;
888
+ } catch {
889
+ backend = await currentAttachmentBackend();
890
+ }
891
+ const projection = projectionCapture.status === "ready" ? await projectDocumentAttachment(projectionCapture.context, {
892
+ attachmentId: meta.id,
893
+ sha256: meta.sha256,
894
+ ownerId,
895
+ ownerType,
896
+ label: absPath.split(/[\\/]/).pop() ?? meta.sha256.slice(0, 12)
897
+ }) : projectionCapture.outcome;
898
+ try {
899
+ writeAuditEntry(projectRoot, {
900
+ op: "docs.add",
901
+ slug,
902
+ type,
903
+ attachmentId: meta.id,
904
+ sha256: meta.sha256,
905
+ ownerId,
906
+ summary: `Added doc '${slug ?? meta.sha256.slice(0, 12)}'${type ? ` of type '${type}'` : ""} for owner ${ownerId}`
907
+ });
908
+ } catch {
909
+ }
910
+ return lafsSuccess(
911
+ {
912
+ projection,
913
+ attachmentId: meta.id,
914
+ sha256: meta.sha256,
915
+ refCount: meta.refCount,
916
+ kind: "local-file",
917
+ ownerId,
918
+ ownerType,
919
+ // Cast: core returns 'llmtxt'|'legacy'; contracts uses 'legacy'|'llmstxt-v2' (T1529)
920
+ attachmentBackend: backend,
921
+ ...slug !== void 0 ? { slug } : {},
922
+ ...type !== void 0 ? { type } : {},
923
+ ...adrNumber !== void 0 ? { adrNumber } : {}
924
+ },
925
+ "add"
926
+ );
927
+ }
928
+ if (hasContent) {
929
+ const bytes = Buffer.from(inlineContent, "utf-8");
930
+ if (type !== void 0) {
931
+ let registry;
932
+ try {
933
+ registry = DocKindRegistry.load(projectRoot);
934
+ } catch {
935
+ registry = void 0;
936
+ }
937
+ const check = validateDocBody(type, inlineContent, registry);
938
+ if (!check.ok) {
939
+ const missingList = check.missing.join(", ");
940
+ if (strictMode === true) {
941
+ if (slug !== void 0) releaseReservedSlug(slug);
942
+ return lafsError(
943
+ "E_DOC_SCHEMA_MISMATCH",
944
+ `body for kind '${type}' is missing required section(s): ${missingList}`,
945
+ "add",
946
+ `Add the missing H2 section(s) \u2014 '## ${check.missing[0] ?? ""}' \u2014 then retry. Pass --strict=false (default) to surface as an advisory warning instead of an error.`,
947
+ { kind: type, missing: check.missing, strict: true }
948
+ );
949
+ }
950
+ pushWarning({
951
+ code: "W_DOC_SCHEMA_MISMATCH",
952
+ message: `body for kind '${type}' is missing required section(s): ${missingList}. Add '--strict' to fail on schema violations.`
953
+ });
954
+ }
955
+ }
956
+ const mime = "text/markdown";
957
+ const attachment = {
958
+ kind: "blob",
959
+ mime,
960
+ ...description ? { description } : {},
961
+ ...labels ? { labels } : {}
962
+ };
963
+ let meta;
964
+ try {
965
+ meta = await store.put(
966
+ bytes,
967
+ attachment,
968
+ ownerType,
969
+ ownerId,
970
+ attachedBy,
971
+ projectRoot,
972
+ extras
973
+ );
974
+ } catch (err) {
975
+ if (slug !== void 0) releaseReservedSlug(slug);
976
+ if (err instanceof SlugCollisionError) {
977
+ return {
978
+ success: false,
979
+ error: {
980
+ code: "E_SLUG_RESERVED",
981
+ message: SLUG_COLLISION_GUIDANCE.replaceAll("{slug}", err.slug ?? ""),
982
+ fix: `cleo docs update ${err.slug ?? "<slug>"} --content "..."`,
983
+ details: {
984
+ suggestions: err.suggestions,
985
+ aliases: ["E_SLUG_TAKEN"]
986
+ }
987
+ }
988
+ };
989
+ }
990
+ throw err;
991
+ }
992
+ if (adrNumber !== void 0 && slug !== void 0) consumeReservedSlug(slug);
993
+ const blobName = slug ?? meta.sha256.slice(0, 12);
994
+ let backend = "llmtxt";
995
+ try {
996
+ const blobMirror = createAttachmentBlobStore(projectRoot);
997
+ const mirrorResult = await blobMirror.put(ownerId, {
998
+ name: blobName,
999
+ data: new Uint8Array(bytes),
1000
+ contentType: mime
1001
+ });
1002
+ backend = mirrorResult.backend;
1003
+ } catch {
1004
+ backend = await currentAttachmentBackend();
1005
+ }
1006
+ const projection = projectionCapture.status === "ready" ? await projectDocumentAttachment(projectionCapture.context, {
1007
+ attachmentId: meta.id,
1008
+ sha256: meta.sha256,
1009
+ ownerId,
1010
+ ownerType,
1011
+ label: blobName
1012
+ }) : projectionCapture.outcome;
1013
+ try {
1014
+ writeAuditEntry(projectRoot, {
1015
+ op: "docs.add",
1016
+ slug,
1017
+ type,
1018
+ attachmentId: meta.id,
1019
+ sha256: meta.sha256,
1020
+ ownerId,
1021
+ summary: `Added inline doc '${slug ?? meta.sha256.slice(0, 12)}'${type ? ` of type '${type}'` : ""} for owner ${ownerId}`
1022
+ });
1023
+ } catch {
1024
+ }
1025
+ return lafsSuccess(
1026
+ {
1027
+ projection,
1028
+ attachmentId: meta.id,
1029
+ sha256: meta.sha256,
1030
+ refCount: meta.refCount,
1031
+ kind: "blob",
1032
+ ownerId,
1033
+ ownerType,
1034
+ // Cast: core returns 'llmtxt'|'legacy'; contracts uses 'legacy'|'llmstxt-v2' (T1529)
1035
+ attachmentBackend: backend,
1036
+ ...slug !== void 0 ? { slug } : {},
1037
+ ...type !== void 0 ? { type } : {},
1038
+ ...adrNumber !== void 0 ? { adrNumber } : {}
1039
+ },
1040
+ "add"
1041
+ );
1042
+ }
1043
+ if (url) {
1044
+ const attachment = {
1045
+ kind: "url",
1046
+ url,
1047
+ ...description ? { description } : {},
1048
+ ...labels ? { labels } : {}
1049
+ };
1050
+ const urlBytes = Buffer.from(url, "utf-8");
1051
+ let meta;
1052
+ try {
1053
+ meta = await store.put(
1054
+ urlBytes,
1055
+ attachment,
1056
+ ownerType,
1057
+ ownerId,
1058
+ attachedBy,
1059
+ projectRoot,
1060
+ extras
1061
+ );
1062
+ } catch (err) {
1063
+ if (slug !== void 0) releaseReservedSlug(slug);
1064
+ if (err instanceof SlugCollisionError) {
1065
+ return {
1066
+ success: false,
1067
+ error: {
1068
+ code: "E_SLUG_RESERVED",
1069
+ message: SLUG_COLLISION_GUIDANCE.replaceAll("{slug}", err.slug ?? ""),
1070
+ fix: `cleo docs update ${err.slug ?? "<slug>"} --file <your-file>`,
1071
+ details: {
1072
+ suggestions: err.suggestions,
1073
+ aliases: ["E_SLUG_TAKEN"]
1074
+ }
1075
+ }
1076
+ };
1077
+ }
1078
+ throw err;
1079
+ }
1080
+ if (adrNumber !== void 0 && slug !== void 0) consumeReservedSlug(slug);
1081
+ const backend = await currentAttachmentBackend();
1082
+ const projection = projectionCapture.status === "ready" ? await projectDocumentAttachment(projectionCapture.context, {
1083
+ attachmentId: meta.id,
1084
+ sha256: meta.sha256,
1085
+ ownerId,
1086
+ ownerType,
1087
+ label: url
1088
+ }) : projectionCapture.outcome;
1089
+ try {
1090
+ writeAuditEntry(projectRoot, {
1091
+ op: "docs.add",
1092
+ slug,
1093
+ type,
1094
+ attachmentId: meta.id,
1095
+ sha256: meta.sha256,
1096
+ ownerId,
1097
+ summary: `Added URL doc '${slug ?? url}'${type ? ` of type '${type}'` : ""} for owner ${ownerId}`
1098
+ });
1099
+ } catch {
1100
+ }
1101
+ return lafsSuccess(
1102
+ {
1103
+ projection,
1104
+ attachmentId: meta.id,
1105
+ sha256: meta.sha256,
1106
+ refCount: meta.refCount,
1107
+ kind: "url",
1108
+ url,
1109
+ ownerId,
1110
+ ownerType,
1111
+ // Cast: core returns 'llmtxt'|'legacy'; contracts uses 'legacy'|'llmstxt-v2' (T1529)
1112
+ attachmentBackend: backend,
1113
+ ...slug !== void 0 ? { slug } : {},
1114
+ ...type !== void 0 ? { type } : {},
1115
+ ...adrNumber !== void 0 ? { adrNumber } : {}
1116
+ },
1117
+ "add"
1118
+ );
1119
+ }
1120
+ return lafsError("E_INVALID_INPUT", "Unreachable: no file or url", "add");
1121
+ } finally {
1122
+ if (projectionCapture.status === "ready") projectionCapture.context.close();
1123
+ }
1124
+ }
1125
+ );
1126
+ },
1127
+ // ── docs.remove ────────────────────────────────────────────────────────────
1128
+ remove: async (params) => {
1129
+ const { attachmentRef: ref, from: fromOwner } = params;
1130
+ if (!ref) {
1131
+ return lafsError(
1132
+ "E_INVALID_INPUT",
1133
+ "attachmentRef is required (attachment ID or SHA-256 hex)",
1134
+ "remove"
1135
+ );
1136
+ }
1137
+ if (!fromOwner) {
1138
+ return lafsError("E_INVALID_INPUT", "--from <ownerId> is required", "remove");
1139
+ }
1140
+ const store = createAttachmentStore();
1141
+ const ownerType = inferOwnerType(fromOwner);
1142
+ let attachmentId = ref;
1143
+ if (/^[0-9a-f]{64}$/i.test(ref)) {
1144
+ const result = await store.get(ref);
1145
+ if (!result) {
1146
+ return lafsError("E_NOT_FOUND", `No attachment found with SHA-256: ${ref}`, "remove");
1147
+ }
1148
+ attachmentId = result.metadata.id;
1149
+ }
1150
+ const derefResult = await store.deref(attachmentId, ownerType, fromOwner);
1151
+ if (derefResult.status === "not-found") {
1152
+ return lafsError(
1153
+ "E_NOT_FOUND",
1154
+ `Attachment ref not found: ${attachmentId} on owner ${fromOwner}`,
1155
+ "remove"
1156
+ );
1157
+ }
1158
+ const blobPurged = derefResult.status === "removed";
1159
+ const refCountAfter = derefResult.status === "derefd" ? derefResult.refCountAfter : 0;
1160
+ try {
1161
+ const blobMirror = createAttachmentBlobStore(getProjectRoot());
1162
+ await blobMirror.remove(attachmentId, fromOwner);
1163
+ } catch {
1164
+ }
1165
+ const backend = await currentAttachmentBackend();
1166
+ try {
1167
+ writeAuditEntry(getProjectRoot(), {
1168
+ op: "docs.remove",
1169
+ attachmentId,
1170
+ ownerId: fromOwner,
1171
+ summary: `Removed attachment ${attachmentId} from owner ${fromOwner}${blobPurged ? " (blob purged)" : ""}`
1172
+ });
1173
+ } catch {
1174
+ }
1175
+ return lafsSuccess(
1176
+ {
1177
+ removed: blobPurged,
1178
+ attachmentId,
1179
+ from: fromOwner,
1180
+ refCountAfter,
1181
+ blobPurged,
1182
+ // Cast: core returns 'llmtxt'|'legacy'; contracts uses 'legacy'|'llmstxt-v2' (T1529)
1183
+ attachmentBackend: backend
1184
+ },
1185
+ "remove"
1186
+ );
1187
+ },
1188
+ // ── docs.update (T10161 — E12.C4 / Saga T9855) ─────────────────────────────
1189
+ update: async (params) => {
1190
+ const { slug: rawSlug, file: filePath, content: inlineContent, status: rawStatus } = params;
1191
+ if (typeof rawSlug !== "string" || rawSlug.length === 0) {
1192
+ return lafsError("E_INVALID_INPUT", "slug is required", "update");
1193
+ }
1194
+ const hasFile = typeof filePath === "string" && filePath.length > 0;
1195
+ const hasContent = typeof inlineContent === "string";
1196
+ const statusOnly = !hasFile && !hasContent;
1197
+ if (hasFile && hasContent) {
1198
+ return lafsError(
1199
+ "E_INVALID_INPUT",
1200
+ "--file and --content are mutually exclusive",
1201
+ "update",
1202
+ 'Use `cleo docs update <slug> --file ./new.md` OR `cleo docs update <slug> --content "..."`.'
1203
+ );
1204
+ }
1205
+ if (statusOnly && rawStatus === void 0) {
1206
+ return lafsError(
1207
+ "E_INVALID_INPUT",
1208
+ "Provide --file <path>, --content <text>, or --status <status> alone",
1209
+ "update",
1210
+ 'Use `--file ./new.md`, `--content "..."`, or `cleo docs update <slug> --status accepted` to change only the lifecycle status.'
1211
+ );
1212
+ }
1213
+ if (rawStatus !== void 0 && !isLifecycleStatus(rawStatus)) {
1214
+ return lafsError(
1215
+ "E_INVALID_INPUT",
1216
+ `status must be one of: ${DOCS_UPDATE_LIFECYCLE_STATUS_LIST} \u2014 got '${String(rawStatus)}'`,
1217
+ "update"
1218
+ );
1219
+ }
1220
+ const projectRoot = getProjectRoot();
1221
+ const resolvedParams = hasFile ? { ...params, file: resolve(filePath) } : params;
1222
+ const outcome = await updateDocBySlug(projectRoot, resolvedParams);
1223
+ if (!outcome.ok) {
1224
+ return lafsError(
1225
+ outcome.error.code,
1226
+ outcome.error.message,
1227
+ "update",
1228
+ void 0,
1229
+ "details" in outcome.error ? outcome.error.details : void 0
1230
+ );
1231
+ }
1232
+ let backend = "llmtxt";
1233
+ if (statusOnly) {
1234
+ backend = await currentAttachmentBackend();
1235
+ } else {
1236
+ try {
1237
+ const blobMirror = createAttachmentBlobStore(getProjectRoot());
1238
+ const updatedBytes = hasFile ? new Uint8Array(await readFile(resolve(filePath))) : new Uint8Array(Buffer.from(inlineContent, "utf-8"));
1239
+ const contentType = hasFile ? mimeFromPath(resolve(filePath)) : "text/plain";
1240
+ const store = createAttachmentStore();
1241
+ const rows = await store.listAllInProject(projectRoot);
1242
+ const ownerIds = Array.from(
1243
+ new Set(
1244
+ rows.filter((row) => row.metadata.id === outcome.result.attachmentId).map((row) => row.ownerId)
1245
+ )
1246
+ );
1247
+ const mirrorOwnerIds = ownerIds.length > 0 ? ownerIds : [`slug:${outcome.result.slug}`];
1248
+ for (const mirrorOwnerId of mirrorOwnerIds) {
1249
+ const mirrorResult = await blobMirror.put(mirrorOwnerId, {
1250
+ name: outcome.result.slug,
1251
+ data: updatedBytes,
1252
+ contentType
1253
+ });
1254
+ backend = mirrorResult.backend;
1255
+ }
1256
+ } catch {
1257
+ backend = await currentAttachmentBackend();
1258
+ }
1259
+ }
1260
+ try {
1261
+ writeAuditEntry(getProjectRoot(), {
1262
+ op: "docs.update",
1263
+ slug: outcome.result.slug,
1264
+ type: outcome.result.type ?? void 0,
1265
+ attachmentId: outcome.result.attachmentId,
1266
+ sha256: outcome.result.sha256,
1267
+ previousSha256: outcome.result.previousSha256 ?? void 0,
1268
+ summary: `Updated doc '${outcome.result.slug}'${outcome.result.lifecycleStatus ? ` (status: ${outcome.result.lifecycleStatus})` : ""}`
1269
+ });
1270
+ } catch {
1271
+ }
1272
+ return lafsSuccess(
1273
+ {
1274
+ slug: outcome.result.slug,
1275
+ ...outcome.result.type !== null ? { type: outcome.result.type } : {},
1276
+ attachmentId: outcome.result.attachmentId,
1277
+ previousAttachmentId: outcome.result.previousAttachmentId,
1278
+ sha256: outcome.result.sha256,
1279
+ previousSha256: outcome.result.previousSha256,
1280
+ changed: outcome.result.changed,
1281
+ lifecycleStatus: outcome.result.lifecycleStatus,
1282
+ updatedAt: outcome.result.updatedAt,
1283
+ version: outcome.result.version,
1284
+ /** Version SSoT (T11181) — canonical version identifiers. */
1285
+ ownerVersion: outcome.result.ownerVersion,
1286
+ /** Sequential doc version counter (T11181). */
1287
+ docVersion: outcome.result.docVersion,
1288
+ squashed: outcome.result.squashed,
1289
+ summary: outcome.result.summary,
1290
+ // T11053 — surface which backend stored the updated blob so
1291
+ // observability consumers can confirm the V2 mirror succeeded.
1292
+ attachmentBackend: backend,
1293
+ ...outcome.result.dryRun === true ? { dryRun: true } : {},
1294
+ ...outcome.result.wouldWrite !== void 0 ? { wouldWrite: outcome.result.wouldWrite } : {},
1295
+ ...outcome.result.wouldChange !== void 0 ? { wouldChange: outcome.result.wouldChange } : {}
1296
+ },
1297
+ "update"
1298
+ );
1299
+ },
1300
+ // ── docs.supersede ─────────────────────────────────────────────────────────
1301
+ supersede: async (params) => {
1302
+ const { oldSlug, newSlug, reason } = params;
1303
+ if (typeof oldSlug !== "string" || oldSlug.length === 0) {
1304
+ return lafsError("E_INVALID_INPUT", "<oldSlug> is required", "supersede");
1305
+ }
1306
+ if (typeof newSlug !== "string" || newSlug.length === 0) {
1307
+ return lafsError("E_INVALID_INPUT", "<newSlug> is required", "supersede");
1308
+ }
1309
+ try {
1310
+ const result = await supersedeDoc(getProjectRoot(), {
1311
+ oldSlug,
1312
+ newSlug,
1313
+ ...typeof reason === "string" && reason.length > 0 ? { reason } : {}
1314
+ });
1315
+ const payload = {
1316
+ oldSlug: result.oldSlug,
1317
+ newSlug: result.newSlug,
1318
+ oldAttachmentId: result.oldAttachmentId,
1319
+ newAttachmentId: result.newAttachmentId,
1320
+ supersededAt: result.supersededAt,
1321
+ edgeId: result.edgeId,
1322
+ ...result.reason !== void 0 ? { reason: result.reason } : {}
1323
+ };
1324
+ try {
1325
+ writeAuditEntry(getProjectRoot(), {
1326
+ op: "docs.supersede",
1327
+ slug: result.newSlug,
1328
+ attachmentId: result.newAttachmentId,
1329
+ summary: `Superseded '${result.oldSlug}' \u2192 '${result.newSlug}'${result.reason ? ` (reason: ${result.reason})` : ""}`
1330
+ });
1331
+ } catch {
1332
+ }
1333
+ return lafsSuccess(payload, "supersede");
1334
+ } catch (err) {
1335
+ const code = err && typeof err === "object" && "code" in err && typeof err.code === "number" ? (
1336
+ // Map ExitCode (number) → stable LAFS string code expected by callers.
1337
+ err.code === 4 ? SUPERSEDE_NOT_FOUND_CODE : err.code === 6 ? SUPERSEDE_SAME_SLUG_CODE : "E_INTERNAL"
1338
+ ) : "E_INTERNAL";
1339
+ const message = err instanceof Error ? err.message : "supersede failed";
1340
+ return lafsError(code, message, "supersede");
1341
+ }
1342
+ }
1343
+ });
1344
+ function docsEnvelopeToResponse(envelope, gateway, operation, startTime) {
1345
+ if (!envelope.success) {
1346
+ return {
1347
+ meta: dispatchMeta(gateway, "docs", operation, startTime),
1348
+ success: false,
1349
+ error: {
1350
+ code: String(envelope.error?.code ?? "E_INTERNAL"),
1351
+ message: envelope.error?.message ?? "Unknown error",
1352
+ ...envelope.error?.fix !== void 0 ? { fix: envelope.error.fix } : {},
1353
+ // T9636 — preserve structured details (e.g. slug suggestions) so the
1354
+ // CLI can render alternative slugs without a separate API call.
1355
+ ...envelope.error?.details !== void 0 ? { details: envelope.error.details } : {}
1356
+ }
1357
+ };
1358
+ }
1359
+ let attachmentBackend;
1360
+ let dryRun;
1361
+ let hint;
1362
+ let responseData = envelope.data;
1363
+ if (responseData !== null && responseData !== void 0 && typeof responseData === "object") {
1364
+ const dataObj = responseData;
1365
+ let cleanedData = dataObj;
1366
+ let cleaned = false;
1367
+ if ("attachmentBackend" in cleanedData && cleanedData["attachmentBackend"] !== void 0) {
1368
+ attachmentBackend = cleanedData["attachmentBackend"];
1369
+ const { attachmentBackend: _lifted, ...rest } = cleanedData;
1370
+ cleanedData = rest;
1371
+ cleaned = true;
1372
+ }
1373
+ if ("hint" in cleanedData && typeof cleanedData["hint"] === "string") {
1374
+ hint = cleanedData["hint"];
1375
+ }
1376
+ if (cleanedData["dryRun"] === true) {
1377
+ dryRun = true;
1378
+ }
1379
+ if (cleaned) {
1380
+ responseData = cleanedData;
1381
+ }
1382
+ }
1383
+ return {
1384
+ meta: {
1385
+ ...dispatchMeta(gateway, "docs", operation, startTime),
1386
+ ...attachmentBackend !== void 0 ? { attachmentBackend } : {},
1387
+ ...dryRun === true ? { dryRun: true } : {},
1388
+ ...hint !== void 0 ? { hint } : {}
1389
+ },
1390
+ success: true,
1391
+ data: responseData
1392
+ };
1393
+ }
1394
+ var QUERY_OPS = /* @__PURE__ */ new Set([
1395
+ "list",
1396
+ "fetch",
1397
+ "generate",
1398
+ "llm-output",
1399
+ "export",
1400
+ "search",
1401
+ "find",
1402
+ "merge",
1403
+ "rank",
1404
+ "versions",
1405
+ "status",
1406
+ "audit"
1407
+ ]);
1408
+ var MUTATE_OPS = /* @__PURE__ */ new Set([
1409
+ "add",
1410
+ "remove",
1411
+ "update",
1412
+ "supersede",
1413
+ "publish",
1414
+ "publish-pr",
1415
+ "sync",
1416
+ "import"
1417
+ ]);
1418
+ async function dispatchDocsLegacyQuery(operation, params) {
1419
+ const projectRoot = getProjectRoot();
1420
+ switch (operation) {
1421
+ case "export":
1422
+ return exportDocument({
1423
+ taskId: String(params["taskId"]),
1424
+ includeAttachments: params["includeAttachments"] !== false,
1425
+ includeMemoryRefs: params["includeMemoryRefs"] === true,
1426
+ projectRoot
1427
+ });
1428
+ case "search": {
1429
+ const limit = typeof params["limit"] === "number" ? params["limit"] : 10;
1430
+ if (typeof params["ownerId"] === "string" && params["ownerId"].length > 0) {
1431
+ return searchDocs(String(params["query"]), {
1432
+ ownerId: params["ownerId"],
1433
+ limit,
1434
+ projectRoot
1435
+ });
1436
+ }
1437
+ return searchAllProjectDocs(String(params["query"]), {
1438
+ limit,
1439
+ type: typeof params["type"] === "string" ? params["type"] : void 0,
1440
+ projectRoot
1441
+ });
1442
+ }
1443
+ case "find":
1444
+ return findSimilarDocs(String(params["similarSlug"]), {
1445
+ ...typeof params["limit"] === "number" ? { limit: params["limit"] } : {},
1446
+ ...typeof params["threshold"] === "number" ? { threshold: params["threshold"] } : {},
1447
+ allKinds: params["allKinds"] === true,
1448
+ projectRoot
1449
+ });
1450
+ case "merge":
1451
+ return mergeDocs(String(params["attA"]), String(params["attB"]), {
1452
+ strategy: params["strategy"] === "cherry-pick" || params["strategy"] === "multi-diff" ? params["strategy"] : "three-way",
1453
+ base: typeof params["base"] === "string" ? params["base"] : void 0
1454
+ });
1455
+ case "rank":
1456
+ return rankDocs({
1457
+ ownerId: String(params["ownerId"]),
1458
+ query: typeof params["query"] === "string" ? params["query"] : void 0,
1459
+ projectRoot
1460
+ });
1461
+ case "versions":
1462
+ return listDocVersions({
1463
+ ownerId: String(params["ownerId"]),
1464
+ name: typeof params["name"] === "string" ? params["name"] : void 0,
1465
+ projectRoot
1466
+ });
1467
+ case "audit":
1468
+ if (params["verify"] === true) return verifyAuditTrail(projectRoot);
1469
+ if (typeof params["slug"] !== "string" || !params["slug"]) {
1470
+ throw new Error("Document audit requires slug or verify");
1471
+ }
1472
+ return readAuditLog(projectRoot, params["slug"]);
1473
+ case "status": {
1474
+ const model = createDocsReadModel();
1475
+ return model.status(projectRoot);
1476
+ }
1477
+ default:
1478
+ throw new Error(`Unsupported docs query operation: ${operation}`);
1479
+ }
1480
+ }
1481
+ async function dispatchDocsLegacyMutate(operation, params) {
1482
+ const projectRoot = getProjectRoot();
1483
+ switch (operation) {
1484
+ case "publish": {
1485
+ if (params["target"] === "pr") return dispatchDocsLegacyMutate("publish-pr", params);
1486
+ if (params["target"] !== void 0 && params["target"] !== "file") {
1487
+ throw new Error("Publication target must be file or pr");
1488
+ }
1489
+ if (!params["ownerId"] || !params["toPath"]) {
1490
+ throw new Error("File publication requires ownerId and toPath");
1491
+ }
1492
+ const result = await publishDocs({
1493
+ ownerId: String(params["ownerId"]),
1494
+ toPath: String(params["toPath"]),
1495
+ attachmentId: typeof params["attachmentId"] === "string" ? params["attachmentId"] : void 0,
1496
+ projectRoot
1497
+ });
1498
+ try {
1499
+ await recordPublication({
1500
+ ownerId: result.ownerId,
1501
+ blobName: result.blobName,
1502
+ publishedPath: result.relativePath,
1503
+ lastBlobSha: result.blobSha256,
1504
+ projectRoot
1505
+ });
1506
+ } catch {
1507
+ }
1508
+ try {
1509
+ writeAuditEntry(projectRoot, {
1510
+ op: "docs.publish",
1511
+ slug: result.blobName,
1512
+ attachmentId: result.blobSha256,
1513
+ summary: `Published doc '${result.blobName}' to ${result.relativePath}`
1514
+ });
1515
+ } catch {
1516
+ }
1517
+ return result;
1518
+ }
1519
+ case "publish-pr": {
1520
+ if (!params["slugOrId"]) throw new Error("PR publication requires slugOrId");
1521
+ const prResult = await publishDocsAsPr({
1522
+ slugOrId: String(params["slugOrId"]),
1523
+ ...typeof params["slug"] === "string" ? { slug: params["slug"] } : {},
1524
+ ...typeof params["type"] === "string" ? { type: params["type"] } : {},
1525
+ ...typeof params["title"] === "string" ? { title: params["title"] } : {},
1526
+ ...typeof params["body"] === "string" ? { body: params["body"] } : {},
1527
+ ...typeof params["base"] === "string" ? { base: params["base"] } : {},
1528
+ ...typeof params["taskId"] === "string" ? { taskId: params["taskId"] } : {}
1529
+ });
1530
+ if (prResult.success) {
1531
+ try {
1532
+ writeAuditEntry(projectRoot, {
1533
+ op: "docs.publish-pr",
1534
+ slug: prResult.data.slug,
1535
+ type: prResult.data.type,
1536
+ attachmentId: prResult.data.blobSha,
1537
+ summary: `Published PR for doc '${prResult.data.slug}' (${prResult.data.action}) \u2014 ${prResult.data.prUrl}`
1538
+ });
1539
+ } catch {
1540
+ }
1541
+ }
1542
+ return prResult;
1543
+ }
1544
+ case "sync": {
1545
+ const syncResult = await syncFromGit({
1546
+ ownerId: String(params["ownerId"]),
1547
+ fromPath: String(params["fromPath"]),
1548
+ blobName: typeof params["blobName"] === "string" ? params["blobName"] : void 0,
1549
+ contentType: typeof params["contentType"] === "string" ? params["contentType"] : void 0,
1550
+ projectRoot
1551
+ });
1552
+ try {
1553
+ writeAuditEntry(projectRoot, {
1554
+ op: "docs.sync",
1555
+ slug: typeof params["blobName"] === "string" && params["blobName"] || void 0,
1556
+ ownerId: String(params["ownerId"]),
1557
+ summary: `Synced doc from '${String(params["fromPath"])}' for owner ${String(params["ownerId"])}`
1558
+ });
1559
+ } catch {
1560
+ }
1561
+ return syncResult;
1562
+ }
1563
+ case "import": {
1564
+ const scanRoot = String(params["scanRoot"]);
1565
+ const accessor = createAttachmentStoreDocsAccessor(projectRoot);
1566
+ try {
1567
+ const result = await runDocsImport({
1568
+ root: scanRoot,
1569
+ accessor,
1570
+ dryRun: params["dryRun"] === true,
1571
+ force: params["force"] === true,
1572
+ manifestPath: typeof params["manifestPath"] === "string" ? params["manifestPath"] : void 0,
1573
+ auditDir: projectRoot,
1574
+ classify: makeClassifierForScanRoot(scanRoot, projectRoot)
1575
+ });
1576
+ try {
1577
+ writeAuditEntry(projectRoot, {
1578
+ op: "docs.import",
1579
+ summary: `Imported ${result.counters.importCount} created, ${result.counters.noopCount} skipped, ${result.counters.errorCount} errors from '${scanRoot}'`
1580
+ });
1581
+ } catch {
1582
+ }
1583
+ return {
1584
+ dryRun: result.dryRun,
1585
+ counters: result.counters,
1586
+ entries: result.entries,
1587
+ manifestPath: result.manifestPath ?? null
1588
+ };
1589
+ } finally {
1590
+ await accessor.close().catch(() => {
1591
+ });
1592
+ }
1593
+ }
1594
+ default:
1595
+ throw new Error(`Unsupported docs mutate operation: ${operation}`);
1596
+ }
1597
+ }
1598
+ var DocsHandler = class {
1599
+ // -----------------------------------------------------------------------
1600
+ // Query
1601
+ // -----------------------------------------------------------------------
1602
+ /**
1603
+ * Execute a read-only docs query operation.
1604
+ *
1605
+ * @param operation - The docs query op name (e.g. 'list', 'fetch', 'generate').
1606
+ * @param params - Raw params from the dispatcher (narrowed internally).
1607
+ */
1608
+ async query(operation, params) {
1609
+ const startTime = Date.now();
1610
+ if (!QUERY_OPS.has(operation)) {
1611
+ return unsupportedOp("query", "docs", operation, startTime);
1612
+ }
1613
+ try {
1614
+ const projectRoot = getProjectRoot();
1615
+ return await worktreeScope.run(
1616
+ {
1617
+ ...worktreeScope.getStore(),
1618
+ worktreeRoot: projectRoot,
1619
+ projectHash: generateProjectHash(projectRoot)
1620
+ },
1621
+ async () => {
1622
+ if (operation in _docsTypedHandler.operations) {
1623
+ const envelope = await typedDispatch(
1624
+ _docsTypedHandler,
1625
+ operation,
1626
+ params ?? {}
1627
+ );
1628
+ return docsEnvelopeToResponse(envelope, "query", operation, startTime);
1629
+ }
1630
+ return {
1631
+ meta: dispatchMeta("query", "docs", operation, startTime),
1632
+ success: true,
1633
+ data: await dispatchDocsLegacyQuery(operation, params ?? {})
1634
+ };
1635
+ }
1636
+ );
1637
+ } catch (error) {
1638
+ return handleErrorResult("query", "docs", operation, error, startTime);
1639
+ }
1640
+ }
1641
+ // -----------------------------------------------------------------------
1642
+ // Mutate
1643
+ // -----------------------------------------------------------------------
1644
+ /**
1645
+ * Execute a state-modifying docs mutation operation.
1646
+ *
1647
+ * @param operation - The docs mutate op name (e.g. 'add', 'remove').
1648
+ * @param params - Raw params from the dispatcher (narrowed internally).
1649
+ */
1650
+ async mutate(operation, params) {
1651
+ const startTime = Date.now();
1652
+ if (!MUTATE_OPS.has(operation)) {
1653
+ return unsupportedOp("mutate", "docs", operation, startTime);
1654
+ }
1655
+ try {
1656
+ const projectRoot = getProjectRoot();
1657
+ return await worktreeScope.run(
1658
+ {
1659
+ ...worktreeScope.getStore(),
1660
+ worktreeRoot: projectRoot,
1661
+ projectHash: generateProjectHash(projectRoot)
1662
+ },
1663
+ async () => {
1664
+ if (operation in _docsTypedHandler.operations) {
1665
+ const envelope = await typedDispatch(
1666
+ _docsTypedHandler,
1667
+ operation,
1668
+ params ?? {}
1669
+ );
1670
+ return docsEnvelopeToResponse(envelope, "mutate", operation, startTime);
1671
+ }
1672
+ return {
1673
+ meta: dispatchMeta("mutate", "docs", operation, startTime),
1674
+ success: true,
1675
+ data: await dispatchDocsLegacyMutate(operation, params ?? {})
1676
+ };
1677
+ }
1678
+ );
1679
+ } catch (error) {
1680
+ return handleErrorResult("mutate", "docs", operation, error, startTime);
1681
+ }
1682
+ }
1683
+ // -----------------------------------------------------------------------
1684
+ // Supported operations
1685
+ // -----------------------------------------------------------------------
1686
+ /** Declared operations for introspection and validation. */
1687
+ getSupportedOperations() {
1688
+ return {
1689
+ query: [
1690
+ "list",
1691
+ "fetch",
1692
+ "generate",
1693
+ "llm-output",
1694
+ "export",
1695
+ "search",
1696
+ "find",
1697
+ "merge",
1698
+ "rank",
1699
+ "versions",
1700
+ "status",
1701
+ "audit"
1702
+ ],
1703
+ mutate: ["add", "remove", "update", "supersede", "publish", "publish-pr", "sync", "import"]
1704
+ };
1705
+ }
1706
+ };
1707
+ export {
1708
+ DocsHandler
1709
+ };
1710
+ //# sourceMappingURL=docs-CLQKEEUK.js.map