@plebeiantech/lat.md 0.12.3-fork.13 → 0.12.3-fork.14

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 (274) hide show
  1. package/README.md +24 -0
  2. package/dist/src/cli/check-context.d.ts +56 -0
  3. package/dist/src/cli/check-context.js +215 -0
  4. package/dist/src/cli/check-coverage.js +9 -5
  5. package/dist/src/cli/check-frontmatter.js +1 -1
  6. package/dist/src/cli/check-mode.js +1 -1
  7. package/dist/src/cli/check-status.js +1 -1
  8. package/dist/src/cli/check.d.ts +19 -12
  9. package/dist/src/cli/check.js +259 -206
  10. package/dist/src/cli/context.js +1 -1
  11. package/dist/src/cli/expand.d.ts +1 -2
  12. package/dist/src/cli/expand.js +52 -5
  13. package/dist/src/cli/external.d.ts +11 -0
  14. package/dist/src/cli/external.js +185 -0
  15. package/dist/src/cli/fork-instructions.d.ts +1 -0
  16. package/dist/src/cli/fork-instructions.js +3 -2
  17. package/dist/src/cli/hook.d.ts +26 -0
  18. package/dist/src/cli/hook.js +112 -40
  19. package/dist/src/cli/index.js +55 -3
  20. package/dist/src/cli/init.d.ts +1 -0
  21. package/dist/src/cli/init.js +40 -2
  22. package/dist/src/cli/locate.js +4 -3
  23. package/dist/src/cli/refs.d.ts +2 -1
  24. package/dist/src/cli/refs.js +88 -43
  25. package/dist/src/cli/reindex.js +2 -1
  26. package/dist/src/cli/search.d.ts +12 -3
  27. package/dist/src/cli/search.js +45 -49
  28. package/dist/src/cli/section.d.ts +3 -1
  29. package/dist/src/cli/section.js +114 -38
  30. package/dist/src/code-refs.d.ts +17 -5
  31. package/dist/src/code-refs.js +246 -65
  32. package/dist/src/context.d.ts +3 -0
  33. package/dist/src/document-formats.d.ts +7 -0
  34. package/dist/src/document-formats.js +39 -0
  35. package/dist/src/extensions/alert-marker.d.ts +25 -0
  36. package/dist/src/extensions/alert-marker.js +55 -0
  37. package/dist/src/external-documents.d.ts +56 -0
  38. package/dist/src/external-documents.js +404 -0
  39. package/dist/src/external-sources.d.ts +136 -0
  40. package/dist/src/external-sources.js +1098 -0
  41. package/dist/src/fork/antigravity-hook.d.ts +47 -0
  42. package/dist/src/fork/antigravity-hook.js +424 -0
  43. package/dist/src/fork/antigravity-init.d.ts +17 -0
  44. package/dist/src/fork/antigravity-init.js +124 -0
  45. package/dist/src/fork/frontmatter-fields.d.ts +36 -0
  46. package/dist/src/fork/frontmatter-fields.js +23 -0
  47. package/dist/src/format.d.ts +5 -2
  48. package/dist/src/format.js +8 -3
  49. package/dist/src/graph-export.js +1 -1
  50. package/dist/src/lattice-model.d.ts +77 -0
  51. package/dist/src/lattice-model.js +464 -0
  52. package/dist/src/lattice.d.ts +9 -104
  53. package/dist/src/lattice.js +69 -516
  54. package/dist/src/markdown-analysis-cache.d.ts +20 -0
  55. package/dist/src/markdown-analysis-cache.js +139 -0
  56. package/dist/src/markdown-analysis-worker.d.ts +16 -0
  57. package/dist/src/markdown-analysis-worker.js +33 -0
  58. package/dist/src/markdown-analysis.d.ts +50 -0
  59. package/dist/src/markdown-analysis.js +139 -0
  60. package/dist/src/markdown-analyzer-loader.d.ts +4 -0
  61. package/dist/src/markdown-analyzer-loader.js +13 -0
  62. package/dist/src/markdown-validation.d.ts +25 -0
  63. package/dist/src/markdown-validation.js +104 -0
  64. package/dist/src/mcp/server.js +27 -11
  65. package/dist/src/parser-cache.d.ts +17 -0
  66. package/dist/src/parser-cache.js +65 -0
  67. package/dist/src/parser-import.d.ts +8 -0
  68. package/dist/src/parser-import.js +1 -0
  69. package/dist/src/parser.js +80 -5
  70. package/dist/src/path.d.ts +2 -0
  71. package/dist/src/path.js +4 -0
  72. package/dist/src/profiler.d.ts +16 -0
  73. package/dist/src/profiler.js +81 -0
  74. package/dist/src/project-analysis.d.ts +59 -0
  75. package/dist/src/project-analysis.js +233 -0
  76. package/dist/src/project-discovery.d.ts +6 -0
  77. package/dist/src/project-discovery.js +30 -0
  78. package/dist/src/repository-path.d.ts +11 -0
  79. package/dist/src/repository-path.js +52 -0
  80. package/dist/src/search/db.d.ts +1 -1
  81. package/dist/src/search/db.js +2 -2
  82. package/dist/src/search/embedder.d.ts +2 -1
  83. package/dist/src/search/embedder.js +6 -5
  84. package/dist/src/search/index.d.ts +2 -1
  85. package/dist/src/search/index.js +10 -8
  86. package/dist/src/search/query.d.ts +20 -0
  87. package/dist/src/search/query.js +67 -0
  88. package/dist/src/search/search.d.ts +3 -1
  89. package/dist/src/search/search.js +5 -2
  90. package/dist/src/source-formats.d.ts +7 -0
  91. package/dist/src/source-formats.js +26 -0
  92. package/dist/src/source-parser.d.ts +44 -4
  93. package/dist/src/source-parser.js +494 -57
  94. package/dist/src/view/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  95. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  96. package/dist/src/view/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  97. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  98. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  99. package/dist/src/view/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  100. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  101. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  102. package/dist/src/view/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  103. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  104. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  105. package/dist/src/view/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  106. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  107. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  108. package/dist/src/view/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  109. package/dist/src/view/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  110. package/dist/src/view/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  111. package/dist/src/view/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  112. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  113. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  114. package/dist/src/view/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  115. package/dist/src/view/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  116. package/dist/src/view/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  117. package/dist/src/view/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  118. package/dist/src/view/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  119. package/dist/src/view/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  120. package/dist/src/view/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  121. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  122. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  123. package/dist/src/view/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  124. package/dist/src/view/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  125. package/dist/src/view/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  126. package/dist/src/view/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  127. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  128. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  129. package/dist/src/view/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  130. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  131. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  132. package/dist/src/view/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  133. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  134. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  135. package/dist/src/view/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  136. package/dist/src/view/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  137. package/dist/src/view/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  138. package/dist/src/view/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  139. package/dist/src/view/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  140. package/dist/src/view/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  141. package/dist/src/view/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  142. package/dist/src/view/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  143. package/dist/src/view/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  144. package/dist/src/view/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  145. package/dist/src/view/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  146. package/dist/src/view/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  147. package/dist/src/view/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  148. package/dist/src/view/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  149. package/dist/src/view/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  150. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  151. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  152. package/dist/src/view/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  153. package/dist/src/view/client/assets/MarkdownEditor-B7quqPb8.js +28 -0
  154. package/dist/src/view/client/assets/OrbitControls-DwcpQNja.js +1 -0
  155. package/dist/src/view/client/assets/STLLoader-CLWTKt5i.js +1 -0
  156. package/dist/src/view/client/assets/abnfDiagram-VCTEODGH-V7-T6qsl.js +1 -0
  157. package/dist/src/view/client/assets/arc-BnwR8Bu7.js +1 -0
  158. package/dist/src/view/client/assets/architectureDiagram-5GKGNRK7-u97vDna9.js +36 -0
  159. package/dist/src/view/client/assets/blockDiagram-I7D4REHJ-DETl8e_H.js +129 -0
  160. package/dist/src/view/client/assets/c4Diagram-7LVT6UL2-DJRAT1Ve.js +38 -0
  161. package/dist/src/view/client/assets/channel-BwQbnWCN.js +1 -0
  162. package/dist/src/view/client/assets/chunk-2Q5K7J3B-C0TmOC1Q.js +1 -0
  163. package/dist/src/view/client/assets/chunk-5VM5RSS4-dfBOrYE6.js +15 -0
  164. package/dist/src/view/client/assets/chunk-F27PBJKO-DAnks99K.js +1 -0
  165. package/dist/src/view/client/assets/chunk-IMKFNOWR-CPjB07if.js +231 -0
  166. package/dist/src/view/client/assets/chunk-JWPE2WC7-VvU_gZI6.js +1 -0
  167. package/dist/src/view/client/assets/chunk-POPQ4Y6H-DDUbVF55.js +1 -0
  168. package/dist/src/view/client/assets/chunk-SVP7TREG-BHROkr6D.js +88 -0
  169. package/dist/src/view/client/assets/chunk-TICWLB2K-95PzGIOg.js +206 -0
  170. package/dist/src/view/client/assets/chunk-XXDRQBXY-MdmuLhIs.js +1 -0
  171. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-HvQKkIS-.js +1 -0
  172. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-HvQKkIS-.js +1 -0
  173. package/dist/src/view/client/assets/cose-bilkent-JH36ORCC-CauUf_rN.js +1 -0
  174. package/dist/src/view/client/assets/cynefin-OW5HDTMX-CeA8IKWo.js +166 -0
  175. package/dist/src/view/client/assets/cynefinDiagram-5FMLGOSQ-L1rtcT8l.js +62 -0
  176. package/dist/src/view/client/assets/cytoscape.esm-DzSz-X2X.js +321 -0
  177. package/dist/src/view/client/assets/dagre-GXQ25YYZ-DLQwTa3H.js +4 -0
  178. package/dist/src/view/client/assets/defaultLocale-DX6XiGOO.js +1 -0
  179. package/dist/src/view/client/assets/diagram-S7CK7UJ4-kbKdIyXG.js +30 -0
  180. package/dist/src/view/client/assets/diagram-UQ7AKVKN-kmzp92RC.js +41 -0
  181. package/dist/src/view/client/assets/diagram-VSXAHHWV-EXJTU8qq.js +3 -0
  182. package/dist/src/view/client/assets/diagram-VX7I27RA-DAiIyMCG.js +24 -0
  183. package/dist/src/view/client/assets/diagram-Z3DM3KII-G9wz50ZV.js +24 -0
  184. package/dist/src/view/client/assets/ebnfDiagram-PWID7BFC-D2tVRCNA.js +1 -0
  185. package/dist/src/view/client/assets/erDiagram-RLTQ6QDP-C925J5A3.js +99 -0
  186. package/dist/src/view/client/assets/flowDiagram-HODETNUW-DzoCa-Nq.js +168 -0
  187. package/dist/src/view/client/assets/ganttDiagram-EL5Y4UJY-D2ebbg4p.js +292 -0
  188. package/dist/src/view/client/assets/gitGraphDiagram-WWUBYQGX-B4QratYy.js +106 -0
  189. package/dist/src/view/client/assets/index-BnENo9bV.js +1 -0
  190. package/dist/src/view/client/assets/index-D0ajr_Ja.css +1 -0
  191. package/dist/src/view/client/assets/index-KZcnpXJH.js +321 -0
  192. package/dist/src/view/client/assets/infoDiagram-27XIBGKW-DL4mtHkt.js +2 -0
  193. package/dist/src/view/client/assets/init-Gi6I4Gst.js +1 -0
  194. package/dist/src/view/client/assets/ishikawaDiagram-5VMMS53U-CW4mto2d.js +70 -0
  195. package/dist/src/view/client/assets/journeyDiagram-3NMN7TZE-8R4eacFW.js +139 -0
  196. package/dist/src/view/client/assets/kanban-definition-UXKFOSKX-Cy9ioXEJ.js +89 -0
  197. package/dist/src/view/client/assets/katex-HP8lGamR.js +257 -0
  198. package/dist/src/view/client/assets/layout-C0MFuhth.js +1 -0
  199. package/dist/src/view/client/assets/linear-Dv3N4dQR.js +1 -0
  200. package/dist/src/view/client/assets/logo-small-RR_KBOAT.svg +149 -0
  201. package/dist/src/view/client/assets/maplibre-gl-DnqZgfUS.js +800 -0
  202. package/dist/src/view/client/assets/mermaid.core-bds9A7e2.js +310 -0
  203. package/dist/src/view/client/assets/mindmap-definition-YA3MSWOX-DjmGW355.js +96 -0
  204. package/dist/src/view/client/assets/ordinal-Cboi1Yqb.js +1 -0
  205. package/dist/src/view/client/assets/pegDiagram-XKGWAZYB-BWsZp0ab.js +1 -0
  206. package/dist/src/view/client/assets/pieDiagram-E7YTZNPT-CCH2gGR-.js +39 -0
  207. package/dist/src/view/client/assets/quadrantDiagram-AXDQQJYC-CjocPJFz.js +7 -0
  208. package/dist/src/view/client/assets/railroadDiagram-O6MQD6OU-BjLeb2KF.js +1 -0
  209. package/dist/src/view/client/assets/requirementDiagram-BXWQKSXE-Ct6AoXRr.js +84 -0
  210. package/dist/src/view/client/assets/sankeyDiagram-P5KCCOFB-CIpgGN_w.js +40 -0
  211. package/dist/src/view/client/assets/sequenceDiagram-WJ2MYXX4-DrmLFj6w.js +162 -0
  212. package/dist/src/view/client/assets/sizeCapture-INFHLROL-BdFMe2Lr.js +1 -0
  213. package/dist/src/view/client/assets/stateDiagram-D77RDMKH-Zd9F1goW.js +1 -0
  214. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-ByIKCftl.js +1 -0
  215. package/dist/src/view/client/assets/swimlanes-42K2YHIH-a7VFwi00.js +1 -0
  216. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-CzxaUHB-.js +8 -0
  217. package/dist/src/view/client/assets/three.module-PDSP0dbZ.js +4108 -0
  218. package/dist/src/view/client/assets/timeline-definition-24CTP7MA-BExPu6X5.js +120 -0
  219. package/dist/src/view/client/assets/vennDiagram-4TSXK5OY-PC1MU3si.js +34 -0
  220. package/dist/src/view/client/assets/wardleyDiagram-VM6X3IG4-DNWqU3fa.js +78 -0
  221. package/dist/src/view/client/assets/xychartDiagram-S5SC5T6Z-E1uA28_D.js +7 -0
  222. package/dist/src/view/client/index.html +2 -2
  223. package/dist/src/view/client-shell.d.ts +2 -0
  224. package/dist/src/view/client-shell.js +5 -0
  225. package/dist/src/view/diagnostics.d.ts +3 -2
  226. package/dist/src/view/diagnostics.js +49 -58
  227. package/dist/src/view/document-edit.d.ts +8 -0
  228. package/dist/src/view/document-edit.js +25 -0
  229. package/dist/src/view/document-route.d.ts +12 -0
  230. package/dist/src/view/document-route.js +93 -0
  231. package/dist/src/view/document-tree.d.ts +18 -0
  232. package/dist/src/view/document-tree.js +139 -0
  233. package/dist/src/view/external-document-tree.d.ts +3 -0
  234. package/dist/src/view/external-document-tree.js +674 -0
  235. package/dist/src/view/git-diff.js +187 -0
  236. package/dist/src/view/git.js +1 -1
  237. package/dist/src/view/graph.d.ts +3 -2
  238. package/dist/src/view/graph.js +94 -7
  239. package/dist/src/view/highlight.d.ts +10 -2
  240. package/dist/src/view/highlight.js +4540 -1360
  241. package/dist/src/view/markdown.d.ts +3 -2
  242. package/dist/src/view/markdown.js +214 -53
  243. package/dist/src/view/protocol.d.ts +59 -6
  244. package/dist/src/view/references.d.ts +10 -25
  245. package/dist/src/view/references.js +117 -107
  246. package/dist/src/view/repository.d.ts +13 -3
  247. package/dist/src/view/repository.js +234 -15
  248. package/dist/src/view/search.d.ts +1 -1
  249. package/dist/src/view/search.js +3 -7
  250. package/dist/src/view/server.d.ts +11 -2
  251. package/dist/src/view/server.js +212 -70
  252. package/dist/src/view/source-target.js +5 -8
  253. package/dist/src/view/static-build.d.ts +1 -0
  254. package/dist/src/view/static-build.js +245 -42
  255. package/dist/src/view/static-protocol.d.ts +19 -2
  256. package/dist/src/view/store.d.ts +16 -3
  257. package/dist/src/view/store.js +228 -36
  258. package/dist/src/view/table-of-contents.d.ts +2 -2
  259. package/dist/src/view/table-of-contents.js +2 -22
  260. package/dist/src/walk.d.ts +5 -3
  261. package/dist/src/walk.js +102 -8
  262. package/package.json +46 -8
  263. package/plugins/lat-md/README.md +61 -0
  264. package/plugins/lat-md/hooks.json +38 -0
  265. package/plugins/lat-md/plugin.json +9 -0
  266. package/plugins/lat-md/rules/AGENTS.md +118 -0
  267. package/plugins/lat-md/skills/lat-md/SKILL.md +178 -0
  268. package/plugins/lat-md/skills/lat-md-conventions/SKILL.md +182 -0
  269. package/templates/AGENTS.md +15 -3
  270. package/templates/cursor-rules.md +12 -3
  271. package/templates/skill/SKILL.md +22 -1
  272. package/dist/src/view/client/assets/index-C3iaZyYT.css +0 -1
  273. package/dist/src/view/client/assets/index-KWi67IMz.js +0 -334
  274. package/dist/src/view/client/assets/logo-CNF8zs47.svg +0 -182
@@ -1,15 +1,23 @@
1
+ import { lstatSync } from 'node:fs';
1
2
  import { readFile } from 'node:fs/promises';
2
3
  import { execFile } from 'node:child_process';
4
+ import { availableParallelism } from 'node:os';
3
5
  import { join, posix, relative } from 'node:path';
4
- import { toPosix, walkEntries } from './walk.js';
6
+ import { isSourceFilePath, SOURCE_FILE_EXTENSIONS } from './source-formats.js';
7
+ import { toPosix } from './path.js';
8
+ import { ALWAYS_IGNORED_DIRECTORIES, walkEntries } from './walk.js';
5
9
  /** Glob patterns used to exclude directories/files from code-ref scanning.
6
10
  * Shared between rg args and the TS fallback's walkFiles filter. */
7
- const EXCLUDE_DIRS = ['lat.md', '.claude'];
8
- const EXCLUDE_GLOBS = ['*.md'];
9
- /** Walk project files for code-ref scanning. Uses walkEntries for .gitignore
10
- * support, then additionally skips .md files, lat.md/, .claude/, and sub-projects. */
11
+ const EXCLUDE_DIRS = ['lat.md', '.claude', ...ALWAYS_IGNORED_DIRECTORIES];
12
+ const EXCLUDE_GLOBS = ['*.md', '.*', '**/.*'];
13
+ const RG_IGNORE_ARGS = ['--no-require-git', '--ignore-file-case-insensitive'];
14
+ /** Walk supported source files for code-ref scanning. Uses walkEntries for
15
+ * .gitignore support, then additionally skips lat.md/, .claude/, generated
16
+ * UI output, and sub-projects. */
11
17
  export async function walkFiles(dir) {
12
18
  const entries = (await walkEntries(dir)).map(toPosix);
19
+ // Generated UI output carries a .lat-ui-build marker; the whole directory it
20
+ // marks is build product, not source, so nothing in it is a real code ref.
13
21
  const generatedOutputs = new Set(entries
14
22
  .filter((entry) => entry.endsWith('/.lat-ui-build'))
15
23
  .map((entry) => `${posix.dirname(entry)}/`));
@@ -21,7 +29,7 @@ export async function walkFiles(dir) {
21
29
  subProjects.add(e.slice(0, i + 1));
22
30
  }
23
31
  return entries
24
- .filter((e) => !e.endsWith('.md') &&
32
+ .filter((e) => isSourceFilePath(e) &&
25
33
  !e.startsWith('lat.md/') &&
26
34
  !e.startsWith('.claude/') &&
27
35
  ![...generatedOutputs].some((prefix) => e.startsWith(prefix)) &&
@@ -97,6 +105,9 @@ function extractRefsFromLine(line) {
97
105
  }
98
106
  return targets;
99
107
  }
108
+ function profileScan(profile, label, work) {
109
+ return profile ? profile.time(label, work) : work();
110
+ }
100
111
  /**
101
112
  * Run an external command and return stdout, or null if the command is not found
102
113
  * or fails.
@@ -105,13 +116,13 @@ function tryExec(cmd, args, cwd) {
105
116
  return new Promise((resolve) => {
106
117
  execFile(cmd, args, { cwd, maxBuffer: 50 * 1024 * 1024 }, (err, out) => {
107
118
  if (err) {
108
- // Exit code 1 with no stderr typically means "no matches" for grep/rg
119
+ // Exit code 1 with no stderr typically means "no matches" for rg.
109
120
  const exitCode = err.code;
110
121
  if (exitCode === 'ENOENT') {
111
122
  resolve(null); // command not found
112
123
  return;
113
124
  }
114
- // rg/grep exit 1 = no matches (not an error)
125
+ // rg exit 1 = no matches (not an error)
115
126
  if ('status' in err &&
116
127
  err.status === 1 &&
117
128
  out === '') {
@@ -134,7 +145,7 @@ async function findSubProjects(projectRoot) {
134
145
  // List files inside any lat.md/ dir, then extract unique parent paths.
135
146
  // The root lat.md/ is excluded by EXCLUDE_DIRS in the caller, so we only
136
147
  // need to find nested ones here — search for files under */lat.md/.
137
- const out = await tryExec('rg', ['--files', '--glob', '**/lat.md/**', '.'], projectRoot);
148
+ const out = await tryExec('rg', ['--files', ...RG_IGNORE_ARGS, '--glob', '**/lat.md/**', '.'], projectRoot);
138
149
  if (!out)
139
150
  return [];
140
151
  const subProjects = new Set();
@@ -152,9 +163,69 @@ async function findSubProjects(projectRoot) {
152
163
  }
153
164
  return [...subProjects];
154
165
  }
155
- /** Find static UI exports so generated JSON and bundles never become code refs. */
166
+ function nestedLatProjects(paths) {
167
+ const projects = new Set();
168
+ for (const path of paths) {
169
+ const index = path.indexOf('/lat.md/');
170
+ if (index !== -1)
171
+ projects.add(path.slice(0, index));
172
+ }
173
+ return [...projects];
174
+ }
175
+ function hasDotDirectory(path) {
176
+ const parts = path.split('/');
177
+ return parts.slice(0, -1).some((part) => part.startsWith('.'));
178
+ }
179
+ /** List readable regular source files tracked by the enclosing Git repository. */
180
+ async function findGitTrackedSourceFiles(projectRoot) {
181
+ const out = await tryExec('git', ['ls-files', '--stage', '-z', '--', '.'], projectRoot);
182
+ if (out === null)
183
+ return null;
184
+ const entries = out
185
+ .split('\0')
186
+ .filter(Boolean)
187
+ .flatMap((entry) => {
188
+ const tab = entry.indexOf('\t');
189
+ if (tab === -1)
190
+ return [];
191
+ const mode = entry.slice(0, entry.indexOf(' '));
192
+ if (mode !== '100644' && mode !== '100755')
193
+ return [];
194
+ return [toPosix(entry.slice(tab + 1))];
195
+ });
196
+ const subProjects = nestedLatProjects(entries);
197
+ const candidates = entries.filter((path) => isSourceFilePath(path) &&
198
+ !hasDotDirectory(path) &&
199
+ !path.startsWith('lat.md/') &&
200
+ !subProjects.some((project) => path === project || path.startsWith(`${project}/`)));
201
+ return candidates
202
+ .flatMap((path) => {
203
+ const absolute = join(projectRoot, path);
204
+ try {
205
+ return lstatSync(absolute).isFile() ? [absolute] : [];
206
+ }
207
+ catch (error) {
208
+ if (error.code === 'ENOENT')
209
+ return [];
210
+ throw error;
211
+ }
212
+ })
213
+ .sort((a, b) => a.localeCompare(b, 'en'));
214
+ }
215
+ /**
216
+ * Directories holding generated UI output, found by the `.lat-ui-build` marker
217
+ * the build writes beside what it produces. Build product is not source, so a
218
+ * `@lat:` string inside it is not a reference to anything.
219
+ */
156
220
  async function findGeneratedOutputs(projectRoot) {
157
- const out = await tryExec('rg', ['--files', '--hidden', '--glob', '**/.lat-ui-build', '.'], projectRoot);
221
+ const out = await tryExec('rg', [
222
+ '--files',
223
+ '--hidden',
224
+ ...RG_IGNORE_ARGS,
225
+ '--glob',
226
+ '**/.lat-ui-build',
227
+ '.',
228
+ ], projectRoot);
158
229
  if (!out)
159
230
  return [];
160
231
  return [
@@ -167,7 +238,7 @@ async function findGeneratedOutputs(projectRoot) {
167
238
  ];
168
239
  }
169
240
  /** Build rg glob exclusion args. */
170
- function rgExcludeArgs(subProjects, generatedOutputs) {
241
+ function rgExcludeArgs(subProjects, generatedOutputs = []) {
171
242
  const args = [];
172
243
  for (const dir of EXCLUDE_DIRS)
173
244
  args.push('--glob', `!${dir}/`);
@@ -179,44 +250,105 @@ function rgExcludeArgs(subProjects, generatedOutputs) {
179
250
  args.push('--glob', `!${output}/`);
180
251
  return args;
181
252
  }
182
- /**
183
- * Try scanning with ripgrep. Returns parsed refs and scanned file list, or null
184
- * if rg is not available. rg respects .gitignore by default; we add glob
185
- * exclusions for lat.md/, .claude/, *.md files, and sub-projects.
186
- */
187
- async function tryRipgrep(projectRoot) {
188
- // Detect sub-projects first so we can exclude them from all rg calls
189
- const subProjects = await findSubProjects(projectRoot);
190
- const generatedOutputs = await findGeneratedOutputs(projectRoot);
191
- const excludes = rgExcludeArgs(subProjects, generatedOutputs);
192
- // Search for @lat refs
253
+ /** Build an rg file type from the shared supported-source registry. */
254
+ function rgSourceIncludeArgs() {
255
+ return [
256
+ ...SOURCE_FILE_EXTENSIONS.flatMap((extension) => [
257
+ '--type-add',
258
+ `latsource:*${extension}`,
259
+ ]),
260
+ '--type',
261
+ 'latsource',
262
+ ];
263
+ }
264
+ async function discoverRipgrepExcludes(projectRoot, profile) {
265
+ const [subProjects, generatedOutputs] = await Promise.all([
266
+ profileScan(profile, 'find nested lat.md projects with ripgrep', () => findSubProjects(projectRoot)),
267
+ profileScan(profile, 'find generated UI output with ripgrep', () => findGeneratedOutputs(projectRoot)),
268
+ ]);
269
+ return rgExcludeArgs(subProjects, generatedOutputs);
270
+ }
271
+ function ripgrepPathBatches(paths) {
272
+ const batches = [];
273
+ let batch = [];
274
+ let length = 0;
275
+ for (const path of paths) {
276
+ if (batch.length > 0 && length + path.length + 1 > 16_000) {
277
+ batches.push(batch);
278
+ batch = [];
279
+ length = 0;
280
+ }
281
+ batch.push(path);
282
+ length += path.length + 1;
283
+ }
284
+ if (batch.length > 0)
285
+ batches.push(batch);
286
+ return batches;
287
+ }
288
+ async function runRipgrepBatches(projectRoot, args, paths) {
289
+ const batches = ripgrepPathBatches(paths);
290
+ if (batches.length === 0)
291
+ return [];
292
+ const results = new Array(batches.length);
293
+ let nextIndex = 0;
294
+ const workerCount = Math.min(availableParallelism(), batches.length);
295
+ await Promise.all(Array.from({ length: workerCount }, async () => {
296
+ while (true) {
297
+ const index = nextIndex++;
298
+ if (index >= batches.length)
299
+ return;
300
+ results[index] = await tryExec('rg', [...args, '--', ...batches[index]], projectRoot);
301
+ }
302
+ }));
303
+ return results.some((result) => result === null)
304
+ ? null
305
+ : results;
306
+ }
307
+ /** Search supported source files for code references with ripgrep. */
308
+ async function tryRipgrepCodeRefs(projectRoot, excludes, profile, files) {
193
309
  const searchArgs = [
194
310
  '--no-heading',
195
311
  '--line-number',
196
312
  '--with-filename',
313
+ ...RG_IGNORE_ARGS,
314
+ ...rgSourceIncludeArgs(),
197
315
  ...excludes,
198
316
  '@lat:.*\\[\\[',
199
- '.',
200
317
  ];
201
- const out = await tryExec('rg', searchArgs, projectRoot);
202
- if (out === null)
318
+ const outputs = await profileScan(profile, 'scan @lat references with ripgrep', () => files
319
+ ? runRipgrepBatches(projectRoot, searchArgs, files.map((file) => toPosix(relative(projectRoot, file))))
320
+ : tryExec('rg', [...searchArgs, '.'], projectRoot).then((output) => output === null ? null : [output]));
321
+ if (outputs === null)
322
+ return null;
323
+ const refs = outputs.flatMap((output) => parseGrepOutput(output, projectRoot).refs);
324
+ refs.sort((a, b) => a.file.localeCompare(b.file, 'en') || a.line - b.line);
325
+ return refs;
326
+ }
327
+ /** Discover the supported source-file scope with ripgrep. */
328
+ async function tryRipgrepSourceFiles(projectRoot, excludes, profile) {
329
+ const filesOut = await profileScan(profile, 'list source files with ripgrep', () => tryExec('rg', [
330
+ '--files',
331
+ ...RG_IGNORE_ARGS,
332
+ ...rgSourceIncludeArgs(),
333
+ ...excludes,
334
+ '.',
335
+ ], projectRoot));
336
+ if (filesOut === null)
203
337
  return null;
204
- const { refs } = parseGrepOutput(out);
205
- // List all scanned files (for stats) — rg --files is fast
206
- const filesOut = await tryExec('rg', ['--files', ...excludes, '.'], projectRoot);
207
338
  const files = (filesOut || '')
208
339
  .split('\n')
209
340
  .filter(Boolean)
210
341
  .map((f) => {
211
342
  const clean = toPosix(f).replace(/^\.\//, '');
212
343
  return join(projectRoot, clean);
213
- });
214
- return { refs, files };
344
+ })
345
+ .sort((a, b) => a.localeCompare(b, 'en'));
346
+ return files;
215
347
  }
216
348
  /**
217
349
  * Parse rg output lines (file:line:content) into CodeRef entries.
218
350
  */
219
- function parseGrepOutput(output) {
351
+ function parseGrepOutput(output, projectRoot) {
220
352
  const refs = [];
221
353
  if (!output.trim())
222
354
  return { refs };
@@ -250,30 +382,51 @@ function parseGrepOutput(output) {
250
382
  }
251
383
  return { refs };
252
384
  }
253
- /**
254
- * TypeScript fallback: read every file and scan for @lat refs.
255
- */
256
- async function scanWithTs(files, projectRoot) {
385
+ async function scanFileWithTs(file, projectRoot) {
386
+ let content;
387
+ try {
388
+ content = await readFile(file, 'utf-8');
389
+ }
390
+ catch (err) {
391
+ return {
392
+ refs: [],
393
+ error: `Error: failed to read ${file}: ${err.message}\n`,
394
+ };
395
+ }
257
396
  const refs = [];
258
- for (const file of files) {
259
- let content;
260
- try {
261
- content = await readFile(file, 'utf-8');
262
- }
263
- catch (err) {
264
- process.stderr.write(`Error: failed to read ${file}: ${err.message}\n`);
265
- continue;
397
+ const relativePath = toPosix(relative(projectRoot, file));
398
+ const lines = content.split('\n');
399
+ for (let i = 0; i < lines.length; i++) {
400
+ // Same literal-span and `lat:ignore` filtering the ripgrep path applies in
401
+ // parseGrepOutput, so both paths agree on what counts as a reference.
402
+ for (const target of extractRefsFromLine(lines[i])) {
403
+ refs.push({
404
+ target,
405
+ file: relativePath,
406
+ line: i + 1,
407
+ });
266
408
  }
267
- const lines = content.split('\n');
268
- for (let i = 0; i < lines.length; i++) {
269
- for (const target of extractRefsFromLine(lines[i])) {
270
- refs.push({
271
- target,
272
- file: toPosix(relative(projectRoot, file)),
273
- line: i + 1,
274
- });
275
- }
409
+ }
410
+ return { refs };
411
+ }
412
+ /** TypeScript fallback: scan supported source files through a bounded pool. */
413
+ async function scanWithTs(files, projectRoot) {
414
+ const results = new Array(files.length);
415
+ let nextIndex = 0;
416
+ const workerCount = Math.min(availableParallelism(), files.length);
417
+ await Promise.all(Array.from({ length: workerCount }, async () => {
418
+ while (true) {
419
+ const index = nextIndex++;
420
+ if (index >= files.length)
421
+ return;
422
+ results[index] = await scanFileWithTs(files[index], projectRoot);
276
423
  }
424
+ }));
425
+ const refs = [];
426
+ for (const result of results) {
427
+ if (result.error)
428
+ process.stderr.write(result.error);
429
+ refs.push(...result.refs);
277
430
  }
278
431
  return refs;
279
432
  }
@@ -282,17 +435,45 @@ export async function hasRipgrep() {
282
435
  const result = await tryExec('rg', ['--version'], '.');
283
436
  return result !== null;
284
437
  }
285
- export async function scanCodeRefs(projectRoot) {
286
- // Fast path: use rg for both searching and file listing
287
- // _LAT_DISABLE_RG is a test-only escape hatch to force the TS fallback
288
- if (process.env._LAT_DISABLE_RG !== '1') {
289
- const rgResult = await tryRipgrep(projectRoot);
290
- if (rgResult !== null) {
291
- return { refs: rgResult.refs, files: rgResult.files, usedRg: true };
438
+ /**
439
+ * Create a lazy project-scoped discovery API. Code-reference scanning and
440
+ * source-file inventory are separate operations, but share ripgrep exclusion
441
+ * discovery and coalesce fallback file walking when both are requested.
442
+ */
443
+ export function createCodeReferenceDiscovery(projectRoot, profile) {
444
+ let excludesPromise;
445
+ let trackedFilesPromise;
446
+ let sourceFilesPromise;
447
+ let scanPromise;
448
+ const ripgrepExcludes = () => (excludesPromise ??= discoverRipgrepExcludes(projectRoot, profile));
449
+ const trackedFiles = () => (trackedFilesPromise ??= profileScan(profile, 'list tracked source files with git', () => findGitTrackedSourceFiles(projectRoot)));
450
+ const listSourceFiles = () => (sourceFilesPromise ??= (async () => {
451
+ const tracked = await trackedFiles();
452
+ if (tracked !== null)
453
+ return tracked;
454
+ if (process.env._LAT_DISABLE_RG !== '1') {
455
+ const files = await tryRipgrepSourceFiles(projectRoot, await ripgrepExcludes(), profile);
456
+ if (files !== null)
457
+ return files;
292
458
  }
293
- }
294
- // Fallback: walk files ourselves and scan with TS
295
- const files = await walkFiles(projectRoot);
296
- const refs = await scanWithTs(files, projectRoot);
297
- return { refs, files, usedRg: false };
459
+ return profileScan(profile, 'walk project source files', () => walkFiles(projectRoot));
460
+ })());
461
+ const scan = () => (scanPromise ??= (async () => {
462
+ const tracked = await trackedFiles();
463
+ if (process.env._LAT_DISABLE_RG !== '1') {
464
+ const refs = await tryRipgrepCodeRefs(projectRoot, tracked === null ? await ripgrepExcludes() : [], profile, tracked ?? undefined);
465
+ if (refs !== null)
466
+ return { refs };
467
+ }
468
+ const refs = await profileScan(profile, 'scan project files with TypeScript fallback', async () => scanWithTs(await listSourceFiles(), projectRoot));
469
+ return { refs };
470
+ })());
471
+ return { scan, listSourceFiles };
472
+ }
473
+ export async function scanCodeRefs(projectRoot, profile) {
474
+ return createCodeReferenceDiscovery(projectRoot, profile).scan();
475
+ }
476
+ /** Discover the source files that may contain code references. */
477
+ export async function discoverSourceFiles(projectRoot, profile) {
478
+ return createCodeReferenceDiscovery(projectRoot, profile).listSourceFiles();
298
479
  }
@@ -1,3 +1,4 @@
1
+ import type { MarkdownProjectSession } from './project-analysis.js';
1
2
  export type Styler = {
2
3
  bold: (s: string) => string;
3
4
  dim: (s: string) => string;
@@ -16,6 +17,8 @@ export type CmdContext = {
16
17
  mode: 'cli' | 'mcp';
17
18
  /** The check target was supplied explicitly instead of discovered as lat.md. */
18
19
  headless?: boolean;
20
+ /** Lazy Markdown analysis shared by nested operations in this request. */
21
+ analysis?: MarkdownProjectSession;
19
22
  };
20
23
  export type CmdResult = {
21
24
  output: string;
@@ -0,0 +1,7 @@
1
+ /** Document formats that external sources can resolve by heading. */
2
+ export declare const DOCUMENT_FILE_EXTENSIONS: ReadonlySet<string>;
3
+ export type DocumentFormat = 'asciidoc' | 'markdown' | 'restructuredtext';
4
+ export declare function documentFormat(path: string): DocumentFormat | null;
5
+ export declare function isDocumentPath(path: string): boolean;
6
+ export declare function stripDocumentExtension(path: string): string;
7
+ export declare function documentFormatLabel(format: DocumentFormat): string;
@@ -0,0 +1,39 @@
1
+ /** Document formats that external sources can resolve by heading. */
2
+ export const DOCUMENT_FILE_EXTENSIONS = new Set([
3
+ '.adoc',
4
+ '.asciidoc',
5
+ '.md',
6
+ '.rst',
7
+ ]);
8
+ export function documentFormat(path) {
9
+ const lower = path.toLowerCase();
10
+ if (lower.endsWith('.md'))
11
+ return 'markdown';
12
+ if (lower.endsWith('.rst'))
13
+ return 'restructuredtext';
14
+ if (lower.endsWith('.adoc') || lower.endsWith('.asciidoc')) {
15
+ return 'asciidoc';
16
+ }
17
+ return null;
18
+ }
19
+ export function isDocumentPath(path) {
20
+ return documentFormat(path) !== null;
21
+ }
22
+ export function stripDocumentExtension(path) {
23
+ const lower = path.toLowerCase();
24
+ for (const extension of DOCUMENT_FILE_EXTENSIONS) {
25
+ if (lower.endsWith(extension))
26
+ return path.slice(0, -extension.length);
27
+ }
28
+ return path;
29
+ }
30
+ export function documentFormatLabel(format) {
31
+ switch (format) {
32
+ case 'asciidoc':
33
+ return 'AsciiDoc';
34
+ case 'markdown':
35
+ return 'Markdown';
36
+ case 'restructuredtext':
37
+ return 'reStructuredText';
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ import type { Data, Literal, Root } from 'mdast';
2
+ import type { Options } from 'mdast-util-to-markdown';
3
+ export declare const ALERT_KINDS: readonly ["NOTE", "TIP", "IMPORTANT", "WARNING", "CAUTION"];
4
+ export type AlertKind = (typeof ALERT_KINDS)[number];
5
+ export interface AlertMarker extends Literal {
6
+ type: 'alertMarker';
7
+ value: AlertKind;
8
+ data?: Data;
9
+ }
10
+ /** Promote GitHub alert markers so serialization does not escape their brackets. */
11
+ export declare function markAlertMarkers(tree: Root): void;
12
+ export declare function alertMarkerToMarkdown(): Options;
13
+ declare module 'mdast' {
14
+ interface RootContentMap {
15
+ alertMarker: AlertMarker;
16
+ }
17
+ interface PhrasingContentMap {
18
+ alertMarker: AlertMarker;
19
+ }
20
+ }
21
+ declare module 'mdast-util-to-markdown' {
22
+ interface ConstructNameMap {
23
+ alertMarker: 'alertMarker';
24
+ }
25
+ }
@@ -0,0 +1,55 @@
1
+ import { visit } from 'unist-util-visit';
2
+ export const ALERT_KINDS = [
3
+ 'NOTE',
4
+ 'TIP',
5
+ 'IMPORTANT',
6
+ 'WARNING',
7
+ 'CAUTION',
8
+ ];
9
+ const ALERT_PATTERN = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\](?:\r?\n|$)/;
10
+ /** Promote GitHub alert markers so serialization does not escape their brackets. */
11
+ export function markAlertMarkers(tree) {
12
+ visit(tree, 'blockquote', (node) => {
13
+ const firstBlock = node.children[0];
14
+ if (firstBlock?.type !== 'paragraph')
15
+ return;
16
+ const firstInline = firstBlock.children[0];
17
+ if (firstInline?.type !== 'text')
18
+ return;
19
+ const match = firstInline.value.match(ALERT_PATTERN);
20
+ if (!match)
21
+ return;
22
+ const marker = {
23
+ type: 'alertMarker',
24
+ value: match[1],
25
+ };
26
+ const start = firstInline.position?.start;
27
+ if (start) {
28
+ const markerLength = match[0].replace(/\r?\n$/, '').length;
29
+ marker.position = {
30
+ start,
31
+ end: {
32
+ line: start.line,
33
+ column: start.column + markerLength,
34
+ ...(start.offset === undefined
35
+ ? {}
36
+ : { offset: start.offset + markerLength }),
37
+ },
38
+ };
39
+ }
40
+ const remaining = firstInline.value.slice(match[0].length);
41
+ const replacement = [marker];
42
+ if (remaining !== '')
43
+ replacement.push({ type: 'text', value: remaining });
44
+ firstBlock.children.splice(0, 1, ...replacement);
45
+ });
46
+ }
47
+ function alertMarkerHandler(node, _parent, state, _info) {
48
+ const exit = state.enter('alertMarker');
49
+ const value = `[!${node.value}]\n`;
50
+ exit();
51
+ return value;
52
+ }
53
+ export function alertMarkerToMarkdown() {
54
+ return { handlers: { alertMarker: alertMarkerHandler } };
55
+ }
@@ -0,0 +1,56 @@
1
+ import { type Section } from './lattice-model.js';
2
+ import { type DocumentFormat } from './document-formats.js';
3
+ import type { ParserImportObserver } from './parser-import.js';
4
+ import type { ViewDocumentTree } from './view/protocol.js';
5
+ export type ExternalDocumentSection = {
6
+ title: string;
7
+ depth: number;
8
+ anchor: string;
9
+ aliases: string[];
10
+ hierarchy: string[];
11
+ startLine: number;
12
+ endLine: number;
13
+ };
14
+ /** Serializable document facts retained after a format parser discards its AST. */
15
+ export type ExternalDocumentAnalysis = {
16
+ format: DocumentFormat;
17
+ title: string;
18
+ sections: ExternalDocumentSection[];
19
+ };
20
+ export type ExternalDocumentCacheStatus = 'disabled' | 'hit' | 'miss';
21
+ export type ExternalDocumentAnalysisTimings = {
22
+ hashMs: number;
23
+ cacheReadMs: number;
24
+ cacheWriteMs: number;
25
+ parseMs: number;
26
+ cacheStatus: ExternalDocumentCacheStatus;
27
+ };
28
+ export type ExternalDocumentFileAnalysis = {
29
+ path: string;
30
+ document: ExternalDocumentAnalysis;
31
+ timings: ExternalDocumentAnalysisTimings;
32
+ };
33
+ export type AnalyzeExternalDocumentOptions = {
34
+ identity?: string;
35
+ cache?: boolean;
36
+ runtime?: ExternalDocumentParserRuntime;
37
+ onFileAnalyzed?: (analysis: ExternalDocumentFileAnalysis) => void;
38
+ onParserImport?: ParserImportObserver;
39
+ };
40
+ /** Accept legacy AsciiDoc source listings whose delimiter lengths do not match. */
41
+ export declare function asciidocCompatibleContent(content: string): string;
42
+ export declare function analyzeExternalDocument(path: string, content: string, onParserImport?: ParserImportObserver, importDetail?: string): Promise<ExternalDocumentAnalysis>;
43
+ /** Request-scoped owner for external document parser work. */
44
+ export declare class ExternalDocumentParserRuntime {
45
+ readonly analyses: Map<string, Promise<ExternalDocumentFileAnalysis>>;
46
+ clear(): void;
47
+ }
48
+ /** Return the shared parsed-cache path for one external document identity. */
49
+ export declare function externalDocumentAnalysisCachePath(latDir: string, identity: string): string;
50
+ /** Analyze an external document through the shared persistent parser cache. */
51
+ export declare function analyzeExternalDocumentCached(path: string, content: string, latDir: string, options?: AnalyzeExternalDocumentOptions): Promise<ExternalDocumentFileAnalysis>;
52
+ export declare function findExternalDocumentSection(analysis: ExternalDocumentAnalysis, fragment: string): ExternalDocumentSection | undefined;
53
+ /** Project format-neutral document sections into the existing browser TOC model. */
54
+ export declare function externalDocumentSections(path: string, analysis: ExternalDocumentAnalysis): Section[];
55
+ /** Add zero-size alias anchors to the normalized external document tree. */
56
+ export declare function addExternalDocumentAliasAnchors(source: ViewDocumentTree, analysis: ExternalDocumentAnalysis): ViewDocumentTree;