mdrules 0.0.0-stage → 0.1.1

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 (287) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +107 -2
  3. package/dist/cli.js +926 -0
  4. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  5. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  6. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  7. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  8. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  9. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  10. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  11. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  12. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  13. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  14. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  15. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  16. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  17. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  18. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  19. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  20. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  21. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  22. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  23. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  24. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  25. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  26. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  27. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  28. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  29. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  30. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  31. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  32. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  33. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  34. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  35. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  36. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  37. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  38. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  39. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  40. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  41. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  42. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  43. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  44. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  45. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  46. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  47. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  48. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  49. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  50. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  51. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  52. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  53. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  54. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  55. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  56. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  57. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  58. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  59. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  60. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  61. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  62. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  63. package/dist/web/assets/abnfDiagram-WEYOIA3C-DKgk2hIQ.js +1 -0
  64. package/dist/web/assets/apl-gfMMiTNf.js +1 -0
  65. package/dist/web/assets/arc-CCAU-51h.js +1 -0
  66. package/dist/web/assets/architecture-WOLXFQ4H-BcNYkHmW.js +1 -0
  67. package/dist/web/assets/architectureDiagram-ZHVYKT53-DgRlfGj2.js +36 -0
  68. package/dist/web/assets/array-BifhSqXX.js +1 -0
  69. package/dist/web/assets/asciiarmor-C_eisQCp.js +1 -0
  70. package/dist/web/assets/asn1-DCl_8MCW.js +1 -0
  71. package/dist/web/assets/asterisk-BEn0Cwpx.js +1 -0
  72. package/dist/web/assets/blockDiagram-RJAE7QA3-DoBplOhb.js +140 -0
  73. package/dist/web/assets/brainfuck-D5EjA2JK.js +1 -0
  74. package/dist/web/assets/c4Diagram-XDPPPE54-CGKzgX6O.js +38 -0
  75. package/dist/web/assets/channel-BWmWik05.js +1 -0
  76. package/dist/web/assets/chunk-2E7WHVMD-DhQx5a0n.js +88 -0
  77. package/dist/web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  78. package/dist/web/assets/chunk-4EMNKR2T-vHF11V5m.js +1 -0
  79. package/dist/web/assets/chunk-55XCU76K-DgZ0btzr.js +1 -0
  80. package/dist/web/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  81. package/dist/web/assets/chunk-7S6XSTFO-DoKaEIP0.js +2 -0
  82. package/dist/web/assets/chunk-AQDTSKZB-DktDdZ_o.js +72 -0
  83. package/dist/web/assets/chunk-DSNLSHJZ-C_3sVqJn.js +129 -0
  84. package/dist/web/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
  85. package/dist/web/assets/chunk-HAGFOTED-DhCQIE99.js +62 -0
  86. package/dist/web/assets/chunk-HNE4Q36P-D_sbl6UM.js +1 -0
  87. package/dist/web/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
  88. package/dist/web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  89. package/dist/web/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
  90. package/dist/web/assets/chunk-NQOKRVIF-UuKYBp6F.js +213 -0
  91. package/dist/web/assets/chunk-UHW7PFBP-BkreF8rs.js +1 -0
  92. package/dist/web/assets/chunk-VQ5W62QI-Cb7PeOKH.js +1 -0
  93. package/dist/web/assets/chunk-WQQL4CDK-GsIKInJ-.js +10 -0
  94. package/dist/web/assets/chunk-XXDRQBXY-Bbz14gys.js +1 -0
  95. package/dist/web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  96. package/dist/web/assets/chunk-YZO67HFG--IdJYNXK.js +1 -0
  97. package/dist/web/assets/chunk-ZAUX2LTX-DmenwPIM.js +1 -0
  98. package/dist/web/assets/chunk-ZCHMQSOR-BZ2XP8BW.js +2 -0
  99. package/dist/web/assets/classDiagram-v2-4MYWR3UA-B_FJCXgY.js +217 -0
  100. package/dist/web/assets/clike-xvONpD0Z.js +1 -0
  101. package/dist/web/assets/clojure-BflJGmDX.js +1 -0
  102. package/dist/web/assets/cmake-84nbDH0I.js +1 -0
  103. package/dist/web/assets/cobol-DHLQUbN7.js +1 -0
  104. package/dist/web/assets/coffeescript-De_zI4J0.js +1 -0
  105. package/dist/web/assets/commonlisp-DgAKBe0r.js +1 -0
  106. package/dist/web/assets/cose-bilkent-JH36ORCC-DMBdq3mq.js +1 -0
  107. package/dist/web/assets/crystal-Bsdphhtm.js +1 -0
  108. package/dist/web/assets/css-CnaYoQib.js +1 -0
  109. package/dist/web/assets/cynefin-EF2NZ3EQ-BthcZtsD.js +1 -0
  110. package/dist/web/assets/cynefinDiagram-WF24UDRP-Bva6JySb.js +62 -0
  111. package/dist/web/assets/cypher-p9eYesGn.js +1 -0
  112. package/dist/web/assets/cytoscape.esm-BegBNzOV.js +321 -0
  113. package/dist/web/assets/d-DWkQyNnU.js +1 -0
  114. package/dist/web/assets/dagre-NK4GIZVX-BE6DKQYs.js +4 -0
  115. package/dist/web/assets/defaultLocale-BFoDCU3G.js +1 -0
  116. package/dist/web/assets/diagram-CBK3MWTC-DuDzgplS.js +24 -0
  117. package/dist/web/assets/diagram-I5XIIV2D-DU3jaZXW.js +24 -0
  118. package/dist/web/assets/diagram-ODIL2UCW-DYI3Rj6j.js +30 -0
  119. package/dist/web/assets/diagram-PFBEJUXE-FD1CYRbT.js +3 -0
  120. package/dist/web/assets/diagram-RJA3I4VV-BsbAupu0.js +41 -0
  121. package/dist/web/assets/diagram-TYUNFSNR-BMB0kMWv.js +200 -0
  122. package/dist/web/assets/diff-ChtP43wD.js +1 -0
  123. package/dist/web/assets/dist-1HFNA2Sd.js +9 -0
  124. package/dist/web/assets/dist-ABZ0bfMR.js +1 -0
  125. package/dist/web/assets/dist-B-4tAY5T.js +12 -0
  126. package/dist/web/assets/dist-B5RhPiDb.js +1 -0
  127. package/dist/web/assets/dist-BFFH-h4L.js +1 -0
  128. package/dist/web/assets/dist-Be0WQzsz.js +1 -0
  129. package/dist/web/assets/dist-BoeMvgh-.js +2 -0
  130. package/dist/web/assets/dist-C6oRdq_x.js +1 -0
  131. package/dist/web/assets/dist-CFaMxIWT.js +1 -0
  132. package/dist/web/assets/dist-CIDoXcx0.js +1 -0
  133. package/dist/web/assets/dist-CUajnf5G.js +1 -0
  134. package/dist/web/assets/dist-CXAToOJL.js +1 -0
  135. package/dist/web/assets/dist-CugnsBBM.js +1 -0
  136. package/dist/web/assets/dist-D5_2d6Ki.js +1 -0
  137. package/dist/web/assets/dist-D6VkQ_7h.js +11 -0
  138. package/dist/web/assets/dist-DTXSqpYP.js +1 -0
  139. package/dist/web/assets/dist-EDnzgrlE.js +1 -0
  140. package/dist/web/assets/dist-hiB1k3yb.js +1 -0
  141. package/dist/web/assets/dist-uYDRxuA0.js +1 -0
  142. package/dist/web/assets/dockerfile-DJkHQgkl.js +1 -0
  143. package/dist/web/assets/dtd-DTF72YNO.js +1 -0
  144. package/dist/web/assets/dylan-S7ucR4pR.js +1 -0
  145. package/dist/web/assets/ebnf-D4c0_ac3.js +1 -0
  146. package/dist/web/assets/ebnfDiagram-V4P3TTPT-C5zEPRhM.js +1 -0
  147. package/dist/web/assets/ecl-BVIeWmwY.js +1 -0
  148. package/dist/web/assets/eiffel-BEjRio4Q.js +1 -0
  149. package/dist/web/assets/elk-QONTBCTQ-BR5YBYTe.js +27 -0
  150. package/dist/web/assets/elm-Cshzl8qu.js +1 -0
  151. package/dist/web/assets/erDiagram-KYQIGQAA-B-5pcNVz.js +99 -0
  152. package/dist/web/assets/erlang-BV0c4Hdn.js +1 -0
  153. package/dist/web/assets/eventmodeling-K75KTNOO-DkMnS-Cz.js +1 -0
  154. package/dist/web/assets/factor-LKH5gN8L.js +1 -0
  155. package/dist/web/assets/fcl-ClOhbFR7.js +1 -0
  156. package/dist/web/assets/flowDiagram-IUGLLWBU-Dq34jEaq.js +1 -0
  157. package/dist/web/assets/forth-D6RzAl64.js +1 -0
  158. package/dist/web/assets/fortran-Bt6PBEDR.js +1 -0
  159. package/dist/web/assets/ganttDiagram-R7GPNTJY-B21dBS-O.js +292 -0
  160. package/dist/web/assets/gas-BHEdbvp9.js +1 -0
  161. package/dist/web/assets/gherkin-oBAE_ms0.js +1 -0
  162. package/dist/web/assets/gitGraph-VSP46ZUC-DalD3PH5.js +1 -0
  163. package/dist/web/assets/gitGraphDiagram-PDYL7XHY-CWi1FEeW.js +106 -0
  164. package/dist/web/assets/graphlib-DS17s2tU.js +1 -0
  165. package/dist/web/assets/groovy-CUpZ7dEl.js +1 -0
  166. package/dist/web/assets/haskell-BRsoo5mP.js +1 -0
  167. package/dist/web/assets/haxe-DjVOVvNP.js +1 -0
  168. package/dist/web/assets/http-CLVgA2GD.js +1 -0
  169. package/dist/web/assets/idl-BUZw3wgd.js +1 -0
  170. package/dist/web/assets/index-DBrCTV1V.js +58 -0
  171. package/dist/web/assets/index-DxpaDO0r.css +1 -0
  172. package/dist/web/assets/info-OHQRW6UA-CByswqH6.js +1 -0
  173. package/dist/web/assets/infoDiagram-MVDRKAX5-DizZ8XVo.js +2 -0
  174. package/dist/web/assets/init-C-OQMol4.js +1 -0
  175. package/dist/web/assets/ishikawaDiagram-HPEHV2GE-DQoKMoDQ.js +70 -0
  176. package/dist/web/assets/javascript-Bu8mWwtz.js +1 -0
  177. package/dist/web/assets/journeyDiagram-BOSHW7O7-DKj7UdLQ.js +139 -0
  178. package/dist/web/assets/julia-CQfgDRfP.js +1 -0
  179. package/dist/web/assets/kanban-definition-FNSA4HC5-bTblh8-S.js +89 -0
  180. package/dist/web/assets/katex-B_JcIwqj.js +257 -0
  181. package/dist/web/assets/katex-DMqEsVPU.js +257 -0
  182. package/dist/web/assets/katex-Ngnvt50Q.css +1 -0
  183. package/dist/web/assets/line-DWkG8aZQ.js +1 -0
  184. package/dist/web/assets/linear-aVPxw88X.js +1 -0
  185. package/dist/web/assets/livescript-BXxG0Yva.js +1 -0
  186. package/dist/web/assets/lua-DPCEkfD_.js +1 -0
  187. package/dist/web/assets/mathematica-u8YMmbU0.js +1 -0
  188. package/dist/web/assets/mbox-BEMVcqjs.js +1 -0
  189. package/dist/web/assets/mermaid-parser.core-C-J7_HBm.js +7 -0
  190. package/dist/web/assets/mermaid.core-DpHqjC1s.js +44 -0
  191. package/dist/web/assets/mindmap-definition-6OY57UG3-DnifqP1p.js +98 -0
  192. package/dist/web/assets/mirc-C9zpzAZU.js +1 -0
  193. package/dist/web/assets/mllike-B45xgp2S.js +1 -0
  194. package/dist/web/assets/modelica-CqHI_q-D.js +1 -0
  195. package/dist/web/assets/mscgen-qgSLujhx.js +1 -0
  196. package/dist/web/assets/mumps-BSzj6Xyz.js +1 -0
  197. package/dist/web/assets/nginx-8H7HVH4w.js +1 -0
  198. package/dist/web/assets/nsis-viPvXFiq.js +1 -0
  199. package/dist/web/assets/ntriples-CzMBulkp.js +1 -0
  200. package/dist/web/assets/octave-D2Q8cUp1.js +1 -0
  201. package/dist/web/assets/ordinal-BDEzSJ7C.js +1 -0
  202. package/dist/web/assets/oz-BwTct_5T.js +1 -0
  203. package/dist/web/assets/packet-JDAUHWVQ-_ADKLP5T.js +1 -0
  204. package/dist/web/assets/pascal-Dp_KdFgX.js +1 -0
  205. package/dist/web/assets/path-fybaL0A-.js +1 -0
  206. package/dist/web/assets/pegDiagram-ECIUJNBX-_SU4-PwS.js +1 -0
  207. package/dist/web/assets/perl-BkSkiI9m.js +1 -0
  208. package/dist/web/assets/pie-XZMESJXO-BfbJN8hk.js +1 -0
  209. package/dist/web/assets/pieDiagram-GNMPY74T-DQQKmEIp.js +39 -0
  210. package/dist/web/assets/pig-AF4Hwhju.js +1 -0
  211. package/dist/web/assets/powershell-D8WpQPaX.js +1 -0
  212. package/dist/web/assets/properties-C357ku5U.js +1 -0
  213. package/dist/web/assets/protobuf-D1ij_kNL.js +1 -0
  214. package/dist/web/assets/pug-Dwd_FmgJ.js +1 -0
  215. package/dist/web/assets/puppet-BZyAS7I4.js +1 -0
  216. package/dist/web/assets/python-B_1Jd8HM.js +1 -0
  217. package/dist/web/assets/q-B9NhS7L_.js +1 -0
  218. package/dist/web/assets/quadrantDiagram-D57K4MC3-BLtF0lyY.js +7 -0
  219. package/dist/web/assets/r-CxDmU1I4.js +1 -0
  220. package/dist/web/assets/radar-ABXABTNO-D7Tlesuz.js +1 -0
  221. package/dist/web/assets/railroad-I3PHUGI6-CA4jSH3I.js +1 -0
  222. package/dist/web/assets/railroad-abnf-LNEFI6M7-CumrL10E.js +1 -0
  223. package/dist/web/assets/railroad-ebnf-DWYD2UWJ-2GeHQm3G.js +1 -0
  224. package/dist/web/assets/railroad-peg-JR7BVNR7-CGbW9a0w.js +1 -0
  225. package/dist/web/assets/railroadDiagram-Y72NRBL7-BQKP5iZM.js +1 -0
  226. package/dist/web/assets/requirementDiagram-EQYSW5RA-Cn_K53gc.js +84 -0
  227. package/dist/web/assets/rough.esm-Dy-Kn_BL.js +1 -0
  228. package/dist/web/assets/rpm-gpDK5sbt.js +1 -0
  229. package/dist/web/assets/ruby-ChfNwlCY.js +1 -0
  230. package/dist/web/assets/sankeyDiagram-SY24JHO5-BouDevNW.js +40 -0
  231. package/dist/web/assets/sas-C2OyD2Y6.js +1 -0
  232. package/dist/web/assets/scheme-D9qYN0V5.js +1 -0
  233. package/dist/web/assets/sequenceDiagram-BLEHNHQU-C0rguio1.js +169 -0
  234. package/dist/web/assets/shell-DwuoZtxw.js +1 -0
  235. package/dist/web/assets/sieve-tLWDfEkZ.js +1 -0
  236. package/dist/web/assets/simple-mode-DXiLM1-G.js +1 -0
  237. package/dist/web/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  238. package/dist/web/assets/smalltalk-BLp5-jwC.js +1 -0
  239. package/dist/web/assets/solr-B78wSQJQ.js +1 -0
  240. package/dist/web/assets/sparql-Dz-mlCAC.js +1 -0
  241. package/dist/web/assets/spreadsheet-CTIncYxj.js +1 -0
  242. package/dist/web/assets/sql-DuQMFDvy.js +1 -0
  243. package/dist/web/assets/src-BJB85M8z.js +1 -0
  244. package/dist/web/assets/stateDiagram-v2-A6IESKWZ-BzgsnDJf.js +291 -0
  245. package/dist/web/assets/stex-DNzd62Q_.js +1 -0
  246. package/dist/web/assets/stylus-BOVgKnng.js +1 -0
  247. package/dist/web/assets/swift-DKB6_1j6.js +1 -0
  248. package/dist/web/assets/swimlanes-B3ENRKFQ-BAnQnO43.js +1 -0
  249. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-BLBJ1_iu.js +8 -0
  250. package/dist/web/assets/tcl-BGfruO1u.js +1 -0
  251. package/dist/web/assets/textile-C4jVoHG1.js +1 -0
  252. package/dist/web/assets/tiddlywiki-VlUiK86J.js +1 -0
  253. package/dist/web/assets/tiki-DTszW0OQ.js +1 -0
  254. package/dist/web/assets/timeline-definition-JXYKGLGB-i_V2SDud.js +120 -0
  255. package/dist/web/assets/toml-BPTmHmyx.js +1 -0
  256. package/dist/web/assets/treeView-D4JQ5SDB-blg1ho_V.js +1 -0
  257. package/dist/web/assets/treemap-SAJKECNS-GWe0sLdw.js +1 -0
  258. package/dist/web/assets/troff-C2dAgh7P.js +1 -0
  259. package/dist/web/assets/ttcn-PPSTk1ow.js +1 -0
  260. package/dist/web/assets/ttcn-cfg-2b4Gb5sE.js +1 -0
  261. package/dist/web/assets/turtle-Cx3rYX2g.js +1 -0
  262. package/dist/web/assets/usecaseDiagram-WPOLBNNX-C2epnXsY.js +328 -0
  263. package/dist/web/assets/vb-BthdM_4N.js +1 -0
  264. package/dist/web/assets/vbscript-D9f6rSsU.js +1 -0
  265. package/dist/web/assets/velocity-CqftRsjg.js +1 -0
  266. package/dist/web/assets/vennDiagram-Q3Y3IDCW-CYguUs2o.js +34 -0
  267. package/dist/web/assets/verilog-CjI9Y6RI.js +1 -0
  268. package/dist/web/assets/vhdl-kS471soi.js +1 -0
  269. package/dist/web/assets/wardley-7MLQ67FV-CA1BMgJ-.js +1 -0
  270. package/dist/web/assets/wardleyDiagram-IVAIDKWA-COJi2fLq.js +78 -0
  271. package/dist/web/assets/webidl-D5jiJvOU.js +1 -0
  272. package/dist/web/assets/xquery-BKJx4mf9.js +1 -0
  273. package/dist/web/assets/xychartDiagram-4URNHDU4-BxweoZn5.js +7 -0
  274. package/dist/web/assets/yacas-CXXgtw0p.js +1 -0
  275. package/dist/web/assets/z80-Co3PbHdE.js +1 -0
  276. package/dist/web/index.html +17 -0
  277. package/package.json +78 -3
  278. package/templates/docs/architecture.md +21 -0
  279. package/templates/docs/decisions.md +11 -0
  280. package/templates/docs/phases/README.md +25 -0
  281. package/templates/docs/rules.md +11 -0
  282. package/templates/docs/tasks.md +15 -0
  283. package/templates/main.md +15 -0
  284. package/templates/rules/ask-before-commit.md +4 -0
  285. package/templates/rules/lang-es-code-en.md +5 -0
  286. package/templates/rules/pnpm-only.md +4 -0
  287. package/templates/skill/SKILL.md +62 -0
package/dist/cli.js ADDED
@@ -0,0 +1,926 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/core/config.ts
4
+ import fs from "fs";
5
+ import os from "os";
6
+ import path from "path";
7
+ import { fileURLToPath } from "url";
8
+ var LANGS = ["en", "es", "fr", "pt", "de", "it"];
9
+ var LANG_NAMES = { en: "English", es: "Espa\xF1ol", fr: "Fran\xE7ais", pt: "Portugu\xEAs", de: "Deutsch", it: "Italiano" };
10
+ var DEFAULT_SOURCE = "en";
11
+ var isLang = (v) => LANGS.includes(v);
12
+ var MAIN_DOCS = ["CLAUDE.md", "AGENTS.md"];
13
+ var PKG_ROOT = (() => {
14
+ let dir = path.dirname(fileURLToPath(import.meta.url));
15
+ while (!fs.existsSync(path.join(dir, "package.json"))) dir = path.dirname(dir);
16
+ return dir;
17
+ })();
18
+ var TEMPLATES_DIR = path.join(PKG_ROOT, "templates");
19
+ var WEB_DIR = path.join(PKG_ROOT, "dist", "web");
20
+ var GLOBAL_DIR = process.env.MDRULES_HOME ?? path.join(os.homedir(), ".mdrules");
21
+ var stateDir = (root2) => path.join(root2, ".mdrules");
22
+ var configFile = (root2) => path.join(stateDir(root2), "config.json");
23
+ function readConfig(root2) {
24
+ try {
25
+ const raw = JSON.parse(fs.readFileSync(configFile(root2), "utf8"));
26
+ const langs = Array.isArray(raw.langs) ? raw.langs : raw.lang ? [raw.lang] : [];
27
+ return { mainDoc: raw.mainDoc ?? null, langs: langs.filter(isLang), initializedAt: raw.initializedAt };
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function writeConfig(root2, config) {
33
+ fs.mkdirSync(stateDir(root2), { recursive: true });
34
+ fs.writeFileSync(configFile(root2), JSON.stringify(config, null, 2) + "\n");
35
+ }
36
+ function safeResolve(root2, rel) {
37
+ const abs = path.resolve(root2, rel);
38
+ if (abs !== root2 && !abs.startsWith(root2 + path.sep)) throw new Error(`Path outside project: ${rel}`);
39
+ return abs;
40
+ }
41
+ var toPosix = (p2) => p2.split(path.sep).join("/");
42
+ var DEFAULT_SETTINGS = { font: "inter", size: 15, lineHeight: 1.65, padding: 28, width: "full", wrap: true };
43
+ var settingsFile = () => path.join(GLOBAL_DIR, "settings.json");
44
+ function readSettings() {
45
+ try {
46
+ return { ...DEFAULT_SETTINGS, ...JSON.parse(fs.readFileSync(settingsFile(), "utf8")) };
47
+ } catch {
48
+ return { ...DEFAULT_SETTINGS };
49
+ }
50
+ }
51
+ function writeSettings(patch) {
52
+ const next = { ...readSettings(), ...patch };
53
+ fs.mkdirSync(GLOBAL_DIR, { recursive: true });
54
+ fs.writeFileSync(settingsFile(), JSON.stringify(next, null, 2) + "\n");
55
+ return next;
56
+ }
57
+
58
+ // src/core/i18n.ts
59
+ import crypto from "crypto";
60
+ import fs4 from "fs";
61
+ import path4 from "path";
62
+
63
+ // src/core/langdetect.ts
64
+ var STOPWORDS = {
65
+ en: ["the", "and", "is", "are", "of", "to", "in", "for", "with", "this", "that", "it", "on", "be", "as", "by", "not", "or", "from", "when", "each", "use", "should", "will", "can", "all", "has", "have", "which", "only"],
66
+ es: ["el", "la", "los", "las", "de", "del", "que", "y", "en", "un", "una", "para", "con", "por", "es", "son", "se", "como", "al", "lo", "m\xE1s", "pero", "su", "sus", "este", "esta", "cuando", "cada", "debe", "tambi\xE9n"],
67
+ fr: ["le", "la", "les", "de", "des", "du", "et", "est", "un", "une", "pour", "dans", "avec", "que", "qui", "en", "sur", "par", "pas", "au", "aux", "ce", "cette", "sont", "ou", "chaque", "doit", "quand", "aussi", "\xEAtre"],
68
+ pt: ["o", "os", "as", "de", "do", "da", "dos", "das", "que", "e", "em", "um", "uma", "para", "com", "por", "n\xE3o", "\xE9", "s\xE3o", "se", "como", "ao", "mais", "mas", "seu", "sua", "cada", "deve", "quando", "tamb\xE9m"],
69
+ de: ["der", "die", "das", "und", "ist", "sind", "ein", "eine", "zu", "den", "dem", "mit", "f\xFCr", "von", "auf", "nicht", "auch", "es", "im", "bei", "wird", "werden", "oder", "wenn", "jede", "jeder", "soll", "muss", "kann", "nur"],
70
+ it: ["il", "lo", "la", "gli", "le", "di", "del", "della", "che", "e", "\xE8", "un", "una", "per", "con", "non", "sono", "si", "come", "al", "alla", "pi\xF9", "ma", "suo", "questo", "questa", "quando", "ogni", "deve", "anche"]
71
+ };
72
+ var SETS = Object.fromEntries(Object.entries(STOPWORDS).map(([l, w]) => [l, new Set(w)]));
73
+ function prose(md) {
74
+ return md.replace(/^---\r?\n[\s\S]*?\r?\n---/, " ").replace(/```[\s\S]*?```/g, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/`[^`]*`/g, " ").replace(/\]\([^)]*\)/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[|#>*_\-[\]()]/g, " ");
75
+ }
76
+ function detectLang(md) {
77
+ const words = prose(md).toLowerCase().match(/[\p{L}]+/gu) ?? [];
78
+ if (words.length < 25) return null;
79
+ const scores = Object.keys(SETS).map((lang) => ({ lang, hits: words.reduce((n, w) => n + (SETS[lang].has(w) ? 1 : 0), 0) }));
80
+ scores.sort((a, b) => b.hits - a.hits);
81
+ const [best, second] = scores;
82
+ if (best.hits < 6 || best.hits < second.hits * 1.5) return null;
83
+ return best.lang;
84
+ }
85
+
86
+ // src/core/rules.ts
87
+ import fs2 from "fs";
88
+ import path2 from "path";
89
+ import YAML from "yaml";
90
+ var rulesDir = () => path2.join(GLOBAL_DIR, "rules");
91
+ var START = "<!-- mdrules:rules:start -->";
92
+ var END = "<!-- mdrules:rules:end -->";
93
+ var slugify = (s) => s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
94
+ function seedRules() {
95
+ if (fs2.existsSync(rulesDir())) return;
96
+ fs2.mkdirSync(rulesDir(), { recursive: true });
97
+ const src = path2.join(TEMPLATES_DIR, "rules");
98
+ for (const f of fs2.readdirSync(src)) fs2.copyFileSync(path2.join(src, f), path2.join(rulesDir(), f));
99
+ }
100
+ function parseRule(id, text) {
101
+ const m = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
102
+ const meta = m ? YAML.parse(m[1]) ?? {} : {};
103
+ return { id, title: meta.title ?? id, body: (m ? m[2] : text).trim() };
104
+ }
105
+ function listRules() {
106
+ seedRules();
107
+ return fs2.readdirSync(rulesDir()).filter((f) => f.endsWith(".md")).map((f) => parseRule(f.slice(0, -3), fs2.readFileSync(path2.join(rulesDir(), f), "utf8"))).sort((a, b) => a.title.localeCompare(b.title));
108
+ }
109
+ function saveRule(rule) {
110
+ seedRules();
111
+ const id = rule.id || slugify(rule.title) || `rule-${Date.now()}`;
112
+ const text = `---
113
+ ${YAML.stringify({ title: rule.title }).trim()}
114
+ ---
115
+ ${rule.body.trim()}
116
+ `;
117
+ fs2.writeFileSync(path2.join(rulesDir(), `${id}.md`), text);
118
+ return { id, title: rule.title, body: rule.body.trim() };
119
+ }
120
+ function deleteRule(id) {
121
+ fs2.rmSync(path2.join(rulesDir(), `${path2.basename(id)}.md`), { force: true });
122
+ }
123
+ function appliedRuleIds(docText) {
124
+ const section = extractSection(docText);
125
+ if (!section) return [];
126
+ return [...section.matchAll(/<!-- rule:([\w-]+) -->/g)].map((m) => m[1]);
127
+ }
128
+ function extractSection(text) {
129
+ const s = text.indexOf(START);
130
+ const e = text.indexOf(END);
131
+ return s >= 0 && e > s ? text.slice(s, e + END.length) : null;
132
+ }
133
+ function writtenRules(docText) {
134
+ const section = extractSection(docText) ?? "";
135
+ const out = {};
136
+ for (const m of section.matchAll(/<!-- rule:([\w-]+) -->\n([\s\S]*?)(?=\n+<!-- (?:rule:|mdrules:rules:end))/g)) out[m[1]] = { id: m[1], title: m[1], body: m[2].trim() };
137
+ return out;
138
+ }
139
+ function sourceLangOf(docText) {
140
+ const m = /<!-- mdrules:source-lang:(\w+) -->/.exec(extractSection(docText) ?? "");
141
+ return m && isLang(m[1]) ? m[1] : DEFAULT_SOURCE;
142
+ }
143
+ function projectSourceLang(root2, mainDoc) {
144
+ const doc = mainDoc ?? MAIN_DOCS.find((d) => fs2.existsSync(path2.join(root2, d)));
145
+ if (!doc) return DEFAULT_SOURCE;
146
+ try {
147
+ return sourceLangOf(fs2.readFileSync(path2.join(root2, doc), "utf8"));
148
+ } catch {
149
+ return DEFAULT_SOURCE;
150
+ }
151
+ }
152
+ function renderSection(rules, sourceLang) {
153
+ const body = rules.map((r) => `<!-- rule:${r.id} -->
154
+ ${r.body}`).join("\n\n");
155
+ return [
156
+ START,
157
+ "## Working rules",
158
+ "",
159
+ "This project uses mdrules: follow `.claude/skills/mdrules/SKILL.md` when editing any `.md` file.",
160
+ "",
161
+ `<!-- mdrules:source-lang:${sourceLang} -->`,
162
+ `- Source language of every \`.md\` file: **${LANG_NAMES[sourceLang]}** (\`${sourceLang}\`).`,
163
+ ...body ? ["", body] : [],
164
+ END
165
+ ].join("\n");
166
+ }
167
+ function applyRules(docText, rules, sourceLang = sourceLangOf(docText)) {
168
+ const section = renderSection(rules, sourceLang);
169
+ const existing = extractSection(docText);
170
+ if (existing) return docText.replace(existing, section);
171
+ return docText.replace(/\s*$/, "") + "\n\n" + section + "\n";
172
+ }
173
+ function applyRulesToFile(file, ids, sourceLang) {
174
+ const text = fs2.existsSync(file) ? fs2.readFileSync(file, "utf8") : "";
175
+ const all = listRules();
176
+ const written = writtenRules(text);
177
+ const rules = (ids ?? appliedRuleIds(text)).map((id) => all.find((r) => r.id === id) ?? written[id]).filter((r) => !!r);
178
+ fs2.writeFileSync(file, applyRules(text, rules, sourceLang ?? sourceLangOf(text)));
179
+ }
180
+
181
+ // src/core/scan.ts
182
+ import fs3 from "fs";
183
+ import path3 from "path";
184
+ import ignore from "ignore";
185
+ var ALWAYS_SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", ".mdrules", "dist", "build", ".next", ".turbo", "coverage", ".venv"]);
186
+ var IGNORE_FILE = ".mdrulesignore";
187
+ function loadIgnore(root2, file) {
188
+ const ig = ignore();
189
+ try {
190
+ ig.add(fs3.readFileSync(path3.join(root2, file), "utf8"));
191
+ } catch {
192
+ }
193
+ return ig;
194
+ }
195
+ function readIgnoreList(root2) {
196
+ try {
197
+ return fs3.readFileSync(path3.join(root2, IGNORE_FILE), "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
198
+ } catch {
199
+ return [];
200
+ }
201
+ }
202
+ function setIgnored(root2, rel, kind, ignored) {
203
+ const entry = kind === "dir" ? `${rel}/` : rel;
204
+ const lines = readIgnoreList(root2).filter((l) => l !== entry && l !== rel);
205
+ if (ignored) lines.push(entry);
206
+ fs3.writeFileSync(path3.join(root2, IGNORE_FILE), lines.length ? lines.join("\n") + "\n" : "");
207
+ }
208
+ function watchSkips(root2) {
209
+ const gitIgnore = loadIgnore(root2, ".gitignore");
210
+ return (rel, isDir) => {
211
+ if (!rel || rel.startsWith("..")) return false;
212
+ if (rel.split("/").some((s) => ALWAYS_SKIP.has(s))) return true;
213
+ if (isDir !== false && gitIgnore.ignores(rel + "/")) return true;
214
+ return isDir !== true && gitIgnore.ignores(rel);
215
+ };
216
+ }
217
+ function scanTree(root2) {
218
+ const gitIgnore = loadIgnore(root2, ".gitignore");
219
+ const mdIgnore = loadIgnore(root2, IGNORE_FILE);
220
+ function walk(dirAbs, parentIgnored) {
221
+ let entries;
222
+ try {
223
+ entries = fs3.readdirSync(dirAbs, { withFileTypes: true });
224
+ } catch {
225
+ return [];
226
+ }
227
+ const nodes = [];
228
+ for (const e of entries) {
229
+ if (ALWAYS_SKIP.has(e.name)) continue;
230
+ const abs = path3.join(dirAbs, e.name);
231
+ const rel = toPosix(path3.relative(root2, abs));
232
+ if (e.isDirectory()) {
233
+ if (gitIgnore.ignores(rel + "/")) continue;
234
+ const ignored = parentIgnored || mdIgnore.ignores(rel + "/");
235
+ const children = walk(abs, ignored);
236
+ if (!children.length) continue;
237
+ const project = MAIN_DOCS.some((d) => children.some((c) => c.kind === "file" && c.name === d));
238
+ nodes.push({ name: e.name, path: rel, kind: "dir", project: project || void 0, ignored: ignored || void 0, children });
239
+ } else if (e.isFile() && e.name.toLowerCase().endsWith(".md")) {
240
+ if (gitIgnore.ignores(rel)) continue;
241
+ const ignored = parentIgnored || mdIgnore.ignores(rel);
242
+ nodes.push({ name: e.name, path: rel, kind: "file", ignored: ignored || void 0 });
243
+ }
244
+ }
245
+ return nodes.sort(compareNodes);
246
+ }
247
+ return walk(root2, false);
248
+ }
249
+ function compareNodes(a, b) {
250
+ const rank = (n) => n.kind === "file" && MAIN_DOCS.includes(n.name) ? 0 : n.kind === "dir" ? 1 : 2;
251
+ return rank(a) - rank(b) || a.name.localeCompare(b.name);
252
+ }
253
+ function flattenFiles(nodes, includeIgnored = false) {
254
+ const out = [];
255
+ for (const n of nodes) {
256
+ if (n.ignored && !includeIgnored) continue;
257
+ if (n.kind === "file") out.push(n);
258
+ else out.push(...flattenFiles(n.children ?? [], includeIgnored));
259
+ }
260
+ return out;
261
+ }
262
+ function findSubprojects(nodes) {
263
+ const out = [];
264
+ for (const n of nodes) {
265
+ if (n.kind !== "dir") continue;
266
+ if (n.project) out.push(n.path);
267
+ out.push(...findSubprojects(n.children ?? []));
268
+ }
269
+ return out;
270
+ }
271
+
272
+ // src/core/i18n.ts
273
+ var stateFile = (root2) => path4.join(stateDir(root2), "state.json");
274
+ var translationPath = (root2, lang, rel) => path4.join(stateDir(root2), "i18n", lang, rel);
275
+ var hash = (text) => crypto.createHash("sha1").update(text).digest("hex").slice(0, 12);
276
+ var readText = (abs) => {
277
+ try {
278
+ return fs4.readFileSync(abs, "utf8");
279
+ } catch {
280
+ return null;
281
+ }
282
+ };
283
+ function readState(root2) {
284
+ try {
285
+ const raw = JSON.parse(fs4.readFileSync(stateFile(root2), "utf8"));
286
+ if (!raw.translations) return { translations: raw, keepLanguage: {} };
287
+ return { translations: raw.translations ?? {}, keepLanguage: raw.keepLanguage ?? {} };
288
+ } catch {
289
+ return { translations: {}, keepLanguage: {} };
290
+ }
291
+ }
292
+ function writeState(root2, state) {
293
+ fs4.mkdirSync(stateDir(root2), { recursive: true });
294
+ fs4.writeFileSync(stateFile(root2), JSON.stringify(state, null, 2) + "\n");
295
+ }
296
+ function fileStatus(root2, lang, rel) {
297
+ const source = readText(path4.join(root2, rel));
298
+ const translation = readText(translationPath(root2, lang, rel));
299
+ if (translation === null || source === null) return "missing";
300
+ const recorded = readState(root2).translations[lang]?.[rel];
301
+ if (!recorded) return "outdated";
302
+ const sourceChanged = hash(source) !== recorded.source;
303
+ const translationChanged = hash(translation) !== recorded.translation;
304
+ if (sourceChanged && translationChanged) return "conflict";
305
+ if (sourceChanged) return "outdated";
306
+ if (translationChanged) return "pending-sync";
307
+ return "synced";
308
+ }
309
+ function allStatuses(root2, lang) {
310
+ return flattenFiles(scanTree(root2)).map((f) => ({
311
+ path: f.path,
312
+ lang,
313
+ status: fileStatus(root2, lang, f.path),
314
+ translation: path4.relative(root2, translationPath(root2, lang, f.path))
315
+ }));
316
+ }
317
+ function foreignFiles(root2, sourceLang) {
318
+ const { keepLanguage: keepLanguage2 } = readState(root2);
319
+ const out = [];
320
+ for (const f of flattenFiles(scanTree(root2))) {
321
+ const text = readText(path4.join(root2, f.path));
322
+ const detected = text ? detectLang(text) : null;
323
+ if (detected && detected !== sourceLang && keepLanguage2[f.path] !== detected) out.push({ path: f.path, detected });
324
+ }
325
+ return out;
326
+ }
327
+ function syncReport(root2) {
328
+ const config = readConfig(root2);
329
+ const sourceLang = projectSourceLang(root2, config?.mainDoc);
330
+ const langs = (config?.langs ?? []).filter((l) => l !== sourceLang);
331
+ return {
332
+ sourceLang,
333
+ langs,
334
+ foreign: foreignFiles(root2, sourceLang),
335
+ files: langs.flatMap((l) => allStatuses(root2, l))
336
+ };
337
+ }
338
+ function markSynced(root2, lang, rel) {
339
+ const source = readText(path4.join(root2, rel));
340
+ const translation = readText(translationPath(root2, lang, rel));
341
+ if (source === null) throw new Error(`Source not found: ${rel}`);
342
+ if (translation === null) throw new Error(`Translation not found: ${path4.relative(root2, translationPath(root2, lang, rel))}`);
343
+ const state = readState(root2);
344
+ state.translations[lang] ??= {};
345
+ state.translations[lang][rel] = { source: hash(source), translation: hash(translation) };
346
+ writeState(root2, state);
347
+ }
348
+ function keepLanguage(root2, rel) {
349
+ const text = readText(path4.join(root2, rel));
350
+ const detected = text ? detectLang(text) : null;
351
+ if (!detected) throw new Error(`Could not detect the language of ${rel}`);
352
+ const state = readState(root2);
353
+ state.keepLanguage[rel] = detected;
354
+ writeState(root2, state);
355
+ return detected;
356
+ }
357
+
358
+ // src/server/index.ts
359
+ import fs6 from "fs";
360
+ import http from "http";
361
+ import path6 from "path";
362
+ import { watch } from "chokidar";
363
+ import open from "open";
364
+ import pc from "picocolors";
365
+ import { WebSocketServer } from "ws";
366
+
367
+ // src/core/dashboard.ts
368
+ import fs5 from "fs";
369
+ import path5 from "path";
370
+ import YAML2 from "yaml";
371
+ function parseFrontmatter(text) {
372
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---/);
373
+ if (!m) return {};
374
+ try {
375
+ return YAML2.parse(m[1]) ?? {};
376
+ } catch {
377
+ return {};
378
+ }
379
+ }
380
+ function summarize(root2) {
381
+ return flattenFiles(scanTree(root2)).map((f) => {
382
+ const text = fs5.readFileSync(path5.join(root2, f.path), "utf8");
383
+ const meta = parseFrontmatter(text);
384
+ const total = text.match(/^\s*[-*+] \[[ xX]\]/gm)?.length ?? 0;
385
+ const done = text.match(/^\s*[-*+] \[[xX]\]/gm)?.length ?? 0;
386
+ const heading = text.match(/^#\s+(.+)$/m)?.[1];
387
+ return {
388
+ path: f.path,
389
+ title: meta.title ?? heading ?? f.name.replace(/\.md$/i, ""),
390
+ type: meta.type ?? null,
391
+ status: meta.status ?? null,
392
+ phase: typeof meta.phase === "number" ? meta.phase : null,
393
+ updated: meta.updated ? String(meta.updated instanceof Date ? meta.updated.toISOString().slice(0, 10) : meta.updated) : null,
394
+ tasks: { done, total }
395
+ };
396
+ });
397
+ }
398
+
399
+ // src/core/git.ts
400
+ import { execFileSync } from "child_process";
401
+ function git(root2, args2) {
402
+ try {
403
+ return execFileSync("git", ["-c", "core.quotepath=off", ...args2], { cwd: root2, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 32 * 1024 * 1024 });
404
+ } catch (err) {
405
+ return typeof err?.stdout === "string" && err.stdout ? err.stdout : null;
406
+ }
407
+ }
408
+ var isGitRepo = (root2) => git(root2, ["rev-parse", "--is-inside-work-tree"])?.trim() === "true";
409
+ function gitStatuses(root2) {
410
+ const prefix = git(root2, ["rev-parse", "--show-prefix"])?.trim() ?? "";
411
+ const out = git(root2, ["status", "--porcelain=v1", "-z", "--untracked-files=all", "--", "."]);
412
+ const result = {};
413
+ if (!out) return result;
414
+ const parts = out.split("\0");
415
+ for (let i = 0; i < parts.length; i++) {
416
+ const entry = parts[i];
417
+ if (entry.length < 4) continue;
418
+ const code = entry.slice(0, 2);
419
+ let file = entry.slice(3);
420
+ if (code[0] === "R" || code[0] === "C") i++;
421
+ if (!file.toLowerCase().endsWith(".md")) continue;
422
+ if (prefix && file.startsWith(prefix)) file = file.slice(prefix.length);
423
+ if (file.startsWith(".mdrules/")) continue;
424
+ result[file] = code === "??" ? "U" : code.includes("D") ? "D" : code.includes("A") ? "A" : "M";
425
+ }
426
+ return result;
427
+ }
428
+ function gitDiff(root2, rel) {
429
+ const status = gitStatuses(root2)[rel];
430
+ if (status === "U") return git(root2, ["diff", "--no-index", "--", "/dev/null", rel]) ?? "";
431
+ const hasHead = git(root2, ["rev-parse", "--verify", "HEAD"]) !== null;
432
+ return git(root2, hasHead ? ["diff", "HEAD", "--", rel] : ["diff", "--cached", "--", rel]) ?? "";
433
+ }
434
+
435
+ // src/server/index.ts
436
+ var IMAGE_MIME = {
437
+ ".png": "image/png",
438
+ ".jpg": "image/jpeg",
439
+ ".jpeg": "image/jpeg",
440
+ ".gif": "image/gif",
441
+ ".webp": "image/webp",
442
+ ".avif": "image/avif",
443
+ ".svg": "image/svg+xml",
444
+ ".bmp": "image/bmp",
445
+ ".ico": "image/x-icon"
446
+ };
447
+ var MIME = {
448
+ ".html": "text/html; charset=utf-8",
449
+ ".js": "text/javascript",
450
+ ".css": "text/css",
451
+ ".svg": "image/svg+xml",
452
+ ".json": "application/json",
453
+ ".woff2": "font/woff2"
454
+ };
455
+ var HttpError = class extends Error {
456
+ constructor(status, message) {
457
+ super(message);
458
+ this.status = status;
459
+ }
460
+ status;
461
+ };
462
+ async function readBody(req) {
463
+ let data = "";
464
+ for await (const chunk of req) data += chunk;
465
+ if (!data) return {};
466
+ if (!req.headers["content-type"]?.startsWith("application/json")) throw new HttpError(415, "Expected application/json");
467
+ return JSON.parse(data);
468
+ }
469
+ var LOCAL_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
470
+ function isLocalRequest(req) {
471
+ const host = req.headers.host ?? "";
472
+ try {
473
+ if (!LOCAL_HOSTS.has(new URL(`http://${host}`).hostname)) return false;
474
+ return !req.headers.origin || new URL(req.headers.origin).host === host;
475
+ } catch {
476
+ return false;
477
+ }
478
+ }
479
+ async function startServer({ root: root2, port, open: openBrowser }) {
480
+ const config = () => readConfig(root2) ?? { mainDoc: null, langs: [] };
481
+ const sourceLang = () => projectSourceLang(root2, readConfig(root2)?.mainDoc);
482
+ const viewLang = (value) => isLang(value) && value !== sourceLang() && config().langs.includes(value) ? value : null;
483
+ const mdPath = (rel) => {
484
+ if (typeof rel !== "string" || !rel.toLowerCase().endsWith(".md")) throw new HttpError(400, "Expected a .md path");
485
+ safeResolve(root2, rel);
486
+ return rel;
487
+ };
488
+ const deletable = (rel) => {
489
+ if (typeof rel !== "string" || !rel.trim()) throw new HttpError(400, "Expected a path");
490
+ const abs = safeResolve(root2, rel);
491
+ if (abs === root2) throw new HttpError(400, "Refusing to delete the project root");
492
+ if (!fs6.existsSync(abs)) throw new HttpError(404, "Not found");
493
+ return abs;
494
+ };
495
+ const routes = {
496
+ "GET /api/info": () => {
497
+ const c = config();
498
+ return { name: path6.basename(root2), mainDoc: c.mainDoc ?? null, sourceLang: sourceLang(), langs: c.langs.filter((l) => l !== sourceLang()), git: isGitRepo(root2) };
499
+ },
500
+ "PUT /api/config": (_, body) => {
501
+ const c = config();
502
+ if (Array.isArray(body.langs)) c.langs = body.langs.filter(isLang);
503
+ if (isLang(body.sourceLang) && body.sourceLang !== sourceLang()) {
504
+ if (!c.mainDoc) throw new HttpError(400, "No main document configured; run `mdrules init`");
505
+ applyRulesToFile(path6.join(root2, c.mainDoc), void 0, body.sourceLang);
506
+ }
507
+ writeConfig(root2, c);
508
+ return { ...c, langs: c.langs.filter((l) => l !== sourceLang()) };
509
+ },
510
+ "GET /api/settings": () => readSettings(),
511
+ "PUT /api/settings": (_, body) => writeSettings(body),
512
+ "GET /api/tree": (url2) => {
513
+ const l = viewLang(url2.searchParams.get("lang"));
514
+ const sync2 = l ? Object.fromEntries(allStatuses(root2, l).map((e) => [e.path, e.status])) : {};
515
+ const foreign = Object.fromEntries(foreignFiles(root2, sourceLang()).map((f) => [f.path, f.detected]));
516
+ return { tree: scanTree(root2), git: gitStatuses(root2), sync: sync2, foreign };
517
+ },
518
+ "POST /api/keep-language": (_, body) => ({ lang: keepLanguage(root2, mdPath(body.path)) }),
519
+ "GET /api/file": (url2) => {
520
+ const rel = mdPath(url2.searchParams.get("path"));
521
+ const l = viewLang(url2.searchParams.get("lang"));
522
+ const source = fs6.readFileSync(safeResolve(root2, rel), "utf8");
523
+ if (l) {
524
+ const tPath = translationPath(root2, l, rel);
525
+ if (fs6.existsSync(tPath)) return { path: rel, content: fs6.readFileSync(tPath, "utf8"), target: "translation", status: fileStatus(root2, l, rel) };
526
+ return { path: rel, content: source, target: "source", status: "missing" };
527
+ }
528
+ return { path: rel, content: source, target: "source", status: null };
529
+ },
530
+ "PUT /api/file": (_, body) => {
531
+ const rel = mdPath(body.path);
532
+ const l = viewLang(body.lang);
533
+ const file = body.target === "translation" && l ? translationPath(root2, l, rel) : safeResolve(root2, rel);
534
+ fs6.mkdirSync(path6.dirname(file), { recursive: true });
535
+ fs6.writeFileSync(file, String(body.content ?? ""));
536
+ return { ok: true, status: l ? fileStatus(root2, l, rel) : null };
537
+ },
538
+ "POST /api/file": (_, body) => {
539
+ const rel = mdPath(body.path);
540
+ const file = safeResolve(root2, rel);
541
+ if (fs6.existsSync(file)) throw new HttpError(409, "File already exists");
542
+ fs6.mkdirSync(path6.dirname(file), { recursive: true });
543
+ const title = path6.basename(rel, ".md").replace(/^\d+[-_]/, "").replace(/[-_]/g, " ");
544
+ fs6.writeFileSync(file, `# ${title.charAt(0).toUpperCase() + title.slice(1)}
545
+
546
+ `);
547
+ return { ok: true, path: rel };
548
+ },
549
+ "GET /api/delete-preview": (url2) => {
550
+ const abs = deletable(url2.searchParams.get("path"));
551
+ if (!fs6.statSync(abs).isDirectory()) return { kind: "file", files: 1, md: 1 };
552
+ const files = fs6.readdirSync(abs, { recursive: true, withFileTypes: true }).filter((e) => e.isFile());
553
+ return { kind: "dir", files: files.length, md: files.filter((e) => e.name.toLowerCase().endsWith(".md")).length };
554
+ },
555
+ "DELETE /api/path": (url2) => {
556
+ const rel = toPosix(path6.relative(root2, deletable(url2.searchParams.get("path"))));
557
+ fs6.rmSync(safeResolve(root2, rel), { recursive: true });
558
+ for (const l of config().langs) fs6.rmSync(translationPath(root2, l, rel), { recursive: true, force: true });
559
+ return { ok: true };
560
+ },
561
+ "POST /api/ignore": (_, body) => {
562
+ safeResolve(root2, body.path);
563
+ setIgnored(root2, body.path, body.kind === "dir" ? "dir" : "file", !!body.ignored);
564
+ return { ok: true };
565
+ },
566
+ "GET /api/diff": (url2) => ({ diff: gitDiff(root2, mdPath(url2.searchParams.get("path"))) }),
567
+ "GET /api/dashboard": () => ({ docs: summarize(root2) }),
568
+ "GET /api/rules": () => {
569
+ const mainDoc = readConfig(root2)?.mainDoc;
570
+ const text = mainDoc && fs6.existsSync(path6.join(root2, mainDoc)) ? fs6.readFileSync(path6.join(root2, mainDoc), "utf8") : "";
571
+ return { rules: listRules(), applied: appliedRuleIds(text), mainDoc: mainDoc ?? null };
572
+ },
573
+ "PUT /api/rules": (_, body) => saveRule(body),
574
+ "DELETE /api/rules": (url2) => {
575
+ deleteRule(url2.searchParams.get("id") ?? "");
576
+ return { ok: true };
577
+ },
578
+ "POST /api/rules/apply": (_, body) => {
579
+ const mainDoc = readConfig(root2)?.mainDoc;
580
+ if (!mainDoc) throw new HttpError(400, "No main document configured; run `mdrules init`");
581
+ applyRulesToFile(path6.join(root2, mainDoc), body.ids ?? []);
582
+ return { ok: true };
583
+ }
584
+ };
585
+ const server = http.createServer(async (req, res) => {
586
+ if (!isLocalRequest(req)) {
587
+ res.writeHead(403).end("Forbidden");
588
+ return;
589
+ }
590
+ const url2 = new URL(req.url ?? "/", "http://localhost");
591
+ const route = routes[`${req.method} ${url2.pathname}`];
592
+ if (route) {
593
+ try {
594
+ const result = await route(url2, req.method === "GET" || req.method === "DELETE" ? {} : await readBody(req));
595
+ res.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(result));
596
+ } catch (err) {
597
+ const status = err instanceof HttpError ? err.status : err.code === "ENOENT" ? 404 : 500;
598
+ res.writeHead(status, { "content-type": "application/json" }).end(JSON.stringify({ error: err.message }));
599
+ }
600
+ return;
601
+ }
602
+ if (req.method === "GET" && url2.pathname === "/api/asset") return serveAsset(url2.searchParams.get("path") ?? "", res);
603
+ serveStatic(url2.pathname, res);
604
+ });
605
+ function serveAsset(rel, res) {
606
+ let file;
607
+ try {
608
+ file = safeResolve(root2, rel);
609
+ } catch {
610
+ res.writeHead(404).end();
611
+ return;
612
+ }
613
+ const type = IMAGE_MIME[path6.extname(file).toLowerCase()];
614
+ if (!type || !fs6.existsSync(file) || !fs6.statSync(file).isFile()) {
615
+ res.writeHead(404).end();
616
+ return;
617
+ }
618
+ res.writeHead(200, { "content-type": type, "cache-control": "no-cache" });
619
+ fs6.createReadStream(file).pipe(res);
620
+ }
621
+ const actualPort = await listen(server, port);
622
+ const wss = new WebSocketServer({ server, path: "/ws", verifyClient: ({ req }) => isLocalRequest(req) });
623
+ const broadcast = (msg) => {
624
+ const data = JSON.stringify(msg);
625
+ for (const client of wss.clients) client.send(data);
626
+ };
627
+ const skips = watchSkips(root2);
628
+ watch(root2, {
629
+ ignoreInitial: true,
630
+ // Unreadable folders (e.g. caches owned by another user) are skipped instead of failing.
631
+ ignorePermissionErrors: true,
632
+ ignored: (p2, stats) => {
633
+ const rel = toPosix(path6.relative(root2, p2));
634
+ if (rel === ".mdrules") return false;
635
+ if (rel.startsWith(".mdrules/")) return !rel.startsWith(".mdrules/i18n") && rel !== ".mdrules/state.json" && rel !== ".mdrules/config.json";
636
+ return skips(rel, stats ? stats.isDirectory() : void 0);
637
+ }
638
+ }).on("error", (err) => console.warn(pc.yellow(` file watcher: ${err.message}`))).on("all", (event, file) => {
639
+ const abs = path6.resolve(file);
640
+ if (!abs.endsWith(".md") && !abs.endsWith(".json") && !abs.endsWith(".mdrulesignore") && event !== "addDir" && event !== "unlinkDir") return;
641
+ let rel = toPosix(path6.relative(root2, abs));
642
+ const i18n = toPosix(path6.relative(root2, path6.join(stateDir(root2), "i18n")));
643
+ if (rel.startsWith(i18n + "/")) rel = rel.split("/").slice(3).join("/");
644
+ broadcast({ type: "fs", event, path: rel });
645
+ });
646
+ const url = `http://localhost:${actualPort}`;
647
+ console.log(`
648
+ ${pc.bold("mdrules")} ${pc.dim("\u2192")} ${pc.cyan(url)} ${pc.dim(root2)}
649
+ `);
650
+ if (!fs6.existsSync(WEB_DIR)) console.log(pc.yellow(" Web UI not built: run `pnpm build`, or `pnpm dev` and open http://localhost:4320\n"));
651
+ else if (openBrowser) open(url).catch(() => {
652
+ });
653
+ }
654
+ function listen(server, port) {
655
+ return new Promise((resolve, reject) => {
656
+ server.once("error", (err) => {
657
+ if (err.code === "EADDRINUSE") resolve(listen(server, port + 1));
658
+ else reject(err);
659
+ });
660
+ server.listen(port, "127.0.0.1", () => resolve(port));
661
+ });
662
+ }
663
+ function serveStatic(pathname, res) {
664
+ let file = path6.join(WEB_DIR, path6.normalize(pathname).replace(/^(\.\.[/\\])+/, ""));
665
+ if (!file.startsWith(WEB_DIR) || !fs6.existsSync(file) || fs6.statSync(file).isDirectory()) file = path6.join(WEB_DIR, "index.html");
666
+ if (!fs6.existsSync(file)) {
667
+ res.writeHead(404).end("Web UI not built. Run `pnpm build`.");
668
+ return;
669
+ }
670
+ res.writeHead(200, { "content-type": MIME[path6.extname(file)] ?? "application/octet-stream" });
671
+ fs6.createReadStream(file).pipe(res);
672
+ }
673
+
674
+ // src/cli/init.ts
675
+ import fs8 from "fs";
676
+ import path8 from "path";
677
+ import * as p from "@clack/prompts";
678
+ import pc2 from "picocolors";
679
+
680
+ // src/core/scaffold.ts
681
+ import fs7 from "fs";
682
+ import path7 from "path";
683
+ var today = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
684
+ function fill(text, vars) {
685
+ return text.replace(/\{\{(\w+)\}\}/g, (_, k) => vars[k] ?? "");
686
+ }
687
+ function copyTree(src, dest, vars, created, root2) {
688
+ for (const e of fs7.readdirSync(src, { withFileTypes: true })) {
689
+ const from = path7.join(src, e.name);
690
+ const to = path7.join(dest, e.name);
691
+ if (e.isDirectory()) {
692
+ fs7.mkdirSync(to, { recursive: true });
693
+ copyTree(from, to, vars, created, root2);
694
+ } else if (!fs7.existsSync(to)) {
695
+ fs7.writeFileSync(to, fill(fs7.readFileSync(from, "utf8"), vars));
696
+ created.push(toPosix(path7.relative(root2, to)));
697
+ }
698
+ }
699
+ }
700
+ function scaffoldDocs(root2) {
701
+ const created = [];
702
+ fs7.mkdirSync(path7.join(root2, "docs"), { recursive: true });
703
+ copyTree(path7.join(TEMPLATES_DIR, "docs"), path7.join(root2, "docs"), { date: today() }, created, root2);
704
+ return created;
705
+ }
706
+ function createMainDoc(root2, name) {
707
+ const file = path7.join(root2, name);
708
+ if (fs7.existsSync(file)) return;
709
+ const text = fs7.readFileSync(path7.join(TEMPLATES_DIR, "main.md"), "utf8");
710
+ fs7.writeFileSync(file, fill(text, { name: path7.basename(root2), date: today() }));
711
+ }
712
+ function installSkill(root2) {
713
+ const dir = path7.join(root2, ".claude", "skills", "mdrules");
714
+ fs7.mkdirSync(dir, { recursive: true });
715
+ fs7.copyFileSync(path7.join(TEMPLATES_DIR, "skill", "SKILL.md"), path7.join(dir, "SKILL.md"));
716
+ }
717
+ function ensureGitignore(root2) {
718
+ const file = path7.join(root2, ".gitignore");
719
+ const text = fs7.existsSync(file) ? fs7.readFileSync(file, "utf8") : "";
720
+ if (text.split("\n").some((l) => [".mdrules", ".mdrules/", "/.mdrules", "/.mdrules/"].includes(l.trim()))) return;
721
+ fs7.writeFileSync(file, text + (text && !text.endsWith("\n") ? "\n" : "") + ".mdrules/\n");
722
+ }
723
+ function hideInVsCode(root2) {
724
+ const file = path7.join(root2, ".vscode", "settings.json");
725
+ let settings = {};
726
+ if (fs7.existsSync(file)) {
727
+ try {
728
+ settings = JSON.parse(fs7.readFileSync(file, "utf8"));
729
+ } catch {
730
+ return false;
731
+ }
732
+ }
733
+ settings["files.exclude"] = { ...settings["files.exclude"] ?? {}, "**/.mdrules": true };
734
+ fs7.mkdirSync(path7.dirname(file), { recursive: true });
735
+ fs7.writeFileSync(file, JSON.stringify(settings, null, 2) + "\n");
736
+ return true;
737
+ }
738
+
739
+ // src/cli/init.ts
740
+ function check(value) {
741
+ if (p.isCancel(value)) {
742
+ p.cancel("Cancelled.");
743
+ process.exit(0);
744
+ }
745
+ return value;
746
+ }
747
+ async function chooseMainDoc(root2) {
748
+ const existing = MAIN_DOCS.filter((d) => fs8.existsSync(path8.join(root2, d)));
749
+ if (existing.length === 2) {
750
+ return check(
751
+ await p.select({
752
+ message: "Both CLAUDE.md and AGENTS.md exist. Which one is the main document?",
753
+ options: existing.map((d) => ({ value: d, label: d }))
754
+ })
755
+ );
756
+ }
757
+ if (existing.length === 1) {
758
+ const choice2 = check(
759
+ await p.select({
760
+ message: `Found ${pc2.cyan(existing[0])}. Use it as the main document?`,
761
+ options: [
762
+ { value: existing[0], label: `Yes, use ${existing[0]}` },
763
+ ...MAIN_DOCS.filter((d) => d !== existing[0]).map((d) => ({ value: d, label: `No, create ${d}` }))
764
+ ]
765
+ })
766
+ );
767
+ createMainDoc(root2, choice2);
768
+ return choice2;
769
+ }
770
+ const choice = check(
771
+ await p.select({
772
+ message: "No CLAUDE.md or AGENTS.md found. Which one should I create?",
773
+ options: MAIN_DOCS.map((d) => ({ value: d, label: d, hint: d === "CLAUDE.md" ? "Claude Code" : "other agents" }))
774
+ })
775
+ );
776
+ createMainDoc(root2, choice);
777
+ p.log.success(`Created ${choice}`);
778
+ return choice;
779
+ }
780
+ async function runInit(root2) {
781
+ p.intro(pc2.bgCyan(pc2.black(" mdrules ")));
782
+ const previous = readConfig(root2);
783
+ const mainDoc = await chooseMainDoc(root2);
784
+ const mainFile = path8.join(root2, mainDoc);
785
+ if (!fs8.existsSync(path8.join(root2, "docs"))) {
786
+ const create = check(await p.confirm({ message: "Create the base /docs structure?", initialValue: true }));
787
+ if (create) p.log.success(`Created ${scaffoldDocs(root2).join(", ")}`);
788
+ }
789
+ const mainText = fs8.readFileSync(mainFile, "utf8");
790
+ const sourceLang = check(
791
+ await p.select({
792
+ message: "Source language of the .md files (what the AI reads and writes)",
793
+ options: LANGS.map((l) => ({ value: l, label: LANG_NAMES[l], hint: l === "en" ? "default" : void 0 })),
794
+ initialValue: sourceLangOf(mainText)
795
+ })
796
+ );
797
+ const langs = check(
798
+ await p.multiselect({
799
+ message: "Translation languages (view and edit docs in them; the source files never change language)",
800
+ options: LANGS.filter((l) => l !== sourceLang).map((l) => ({ value: l, label: LANG_NAMES[l] })),
801
+ initialValues: (previous?.langs ?? []).filter((l) => l !== sourceLang),
802
+ required: false
803
+ })
804
+ );
805
+ const rules = listRules();
806
+ const applied = appliedRuleIds(mainText);
807
+ const selected = check(
808
+ await p.multiselect({
809
+ message: "Which working rules apply to this project?",
810
+ options: rules.map((r) => ({ value: r.id, label: r.title, hint: r.body.split("\n")[0].replace(/^- /, "") })),
811
+ initialValues: applied,
812
+ required: false
813
+ })
814
+ );
815
+ applyRulesToFile(mainFile, selected, sourceLang);
816
+ const subprojects = findSubprojects(scanTree(root2));
817
+ if (subprojects.length && selected.length) {
818
+ const targets = check(
819
+ await p.multiselect({
820
+ message: "Monorepo detected. Apply the same rules to these projects too?",
821
+ options: subprojects.map((s) => ({ value: s, label: s })),
822
+ required: false
823
+ })
824
+ );
825
+ for (const dir of targets) {
826
+ const doc = MAIN_DOCS.find((d) => fs8.existsSync(path8.join(root2, dir, d)));
827
+ applyRulesToFile(path8.join(root2, dir, doc), selected, sourceLang);
828
+ }
829
+ }
830
+ ensureGitignore(root2);
831
+ if (!previous) {
832
+ const hide = check(await p.confirm({ message: "Hide the .mdrules/ folder in VS Code?", initialValue: true }));
833
+ if (hide && !hideInVsCode(root2)) p.log.warn('.vscode/settings.json has comments; add "**/.mdrules": true to files.exclude by hand.');
834
+ }
835
+ installSkill(root2);
836
+ const config = { mainDoc, langs, initializedAt: previous?.initializedAt ?? (/* @__PURE__ */ new Date()).toISOString() };
837
+ writeConfig(root2, config);
838
+ p.outro(`Ready. Skill installed in ${pc2.cyan(".claude/skills/mdrules")}`);
839
+ return config;
840
+ }
841
+
842
+ // src/cli/index.ts
843
+ var HELP = `mdrules \u2014 visual editor for your project's Markdown
844
+
845
+ Usage
846
+ mdrules init if needed, then open the editor
847
+ mdrules init (re)run the setup: main doc, docs/, rules, language
848
+ mdrules serve open the editor without running init
849
+ mdrules sync --status [--json] translations + files not in the source language
850
+ mdrules sync --mark [--lang xx] <path...>|--all record translations as in sync
851
+ mdrules sync --keep <path...> keep files in their current language
852
+
853
+ Options
854
+ --port <n> server port (default 4319)
855
+ --no-open do not open the browser
856
+ `;
857
+ var args = process.argv.slice(2);
858
+ var flag = (name) => args.includes(name);
859
+ var option = (name) => {
860
+ const i = args.indexOf(name);
861
+ return i >= 0 ? args[i + 1] : void 0;
862
+ };
863
+ var command = args[0] && !args[0].startsWith("-") ? args[0] : "start";
864
+ var root = process.env.MDRULES_ROOT ?? process.cwd();
865
+ async function main() {
866
+ if (flag("--help") || flag("-h")) return console.log(HELP);
867
+ if (command === "sync") return sync();
868
+ if (command === "init") {
869
+ await runInit(root);
870
+ return;
871
+ }
872
+ if (command === "start" && !readConfig(root)) {
873
+ if (process.stdin.isTTY) await runInit(root);
874
+ }
875
+ if (command === "start" || command === "serve") {
876
+ await startServer({ root, port: Number(option("--port") ?? 4319), open: !flag("--no-open") });
877
+ return;
878
+ }
879
+ console.log(HELP);
880
+ process.exitCode = 1;
881
+ }
882
+ function sync() {
883
+ const report = syncReport(root);
884
+ const paths = (after) => args.slice(args.indexOf(after) + 1).filter((a, i, all) => !a.startsWith("--") && all[i - 1] !== "--lang");
885
+ if (flag("--keep")) {
886
+ for (const p2 of paths("--keep")) {
887
+ try {
888
+ console.log(`kept ${p2} (${keepLanguage(root, p2)})`);
889
+ } catch (err) {
890
+ console.error(`skipped ${p2}: ${err.message}`);
891
+ }
892
+ }
893
+ return;
894
+ }
895
+ if (flag("--mark")) {
896
+ const only = option("--lang");
897
+ const langs = only && isLang(only) ? [only] : report.langs;
898
+ const files = flag("--all") ? [...new Set(report.files.map((f) => f.path))] : paths("--mark");
899
+ for (const p2 of files) {
900
+ for (const l of langs) {
901
+ try {
902
+ markSynced(root, l, p2);
903
+ console.log(`synced ${l} ${p2}`);
904
+ } catch (err) {
905
+ if (!flag("--all")) console.error(`skipped ${l} ${p2}: ${err.message}`);
906
+ }
907
+ }
908
+ }
909
+ return;
910
+ }
911
+ if (flag("--json")) return console.log(JSON.stringify(report, null, 2));
912
+ console.log(`Source language: ${report.sourceLang} Translations: ${report.langs.join(", ") || "none"}`);
913
+ if (report.foreign.length) {
914
+ console.log(`
915
+ Not in ${report.sourceLang}:`);
916
+ for (const f of report.foreign) console.log(` ${f.detected} ${f.path}`);
917
+ }
918
+ const pending = report.files.filter((f) => f.status !== "synced");
919
+ if (pending.length) console.log("");
920
+ for (const e of pending) console.log(`${e.lang} ${e.status.padEnd(13)} ${e.path}`);
921
+ if (!pending.length && !report.foreign.length) console.log("Everything in sync.");
922
+ }
923
+ main().catch((err) => {
924
+ console.error(err);
925
+ process.exit(1);
926
+ });