folderview 0.0.0-stage → 0.1.0

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 (450) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +270 -2
  3. package/dist/cli.js +115 -0
  4. package/dist/client/assets/app.css +1 -0
  5. package/dist/client/assets/chunks/abap-EINPUMCJ.js +1 -0
  6. package/dist/client/assets/chunks/abnfDiagram-S7VZAUFO-W2CM2W6D.js +1 -0
  7. package/dist/client/assets/chunks/actionscript-3-O776AQUO.js +1 -0
  8. package/dist/client/assets/chunks/ada-WLOTXRTV.js +1 -0
  9. package/dist/client/assets/chunks/ahk-EF37A2DY.js +1 -0
  10. package/dist/client/assets/chunks/ahk2-FH4K3CKT.js +1 -0
  11. package/dist/client/assets/chunks/angular-html-ZALQFV2H.js +1 -0
  12. package/dist/client/assets/chunks/angular-ts-4IWMF7QO.js +1 -0
  13. package/dist/client/assets/chunks/apache-44AYOEWM.js +1 -0
  14. package/dist/client/assets/chunks/apex-XRYPID42.js +1 -0
  15. package/dist/client/assets/chunks/apl-5HBALFOI.js +1 -0
  16. package/dist/client/assets/chunks/applescript-2DZEHZEC.js +1 -0
  17. package/dist/client/assets/chunks/ara-ZGZQBLXL.js +1 -0
  18. package/dist/client/assets/chunks/architecture-WOLXFQ4H-EJGENNRL.js +1 -0
  19. package/dist/client/assets/chunks/architectureDiagram-YGSQEFNW-2VHWSKO6.js +36 -0
  20. package/dist/client/assets/chunks/asciidoc-GSQAKCPO.js +1 -0
  21. package/dist/client/assets/chunks/asm-BFURM5BK.js +1 -0
  22. package/dist/client/assets/chunks/astro-VJORWDZJ.js +1 -0
  23. package/dist/client/assets/chunks/awk-BSHTWXXX.js +1 -0
  24. package/dist/client/assets/chunks/ballerina-HAOQJ4B2.js +1 -0
  25. package/dist/client/assets/chunks/bat-OSH45EOF.js +1 -0
  26. package/dist/client/assets/chunks/beancount-RBATIHOV.js +1 -0
  27. package/dist/client/assets/chunks/berry-CZUIOUM4.js +1 -0
  28. package/dist/client/assets/chunks/bibtex-KCL2UWHE.js +1 -0
  29. package/dist/client/assets/chunks/bicep-SZJZB3SG.js +1 -0
  30. package/dist/client/assets/chunks/bird2-XBF5YQQV.js +1 -0
  31. package/dist/client/assets/chunks/blade-Q24LEVFC.js +1 -0
  32. package/dist/client/assets/chunks/blockDiagram-APKKGZFW-53LXSOOT.js +140 -0
  33. package/dist/client/assets/chunks/bpmnIcons-APHXDYXF-FMBRQNTY.js +1 -0
  34. package/dist/client/assets/chunks/bsl-TI44NWFB.js +1 -0
  35. package/dist/client/assets/chunks/c-NLHY4Y4N.js +1 -0
  36. package/dist/client/assets/chunks/c3-BUTEM6PO.js +1 -0
  37. package/dist/client/assets/chunks/c4Diagram-KJ2TOQU5-O53G4GQH.js +38 -0
  38. package/dist/client/assets/chunks/cadence-JIRTEU64.js +1 -0
  39. package/dist/client/assets/chunks/cairo-3W6NVDNW.js +1 -0
  40. package/dist/client/assets/chunks/chapel-BPBJ2E7K.js +1 -0
  41. package/dist/client/assets/chunks/chunk-25KVF5ZE.js +1 -0
  42. package/dist/client/assets/chunks/chunk-2CJKSQOI.js +1 -0
  43. package/dist/client/assets/chunks/chunk-2QIJRTWR.js +1 -0
  44. package/dist/client/assets/chunks/chunk-2ZCRJZGF.js +2 -0
  45. package/dist/client/assets/chunks/chunk-3ILNDZNY.js +213 -0
  46. package/dist/client/assets/chunks/chunk-3M2OOQ7S.js +1 -0
  47. package/dist/client/assets/chunks/chunk-3M57NTNK.js +1 -0
  48. package/dist/client/assets/chunks/chunk-3MR6DCZJ.js +1 -0
  49. package/dist/client/assets/chunks/chunk-3WGHS7F7.js +1 -0
  50. package/dist/client/assets/chunks/chunk-4JK75V33.js +1 -0
  51. package/dist/client/assets/chunks/chunk-4NXNVEWK.js +1 -0
  52. package/dist/client/assets/chunks/chunk-4RNNBDFQ.js +1 -0
  53. package/dist/client/assets/chunks/chunk-4T4NVH7V.js +1 -0
  54. package/dist/client/assets/chunks/chunk-4TFFBC35.js +1 -0
  55. package/dist/client/assets/chunks/chunk-4WYBE67P.js +1 -0
  56. package/dist/client/assets/chunks/chunk-56ITEUFA.js +1 -0
  57. package/dist/client/assets/chunks/chunk-5DXRE7IH.js +1 -0
  58. package/dist/client/assets/chunks/chunk-5IMADCNU.js +1 -0
  59. package/dist/client/assets/chunks/chunk-5XZPGKN4.js +1 -0
  60. package/dist/client/assets/chunks/chunk-6O32UKSP.js +1 -0
  61. package/dist/client/assets/chunks/chunk-7BAEB64Q.js +1 -0
  62. package/dist/client/assets/chunks/chunk-7FMWBHZO.js +1 -0
  63. package/dist/client/assets/chunks/chunk-7GFDITUT.js +1 -0
  64. package/dist/client/assets/chunks/chunk-7H4MLBHI.js +1 -0
  65. package/dist/client/assets/chunks/chunk-7OJ4MEEB.js +1 -0
  66. package/dist/client/assets/chunks/chunk-7RSEISFE.js +1 -0
  67. package/dist/client/assets/chunks/chunk-7YNZZQVT.js +1 -0
  68. package/dist/client/assets/chunks/chunk-AB7TIL2G.js +1 -0
  69. package/dist/client/assets/chunks/chunk-ADDF76FL.js +1 -0
  70. package/dist/client/assets/chunks/chunk-AF6UTCD4.js +321 -0
  71. package/dist/client/assets/chunks/chunk-AJ2K6ASU.js +1 -0
  72. package/dist/client/assets/chunks/chunk-AUBAENQZ.js +1 -0
  73. package/dist/client/assets/chunks/chunk-BJEYVZ65.js +1 -0
  74. package/dist/client/assets/chunks/chunk-BLRM6LXA.js +1 -0
  75. package/dist/client/assets/chunks/chunk-BOCTYCDZ.js +1 -0
  76. package/dist/client/assets/chunks/chunk-BU4VRYN7.js +1 -0
  77. package/dist/client/assets/chunks/chunk-CALYHV7D.js +1 -0
  78. package/dist/client/assets/chunks/chunk-CF4W3RZ4.js +1 -0
  79. package/dist/client/assets/chunks/chunk-DCZ2OBSL.js +1 -0
  80. package/dist/client/assets/chunks/chunk-DUFPBTHD.js +1 -0
  81. package/dist/client/assets/chunks/chunk-DUICIQBC.js +88 -0
  82. package/dist/client/assets/chunks/chunk-EH2N475V.js +1 -0
  83. package/dist/client/assets/chunks/chunk-EHLLNPZT.js +1 -0
  84. package/dist/client/assets/chunks/chunk-EIBFAW37.js +1 -0
  85. package/dist/client/assets/chunks/chunk-EO3ER3GN.js +1 -0
  86. package/dist/client/assets/chunks/chunk-FH24BIIA.js +1 -0
  87. package/dist/client/assets/chunks/chunk-FNOXGAL5.js +2 -0
  88. package/dist/client/assets/chunks/chunk-FTY6WLQF.js +3 -0
  89. package/dist/client/assets/chunks/chunk-FZFME6UK.js +1 -0
  90. package/dist/client/assets/chunks/chunk-FZJZZYYO.js +1 -0
  91. package/dist/client/assets/chunks/chunk-G4Z6L7OO.js +1 -0
  92. package/dist/client/assets/chunks/chunk-GNCEAN2B.js +1 -0
  93. package/dist/client/assets/chunks/chunk-GQJIKV3T.js +1 -0
  94. package/dist/client/assets/chunks/chunk-GUMNOKT2.js +1 -0
  95. package/dist/client/assets/chunks/chunk-GXRORAF3.js +1 -0
  96. package/dist/client/assets/chunks/chunk-H36ABDKY.js +1 -0
  97. package/dist/client/assets/chunks/chunk-HAR5NYVW.js +1 -0
  98. package/dist/client/assets/chunks/chunk-HIGPS4L2.js +1 -0
  99. package/dist/client/assets/chunks/chunk-HMOBGTME.js +1 -0
  100. package/dist/client/assets/chunks/chunk-HNO6SQ7M.js +1 -0
  101. package/dist/client/assets/chunks/chunk-HYVZ3GYN.js +1 -0
  102. package/dist/client/assets/chunks/chunk-I6TGFOQS.js +1 -0
  103. package/dist/client/assets/chunks/chunk-IHIOJK7I.js +1 -0
  104. package/dist/client/assets/chunks/chunk-IHJNUMSC.js +1 -0
  105. package/dist/client/assets/chunks/chunk-IP7PB2OC.js +1 -0
  106. package/dist/client/assets/chunks/chunk-ISDTMH2Y.js +1 -0
  107. package/dist/client/assets/chunks/chunk-J65M2LNT.js +1 -0
  108. package/dist/client/assets/chunks/chunk-JCWYZ7X2.js +62 -0
  109. package/dist/client/assets/chunks/chunk-JENWYTLI.js +1 -0
  110. package/dist/client/assets/chunks/chunk-JJ6YWJQS.js +1 -0
  111. package/dist/client/assets/chunks/chunk-JMUVGGX7.js +32 -0
  112. package/dist/client/assets/chunks/chunk-JNQUFMM4.js +1 -0
  113. package/dist/client/assets/chunks/chunk-JPTECOAL.js +1 -0
  114. package/dist/client/assets/chunks/chunk-JZNK4LKS.js +1 -0
  115. package/dist/client/assets/chunks/chunk-KPNXJBIW.js +1 -0
  116. package/dist/client/assets/chunks/chunk-KZO2GZL7.js +1 -0
  117. package/dist/client/assets/chunks/chunk-L2REESOQ.js +1 -0
  118. package/dist/client/assets/chunks/chunk-LJPJXR7R.js +1 -0
  119. package/dist/client/assets/chunks/chunk-LOEZMLCI.js +1 -0
  120. package/dist/client/assets/chunks/chunk-MLYC6FSE.js +1 -0
  121. package/dist/client/assets/chunks/chunk-MMDGEZYU.js +1 -0
  122. package/dist/client/assets/chunks/chunk-MYXE7CGE.js +1 -0
  123. package/dist/client/assets/chunks/chunk-NBH7YOBD.js +15 -0
  124. package/dist/client/assets/chunks/chunk-NCOVM3YF.js +1 -0
  125. package/dist/client/assets/chunks/chunk-NCWOBVU7.js +1 -0
  126. package/dist/client/assets/chunks/chunk-NLRIHHEH.js +1 -0
  127. package/dist/client/assets/chunks/chunk-NUPEOYK6.js +1 -0
  128. package/dist/client/assets/chunks/chunk-O4MVOA7X.js +1 -0
  129. package/dist/client/assets/chunks/chunk-OBHQQZ4H.js +1 -0
  130. package/dist/client/assets/chunks/chunk-OKPNJIIR.js +1 -0
  131. package/dist/client/assets/chunks/chunk-OLMPB57R.js +1 -0
  132. package/dist/client/assets/chunks/chunk-P2FYOAEV.js +1 -0
  133. package/dist/client/assets/chunks/chunk-PI3SNP4C.js +1 -0
  134. package/dist/client/assets/chunks/chunk-PRDTEROB.js +1 -0
  135. package/dist/client/assets/chunks/chunk-PZELHD2H.js +136 -0
  136. package/dist/client/assets/chunks/chunk-QR2Q34LM.js +1 -0
  137. package/dist/client/assets/chunks/chunk-R4GIXL6S.js +1 -0
  138. package/dist/client/assets/chunks/chunk-RORF4F5V.js +1 -0
  139. package/dist/client/assets/chunks/chunk-S73BYTLL.js +1 -0
  140. package/dist/client/assets/chunks/chunk-SFC5MRYR.js +1 -0
  141. package/dist/client/assets/chunks/chunk-SVM2H22K.js +2 -0
  142. package/dist/client/assets/chunks/chunk-SZ6UCGVD.js +1 -0
  143. package/dist/client/assets/chunks/chunk-SZYM6GIJ.js +127 -0
  144. package/dist/client/assets/chunks/chunk-TT5KJZKM.js +1 -0
  145. package/dist/client/assets/chunks/chunk-UFBKUYNH.js +1 -0
  146. package/dist/client/assets/chunks/chunk-UL57AD4T.js +1 -0
  147. package/dist/client/assets/chunks/chunk-UNEI7LMM.js +1 -0
  148. package/dist/client/assets/chunks/chunk-VNQBBFIY.js +1 -0
  149. package/dist/client/assets/chunks/chunk-WGVITPII.js +1 -0
  150. package/dist/client/assets/chunks/chunk-WRA6KJHX.js +10 -0
  151. package/dist/client/assets/chunks/chunk-WS5EHW43.js +1 -0
  152. package/dist/client/assets/chunks/chunk-XE6SLBBE.js +3 -0
  153. package/dist/client/assets/chunks/chunk-XF5T2P7U.js +72 -0
  154. package/dist/client/assets/chunks/chunk-XFRY5WKO.js +1 -0
  155. package/dist/client/assets/chunks/chunk-XWYV4OPA.js +1 -0
  156. package/dist/client/assets/chunks/chunk-YCE5ECKY.js +1 -0
  157. package/dist/client/assets/chunks/chunk-YIN5CSIF.js +1 -0
  158. package/dist/client/assets/chunks/chunk-YLFUX6XH.js +1 -0
  159. package/dist/client/assets/chunks/chunk-YNXJICZM.js +1 -0
  160. package/dist/client/assets/chunks/chunk-YOHF7NGD.js +1 -0
  161. package/dist/client/assets/chunks/chunk-YORIST7Z.js +1 -0
  162. package/dist/client/assets/chunks/chunk-YUL7CG4R.js +1 -0
  163. package/dist/client/assets/chunks/chunk-YUN7JSFJ.js +2 -0
  164. package/dist/client/assets/chunks/chunk-YZ7D2IT7.js +1 -0
  165. package/dist/client/assets/chunks/chunk-Z7LAPMFJ.js +1 -0
  166. package/dist/client/assets/chunks/chunk-ZE325LPC.js +1 -0
  167. package/dist/client/assets/chunks/chunk-ZN7TN6PO.js +1 -0
  168. package/dist/client/assets/chunks/chunk-ZST3EVPO.js +1 -0
  169. package/dist/client/assets/chunks/chunk-ZZHMDDZN.js +1 -0
  170. package/dist/client/assets/chunks/clarity-RKRYQ7WF.js +1 -0
  171. package/dist/client/assets/chunks/classDiagram-v2-L25IHNXF-Y67HVDZV.js +217 -0
  172. package/dist/client/assets/chunks/clojure-2X2DQECJ.js +1 -0
  173. package/dist/client/assets/chunks/cmake-LH5524XE.js +1 -0
  174. package/dist/client/assets/chunks/cobol-7DALQF3W.js +1 -0
  175. package/dist/client/assets/chunks/codeowners-52SZU5P5.js +1 -0
  176. package/dist/client/assets/chunks/codeql-EISH3KUP.js +1 -0
  177. package/dist/client/assets/chunks/coffee-VAWSGA7Y.js +1 -0
  178. package/dist/client/assets/chunks/common-lisp-4MVK2AN6.js +1 -0
  179. package/dist/client/assets/chunks/coq-4VRYZRZV.js +1 -0
  180. package/dist/client/assets/chunks/core-BRBMZSD2.js +12 -0
  181. package/dist/client/assets/chunks/cose-bilkent-JH36ORCC-BIOOHSAA.js +1 -0
  182. package/dist/client/assets/chunks/cpp-RFECMSKD.js +1 -0
  183. package/dist/client/assets/chunks/crystal-ZBGGFAOI.js +1 -0
  184. package/dist/client/assets/chunks/csharp-BZDPMKKW.js +1 -0
  185. package/dist/client/assets/chunks/css-3WWGM6UD.js +1 -0
  186. package/dist/client/assets/chunks/csv-AB4GNWSB.js +1 -0
  187. package/dist/client/assets/chunks/cue-2E46MZP2.js +1 -0
  188. package/dist/client/assets/chunks/cynefin-EF2NZ3EQ-TLFQLWUN.js +1 -0
  189. package/dist/client/assets/chunks/cynefinDiagram-L36ESFBY-FLPXCSSG.js +62 -0
  190. package/dist/client/assets/chunks/cypher-HR3ILFOL.js +1 -0
  191. package/dist/client/assets/chunks/d-TARSZPOL.js +1 -0
  192. package/dist/client/assets/chunks/dagre-SPEB5RXH-7EGEINJ2.js +4 -0
  193. package/dist/client/assets/chunks/dart-SALLJHVI.js +1 -0
  194. package/dist/client/assets/chunks/dax-WYMRGMXC.js +1 -0
  195. package/dist/client/assets/chunks/desktop-ND5CGLLJ.js +1 -0
  196. package/dist/client/assets/chunks/diagram-3B7GL73J-6USY4HZX.js +200 -0
  197. package/dist/client/assets/chunks/diagram-DNEMPZML-BNSOC4VW.js +24 -0
  198. package/dist/client/assets/chunks/diagram-L3MUGCDN-5V5FZYIG.js +41 -0
  199. package/dist/client/assets/chunks/diagram-LA4NIPWU-25VLY2CO.js +24 -0
  200. package/dist/client/assets/chunks/diagram-MHCOC4E2-G2LFP3JU.js +3 -0
  201. package/dist/client/assets/chunks/diagram-XPFHEONP-E6HBBIBV.js +30 -0
  202. package/dist/client/assets/chunks/diff-PWYGPM7B.js +1 -0
  203. package/dist/client/assets/chunks/docker-A4D7DT7W.js +1 -0
  204. package/dist/client/assets/chunks/dotenv-VWQWV2DY.js +1 -0
  205. package/dist/client/assets/chunks/dream-maker-M5YDQS35.js +1 -0
  206. package/dist/client/assets/chunks/ebnfDiagram-UZSYDL2S-BMXXZZPI.js +1 -0
  207. package/dist/client/assets/chunks/edge-3QXIDJHI.js +1 -0
  208. package/dist/client/assets/chunks/elixir-3OX2UHIZ.js +1 -0
  209. package/dist/client/assets/chunks/elk-XV6XMXQE-IPR65FON.js +27 -0
  210. package/dist/client/assets/chunks/elm-CTS65NCT.js +1 -0
  211. package/dist/client/assets/chunks/emacs-lisp-HHS2IDO7.js +1 -0
  212. package/dist/client/assets/chunks/engine-javascript-DNHSF67B.js +141 -0
  213. package/dist/client/assets/chunks/erDiagram-EYBAPDEH-3GEHFWHG.js +99 -0
  214. package/dist/client/assets/chunks/erb-ICYWK6HS.js +1 -0
  215. package/dist/client/assets/chunks/erlang-BDQPNCKX.js +1 -0
  216. package/dist/client/assets/chunks/eventmodeling-K75KTNOO-B27BJTZL.js +1 -0
  217. package/dist/client/assets/chunks/fennel-4ONBA2PH.js +1 -0
  218. package/dist/client/assets/chunks/fish-ATLPBZSD.js +1 -0
  219. package/dist/client/assets/chunks/flowDiagram-MALGAFMO-5PCLR4AE.js +1 -0
  220. package/dist/client/assets/chunks/fluent-GGMONBVW.js +1 -0
  221. package/dist/client/assets/chunks/fortran-fixed-form-5MSBDRWQ.js +1 -0
  222. package/dist/client/assets/chunks/fortran-free-form-TT3RBL75.js +1 -0
  223. package/dist/client/assets/chunks/fsharp-PAGHNW4O.js +1 -0
  224. package/dist/client/assets/chunks/ganttDiagram-23REXITY-VE5MVBTO.js +292 -0
  225. package/dist/client/assets/chunks/gdresource-5OTP326D.js +1 -0
  226. package/dist/client/assets/chunks/gdscript-VPWHSCLF.js +1 -0
  227. package/dist/client/assets/chunks/gdshader-FYLPXFE5.js +1 -0
  228. package/dist/client/assets/chunks/genie-UYMEEMA2.js +1 -0
  229. package/dist/client/assets/chunks/gherkin-SU7D5DMY.js +1 -0
  230. package/dist/client/assets/chunks/git-commit-5CF5QAG7.js +1 -0
  231. package/dist/client/assets/chunks/git-rebase-X72BAUZI.js +1 -0
  232. package/dist/client/assets/chunks/gitGraph-VSP46ZUC-J6CJ5YZF.js +1 -0
  233. package/dist/client/assets/chunks/gitGraphDiagram-STJD7YCW-7YJGT6ZP.js +106 -0
  234. package/dist/client/assets/chunks/gleam-LR42YRKO.js +1 -0
  235. package/dist/client/assets/chunks/glimmer-js-JPF67FJU.js +1 -0
  236. package/dist/client/assets/chunks/glimmer-ts-BYPAVIZT.js +1 -0
  237. package/dist/client/assets/chunks/glsl-GTGUULBN.js +1 -0
  238. package/dist/client/assets/chunks/gn-NMDQA4K3.js +1 -0
  239. package/dist/client/assets/chunks/gnuplot-UUAMYBCZ.js +1 -0
  240. package/dist/client/assets/chunks/go-4RERSTNP.js +1 -0
  241. package/dist/client/assets/chunks/graphql-5A6RK6YF.js +1 -0
  242. package/dist/client/assets/chunks/groovy-O7BJONCU.js +1 -0
  243. package/dist/client/assets/chunks/hack-7QGTNPDP.js +1 -0
  244. package/dist/client/assets/chunks/haml-ON5GAWN4.js +1 -0
  245. package/dist/client/assets/chunks/handlebars-6UOQSUBP.js +1 -0
  246. package/dist/client/assets/chunks/haskell-OIZXZ26Y.js +1 -0
  247. package/dist/client/assets/chunks/haxe-7FFVS4FO.js +1 -0
  248. package/dist/client/assets/chunks/hcl-XFUFQJHV.js +1 -0
  249. package/dist/client/assets/chunks/hjson-QDBHMTD5.js +1 -0
  250. package/dist/client/assets/chunks/hlsl-4LP25FFN.js +1 -0
  251. package/dist/client/assets/chunks/html-7RNQXAAV.js +1 -0
  252. package/dist/client/assets/chunks/html-derivative-ESOY72Q2.js +1 -0
  253. package/dist/client/assets/chunks/http-SAD4PMBD.js +1 -0
  254. package/dist/client/assets/chunks/hurl-ZSJJXPQH.js +1 -0
  255. package/dist/client/assets/chunks/hxml-HJCC37RK.js +1 -0
  256. package/dist/client/assets/chunks/hy-CLDE3P4K.js +1 -0
  257. package/dist/client/assets/chunks/imba-REB34U5V.js +1 -0
  258. package/dist/client/assets/chunks/info-OHQRW6UA-EQQKXR77.js +1 -0
  259. package/dist/client/assets/chunks/infoDiagram-KBXO4MBG-F6KGZCGS.js +2 -0
  260. package/dist/client/assets/chunks/ini-PDFEMGRA.js +1 -0
  261. package/dist/client/assets/chunks/ishikawaDiagram-M35NCXHK-5D6ZOZ34.js +70 -0
  262. package/dist/client/assets/chunks/java-KB6XENAD.js +1 -0
  263. package/dist/client/assets/chunks/javascript-3JX5T423.js +1 -0
  264. package/dist/client/assets/chunks/jinja-V4UNU6K4.js +1 -0
  265. package/dist/client/assets/chunks/jison-KH5XNLJP.js +1 -0
  266. package/dist/client/assets/chunks/journeyDiagram-OPLOXDXO-ANDOJZKW.js +139 -0
  267. package/dist/client/assets/chunks/json-HPXFRRPY.js +1 -0
  268. package/dist/client/assets/chunks/json5-LJM6TXWM.js +1 -0
  269. package/dist/client/assets/chunks/jsonc-UZWRU3JV.js +1 -0
  270. package/dist/client/assets/chunks/jsonl-RFZD5UN4.js +1 -0
  271. package/dist/client/assets/chunks/jsonnet-GFZABBL6.js +1 -0
  272. package/dist/client/assets/chunks/jssm-2YIGBISJ.js +1 -0
  273. package/dist/client/assets/chunks/jsx-KLV2ZWUT.js +1 -0
  274. package/dist/client/assets/chunks/julia-3TZDIPPO.js +1 -0
  275. package/dist/client/assets/chunks/just-UHCONBQS.js +1 -0
  276. package/dist/client/assets/chunks/kanban-definition-BZKZHSQY-GF5I5NVD.js +89 -0
  277. package/dist/client/assets/chunks/katex-PIN72PQZ.js +257 -0
  278. package/dist/client/assets/chunks/kdl-DARTFOCL.js +1 -0
  279. package/dist/client/assets/chunks/kotlin-7KT5DW6Y.js +1 -0
  280. package/dist/client/assets/chunks/kusto-EKYXZTC5.js +1 -0
  281. package/dist/client/assets/chunks/langs-GO3UQR4H.js +1 -0
  282. package/dist/client/assets/chunks/latex-T57MIHR5.js +1 -0
  283. package/dist/client/assets/chunks/lean-5QVPRMV6.js +1 -0
  284. package/dist/client/assets/chunks/less-K6QEH5TN.js +1 -0
  285. package/dist/client/assets/chunks/liquid-3LCNNEIV.js +1 -0
  286. package/dist/client/assets/chunks/llvm-O32ZIVRF.js +1 -0
  287. package/dist/client/assets/chunks/log-C4YPJ5BB.js +1 -0
  288. package/dist/client/assets/chunks/logo-JPMO43A6.js +1 -0
  289. package/dist/client/assets/chunks/lua-YKVSOG7K.js +1 -0
  290. package/dist/client/assets/chunks/luau-K4EECYSO.js +1 -0
  291. package/dist/client/assets/chunks/make-VHSYMHHW.js +1 -0
  292. package/dist/client/assets/chunks/markdown-GC5J46H4.js +1 -0
  293. package/dist/client/assets/chunks/marko-U45YFADC.js +1 -0
  294. package/dist/client/assets/chunks/matlab-AMOKC4LU.js +1 -0
  295. package/dist/client/assets/chunks/mdc-DIGA2UXP.js +1 -0
  296. package/dist/client/assets/chunks/mdx-BZUGCKQA.js +1 -0
  297. package/dist/client/assets/chunks/mermaid-WHDP6ZPA.js +1 -0
  298. package/dist/client/assets/chunks/mermaid.core-SQMPMUDN.js +10 -0
  299. package/dist/client/assets/chunks/mindmap-definition-I2QAS2VK-4NH5S56C.js +98 -0
  300. package/dist/client/assets/chunks/mipsasm-2S4CUGQV.js +1 -0
  301. package/dist/client/assets/chunks/mojo-ZOL2PNKT.js +1 -0
  302. package/dist/client/assets/chunks/moonbit-U3BDAIFE.js +1 -0
  303. package/dist/client/assets/chunks/move-YSXALBWA.js +1 -0
  304. package/dist/client/assets/chunks/narrat-DHFIAUJH.js +1 -0
  305. package/dist/client/assets/chunks/nextflow-ESAKNTI3.js +1 -0
  306. package/dist/client/assets/chunks/nextflow-groovy-FKDSPJUI.js +1 -0
  307. package/dist/client/assets/chunks/nginx-XYAYERLO.js +1 -0
  308. package/dist/client/assets/chunks/nim-XOWBVFDH.js +1 -0
  309. package/dist/client/assets/chunks/nix-RVSTQSHC.js +1 -0
  310. package/dist/client/assets/chunks/nsis-KMDUKQRL.js +1 -0
  311. package/dist/client/assets/chunks/nushell-SKJHHZ7U.js +1 -0
  312. package/dist/client/assets/chunks/objective-c-3B3KXQ7Q.js +1 -0
  313. package/dist/client/assets/chunks/objective-cpp-6JDULPJS.js +1 -0
  314. package/dist/client/assets/chunks/ocaml-TMRFXBVO.js +1 -0
  315. package/dist/client/assets/chunks/odin-IN3PLCK7.js +1 -0
  316. package/dist/client/assets/chunks/openscad-P52IKPNH.js +1 -0
  317. package/dist/client/assets/chunks/org-N3SJ2PIA.js +1 -0
  318. package/dist/client/assets/chunks/packet-JDAUHWVQ-4SWIKSKP.js +1 -0
  319. package/dist/client/assets/chunks/pascal-T7CUWCQ4.js +1 -0
  320. package/dist/client/assets/chunks/pegDiagram-FD4XPPHP-WDKZSEGN.js +1 -0
  321. package/dist/client/assets/chunks/perl-LCZ4KODH.js +1 -0
  322. package/dist/client/assets/chunks/php-4XHMBVR5.js +1 -0
  323. package/dist/client/assets/chunks/pie-XZMESJXO-PSSWOWGV.js +1 -0
  324. package/dist/client/assets/chunks/pieDiagram-J4AKIIQI-BDW5I5ON.js +39 -0
  325. package/dist/client/assets/chunks/pkl-OACG5B67.js +1 -0
  326. package/dist/client/assets/chunks/plsql-7E5C7CJX.js +1 -0
  327. package/dist/client/assets/chunks/po-ZSREFRRP.js +1 -0
  328. package/dist/client/assets/chunks/polar-4GBINVA7.js +1 -0
  329. package/dist/client/assets/chunks/postcss-B7RPVGFW.js +1 -0
  330. package/dist/client/assets/chunks/powerquery-6UFMTY4G.js +1 -0
  331. package/dist/client/assets/chunks/powershell-3STRPCNT.js +1 -0
  332. package/dist/client/assets/chunks/prisma-4TPSPIZ5.js +1 -0
  333. package/dist/client/assets/chunks/prolog-HEAYPKQW.js +1 -0
  334. package/dist/client/assets/chunks/proto-Y3Y3VKXM.js +1 -0
  335. package/dist/client/assets/chunks/pug-7PBPMG3M.js +1 -0
  336. package/dist/client/assets/chunks/puppet-FR35R4OI.js +1 -0
  337. package/dist/client/assets/chunks/purescript-OUHXQAOW.js +1 -0
  338. package/dist/client/assets/chunks/python-SNDG7FNU.js +1 -0
  339. package/dist/client/assets/chunks/qml-UVIOSWP4.js +1 -0
  340. package/dist/client/assets/chunks/qmldir-6JGUNYL5.js +1 -0
  341. package/dist/client/assets/chunks/qss-ZCC466IZ.js +1 -0
  342. package/dist/client/assets/chunks/quadrantDiagram-XTYBLID2-5VKXWVJ6.js +7 -0
  343. package/dist/client/assets/chunks/r-4XW4O3ZF.js +1 -0
  344. package/dist/client/assets/chunks/racket-YJAYXOOG.js +1 -0
  345. package/dist/client/assets/chunks/radar-ABXABTNO-3AXZCEY2.js +1 -0
  346. package/dist/client/assets/chunks/railroad-I3PHUGI6-2PLXYPOT.js +1 -0
  347. package/dist/client/assets/chunks/railroad-abnf-LNEFI6M7-M4DGICQX.js +1 -0
  348. package/dist/client/assets/chunks/railroad-ebnf-DWYD2UWJ-UEIHQMSZ.js +1 -0
  349. package/dist/client/assets/chunks/railroad-peg-JR7BVNR7-I7VLIBXM.js +1 -0
  350. package/dist/client/assets/chunks/railroadDiagram-MRQ6NCDL-Y6IYWEFL.js +1 -0
  351. package/dist/client/assets/chunks/raku-63NEL5JK.js +1 -0
  352. package/dist/client/assets/chunks/razor-J3CJP523.js +1 -0
  353. package/dist/client/assets/chunks/rbs-6GQLT7NW.js +1 -0
  354. package/dist/client/assets/chunks/reg-6Q3OEC2C.js +1 -0
  355. package/dist/client/assets/chunks/regexp-LPIMILT3.js +1 -0
  356. package/dist/client/assets/chunks/rel-TOQGUTHB.js +1 -0
  357. package/dist/client/assets/chunks/requirementDiagram-Y7LWUY3S-CIWXVVWJ.js +84 -0
  358. package/dist/client/assets/chunks/riscv-UELGBOXE.js +1 -0
  359. package/dist/client/assets/chunks/ron-FW7LCJJH.js +1 -0
  360. package/dist/client/assets/chunks/rosmsg-O63VHE3L.js +1 -0
  361. package/dist/client/assets/chunks/rst-3WJXGLA7.js +1 -0
  362. package/dist/client/assets/chunks/ruby-7S7L6JTH.js +1 -0
  363. package/dist/client/assets/chunks/rust-LIK4HRRI.js +1 -0
  364. package/dist/client/assets/chunks/sankeyDiagram-WGJFYUXA-OGNQPX5V.js +40 -0
  365. package/dist/client/assets/chunks/sas-FHDPZ2JH.js +1 -0
  366. package/dist/client/assets/chunks/sass-UI4HW2FN.js +1 -0
  367. package/dist/client/assets/chunks/scala-KN7RQSUJ.js +1 -0
  368. package/dist/client/assets/chunks/scheme-5R527YZ5.js +1 -0
  369. package/dist/client/assets/chunks/scss-KZ6DRE4A.js +1 -0
  370. package/dist/client/assets/chunks/sdbl-FHOCL5SL.js +1 -0
  371. package/dist/client/assets/chunks/sequenceDiagram-5NDRBG5M-QX2V24ZU.js +169 -0
  372. package/dist/client/assets/chunks/shaderlab-2TLHUS2H.js +1 -0
  373. package/dist/client/assets/chunks/shellscript-PIB6ZBDM.js +1 -0
  374. package/dist/client/assets/chunks/shellsession-5KL7NFNN.js +1 -0
  375. package/dist/client/assets/chunks/sizeCapture-INFHLROL-LCS2PIHM.js +1 -0
  376. package/dist/client/assets/chunks/smalltalk-JFLFU247.js +1 -0
  377. package/dist/client/assets/chunks/smithy-HONEXZAM.js +1 -0
  378. package/dist/client/assets/chunks/solidity-SJ3INJFZ.js +1 -0
  379. package/dist/client/assets/chunks/soy-ND4SWTM2.js +1 -0
  380. package/dist/client/assets/chunks/sparql-YB2JQBZD.js +1 -0
  381. package/dist/client/assets/chunks/splunk-UXIDDAWL.js +1 -0
  382. package/dist/client/assets/chunks/sql-K6OMG7SQ.js +1 -0
  383. package/dist/client/assets/chunks/ssh-config-I7KJY3KQ.js +1 -0
  384. package/dist/client/assets/chunks/stata-DNZ3DTFJ.js +1 -0
  385. package/dist/client/assets/chunks/stateDiagram-v2-FJ4FJNEA-LVAUWF3A.js +291 -0
  386. package/dist/client/assets/chunks/stylus-GWPR6IQY.js +1 -0
  387. package/dist/client/assets/chunks/surrealql-KQNHBWLC.js +1 -0
  388. package/dist/client/assets/chunks/svelte-YQKF25S4.js +1 -0
  389. package/dist/client/assets/chunks/swift-ZCIZUJXA.js +1 -0
  390. package/dist/client/assets/chunks/swimlanes-UMQ2AFYF-B3RQOARQ.js +1 -0
  391. package/dist/client/assets/chunks/swimlanesDiagram-OMPLPG4O-JOE33EOV.js +8 -0
  392. package/dist/client/assets/chunks/system-verilog-Y7E6FIO3.js +1 -0
  393. package/dist/client/assets/chunks/systemd-WHC7NBZP.js +1 -0
  394. package/dist/client/assets/chunks/talonscript-WC7SODAH.js +1 -0
  395. package/dist/client/assets/chunks/tasl-QHY2GTCB.js +1 -0
  396. package/dist/client/assets/chunks/tcl-VAMIL5PJ.js +1 -0
  397. package/dist/client/assets/chunks/temml-ISNSX3VV.js +96 -0
  398. package/dist/client/assets/chunks/templ-B3BHKWV4.js +1 -0
  399. package/dist/client/assets/chunks/terraform-Q4UEK6FK.js +1 -0
  400. package/dist/client/assets/chunks/tex-63OWCYAB.js +1 -0
  401. package/dist/client/assets/chunks/timeline-definition-SEUHKTQE-FDFTVAJG.js +120 -0
  402. package/dist/client/assets/chunks/toml-7Z4IPGES.js +1 -0
  403. package/dist/client/assets/chunks/treeView-D4JQ5SDB-ABSGRAGI.js +1 -0
  404. package/dist/client/assets/chunks/treemap-SAJKECNS-MYX2CBJN.js +1 -0
  405. package/dist/client/assets/chunks/ts-tags-DT62HE52.js +1 -0
  406. package/dist/client/assets/chunks/tsv-RTXHWADP.js +1 -0
  407. package/dist/client/assets/chunks/tsx-UANUBOC7.js +1 -0
  408. package/dist/client/assets/chunks/turtle-QVOUNUUL.js +1 -0
  409. package/dist/client/assets/chunks/twig-ZPC4BPDA.js +1 -0
  410. package/dist/client/assets/chunks/typescript-WGWKIMMW.js +1 -0
  411. package/dist/client/assets/chunks/typespec-TYCVR32J.js +1 -0
  412. package/dist/client/assets/chunks/typst-PIBFYUO6.js +1 -0
  413. package/dist/client/assets/chunks/usecaseDiagram-AFA6YXN4-KW7ADINR.js +370 -0
  414. package/dist/client/assets/chunks/v-3ERNWBSP.js +1 -0
  415. package/dist/client/assets/chunks/vala-UCBCT2GS.js +1 -0
  416. package/dist/client/assets/chunks/vb-DGI3VTPA.js +1 -0
  417. package/dist/client/assets/chunks/vennDiagram-NNMJR3RB-RDGLGOGM.js +34 -0
  418. package/dist/client/assets/chunks/verilog-G72NZROS.js +1 -0
  419. package/dist/client/assets/chunks/vhdl-PYGA77XE.js +1 -0
  420. package/dist/client/assets/chunks/viml-OOC5B5UU.js +1 -0
  421. package/dist/client/assets/chunks/vue-GTNHIOPG.js +1 -0
  422. package/dist/client/assets/chunks/vue-html-DKAMJV55.js +1 -0
  423. package/dist/client/assets/chunks/vue-vine-WTM5HREV.js +1 -0
  424. package/dist/client/assets/chunks/vyper-RHYEHOJM.js +1 -0
  425. package/dist/client/assets/chunks/wardley-7MLQ67FV-QJL2HSBT.js +1 -0
  426. package/dist/client/assets/chunks/wardleyDiagram-S7YFUSEH-A4XX3UJR.js +78 -0
  427. package/dist/client/assets/chunks/wasm-ZMM2Z5XV.js +1 -0
  428. package/dist/client/assets/chunks/wenyan-HF5UTKSJ.js +1 -0
  429. package/dist/client/assets/chunks/wgsl-O7D7OPO7.js +1 -0
  430. package/dist/client/assets/chunks/wikitext-T7BSWSKQ.js +1 -0
  431. package/dist/client/assets/chunks/wit-TKCHPPT6.js +1 -0
  432. package/dist/client/assets/chunks/wolfram-7MN66A7N.js +1 -0
  433. package/dist/client/assets/chunks/xml-NLTLAWOD.js +1 -0
  434. package/dist/client/assets/chunks/xsl-NZ4ECK3P.js +1 -0
  435. package/dist/client/assets/chunks/xychartDiagram-GGNKY7IX-OXJILWHR.js +7 -0
  436. package/dist/client/assets/chunks/yaml-HRJLEV3V.js +1 -0
  437. package/dist/client/assets/chunks/zenscript-4LLRSLPI.js +1 -0
  438. package/dist/client/assets/chunks/zig-Y7MUQFUO.js +1 -0
  439. package/dist/client/assets/main.js +169 -0
  440. package/dist/client/index.html +48 -0
  441. package/dist/config.js +322 -0
  442. package/dist/files.js +178 -0
  443. package/dist/git.js +232 -0
  444. package/dist/glob.js +89 -0
  445. package/dist/review.js +261 -0
  446. package/dist/search.js +136 -0
  447. package/dist/server.js +420 -0
  448. package/dist/watch.js +69 -0
  449. package/dist/zip.js +100 -0
  450. package/package.json +61 -4
package/dist/search.js ADDED
@@ -0,0 +1,136 @@
1
+ // The file list (for quick open and name search) and full-text search across it.
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { isHidden, walk } from './files.js';
5
+ import { pathFilter } from './glob.js';
6
+ const MAX_FILE = 2 * 1024 * 1024;
7
+ const MAX_MATCHES = 3000;
8
+ const MAX_PER_FILE = 200;
9
+ const LINE_CAP = 400;
10
+ export class FileIndex {
11
+ scope;
12
+ git;
13
+ maxFile;
14
+ cached;
15
+ constructor(scope, git, maxFile = MAX_FILE) {
16
+ this.scope = scope;
17
+ this.git = git;
18
+ this.maxFile = maxFile;
19
+ }
20
+ invalidate() {
21
+ this.cached = undefined;
22
+ }
23
+ async files() {
24
+ if (this.cached && Date.now() - this.cached.at < 30_000)
25
+ return this.cached.files;
26
+ let files;
27
+ if (this.git)
28
+ files = await this.git.files().catch(() => undefined);
29
+ files ??= walk(this.scope);
30
+ files = files.filter((f) => !f.split('/').some((p) => isHidden(this.scope, p)) && !this.scope.excluded(f) && fs.existsSync(path.join(this.scope.root, f)));
31
+ this.cached = { at: Date.now(), files };
32
+ return files;
33
+ }
34
+ async search(query) {
35
+ const t0 = Date.now();
36
+ const result = { files: [], total: 0, truncated: false, searched: 0, ms: 0 };
37
+ let re;
38
+ try {
39
+ re = makeRegex(query);
40
+ }
41
+ catch (e) {
42
+ return { ...result, error: e instanceof Error ? e.message : String(e) };
43
+ }
44
+ const prefix = query.scope.replace(/^\/+|\/+$/g, '');
45
+ const filter = pathFilter(query.include);
46
+ const all = (await this.files()).filter((f) => (!prefix || f.startsWith(prefix + '/')) && filter(f));
47
+ // in git, git grep says which files can match; only those are read (names are still checked on every file)
48
+ const maybe = this.git ? await this.git.grepFiles(query.q, { regex: query.regex, caseSensitive: query.caseSensitive, word: query.word }) : undefined;
49
+ // read many files at once (each read is mostly waiting on the disk), keep the results in path order
50
+ const found = new Array(all.length);
51
+ let next = 0;
52
+ const worker = async () => {
53
+ while (next < all.length && result.total < MAX_MATCHES) {
54
+ const idx = next++;
55
+ const file = all[idx] ?? '';
56
+ const hits = { path: file, matches: [] };
57
+ re.lastIndex = 0;
58
+ if (re.test(file.slice(file.lastIndexOf('/') + 1)))
59
+ hits.name = true;
60
+ const text = maybe && !maybe.has(file) ? undefined : await readText(path.join(this.scope.root, file), this.maxFile);
61
+ if (maybe && !maybe.has(file))
62
+ result.searched++;
63
+ if (text !== undefined) {
64
+ result.searched++;
65
+ const lines = text.split('\n');
66
+ for (let i = 0; i < lines.length && hits.matches.length < MAX_PER_FILE; i++) {
67
+ const line = (lines[i] ?? '').replace(/\r$/, '');
68
+ const ranges = hitsIn(re, line);
69
+ if (ranges.length)
70
+ hits.matches.push(clip(i + 1, line, ranges));
71
+ }
72
+ }
73
+ if (hits.matches.length || hits.name) {
74
+ found[idx] = hits;
75
+ result.total += hits.matches.length || 1;
76
+ }
77
+ }
78
+ };
79
+ await Promise.all(Array.from({ length: 48 }, worker));
80
+ result.truncated = next < all.length;
81
+ result.files = found.filter((f) => f !== undefined);
82
+ result.ms = Date.now() - t0;
83
+ return result;
84
+ }
85
+ }
86
+ function makeRegex(q) {
87
+ let src = q.regex ? q.q : q.q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
88
+ if (q.word)
89
+ src = `\\b(?:${src})\\b`;
90
+ const re = new RegExp(src, q.caseSensitive ? 'g' : 'gi');
91
+ if (re.test(''))
92
+ throw new Error('That pattern matches nothing at all (an empty match).');
93
+ return re;
94
+ }
95
+ function hitsIn(re, line) {
96
+ const out = [];
97
+ re.lastIndex = 0;
98
+ let m;
99
+ while ((m = re.exec(line)) && out.length < 50) {
100
+ if (m[0] === '') {
101
+ re.lastIndex++;
102
+ continue;
103
+ }
104
+ out.push([m.index, m.index + m[0].length]);
105
+ }
106
+ return out;
107
+ }
108
+ /** long lines are cut around the first hit so the result stays readable */
109
+ function clip(line, text, hits) {
110
+ if (text.length <= LINE_CAP)
111
+ return { line, text, hits };
112
+ const first = hits[0]?.[0] ?? 0;
113
+ const start = Math.max(0, first - 80);
114
+ const end = Math.min(text.length, start + LINE_CAP);
115
+ const lead = start > 0 ? '…' : '';
116
+ const shift = start - lead.length;
117
+ return {
118
+ line,
119
+ text: lead + text.slice(start, end) + (end < text.length ? '…' : ''),
120
+ hits: hits.filter(([a, b]) => a >= start && b <= end).map(([a, b]) => [a - shift, b - shift]),
121
+ };
122
+ }
123
+ async function readText(abs, max) {
124
+ try {
125
+ const st = await fs.promises.stat(abs);
126
+ if (!st.isFile() || st.size > max)
127
+ return undefined;
128
+ const buf = await fs.promises.readFile(abs);
129
+ if (buf.subarray(0, 8192).includes(0))
130
+ return undefined; // binary
131
+ return buf.toString('utf8');
132
+ }
133
+ catch {
134
+ return undefined;
135
+ }
136
+ }
package/dist/server.js ADDED
@@ -0,0 +1,420 @@
1
+ // The HTTP server: the page, the folder API, git, search, review comments and live-reload events.
2
+ import http from 'node:http';
3
+ import fs from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import crypto from 'node:crypto';
8
+ import { NOISE, RAW_TYPES, inside, isHidden, list, serveRaw, toRel } from './files.js';
9
+ import { excluder, parseRules } from './glob.js';
10
+ import { writeZip, ZIP_LIMITS } from './zip.js';
11
+ import { Git } from './git.js';
12
+ import { FileIndex } from './search.js';
13
+ import { Review, agentPrompt } from './review.js';
14
+ import { watchTree } from './watch.js';
15
+ const here = path.dirname(fileURLToPath(import.meta.url));
16
+ const clientDir = path.resolve(here, 'client');
17
+ const version = readVersion();
18
+ const STATIC = {
19
+ '.html': 'text/html; charset=utf-8',
20
+ '.js': 'text/javascript; charset=utf-8',
21
+ '.css': 'text/css; charset=utf-8',
22
+ '.svg': 'image/svg+xml',
23
+ '.woff2': 'font/woff2',
24
+ '.woff': 'font/woff',
25
+ '.ttf': 'font/ttf',
26
+ };
27
+ export async function start(opts) {
28
+ const root = path.resolve(opts.root);
29
+ const scope = {
30
+ root,
31
+ hidden: new Set(['.git', ...(opts.hide ?? [])]),
32
+ hideSecrets: !opts.showSecrets,
33
+ excluded: excluder(parseRules(opts.exclude ?? [])),
34
+ };
35
+ const git = opts.git ? await Git.open(root) : undefined;
36
+ const base = opts.base ?? '/';
37
+ const token = opts.token ?? '';
38
+ const maxFile = (opts.maxFileMb ?? 5) * 1048576;
39
+ const index = new FileIndex(scope, git, (opts.maxFileMb ?? 5) * 1048576);
40
+ const review = new Review(path.resolve(root, opts.reviewDir), root);
41
+ const reviewRel = toRel(scope, review.jsonPath);
42
+ const author = opts.author || (git && (await git.userName())) || os.userInfo().username || 'reviewer';
43
+ const visible = (rel) => !rel.split('/').some((p) => isHidden(scope, p)) && !scope.excluded(rel);
44
+ // ── live events ──
45
+ const clients = new Set();
46
+ const broadcast = (type, data) => {
47
+ const msg = `event: ${type}\ndata: ${JSON.stringify(data)}\n\n`;
48
+ for (const c of clients)
49
+ c.write(msg);
50
+ };
51
+ let status;
52
+ // the review notes are ours, not the project's: keep them out of the changes
53
+ const reviewPrefix = reviewRel.startsWith('..') ? '' : toRel(scope, review.dir) + '/';
54
+ const gitStatus = () => (status ??= git
55
+ ? git.status().then((s) => ({
56
+ ...s,
57
+ changes: s.changes.filter((c) => (!reviewPrefix || !c.path.startsWith(reviewPrefix)) && visible(c.path)),
58
+ ignored: s.ignored.filter((i) => visible(i.replace(/\/$/, ''))),
59
+ }))
60
+ : Promise.reject(new Error('not a git repository')));
61
+ const stopWatch = opts.watch
62
+ ? watchTree(root, git ? path.join(git.top, '.git') : undefined, (b) => {
63
+ if (b.git)
64
+ status = undefined;
65
+ if (b.folders.length || b.files.length)
66
+ index.invalidate();
67
+ broadcast('change', b);
68
+ })
69
+ : () => undefined;
70
+ review.onChange(() => {
71
+ broadcast('comments', { count: review.all().length });
72
+ opts.onReviewChange?.(review.all().filter((c) => c.status === 'open').length, review.all().length);
73
+ });
74
+ review.watch();
75
+ const ping = setInterval(() => {
76
+ for (const c of clients)
77
+ c.write(': ping\n\n');
78
+ }, 25_000);
79
+ ping.unref();
80
+ const allowed = allowedHosts(opts);
81
+ const server = http.createServer((req, res) => {
82
+ handle(req, res).catch((err) => {
83
+ if (!res.headersSent)
84
+ json(res, 500, { error: err instanceof Error ? err.message : String(err) });
85
+ else
86
+ res.end();
87
+ });
88
+ });
89
+ async function handle(req, res) {
90
+ // DNS rebinding: a page on another site that resolves its name to this machine is refused
91
+ const host = (req.headers.host ?? '').replace(/:\d+$/, '').replace(/^\[|\]$/g, '').toLowerCase();
92
+ if (!allowed(host))
93
+ return json(res, 403, { error: `Host "${host}" is not allowed. Start with --allow-host ${host} to allow it.` });
94
+ const url = new URL(req.url ?? '/', 'http://x');
95
+ // served under a path (behind a proxy): everything lives below it
96
+ if (base !== '/') {
97
+ if (url.pathname === base.slice(0, -1))
98
+ return void res.writeHead(301, { location: base + url.search }).end();
99
+ if (!url.pathname.startsWith(base))
100
+ return json(res, 404, { error: 'not found' });
101
+ }
102
+ const p = '/' + url.pathname.slice(base.length);
103
+ // a token: once in the address (it becomes a cookie), as a bearer header, or the cookie
104
+ if (token) {
105
+ const given = url.searchParams.get('token') ?? bearer(req) ?? cookie(req, 'folderview_token') ?? '';
106
+ if (!same(given, token)) {
107
+ if (p === '/' || p === '/index.html')
108
+ return void res.writeHead(401, { 'content-type': 'text/html; charset=utf-8' }).end(LOCKED);
109
+ return json(res, 401, { error: 'This folderview needs its token: open the link with ?token=… once.' });
110
+ }
111
+ if (url.searchParams.has('token')) {
112
+ // keep it as a cookie and take it out of the address bar
113
+ url.searchParams.delete('token');
114
+ res.setHeader('set-cookie', `folderview_token=${encodeURIComponent(token)}; Path=${base}; HttpOnly; SameSite=Strict; Max-Age=31536000`);
115
+ if (p === '/' || p === '/index.html')
116
+ return void res.writeHead(302, { location: base + (url.search || '') }).end();
117
+ }
118
+ }
119
+ const q = (k) => url.searchParams.get(k) ?? '';
120
+ const method = req.method ?? 'GET';
121
+ if (method !== 'GET' && method !== 'HEAD') {
122
+ // writes come only from this page: a JSON body and our own origin
123
+ const origin = req.headers.origin;
124
+ if (origin && new URL(origin).host !== req.headers.host)
125
+ return json(res, 403, { error: 'Cross-origin write refused' });
126
+ if (opts.readOnly)
127
+ return json(res, 403, { error: 'This folderview is read-only' });
128
+ }
129
+ if (p === '/' || p === '/index.html')
130
+ return sendStatic(res, path.join(clientDir, 'index.html'));
131
+ if (p.startsWith('/assets/')) {
132
+ const abs = path.resolve(clientDir, '.' + p);
133
+ if (!abs.startsWith(clientDir + path.sep))
134
+ return json(res, 404, { error: 'not found' });
135
+ return sendStatic(res, abs);
136
+ }
137
+ if (p.startsWith('/raw/')) {
138
+ const rel = decodeURIComponent(p.slice(5));
139
+ if (q('download') === '1')
140
+ res.setHeader('content-disposition', disposition(path.basename(rel)));
141
+ return serveRaw(scope, rel, req, res, q('as') === 'page');
142
+ }
143
+ if (p === '/api/zip')
144
+ return zipFolder(q('p'), res);
145
+ if (p === '/api/info') {
146
+ return json(res, 200, {
147
+ name: opts.title || path.basename(root) || root,
148
+ // the home folder as ~, so a shared screen or screenshot doesn't show the user's account name
149
+ root: root.startsWith(os.homedir()) ? '~' + root.slice(os.homedir().length) : root,
150
+ version,
151
+ git: !!git,
152
+ gitPrefix: git?.prefix ?? '',
153
+ author,
154
+ readOnly: opts.readOnly,
155
+ review: {
156
+ json: reviewRel,
157
+ md: toRel(scope, review.mdPath),
158
+ dir: opts.reviewLabel ?? opts.reviewDir,
159
+ prompt: agentPrompt(toRel(scope, review.mdPath), reviewRel),
160
+ },
161
+ hostname: os.hostname(),
162
+ maxFile,
163
+ token: !!token,
164
+ });
165
+ }
166
+ if (p === '/api/list') {
167
+ const entries = list(scope, q('p'));
168
+ return entries ? json(res, 200, { entries }) : json(res, 404, { error: 'No such folder' });
169
+ }
170
+ if (p === '/api/stat') {
171
+ const abs = inside(scope, q('p'));
172
+ if (!abs || !fs.existsSync(abs))
173
+ return json(res, 404, { error: 'not found' });
174
+ const st = fs.statSync(abs);
175
+ return json(res, 200, { type: st.isDirectory() ? 'folder' : 'file', size: st.size, mtime: st.mtimeMs });
176
+ }
177
+ if (p === '/api/files')
178
+ return json(res, 200, { files: await index.files() });
179
+ if (p === '/api/search') {
180
+ if (!q('q'))
181
+ return json(res, 400, { error: 'Nothing to search for' });
182
+ const result = await index.search({
183
+ q: q('q'),
184
+ scope: q('scope'),
185
+ regex: q('regex') === '1',
186
+ caseSensitive: q('case') === '1',
187
+ word: q('word') === '1',
188
+ include: q('include'),
189
+ });
190
+ // the review notes would match every word that was commented on: leave them out
191
+ if (reviewPrefix)
192
+ result.files = result.files.filter((f) => !f.path.startsWith(reviewPrefix));
193
+ return json(res, 200, result);
194
+ }
195
+ if (p.startsWith('/api/git/')) {
196
+ if (!git)
197
+ return json(res, 404, { error: 'Not a git repository' });
198
+ const rel = q('p');
199
+ if (p !== '/api/git/status' && inside(scope, rel) === undefined)
200
+ return json(res, 404, { error: 'not found' });
201
+ switch (p) {
202
+ case '/api/git/status':
203
+ return json(res, 200, await gitStatus());
204
+ case '/api/git/diff':
205
+ return text(res, await git.diff(rel));
206
+ case '/api/git/show': {
207
+ const rev = q('rev') || 'HEAD';
208
+ if (!isRev(rev))
209
+ return json(res, 400, { error: 'bad revision' });
210
+ return text(res, await git.show(rel, rev));
211
+ }
212
+ case '/api/git/raw': {
213
+ const rev = q('rev') || 'HEAD';
214
+ if (!isRev(rev))
215
+ return json(res, 400, { error: 'bad revision' });
216
+ const buf = await git.showRaw(rel, rev);
217
+ const ext = path.extname(rel).slice(1).toLowerCase();
218
+ res.writeHead(200, { 'content-type': RAW_TYPES[ext] ?? 'application/octet-stream', 'cache-control': 'no-store', 'content-security-policy': "default-src 'none'; style-src 'unsafe-inline'", 'x-content-type-options': 'nosniff' });
219
+ return void res.end(buf);
220
+ }
221
+ case '/api/git/log':
222
+ return json(res, 200, { commits: await git.log(rel) });
223
+ case '/api/git/commit': {
224
+ const h = q('h');
225
+ if (!isRev(h))
226
+ return json(res, 400, { error: 'bad revision' });
227
+ return text(res, await git.commitDiff(rel, h));
228
+ }
229
+ }
230
+ return json(res, 404, { error: 'not found' });
231
+ }
232
+ if (p === '/api/review.md') {
233
+ return text(res, fs.existsSync(review.mdPath) ? fs.readFileSync(review.mdPath, 'utf8') : 'No comments yet.\n', 'text/markdown; charset=utf-8');
234
+ }
235
+ if (p === '/api/comments' && method === 'GET')
236
+ return json(res, 200, { comments: review.all() });
237
+ if (p === '/api/comments' && method === 'POST') {
238
+ const b = await body(req);
239
+ const rel = str(b['path']);
240
+ if (inside(scope, rel) === undefined)
241
+ return json(res, 400, { error: 'No such file' });
242
+ if (!str(b['body']).trim())
243
+ return json(res, 400, { error: 'The comment is empty' });
244
+ const line = num(b['line']), endLine = num(b['endLine']);
245
+ const c = review.add({
246
+ path: rel,
247
+ body: str(b['body']),
248
+ author: str(b['author']) || author,
249
+ ...(line ? { line } : {}),
250
+ ...(endLine ? { endLine } : {}),
251
+ ...(git ? { commit: (await gitStatus().catch(() => undefined))?.head ?? '' } : {}),
252
+ });
253
+ return json(res, 201, c);
254
+ }
255
+ if (p === '/api/comments' && method === 'DELETE' && q('resolved') === '1')
256
+ return json(res, 200, { removed: review.clearResolved() });
257
+ const m = /^\/api\/comments\/([0-9a-f]+)(\/replies)?$/.exec(p);
258
+ if (m) {
259
+ const id = m[1] ?? '';
260
+ if (m[2] && method === 'POST') {
261
+ const b = await body(req);
262
+ const c = review.reply(id, str(b['author']) || author, str(b['body']));
263
+ return c ? json(res, 200, c) : json(res, 404, { error: 'not found' });
264
+ }
265
+ if (method === 'PATCH') {
266
+ const b = await body(req);
267
+ const s = str(b['status']);
268
+ const patch = {};
269
+ if (typeof b['body'] === 'string')
270
+ patch.body = b['body'];
271
+ if (s === 'open' || s === 'resolved')
272
+ patch.status = s;
273
+ const c = review.update(id, patch);
274
+ return c ? json(res, 200, c) : json(res, 404, { error: 'not found' });
275
+ }
276
+ if (method === 'DELETE')
277
+ return review.remove(id) ? json(res, 200, { ok: true }) : json(res, 404, { error: 'not found' });
278
+ }
279
+ if (p === '/api/events') {
280
+ res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-store', connection: 'keep-alive' });
281
+ res.write(`event: hello\ndata: {"watch":${opts.watch}}\n\n`);
282
+ clients.add(res);
283
+ req.on('close', () => clients.delete(res));
284
+ return;
285
+ }
286
+ json(res, 404, { error: 'not found' });
287
+ }
288
+ /** a folder as a zip: what the listing shows (no hidden, excluded or noise folders), within the zip limits */
289
+ async function zipFolder(rel, res) {
290
+ const abs = inside(scope, rel);
291
+ if (!abs || !fs.existsSync(abs) || !fs.statSync(abs).isDirectory())
292
+ return json(res, 404, { error: 'No such folder' });
293
+ const name = rel ? path.basename(abs) : path.basename(root) || 'folder';
294
+ const files = [];
295
+ let bytes = 0;
296
+ const stack = [rel];
297
+ while (stack.length) {
298
+ const dir = stack.pop() ?? '';
299
+ for (const e of list(scope, dir) ?? []) {
300
+ const child = dir ? dir + '/' + e.name : e.name;
301
+ if (e.type === 'folder') {
302
+ if (!NOISE.has(e.name))
303
+ stack.push(child);
304
+ continue;
305
+ }
306
+ bytes += e.size;
307
+ files.push({ abs: path.join(root, child), name: path.posix.join(name, rel ? child.slice(rel.length + 1) : child) });
308
+ }
309
+ if (files.length > ZIP_LIMITS.files || bytes > ZIP_LIMITS.bytes)
310
+ return json(res, 413, { error: `Too big to zip here (${files.length.toLocaleString()} files, ${Math.round(bytes / 1048576)} MB so far)` });
311
+ }
312
+ files.sort((a, b) => a.name.localeCompare(b.name));
313
+ res.writeHead(200, { 'content-type': 'application/zip', 'content-disposition': disposition(name + '.zip'), 'cache-control': 'no-store' });
314
+ await writeZip(res, files);
315
+ res.end();
316
+ }
317
+ const port = await listen(server, opts.port, opts.host);
318
+ return {
319
+ server,
320
+ port,
321
+ close: async () => {
322
+ stopWatch();
323
+ review.close();
324
+ clearInterval(ping);
325
+ for (const c of clients)
326
+ c.end();
327
+ await new Promise((r) => server.close(() => r()));
328
+ },
329
+ };
330
+ }
331
+ /** listen on the port, or the next free one */
332
+ function listen(server, port, host, tries = 20) {
333
+ return new Promise((resolve, reject) => {
334
+ const onError = (err) => {
335
+ server.off('listening', onListening);
336
+ if (err.code === 'EADDRINUSE' && tries > 1 && port !== 0)
337
+ resolve(listen(server, port + 1, host, tries - 1));
338
+ else
339
+ reject(err);
340
+ };
341
+ const onListening = () => {
342
+ server.off('error', onError);
343
+ const a = server.address();
344
+ resolve(typeof a === 'object' && a ? a.port : port);
345
+ };
346
+ server.once('error', onError);
347
+ server.once('listening', onListening);
348
+ server.listen(port, host);
349
+ });
350
+ }
351
+ const LOCKED = '<!doctype html><meta name="viewport" content="width=device-width"><title>folderview</title><body style="font:16px system-ui;padding:2em;max-width:36em;margin:auto"><h1>🔒 This folderview needs its token</h1><p>Open the link you were given (it ends in <code>?token=…</code>). It is kept as a cookie, so you only need it once.</p>';
352
+ const bearer = (req) => /^Bearer (.+)$/i.exec(String(req.headers.authorization ?? ''))?.[1];
353
+ const cookie = (req, name) => {
354
+ for (const part of String(req.headers.cookie ?? '').split(';')) {
355
+ const [k, ...v] = part.trim().split('=');
356
+ if (k === name)
357
+ return decodeURIComponent(v.join('='));
358
+ }
359
+ return undefined;
360
+ };
361
+ function same(a, b) {
362
+ const x = crypto.createHash('sha256').update(a).digest();
363
+ const y = crypto.createHash('sha256').update(b).digest();
364
+ return crypto.timingSafeEqual(x, y);
365
+ }
366
+ const disposition = (name) => `attachment; filename="${name.replace(/[^\x20-\x7e]|["\\]/g, '_')}"; filename*=UTF-8''${encodeURIComponent(name)}`;
367
+ function allowedHosts(opts) {
368
+ const names = new Set(['localhost', os.hostname().toLowerCase(), ...opts.allowHosts.map((h) => h.toLowerCase())]);
369
+ if (opts.host !== '0.0.0.0' && opts.host !== '::')
370
+ names.add(opts.host.toLowerCase());
371
+ return (h) => names.has(h) ||
372
+ h.endsWith('.localhost') ||
373
+ /^\d{1,3}(\.\d{1,3}){3}$/.test(h) || // an IP address can't be rebound
374
+ h.includes(':') || // IPv6 literal
375
+ opts.allowHosts.includes('*');
376
+ }
377
+ function isRev(r) {
378
+ return /^[0-9a-f]{4,40}$/i.test(r) || /^HEAD(~\d{1,4}|\^)?$/.test(r);
379
+ }
380
+ function sendStatic(res, abs) {
381
+ fs.readFile(abs, (err, buf) => {
382
+ if (err)
383
+ return json(res, 404, { error: 'not found' });
384
+ res.writeHead(200, { 'content-type': STATIC[path.extname(abs)] ?? 'application/octet-stream', 'cache-control': 'no-store' }).end(buf);
385
+ });
386
+ }
387
+ function json(res, code, data) {
388
+ res.writeHead(code, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }).end(JSON.stringify(data));
389
+ }
390
+ function text(res, body, type = 'text/plain; charset=utf-8') {
391
+ res.writeHead(200, { 'content-type': type, 'cache-control': 'no-store' }).end(body);
392
+ }
393
+ async function body(req) {
394
+ if (!String(req.headers['content-type'] ?? '').includes('application/json'))
395
+ throw new Error('Send JSON');
396
+ const chunks = [];
397
+ let size = 0;
398
+ for await (const c of req) {
399
+ const b = Buffer.isBuffer(c) ? c : Buffer.from(String(c));
400
+ size += b.length;
401
+ if (size > 1_000_000)
402
+ throw new Error('Too large');
403
+ chunks.push(b);
404
+ }
405
+ const data = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}');
406
+ if (!data || typeof data !== 'object' || Array.isArray(data))
407
+ throw new Error('Send a JSON object');
408
+ return Object.fromEntries(Object.entries(data));
409
+ }
410
+ const str = (v) => (typeof v === 'string' ? v : '');
411
+ const num = (v) => (typeof v === 'number' && Number.isInteger(v) && v > 0 ? v : undefined);
412
+ function readVersion() {
413
+ try {
414
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(here, '..', 'package.json'), 'utf8'));
415
+ return pkg && typeof pkg === 'object' && 'version' in pkg ? String(pkg.version) : '0.0.0';
416
+ }
417
+ catch {
418
+ return '0.0.0';
419
+ }
420
+ }
package/dist/watch.js ADDED
@@ -0,0 +1,69 @@
1
+ // Live reload: watches the folder and tells open pages which folders changed (and when git's state may have).
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { NOISE } from './files.js';
5
+ export function watchTree(root, gitDir, onBatch) {
6
+ let folders = new Set(), files = new Set(), git = false;
7
+ let timer;
8
+ const flush = () => {
9
+ timer = undefined;
10
+ const b = { folders: [...folders], files: [...files], git };
11
+ folders = new Set();
12
+ files = new Set();
13
+ git = false;
14
+ onBatch(b);
15
+ };
16
+ const bump = () => {
17
+ timer ??= setTimeout(flush, 250);
18
+ };
19
+ const closers = [];
20
+ try {
21
+ const w = fs.watch(root, { recursive: true }, (_event, name) => {
22
+ if (!name)
23
+ return bump();
24
+ const rel = String(name).split(path.sep).join('/');
25
+ const parts = rel.split('/');
26
+ if (parts[0] === '.git') {
27
+ // the index, HEAD and refs say git's view moved; objects and logs are noise
28
+ if (/^\.git\/(index|HEAD|refs\/|packed-refs|MERGE_HEAD)/.test(rel)) {
29
+ git = true;
30
+ bump();
31
+ }
32
+ return;
33
+ }
34
+ if (parts.some((p) => NOISE.has(p)))
35
+ return;
36
+ files.add(rel);
37
+ folders.add(parts.slice(0, -1).join('/'));
38
+ git = true; // a working-tree edit changes git status too
39
+ bump();
40
+ });
41
+ w.on('error', () => undefined);
42
+ closers.push(() => w.close());
43
+ }
44
+ catch {
45
+ // recursive watching isn't available here: no live reload, the page still works on refresh
46
+ }
47
+ // a served subfolder of a repo: .git is elsewhere, watch it on its own
48
+ if (gitDir && !gitDir.startsWith(root + path.sep)) {
49
+ try {
50
+ const w = fs.watch(gitDir, (_e, name) => {
51
+ if (name && /^(index|HEAD|packed-refs)$/.test(String(name))) {
52
+ git = true;
53
+ bump();
54
+ }
55
+ });
56
+ w.on('error', () => undefined);
57
+ closers.push(() => w.close());
58
+ }
59
+ catch {
60
+ // fine without it
61
+ }
62
+ }
63
+ return () => {
64
+ for (const c of closers)
65
+ c();
66
+ if (timer)
67
+ clearTimeout(timer);
68
+ };
69
+ }