@plebeiantech/lat.md 0.12.3-fork.17 → 0.12.3-fork.20

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 (244) hide show
  1. package/README.md +1 -1
  2. package/dist/src/cli/agent-invocation.d.ts +6 -0
  3. package/dist/src/cli/agent-invocation.js +23 -0
  4. package/dist/src/cli/fork-instructions.js +1 -1
  5. package/dist/src/cli/fork-scaffold.js +2 -2
  6. package/dist/src/cli/graph.d.ts +1 -1
  7. package/dist/src/cli/hook.js +11 -11
  8. package/dist/src/cli/index.js +41 -59
  9. package/dist/src/cli/init-preferences.js +5 -4
  10. package/dist/src/cli/init.d.ts +1 -1
  11. package/dist/src/cli/init.js +54 -45
  12. package/dist/src/cli/reindex.d.ts +1 -1
  13. package/dist/src/cli/reindex.js +2 -2
  14. package/dist/src/cli/search.d.ts +4 -4
  15. package/dist/src/cli/search.js +41 -28
  16. package/dist/src/cli/ui-build-server.d.ts +1 -1
  17. package/dist/src/cli/ui-build.d.ts +1 -1
  18. package/dist/src/cli/ui.d.ts +1 -1
  19. package/dist/src/fork/antigravity-hook.js +6 -6
  20. package/dist/src/fork/antigravity-init.d.ts +2 -2
  21. package/dist/src/fork/antigravity-init.js +2 -2
  22. package/dist/src/graph-export.js +7 -7
  23. package/dist/src/knowledge/index.js +2 -2
  24. package/dist/src/mcp/server.js +8 -8
  25. package/dist/src/search/cache.d.ts +1 -1
  26. package/dist/src/search/cache.js +40 -7
  27. package/dist/src/search/chunks.d.ts +2 -2
  28. package/dist/src/search/db.d.ts +5 -4
  29. package/dist/src/search/db.js +36 -40
  30. package/dist/src/search/embedder.js +1 -1
  31. package/dist/src/search/index.d.ts +1 -1
  32. package/dist/src/search/index.js +2 -2
  33. package/dist/src/search/lock.d.ts +4 -1
  34. package/dist/src/search/lock.js +30 -8
  35. package/dist/src/search/query.d.ts +5 -2
  36. package/dist/src/search/query.js +55 -38
  37. package/dist/src/search/search.d.ts +3 -1
  38. package/dist/src/search/search.js +21 -12
  39. package/dist/src/search/types.d.ts +2 -18
  40. package/dist/src/view/client/assets/{GraphView-BWlRdQM4.js → GraphView-Dij8mAA_.js} +1 -1
  41. package/dist/src/view/client/assets/{MarkdownEditor-MW-Ck1O0.js → MarkdownEditor-88Wbt0M1.js} +1 -1
  42. package/dist/src/view/client/assets/{abnfDiagram-VCTEODGH-Bn3RshMV.js → abnfDiagram-VCTEODGH-y0DlYa8E.js} +1 -1
  43. package/dist/src/view/client/assets/{arc-En9tdFQF.js → arc-FlMu8dnO.js} +1 -1
  44. package/dist/src/view/client/assets/{architectureDiagram-5GKGNRK7-B-9J1VAM.js → architectureDiagram-5GKGNRK7-DA_uWZW1.js} +1 -1
  45. package/dist/src/view/client/assets/{blockDiagram-I7D4REHJ-QlznwalP.js → blockDiagram-I7D4REHJ-BHQ5LU85.js} +1 -1
  46. package/dist/src/view/client/assets/{c4Diagram-7LVT6UL2-Bp2y8B4_.js → c4Diagram-7LVT6UL2-BRucKCt2.js} +1 -1
  47. package/dist/src/view/client/assets/channel-BgDNA_Ay.js +1 -0
  48. package/dist/src/view/client/assets/{chunk-2Q5K7J3B-CnBKL-lm.js → chunk-2Q5K7J3B-BJPcFivt.js} +1 -1
  49. package/dist/src/view/client/assets/{chunk-5VM5RSS4-LLYMi_n6.js → chunk-5VM5RSS4-v2q99bGz.js} +1 -1
  50. package/dist/src/view/client/assets/{chunk-F27PBJKO-VIeO7VF0.js → chunk-F27PBJKO-CcHOuJCs.js} +1 -1
  51. package/dist/src/view/client/assets/{chunk-IMKFNOWR-D5i67DVD.js → chunk-IMKFNOWR-DNxYuJNq.js} +1 -1
  52. package/dist/src/view/client/assets/{chunk-JWPE2WC7-D4qAtoL3.js → chunk-JWPE2WC7-C0eHKvLW.js} +1 -1
  53. package/dist/src/view/client/assets/{chunk-POPQ4Y6H-BMzOyiW_.js → chunk-POPQ4Y6H-57CWp2Ve.js} +1 -1
  54. package/dist/src/view/client/assets/{chunk-SVP7TREG-DWy5nbfp.js → chunk-SVP7TREG-BqcoxIJw.js} +1 -1
  55. package/dist/src/view/client/assets/{chunk-TICWLB2K-CVqCANFB.js → chunk-TICWLB2K-DRUJR5zH.js} +1 -1
  56. package/dist/src/view/client/assets/{chunk-XXDRQBXY-Bp23h6Tf.js → chunk-XXDRQBXY-Dez0oRoM.js} +1 -1
  57. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-CFZ_Sgh5.js +1 -0
  58. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-CFZ_Sgh5.js +1 -0
  59. package/dist/src/view/client/assets/{cose-bilkent-JH36ORCC-BCw7fCC2.js → cose-bilkent-JH36ORCC-BHtud6Hg.js} +1 -1
  60. package/dist/src/view/client/assets/{cynefin-OW5HDTMX--lYN4N9m.js → cynefin-OW5HDTMX-BjBW8VGk.js} +1 -1
  61. package/dist/src/view/client/assets/{cynefinDiagram-5FMLGOSQ-9sK5EV7v.js → cynefinDiagram-5FMLGOSQ-DwGuD7oF.js} +1 -1
  62. package/dist/src/view/client/assets/{dagre-GXQ25YYZ-CoMdEFCq.js → dagre-GXQ25YYZ-C5zSlGK9.js} +1 -1
  63. package/dist/src/view/client/assets/{diagram-S7CK7UJ4-D13dyWdd.js → diagram-S7CK7UJ4-C_NhA3bj.js} +1 -1
  64. package/dist/src/view/client/assets/{diagram-UQ7AKVKN-PdwLPPPA.js → diagram-UQ7AKVKN-az7QPYNb.js} +1 -1
  65. package/dist/src/view/client/assets/{diagram-VSXAHHWV-CtWWa_A7.js → diagram-VSXAHHWV-BRvDuM8_.js} +1 -1
  66. package/dist/src/view/client/assets/{diagram-VX7I27RA-BeCYcSU-.js → diagram-VX7I27RA-BWLgF6S-.js} +1 -1
  67. package/dist/src/view/client/assets/{diagram-Z3DM3KII-DiWabOBM.js → diagram-Z3DM3KII-DV3d6mL5.js} +1 -1
  68. package/dist/src/view/client/assets/{ebnfDiagram-PWID7BFC-CZQ3MD_K.js → ebnfDiagram-PWID7BFC-yUXrEAvK.js} +1 -1
  69. package/dist/src/view/client/assets/{erDiagram-RLTQ6QDP-B1AhXIrP.js → erDiagram-RLTQ6QDP-D35FN1Pt.js} +1 -1
  70. package/dist/src/view/client/assets/{flowDiagram-HODETNUW-Bhr0JM6P.js → flowDiagram-HODETNUW-BciZqsjT.js} +1 -1
  71. package/dist/src/view/client/assets/{ganttDiagram-EL5Y4UJY-CbP8iAkg.js → ganttDiagram-EL5Y4UJY-BysPGgXS.js} +1 -1
  72. package/dist/src/view/client/assets/{gitGraphDiagram-WWUBYQGX-B9uuGdLF.js → gitGraphDiagram-WWUBYQGX-C3DdJ5xG.js} +1 -1
  73. package/dist/src/view/client/assets/index-CJokoRSp.js +13 -0
  74. package/dist/src/view/client/assets/{infoDiagram-27XIBGKW-BrfwQ_Cq.js → infoDiagram-27XIBGKW-D3HZrDRb.js} +1 -1
  75. package/dist/src/view/client/assets/{ishikawaDiagram-5VMMS53U-CHtJ36re.js → ishikawaDiagram-5VMMS53U-BXyVIXTU.js} +1 -1
  76. package/dist/src/view/client/assets/{journeyDiagram-3NMN7TZE-BChcgX1s.js → journeyDiagram-3NMN7TZE-D4-1NxVU.js} +1 -1
  77. package/dist/src/view/client/assets/{kanban-definition-UXKFOSKX-BnwFsKiB.js → kanban-definition-UXKFOSKX-4Gu_5yBA.js} +1 -1
  78. package/dist/src/view/client/assets/{layout-Dnd0pLdb.js → layout-Jf1K3TMM.js} +1 -1
  79. package/dist/src/view/client/assets/{linear-CFhW2ozn.js → linear-DWfwzUT_.js} +1 -1
  80. package/dist/src/view/client/assets/{mermaid.core--OP6lXtW.js → mermaid.core-DMx_DAl8.js} +5 -5
  81. package/dist/src/view/client/assets/{mindmap-definition-YA3MSWOX-D51y2zbm.js → mindmap-definition-YA3MSWOX-8pxY_RWi.js} +1 -1
  82. package/dist/src/view/client/assets/{pegDiagram-XKGWAZYB--zyQJDvI.js → pegDiagram-XKGWAZYB-DNAw_O5t.js} +1 -1
  83. package/dist/src/view/client/assets/{pieDiagram-E7YTZNPT-Cj8mvpJy.js → pieDiagram-E7YTZNPT-uuvRCDkC.js} +1 -1
  84. package/dist/src/view/client/assets/{quadrantDiagram-AXDQQJYC-qvhJrnBf.js → quadrantDiagram-AXDQQJYC-BER2O4Aq.js} +1 -1
  85. package/dist/src/view/client/assets/{railroadDiagram-O6MQD6OU-CtWvxpSo.js → railroadDiagram-O6MQD6OU-CxEsJ_0n.js} +1 -1
  86. package/dist/src/view/client/assets/{requirementDiagram-BXWQKSXE-CBxen_KG.js → requirementDiagram-BXWQKSXE-yS9rspca.js} +1 -1
  87. package/dist/src/view/client/assets/{sankeyDiagram-P5KCCOFB-B_fUkmfc.js → sankeyDiagram-P5KCCOFB-Bqt70a2j.js} +1 -1
  88. package/dist/src/view/client/assets/{sequenceDiagram-WJ2MYXX4-Dclv4p68.js → sequenceDiagram-WJ2MYXX4-BvOOEJNr.js} +1 -1
  89. package/dist/src/view/client/assets/{sizeCapture-INFHLROL-GfG0sMTZ.js → sizeCapture-INFHLROL-CvO_Pjjo.js} +1 -1
  90. package/dist/src/view/client/assets/{stateDiagram-D77RDMKH-YQWPnzxU.js → stateDiagram-D77RDMKH-KLmVOZkq.js} +1 -1
  91. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-KCS8Mdzu.js +1 -0
  92. package/dist/src/view/client/assets/{swimlanes-42K2YHIH-5yiCveVS.js → swimlanes-42K2YHIH-DC1r4_sq.js} +1 -1
  93. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-B2TcAwis.js +8 -0
  94. package/dist/src/view/client/assets/{timeline-definition-24CTP7MA-BvAbB5Zs.js → timeline-definition-24CTP7MA-ChXLOuBL.js} +1 -1
  95. package/dist/src/view/client/assets/{vennDiagram-4TSXK5OY-guC-r60n.js → vennDiagram-4TSXK5OY-D9_h25-Y.js} +1 -1
  96. package/dist/src/view/client/assets/{wardleyDiagram-VM6X3IG4-C0yXcU2x.js → wardleyDiagram-VM6X3IG4-CsQJGGW0.js} +1 -1
  97. package/dist/src/view/client/assets/{xychartDiagram-S5SC5T6Z-RPmkPNfK.js → xychartDiagram-S5SC5T6Z-DGMuPMlm.js} +1 -1
  98. package/dist/src/view/client/index.html +1 -1
  99. package/dist/src/view/diagnostics.d.ts +2 -2
  100. package/dist/src/view/diagnostics.js +5 -5
  101. package/dist/src/view/external-document-tree.js +1 -1
  102. package/dist/src/view/git-diff.js +1 -1
  103. package/dist/src/view/git.js +1 -1
  104. package/dist/src/view/graph.d.ts +2 -2
  105. package/dist/src/view/graph.js +2 -2
  106. package/dist/src/view/markdown.js +1 -1
  107. package/dist/src/view/preindexed-search.d.ts +1 -1
  108. package/dist/src/view/protocol.d.ts +2 -18
  109. package/dist/src/view/publication.d.ts +2 -0
  110. package/dist/src/view/publication.js +78 -0
  111. package/dist/src/view/references.d.ts +3 -3
  112. package/dist/src/view/references.js +3 -3
  113. package/dist/src/view/repository.d.ts +6 -6
  114. package/dist/src/view/repository.js +28 -14
  115. package/dist/src/view/request-security.d.ts +5 -0
  116. package/dist/src/view/request-security.js +46 -0
  117. package/dist/src/view/search-result.d.ts +1 -1
  118. package/dist/src/view/search-result.js +1 -1
  119. package/dist/src/view/search.d.ts +1 -1
  120. package/dist/src/view/server-build.d.ts +2 -2
  121. package/dist/src/view/server-build.js +2 -2
  122. package/dist/src/view/server-deployment.d.ts +1 -2
  123. package/dist/src/view/server-deployment.js +6 -46
  124. package/dist/src/view/server-index-worker.d.ts +1 -1
  125. package/dist/src/view/server.d.ts +1 -1
  126. package/dist/src/view/server.js +13 -3
  127. package/dist/src/view/source-target.js +2 -2
  128. package/dist/src/view/static-build.d.ts +1 -1
  129. package/dist/src/view/static-build.js +49 -17
  130. package/dist/src/view/store.d.ts +4 -2
  131. package/dist/src/view/store.js +31 -19
  132. package/dist/src/view/table-of-contents.d.ts +1 -1
  133. package/dist/src/view/table-of-contents.js +1 -1
  134. package/dist/src/view/vercel-server-build.d.ts +1 -1
  135. package/package.json +19 -29
  136. package/templates/AGENTS.md +2 -2
  137. package/templates/cursor-rules.md +2 -2
  138. package/templates/opencode-plugin.ts +9 -9
  139. package/templates/pi-extension.ts +11 -11
  140. package/templates/skill/SKILL.md +2 -1
  141. package/dist/src/cli/check-context.d.ts +0 -56
  142. package/dist/src/cli/check-context.js +0 -215
  143. package/dist/src/cli/check-coverage.d.ts +0 -2
  144. package/dist/src/cli/check-coverage.js +0 -75
  145. package/dist/src/cli/check-frontmatter.d.ts +0 -12
  146. package/dist/src/cli/check-frontmatter.js +0 -44
  147. package/dist/src/cli/check-mode.d.ts +0 -21
  148. package/dist/src/cli/check-mode.js +0 -394
  149. package/dist/src/cli/check-status.d.ts +0 -74
  150. package/dist/src/cli/check-status.js +0 -217
  151. package/dist/src/cli/check.d.ts +0 -52
  152. package/dist/src/cli/check.js +0 -834
  153. package/dist/src/cli/context.d.ts +0 -11
  154. package/dist/src/cli/context.js +0 -58
  155. package/dist/src/cli/expand.d.ts +0 -7
  156. package/dist/src/cli/expand.js +0 -141
  157. package/dist/src/cli/external.d.ts +0 -11
  158. package/dist/src/cli/external.js +0 -185
  159. package/dist/src/cli/gen-index.d.ts +0 -45
  160. package/dist/src/cli/gen-index.js +0 -235
  161. package/dist/src/cli/link-scheme.d.ts +0 -54
  162. package/dist/src/cli/link-scheme.js +0 -101
  163. package/dist/src/cli/locate.d.ts +0 -2
  164. package/dist/src/cli/locate.js +0 -18
  165. package/dist/src/cli/refs.d.ts +0 -23
  166. package/dist/src/cli/refs.js +0 -274
  167. package/dist/src/cli/section.d.ts +0 -45
  168. package/dist/src/cli/section.js +0 -328
  169. package/dist/src/cli/select-menu.d.ts +0 -13
  170. package/dist/src/cli/select-menu.js +0 -100
  171. package/dist/src/code-refs.d.ts +0 -29
  172. package/dist/src/code-refs.js +0 -479
  173. package/dist/src/config.d.ts +0 -29
  174. package/dist/src/config.js +0 -83
  175. package/dist/src/context.d.ts +0 -26
  176. package/dist/src/context.js +0 -11
  177. package/dist/src/document-formats.d.ts +0 -7
  178. package/dist/src/document-formats.js +0 -39
  179. package/dist/src/extensions/alert-marker.d.ts +0 -25
  180. package/dist/src/extensions/alert-marker.js +0 -55
  181. package/dist/src/extensions/wiki-link/from-markdown.d.ts +0 -5
  182. package/dist/src/extensions/wiki-link/from-markdown.js +0 -34
  183. package/dist/src/extensions/wiki-link/index.d.ts +0 -4
  184. package/dist/src/extensions/wiki-link/index.js +0 -3
  185. package/dist/src/extensions/wiki-link/syntax.d.ts +0 -14
  186. package/dist/src/extensions/wiki-link/syntax.js +0 -121
  187. package/dist/src/extensions/wiki-link/to-markdown.d.ts +0 -5
  188. package/dist/src/extensions/wiki-link/to-markdown.js +0 -28
  189. package/dist/src/extensions/wiki-link/types.d.ts +0 -34
  190. package/dist/src/extensions/wiki-link/types.js +0 -1
  191. package/dist/src/external-documents.d.ts +0 -56
  192. package/dist/src/external-documents.js +0 -404
  193. package/dist/src/external-sources.d.ts +0 -136
  194. package/dist/src/external-sources.js +0 -1098
  195. package/dist/src/fork/frontmatter-fields.d.ts +0 -36
  196. package/dist/src/fork/frontmatter-fields.js +0 -23
  197. package/dist/src/format.d.ts +0 -16
  198. package/dist/src/format.js +0 -76
  199. package/dist/src/init-version.d.ts +0 -10
  200. package/dist/src/init-version.js +0 -49
  201. package/dist/src/lattice-model.d.ts +0 -84
  202. package/dist/src/lattice-model.js +0 -467
  203. package/dist/src/lattice.d.ts +0 -14
  204. package/dist/src/lattice.js +0 -353
  205. package/dist/src/markdown-analysis-cache.d.ts +0 -20
  206. package/dist/src/markdown-analysis-cache.js +0 -139
  207. package/dist/src/markdown-analysis-worker.d.ts +0 -16
  208. package/dist/src/markdown-analysis-worker.js +0 -33
  209. package/dist/src/markdown-analysis.d.ts +0 -61
  210. package/dist/src/markdown-analysis.js +0 -169
  211. package/dist/src/markdown-analyzer-loader.d.ts +0 -4
  212. package/dist/src/markdown-analyzer-loader.js +0 -13
  213. package/dist/src/markdown-validation.d.ts +0 -25
  214. package/dist/src/markdown-validation.js +0 -104
  215. package/dist/src/parser-cache.d.ts +0 -17
  216. package/dist/src/parser-cache.js +0 -65
  217. package/dist/src/parser-import.d.ts +0 -8
  218. package/dist/src/parser-import.js +0 -1
  219. package/dist/src/parser.d.ts +0 -3
  220. package/dist/src/parser.js +0 -93
  221. package/dist/src/path.d.ts +0 -2
  222. package/dist/src/path.js +0 -4
  223. package/dist/src/profiler.d.ts +0 -16
  224. package/dist/src/profiler.js +0 -81
  225. package/dist/src/project-analysis.d.ts +0 -59
  226. package/dist/src/project-analysis.js +0 -233
  227. package/dist/src/project-discovery.d.ts +0 -6
  228. package/dist/src/project-discovery.js +0 -30
  229. package/dist/src/repository-path.d.ts +0 -11
  230. package/dist/src/repository-path.js +0 -52
  231. package/dist/src/source-formats.d.ts +0 -7
  232. package/dist/src/source-formats.js +0 -30
  233. package/dist/src/source-parser.d.ts +0 -67
  234. package/dist/src/source-parser.js +0 -1749
  235. package/dist/src/untrusted.d.ts +0 -18
  236. package/dist/src/untrusted.js +0 -93
  237. package/dist/src/view/client/assets/channel-uy0fFvcW.js +0 -1
  238. package/dist/src/view/client/assets/classDiagram-ZZMXUADV-DbSEqjA5.js +0 -1
  239. package/dist/src/view/client/assets/classDiagram-v2-VYDZK3BY-DbSEqjA5.js +0 -1
  240. package/dist/src/view/client/assets/index-nBmbYfun.js +0 -13
  241. package/dist/src/view/client/assets/stateDiagram-v2-MP3YSRHH-gUj6Hzgl.js +0 -1
  242. package/dist/src/view/client/assets/swimlanesDiagram-VR7AAH4N-DR7JhrxL.js +0 -8
  243. package/dist/src/walk.d.ts +0 -20
  244. package/dist/src/walk.js +0 -121
@@ -1,100 +0,0 @@
1
- import { styleText } from 'node:util';
2
- /**
3
- * Display an interactive select menu with arrow-key navigation.
4
- * Returns the selected option's value, or null if the user pressed Ctrl+C.
5
- *
6
- * @param defaultIndex - initial cursor position (defaults to 0)
7
- */
8
- export async function selectMenu(options, prompt, defaultIndex) {
9
- if (options.length === 0)
10
- return null;
11
- if (!process.stdin.isTTY) {
12
- // Non-interactive fallback: return first option
13
- return options[0].value;
14
- }
15
- return new Promise((resolve) => {
16
- let cursor = defaultIndex ?? 0;
17
- const stdin = process.stdin;
18
- // Save original stdin state
19
- const wasRaw = stdin.isRaw;
20
- stdin.setRawMode(true);
21
- stdin.resume();
22
- stdin.setEncoding('utf-8');
23
- function render() {
24
- process.stdout.write('\x1B[?25l'); // hide cursor
25
- const lines = [];
26
- if (prompt) {
27
- lines.push(styleText('bold', prompt));
28
- }
29
- for (let i = 0; i < options.length; i++) {
30
- const opt = options[i];
31
- const selected = i === cursor;
32
- const pointer = selected ? '❯' : ' ';
33
- if (selected) {
34
- if (opt.accent) {
35
- lines.push(` ${pointer} ${styleText(['bgGreen', 'black', 'bold'], ` ${opt.label} `)}`);
36
- }
37
- else {
38
- lines.push(` ${pointer} ${styleText(['bgCyan', 'black', 'bold'], ` ${opt.label} `)}`);
39
- }
40
- }
41
- else {
42
- lines.push(` ${pointer} ${styleText('dim', opt.label)}`);
43
- }
44
- }
45
- process.stdout.write(lines.join('\n') + '\n');
46
- }
47
- function clearRender() {
48
- const totalLines = options.length + (prompt ? 1 : 0);
49
- // Move up and clear each line
50
- for (let i = 0; i < totalLines; i++) {
51
- process.stdout.write('\x1B[A\x1B[2K');
52
- }
53
- }
54
- function cleanup() {
55
- stdin.setRawMode(wasRaw ?? false);
56
- stdin.pause();
57
- process.stdout.write('\x1B[?25h'); // show cursor
58
- stdin.removeListener('data', onData);
59
- }
60
- function onData(data) {
61
- const key = data.toString();
62
- // Ctrl+C
63
- if (key === '\x03') {
64
- clearRender();
65
- cleanup();
66
- console.log('');
67
- process.exit(130);
68
- }
69
- // Enter
70
- if (key === '\r' || key === '\n') {
71
- clearRender();
72
- cleanup();
73
- const selected = options[cursor];
74
- // Print the selection
75
- if (prompt) {
76
- console.log(styleText('bold', prompt) +
77
- ' ' +
78
- styleText('green', selected.label));
79
- }
80
- resolve(selected.value);
81
- return;
82
- }
83
- // Arrow keys (escape sequences)
84
- if (key === '\x1B[A' || key === 'k') {
85
- // Up
86
- clearRender();
87
- cursor = (cursor - 1 + options.length) % options.length;
88
- render();
89
- }
90
- else if (key === '\x1B[B' || key === 'j') {
91
- // Down
92
- clearRender();
93
- cursor = (cursor + 1) % options.length;
94
- render();
95
- }
96
- }
97
- stdin.on('data', onData);
98
- render();
99
- });
100
- }
@@ -1,29 +0,0 @@
1
- import type { Profiler } from './profiler.js';
2
- /** Walk supported source files for code-ref scanning. Uses walkEntries for
3
- * .gitignore support, then additionally skips lat.md/, .claude/, generated
4
- * UI output, and sub-projects. */
5
- export declare function walkFiles(dir: string): Promise<string[]>;
6
- export declare const LAT_REF_RE: RegExp;
7
- export type CodeRef = {
8
- target: string;
9
- file: string;
10
- line: number;
11
- };
12
- export type ScanResult = {
13
- refs: CodeRef[];
14
- };
15
- export type CodeReferenceDiscovery = {
16
- scan: () => Promise<ScanResult>;
17
- listSourceFiles: () => Promise<string[]>;
18
- };
19
- /** Check whether ripgrep (`rg`) is available on PATH. */
20
- export declare function hasRipgrep(): Promise<boolean>;
21
- /**
22
- * Create a lazy project-scoped discovery API. Code-reference scanning and
23
- * source-file inventory are separate operations, but share ripgrep exclusion
24
- * discovery and coalesce fallback file walking when both are requested.
25
- */
26
- export declare function createCodeReferenceDiscovery(projectRoot: string, profile?: Pick<Profiler, 'time'>): CodeReferenceDiscovery;
27
- export declare function scanCodeRefs(projectRoot: string, profile?: Pick<Profiler, 'time'>): Promise<ScanResult>;
28
- /** Discover the source files that may contain code references. */
29
- export declare function discoverSourceFiles(projectRoot: string, profile?: Pick<Profiler, 'time'>): Promise<string[]>;
@@ -1,479 +0,0 @@
1
- import { lstatSync } from 'node:fs';
2
- import { readFile } from 'node:fs/promises';
3
- import { execFile } from 'node:child_process';
4
- import { availableParallelism } from 'node:os';
5
- import { join, posix, relative } from 'node:path';
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';
9
- /** Glob patterns used to exclude directories/files from code-ref scanning.
10
- * Shared between rg args and the TS fallback's walkFiles filter. */
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. */
17
- export async function walkFiles(dir) {
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.
21
- const generatedOutputs = new Set(entries
22
- .filter((entry) => entry.endsWith('/.lat-ui-build'))
23
- .map((entry) => `${posix.dirname(entry)}/`));
24
- // Collect directories that contain their own lat.md/ (sub-projects)
25
- const subProjects = new Set();
26
- for (const e of entries) {
27
- const i = e.indexOf('/lat.md/');
28
- if (i !== -1)
29
- subProjects.add(e.slice(0, i + 1));
30
- }
31
- return entries
32
- .filter((e) => isSourceFilePath(e) &&
33
- !e.startsWith('lat.md/') &&
34
- !e.startsWith('.claude/') &&
35
- ![...generatedOutputs].some((prefix) => e.startsWith(prefix)) &&
36
- ![...subProjects].some((prefix) => e.startsWith(prefix)))
37
- .map((e) => join(dir, e));
38
- }
39
- /** Build a RegExp from a verbose template — whitespace is insignificant. */
40
- function re(flags) {
41
- return (strings) => new RegExp(strings.raw[0].replace(/\s+/g, ''), flags);
42
- }
43
- // Line comment (// or #), then @lat: marker, then [[target]]
44
- export const LAT_REF_RE = re('gv') `
45
- (?: // | # )
46
- \s* @lat: \s*
47
- \[\[
48
- ( [^\]]+ )
49
- \]\]
50
- `;
51
- /** Explicit opt-out: a standalone `lat:ignore` token anywhere on the line
52
- * suppresses any @lat: match on that line. This gives an author documenting
53
- * the syntax one obvious escape hatch when a match isn't inside a
54
- * quoted/backticked literal (the common case handled by
55
- * `isInsideQuotedSpan`). Word-boundary lookarounds (rather than `\b`, which
56
- * treats `:` as a boundary on both sides already and wouldn't help) keep
57
- * incidental substrings — `lat:ignore-config`, `mylat:ignore` — from
58
- * suppressing a real ref on the same line, while still matching the token
59
- * at the very start of a line or glued directly to a comment marker
60
- * (`//lat:ignore`), since `/` isn't a word character either. */
61
- const LAT_IGNORE_RE = /(?<![\w])lat:ignore(?![-\w])/;
62
- /** Quote characters treated as delimiting a literal span: plain strings
63
- * ('...' or "...") and backtick spans, which double as inline-code markers
64
- * when a comment is documenting the @lat: syntax itself (e.g. `` `@lat:
65
- * [[section-id]]` ``). A marker whose match falls inside such a span is an
66
- * example, not a real reference, so it is not returned as a ref. */
67
- const QUOTE_CHARS = ['"', '`', "'"];
68
- /**
69
- * Returns true if `index` (an offset into `line`) falls inside a
70
- * quote-delimited span on that line. For each quote character, occurrences
71
- * are paired up in order (open, close, open, close, ...); if a quote
72
- * character appears an odd number of times on the line, it's ambiguous
73
- * (e.g. an apostrophe in prose) and is ignored entirely for that line rather
74
- * than risk hiding a real reference.
75
- */
76
- function isInsideQuotedSpan(line, index) {
77
- for (const q of QUOTE_CHARS) {
78
- const positions = [];
79
- for (let i = 0; i < line.length; i++) {
80
- if (line[i] === q && line[i - 1] !== '\\')
81
- positions.push(i);
82
- }
83
- if (positions.length < 2 || positions.length % 2 !== 0)
84
- continue;
85
- for (let i = 0; i < positions.length; i += 2) {
86
- if (index > positions[i] && index < positions[i + 1])
87
- return true;
88
- }
89
- }
90
- return false;
91
- }
92
- /** Filter regex matches on a single line, dropping ones that are inside a
93
- * quoted/backticked literal or on a line carrying an explicit `lat:ignore`
94
- * opt-out — these document the @lat: syntax rather than using it. */
95
- function extractRefsFromLine(line) {
96
- if (LAT_IGNORE_RE.test(line))
97
- return [];
98
- const targets = [];
99
- LAT_REF_RE.lastIndex = 0;
100
- let match;
101
- while ((match = LAT_REF_RE.exec(line)) !== null) {
102
- if (!isInsideQuotedSpan(line, match.index)) {
103
- targets.push(match[1]);
104
- }
105
- }
106
- return targets;
107
- }
108
- function profileScan(profile, label, work) {
109
- return profile ? profile.time(label, work) : work();
110
- }
111
- /**
112
- * Run an external command and return stdout, or null if the command is not found
113
- * or fails.
114
- */
115
- function tryExec(cmd, args, cwd) {
116
- return new Promise((resolve) => {
117
- execFile(cmd, args, { cwd, maxBuffer: 50 * 1024 * 1024 }, (err, out) => {
118
- if (err) {
119
- // Exit code 1 with no stderr typically means "no matches" for rg.
120
- const exitCode = err.code;
121
- if (exitCode === 'ENOENT') {
122
- resolve(null); // command not found
123
- return;
124
- }
125
- // rg exit 1 = no matches (not an error)
126
- if ('status' in err &&
127
- err.status === 1 &&
128
- out === '') {
129
- resolve('');
130
- return;
131
- }
132
- resolve(null);
133
- return;
134
- }
135
- resolve(out);
136
- });
137
- });
138
- }
139
- /**
140
- * Detect sub-projects (directories containing their own lat.md/) using
141
- * rg --files. Finds files inside nested lat.md/ dirs and extracts the parent
142
- * directory paths. Returns paths relative to projectRoot.
143
- */
144
- async function findSubProjects(projectRoot) {
145
- // List files inside any lat.md/ dir, then extract unique parent paths.
146
- // The root lat.md/ is excluded by EXCLUDE_DIRS in the caller, so we only
147
- // need to find nested ones here — search for files under */lat.md/.
148
- const out = await tryExec('rg', ['--files', ...RG_IGNORE_ARGS, '--glob', '**/lat.md/**', '.'], projectRoot);
149
- if (!out)
150
- return [];
151
- const subProjects = new Set();
152
- for (const rawLine of out.split('\n')) {
153
- if (!rawLine)
154
- continue;
155
- // rg emits native separators on Windows; normalize before matching '/lat.md/'.
156
- const line = toPosix(rawLine);
157
- const clean = line.startsWith('./') ? line.slice(2) : line;
158
- // "tests/cases/foo/lat.md/specs.md" → "tests/cases/foo"
159
- // Skip root lat.md/ (no parent prefix — starts with "lat.md/")
160
- const idx = clean.indexOf('/lat.md/');
161
- if (idx !== -1)
162
- subProjects.add(clean.slice(0, idx));
163
- }
164
- return [...subProjects];
165
- }
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
- */
220
- async function findGeneratedOutputs(projectRoot) {
221
- const out = await tryExec('rg', [
222
- '--files',
223
- '--hidden',
224
- ...RG_IGNORE_ARGS,
225
- '--glob',
226
- '**/.lat-ui-build',
227
- '.',
228
- ], projectRoot);
229
- if (!out)
230
- return [];
231
- return [
232
- ...new Set(out
233
- .split('\n')
234
- .filter(Boolean)
235
- .map((line) => toPosix(line).replace(/^\.\//, ''))
236
- .filter((line) => line.endsWith('/.lat-ui-build'))
237
- .map((line) => posix.dirname(line))),
238
- ];
239
- }
240
- /** Build rg glob exclusion args. */
241
- function rgExcludeArgs(subProjects, generatedOutputs = []) {
242
- const args = [];
243
- for (const dir of EXCLUDE_DIRS)
244
- args.push('--glob', `!${dir}/`);
245
- for (const glob of EXCLUDE_GLOBS)
246
- args.push('--glob', `!${glob}`);
247
- for (const sp of subProjects)
248
- args.push('--glob', `!${sp}/`);
249
- for (const output of generatedOutputs)
250
- args.push('--glob', `!${output}/`);
251
- return args;
252
- }
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) {
309
- const searchArgs = [
310
- '--no-heading',
311
- '--line-number',
312
- '--with-filename',
313
- ...RG_IGNORE_ARGS,
314
- ...rgSourceIncludeArgs(),
315
- ...excludes,
316
- '@lat:.*\\[\\[',
317
- ];
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)
337
- return null;
338
- const files = (filesOut || '')
339
- .split('\n')
340
- .filter(Boolean)
341
- .map((f) => {
342
- const clean = toPosix(f).replace(/^\.\//, '');
343
- return join(projectRoot, clean);
344
- })
345
- .sort((a, b) => a.localeCompare(b, 'en'));
346
- return files;
347
- }
348
- /**
349
- * Parse rg output lines (file:line:content) into CodeRef entries.
350
- */
351
- function parseGrepOutput(output, projectRoot) {
352
- const refs = [];
353
- if (!output.trim())
354
- return { refs };
355
- for (const line of output.split('\n')) {
356
- if (!line)
357
- continue;
358
- // Format: ./path/to/file:linenum:content
359
- const firstColon = line.indexOf(':');
360
- if (firstColon === -1)
361
- continue;
362
- const secondColon = line.indexOf(':', firstColon + 1);
363
- if (secondColon === -1)
364
- continue;
365
- // rg emits native separators (`\` on Windows); normalize to POSIX so the
366
- // stored path matches wiki-link and TS-fallback conventions. This also
367
- // turns a Windows `.\` prefix into `./` for the strip below.
368
- let filePath = toPosix(line.slice(0, firstColon));
369
- const lineNum = parseInt(line.slice(firstColon + 1, secondColon), 10);
370
- const content = line.slice(secondColon + 1);
371
- if (isNaN(lineNum))
372
- continue;
373
- // Strip leading ./ from path
374
- if (filePath.startsWith('./'))
375
- filePath = filePath.slice(2);
376
- // Extract targets using the same regex and literal-span filtering as the
377
- // TS fallback, so both scan paths agree regardless of whether ripgrep is
378
- // installed.
379
- for (const target of extractRefsFromLine(content)) {
380
- refs.push({ target, file: filePath, line: lineNum });
381
- }
382
- }
383
- return { refs };
384
- }
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
- }
396
- const refs = [];
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
- });
408
- }
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);
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);
430
- }
431
- return refs;
432
- }
433
- /** Check whether ripgrep (`rg`) is available on PATH. */
434
- export async function hasRipgrep() {
435
- const result = await tryExec('rg', ['--version'], '.');
436
- return result !== null;
437
- }
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;
458
- }
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();
479
- }
@@ -1,29 +0,0 @@
1
- export declare function getConfigDir(): string;
2
- export declare function getConfigPath(): string;
3
- export type LatConfig = {
4
- llm_key?: string;
5
- /**
6
- * Per-repo embedding backend preference, keyed by absolute lat.md dir. Durable
7
- * (survives deletion of the regenerable `.cache`), so a repo explicitly
8
- * switched to local stays local even after a cache wipe or fresh clone.
9
- */
10
- repos?: Record<string, {
11
- embedding?: 'local';
12
- }>;
13
- };
14
- export declare function readConfig(): LatConfig;
15
- export declare function writeConfig(config: LatConfig): void;
16
- /** Durable per-repo backend choice, or undefined if none recorded. */
17
- export declare function getRepoEmbedding(latDir: string): 'local' | undefined;
18
- /** Record (or clear, with `null`) the durable per-repo backend choice. */
19
- export declare function setRepoEmbedding(latDir: string, embedding: 'local' | null): void;
20
- /**
21
- * Returns the LLM key from (in priority order):
22
- * 1. LAT_LLM_KEY environment variable
23
- * 2. LAT_LLM_KEY_FILE — path to a file containing the key
24
- * 3. LAT_LLM_KEY_HELPER — shell command that prints the key
25
- * 4. llm_key field in ~/.config/lat/config.json
26
- *
27
- * Returns undefined if none is set.
28
- */
29
- export declare function getLlmKey(): string | undefined;