strikethroo 4.0.0 → 4.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 (439) hide show
  1. package/README.md +14 -0
  2. package/dist/cli.js +18 -0
  3. package/dist/cli.js.map +1 -1
  4. package/dist/export-profile.d.ts +6 -0
  5. package/dist/export-profile.d.ts.map +1 -1
  6. package/dist/export-profile.js +46 -4
  7. package/dist/export-profile.js.map +1 -1
  8. package/dist/metadata.d.ts +11 -1
  9. package/dist/metadata.d.ts.map +1 -1
  10. package/dist/metadata.js +75 -11
  11. package/dist/metadata.js.map +1 -1
  12. package/dist/profiles.d.ts.map +1 -1
  13. package/dist/profiles.js +52 -7
  14. package/dist/profiles.js.map +1 -1
  15. package/dist/serve/config-write.d.ts +6 -3
  16. package/dist/serve/config-write.d.ts.map +1 -1
  17. package/dist/serve/config-write.js +20 -21
  18. package/dist/serve/config-write.js.map +1 -1
  19. package/dist/serve/events.d.ts +37 -8
  20. package/dist/serve/events.d.ts.map +1 -1
  21. package/dist/serve/events.js +114 -28
  22. package/dist/serve/events.js.map +1 -1
  23. package/dist/serve/self-review.d.ts +37 -7
  24. package/dist/serve/self-review.d.ts.map +1 -1
  25. package/dist/serve/self-review.js +93 -33
  26. package/dist/serve/self-review.js.map +1 -1
  27. package/dist/serve/server.d.ts +107 -0
  28. package/dist/serve/server.d.ts.map +1 -1
  29. package/dist/serve/server.js +502 -135
  30. package/dist/serve/server.js.map +1 -1
  31. package/dist/serve/workspace-model.d.ts.map +1 -1
  32. package/dist/serve/workspace-model.js +36 -34
  33. package/dist/serve/workspace-model.js.map +1 -1
  34. package/dist/skill-scripts/shared/safe-fs.d.ts +89 -0
  35. package/dist/skill-scripts/shared/safe-fs.d.ts.map +1 -0
  36. package/dist/skill-scripts/shared/safe-fs.js +324 -0
  37. package/dist/skill-scripts/shared/safe-fs.js.map +1 -0
  38. package/dist/types.d.ts +8 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/types.js +13 -1
  41. package/dist/types.js.map +1 -1
  42. package/dist/update.d.ts.map +1 -1
  43. package/dist/update.js +15 -1
  44. package/dist/update.js.map +1 -1
  45. package/dist-web/assets/abnfDiagram-VCTEODGH-BCoAyQ8y.js +1 -0
  46. package/dist-web/assets/apl-gfMMiTNf.js +1 -0
  47. package/dist-web/assets/arc-Pry-7G1_.js +1 -0
  48. package/dist-web/assets/architecture-7GRP2DOG-C2Oj1AcH.js +1 -0
  49. package/dist-web/assets/architectureDiagram-5GKGNRK7-BbYvyste.js +36 -0
  50. package/dist-web/assets/array-BifhSqXX.js +1 -0
  51. package/dist-web/assets/asciiarmor-C_eisQCp.js +1 -0
  52. package/dist-web/assets/asn1-DCl_8MCW.js +1 -0
  53. package/dist-web/assets/asterisk-BEn0Cwpx.js +1 -0
  54. package/dist-web/assets/blockDiagram-I7D4REHJ-CGYIKoI0.js +129 -0
  55. package/dist-web/assets/brainfuck-D5EjA2JK.js +1 -0
  56. package/dist-web/assets/c4Diagram-7LVT6UL2-Cpat9Q1R.js +38 -0
  57. package/dist-web/assets/channel-Da0Eg5hZ.js +1 -0
  58. package/dist-web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  59. package/dist-web/assets/chunk-4HAMMTFA-D1PXshWJ.js +62 -0
  60. package/dist-web/assets/{chunk-FMBD7UC4-zW3dYoIJ.js → chunk-5VM5RSS4-ZNzvKenW.js} +2 -2
  61. package/dist-web/assets/chunk-75Z2AOVW-C19f30iG.js +2 -0
  62. package/dist-web/assets/chunk-DU6HZSFF-CV-KOPc1.js +125 -0
  63. package/dist-web/assets/chunk-F27PBJKO-DMfX40T1.js +1 -0
  64. package/dist-web/assets/chunk-FOHPRMQF-DzxwRta7.js +161 -0
  65. package/dist-web/assets/chunk-GMAD6QVW-Nd9kACgc.js +72 -0
  66. package/dist-web/assets/chunk-GVQU2GXP-3G8ojGFe.js +1 -0
  67. package/dist-web/assets/chunk-IMKFNOWR-CmhGyHNd.js +231 -0
  68. package/dist-web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  69. package/dist-web/assets/chunk-L3NEJ4N5-Dsa1ER8Q.js +1 -0
  70. package/dist-web/assets/chunk-OSK3NFVY-ObCj9P3B.js +10 -0
  71. package/dist-web/assets/chunk-P2QGCYS3-CfNHqVGX.js +1 -0
  72. package/dist-web/assets/chunk-POPQ4Y6H-Cg5tk8by.js +1 -0
  73. package/dist-web/assets/chunk-PWAF6VOD-e6XMS-JR.js +1 -0
  74. package/dist-web/assets/chunk-SHT3W25Y-B1M0HI76.js +168 -0
  75. package/dist-web/assets/chunk-SVP7TREG-XLNHY4Z2.js +88 -0
  76. package/dist-web/assets/chunk-TICWLB2K-Bpm0S7rI.js +206 -0
  77. package/dist-web/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  78. package/dist-web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  79. package/dist-web/assets/classDiagram-ZZMXUADV-CZI086hK.js +1 -0
  80. package/dist-web/assets/classDiagram-v2-VYDZK3BY-CZI086hK.js +1 -0
  81. package/dist-web/assets/clike-D_6L3tnO.js +1 -0
  82. package/dist-web/assets/clojure-BflJGmDX.js +1 -0
  83. package/dist-web/assets/cmake-84nbDH0I.js +1 -0
  84. package/dist-web/assets/cobol-DHLQUbN7.js +1 -0
  85. package/dist-web/assets/coffeescript-De_zI4J0.js +1 -0
  86. package/dist-web/assets/commonlisp-DgAKBe0r.js +1 -0
  87. package/dist-web/assets/cose-bilkent-JH36ORCC-BEpcWcmK.js +1 -0
  88. package/dist-web/assets/crystal-Bsdphhtm.js +1 -0
  89. package/dist-web/assets/css-CnaYoQib.js +1 -0
  90. package/dist-web/assets/cynefin-OW5HDTMX-B5ohibc7.js +1 -0
  91. package/dist-web/assets/cynefinDiagram-5FMLGOSQ-C1202n-x.js +62 -0
  92. package/dist-web/assets/cypher-p9eYesGn.js +1 -0
  93. package/dist-web/assets/cytoscape.esm-Yq6u8L66.js +321 -0
  94. package/dist-web/assets/d-DWkQyNnU.js +1 -0
  95. package/dist-web/assets/dagre-C-rnJpZF.js +1 -0
  96. package/dist-web/assets/dagre-GXQ25YYZ-CQlKKJXg.js +4 -0
  97. package/dist-web/assets/defaultLocale-BFoDCU3G.js +1 -0
  98. package/dist-web/assets/diagram-S7CK7UJ4-DRf7iTH9.js +30 -0
  99. package/dist-web/assets/diagram-UQ7AKVKN-CxSX3b2_.js +41 -0
  100. package/dist-web/assets/diagram-VSXAHHWV-D9vrB5je.js +3 -0
  101. package/dist-web/assets/diagram-VX7I27RA-DTOqcpBV.js +24 -0
  102. package/dist-web/assets/diagram-Z3DM3KII-mlhRA4lR.js +24 -0
  103. package/dist-web/assets/diff-ChtP43wD.js +1 -0
  104. package/dist-web/assets/dist-B-O4eZD_.js +1 -0
  105. package/dist-web/assets/dist-B27L6oW0.js +1 -0
  106. package/dist-web/assets/dist-BKXbBuAc.js +1 -0
  107. package/dist-web/assets/dist-BPcC0hnc.js +9 -0
  108. package/dist-web/assets/dist-BgwxV8e_.js +1 -0
  109. package/dist-web/assets/dist-BlG40nRw.js +1 -0
  110. package/dist-web/assets/dist-Bqc6e86z.js +1 -0
  111. package/dist-web/assets/dist-BsvASXHG.js +1 -0
  112. package/dist-web/assets/dist-C15GN054.js +1 -0
  113. package/dist-web/assets/dist-C4QRmcTO.js +1 -0
  114. package/dist-web/assets/dist-C4lZy0XG.js +6 -0
  115. package/dist-web/assets/dist-CFLbFzpB.js +23 -0
  116. package/dist-web/assets/dist-CP6AUVtv.js +1 -0
  117. package/dist-web/assets/dist-CpYnHHz6.js +1 -0
  118. package/dist-web/assets/dist-DHnGmK79.js +1 -0
  119. package/dist-web/assets/dist-DYmIHv0n.js +13 -0
  120. package/dist-web/assets/dist-DauRO0RO.js +1 -0
  121. package/dist-web/assets/dist-Day7i26p.js +1 -0
  122. package/dist-web/assets/dist-Do_t70vA.js +1 -0
  123. package/dist-web/assets/dist-DqTG_rhR.js +2 -0
  124. package/dist-web/assets/dist-G8nWWSie.js +11 -0
  125. package/dist-web/assets/dist-QfYLz_N1.js +1 -0
  126. package/dist-web/assets/dist-TZhb2tj2.js +1 -0
  127. package/dist-web/assets/dist-Wr2Wo_KE.js +1 -0
  128. package/dist-web/assets/dist-kYRo7Db1.js +1 -0
  129. package/dist-web/assets/dist-kfqV1Lu-.js +2 -0
  130. package/dist-web/assets/dist-v5Q1xZ2K.js +1 -0
  131. package/dist-web/assets/dockerfile-DJkHQgkl.js +1 -0
  132. package/dist-web/assets/dtd-DTF72YNO.js +1 -0
  133. package/dist-web/assets/dylan-BCDoL_-p.js +1 -0
  134. package/dist-web/assets/ebnf-D4c0_ac3.js +1 -0
  135. package/dist-web/assets/ebnfDiagram-PWID7BFC-BhB_RJPM.js +1 -0
  136. package/dist-web/assets/ecl-BVIeWmwY.js +1 -0
  137. package/dist-web/assets/eiffel-BEjRio4Q.js +1 -0
  138. package/dist-web/assets/elm-Cshzl8qu.js +1 -0
  139. package/dist-web/assets/erDiagram-RLTQ6QDP-0wE1kPYz.js +99 -0
  140. package/dist-web/assets/erlang-BV0c4Hdn.js +1 -0
  141. package/dist-web/assets/esm-COEoxUhE.js +2 -0
  142. package/dist-web/assets/eventmodeling-NTZA5JFV-DzkXb9nA.js +1 -0
  143. package/dist-web/assets/factor-LKH5gN8L.js +1 -0
  144. package/dist-web/assets/fcl-ClOhbFR7.js +1 -0
  145. package/dist-web/assets/flowDiagram-HODETNUW-cgl8ipSt.js +1 -0
  146. package/dist-web/assets/forth-D6RzAl64.js +1 -0
  147. package/dist-web/assets/fortran-Bt6PBEDR.js +1 -0
  148. package/dist-web/assets/ganttDiagram-EL5Y4UJY-BsvlpHPt.js +292 -0
  149. package/dist-web/assets/gas-BHEdbvp9.js +1 -0
  150. package/dist-web/assets/gherkin-oBAE_ms0.js +1 -0
  151. package/dist-web/assets/gitGraph-4MIJSDKK-Dm82FCqy.js +1 -0
  152. package/dist-web/assets/gitGraphDiagram-WWUBYQGX-OPit_3vA.js +106 -0
  153. package/dist-web/assets/graphlib-DS17s2tU.js +1 -0
  154. package/dist-web/assets/groovy-CUpZ7dEl.js +1 -0
  155. package/dist-web/assets/haskell-BRsoo5mP.js +1 -0
  156. package/dist-web/assets/haxe-DjVOVvNP.js +1 -0
  157. package/dist-web/assets/http-CLVgA2GD.js +1 -0
  158. package/dist-web/assets/idl-BUZw3wgd.js +1 -0
  159. package/dist-web/assets/index-6XzOqB6r.js +103 -0
  160. package/dist-web/assets/index-CgIHUWsX.css +2 -0
  161. package/dist-web/assets/info-A6RAGUB7-8sl1XQWq.js +1 -0
  162. package/dist-web/assets/infoDiagram-27XIBGKW-DIpdnB7L.js +2 -0
  163. package/dist-web/assets/init-C-OQMol4.js +1 -0
  164. package/dist-web/assets/ishikawaDiagram-5VMMS53U-DpoLDWpF.js +70 -0
  165. package/dist-web/assets/javascript-Bu8mWwtz.js +1 -0
  166. package/dist-web/assets/journeyDiagram-3NMN7TZE-BAEbJ33U.js +139 -0
  167. package/dist-web/assets/julia-CQfgDRfP.js +1 -0
  168. package/dist-web/assets/kanban-definition-UXKFOSKX-CqzyUA0g.js +89 -0
  169. package/dist-web/assets/katex-ZlcWpGUi.js +257 -0
  170. package/dist-web/assets/line-CQRHrtV_.js +1 -0
  171. package/dist-web/assets/linear-SzVmGSw4.js +1 -0
  172. package/dist-web/assets/livescript-BXxG0Yva.js +1 -0
  173. package/dist-web/assets/lua-DPCEkfD_.js +1 -0
  174. package/dist-web/assets/mathematica-u8YMmbU0.js +1 -0
  175. package/dist-web/assets/mbox-BEMVcqjs.js +1 -0
  176. package/dist-web/assets/mermaid-parser.core-XlEvAPi2.js +7 -0
  177. package/dist-web/assets/mermaid.core-CvFTFi5O.js +44 -0
  178. package/dist-web/assets/mindmap-definition-YA3MSWOX-Ch0vW4Mc.js +96 -0
  179. package/dist-web/assets/{mirc-CjQqDB4T.js → mirc-C9zpzAZU.js} +1 -1
  180. package/dist-web/assets/mllike-B45xgp2S.js +1 -0
  181. package/dist-web/assets/modelica-CqHI_q-D.js +1 -0
  182. package/dist-web/assets/mscgen-qgSLujhx.js +1 -0
  183. package/dist-web/assets/mumps-BSzj6Xyz.js +1 -0
  184. package/dist-web/assets/{nginx-DdIZxoE0.js → nginx-8H7HVH4w.js} +1 -1
  185. package/dist-web/assets/nsis-CfSuhXs5.js +1 -0
  186. package/dist-web/assets/ntriples-B9h1VB_g.js +1 -0
  187. package/dist-web/assets/octave-D2Q8cUp1.js +1 -0
  188. package/dist-web/assets/ordinal-BDEzSJ7C.js +1 -0
  189. package/dist-web/assets/oz-BwTct_5T.js +1 -0
  190. package/dist-web/assets/packet-AYTQ26CC-lk-QU-qZ.js +1 -0
  191. package/dist-web/assets/pascal-Dp_KdFgX.js +1 -0
  192. package/dist-web/assets/path-fybaL0A-.js +1 -0
  193. package/dist-web/assets/pegDiagram-XKGWAZYB-Cgf4CYg-.js +1 -0
  194. package/dist-web/assets/perl-BkSkiI9m.js +1 -0
  195. package/dist-web/assets/pie-WAS4IAKB-dWyVjg9O.js +1 -0
  196. package/dist-web/assets/pieDiagram-E7YTZNPT-BDZxWO8n.js +39 -0
  197. package/dist-web/assets/pig-AF4Hwhju.js +1 -0
  198. package/dist-web/assets/powershell-BcIto6Sf.js +1 -0
  199. package/dist-web/assets/properties-C357ku5U.js +1 -0
  200. package/dist-web/assets/protobuf-D1ij_kNL.js +1 -0
  201. package/dist-web/assets/pug-3K-JMW4g.js +1 -0
  202. package/dist-web/assets/puppet-BZyAS7I4.js +1 -0
  203. package/dist-web/assets/python-B_1Jd8HM.js +1 -0
  204. package/dist-web/assets/q-B9NhS7L_.js +1 -0
  205. package/dist-web/assets/quadrantDiagram-AXDQQJYC-DCu9cx1_.js +7 -0
  206. package/dist-web/assets/r-CxDmU1I4.js +1 -0
  207. package/dist-web/assets/radar-RG4KPBEZ-CphwvESj.js +1 -0
  208. package/dist-web/assets/railroad-74A4TZTK-COTrvtXu.js +1 -0
  209. package/dist-web/assets/railroad-abnf-HS5TGJTU-CYfpugMj.js +1 -0
  210. package/dist-web/assets/railroad-ebnf-LZEXJU2U--Ui_4jm6.js +1 -0
  211. package/dist-web/assets/railroad-peg-WCYAUIDC-DzcveMan.js +1 -0
  212. package/dist-web/assets/railroadDiagram-O6MQD6OU-S9ZI1Adi.js +1 -0
  213. package/dist-web/assets/requirementDiagram-BXWQKSXE-a_3FElqS.js +84 -0
  214. package/dist-web/assets/rolldown-runtime-hePW80VL.js +1 -0
  215. package/dist-web/assets/rough.esm-Dy-Kn_BL.js +1 -0
  216. package/dist-web/assets/rpm-gpDK5sbt.js +1 -0
  217. package/dist-web/assets/ruby-BjXV7-Qa.js +1 -0
  218. package/dist-web/assets/sankeyDiagram-P5KCCOFB-D-i6r8wy.js +40 -0
  219. package/dist-web/assets/{sas-B4kiWyti.js → sas-C2OyD2Y6.js} +1 -1
  220. package/dist-web/assets/scheme-D9qYN0V5.js +1 -0
  221. package/dist-web/assets/sequenceDiagram-WJ2MYXX4-D8hA2m0U.js +162 -0
  222. package/dist-web/assets/shell-DwuoZtxw.js +1 -0
  223. package/dist-web/assets/sieve-tLWDfEkZ.js +1 -0
  224. package/dist-web/assets/simple-mode-DXiLM1-G.js +1 -0
  225. package/dist-web/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  226. package/dist-web/assets/smalltalk-BLp5-jwC.js +1 -0
  227. package/dist-web/assets/solr-B78wSQJQ.js +1 -0
  228. package/dist-web/assets/sparql-Dz-mlCAC.js +1 -0
  229. package/dist-web/assets/spreadsheet-CTIncYxj.js +1 -0
  230. package/dist-web/assets/sql-DuQMFDvy.js +1 -0
  231. package/dist-web/assets/src-B6xuSHsQ.js +1 -0
  232. package/dist-web/assets/stateDiagram-D77RDMKH-C14W-8zT.js +1 -0
  233. package/dist-web/assets/stateDiagram-v2-MP3YSRHH-Dhuhsub3.js +1 -0
  234. package/dist-web/assets/stex-DNzd62Q_.js +1 -0
  235. package/dist-web/assets/stylus-BOVgKnng.js +1 -0
  236. package/dist-web/assets/swift-DKB6_1j6.js +1 -0
  237. package/dist-web/assets/swimlanes-42K2YHIH-FMv8YLkC.js +1 -0
  238. package/dist-web/assets/swimlanesDiagram-VR7AAH4N-O94a9jW3.js +8 -0
  239. package/dist-web/assets/tcl-BGfruO1u.js +1 -0
  240. package/dist-web/assets/textile-C4jVoHG1.js +1 -0
  241. package/dist-web/assets/tiddlywiki-VlUiK86J.js +1 -0
  242. package/dist-web/assets/tiki-AK6FwT8q.js +1 -0
  243. package/dist-web/assets/timeline-definition-24CTP7MA-DmBN45fY.js +120 -0
  244. package/dist-web/assets/toml-BPTmHmyx.js +1 -0
  245. package/dist-web/assets/treeView-Q6P3EWNA-C5-PUnPN.js +1 -0
  246. package/dist-web/assets/treemap-WGGIJYW6-C_veVYMi.js +1 -0
  247. package/dist-web/assets/troff-C2dAgh7P.js +1 -0
  248. package/dist-web/assets/ttcn-PPSTk1ow.js +1 -0
  249. package/dist-web/assets/ttcn-cfg-2b4Gb5sE.js +1 -0
  250. package/dist-web/assets/turtle-Cx3rYX2g.js +1 -0
  251. package/dist-web/assets/vb-BthdM_4N.js +1 -0
  252. package/dist-web/assets/vbscript-D9f6rSsU.js +1 -0
  253. package/dist-web/assets/velocity-CqftRsjg.js +1 -0
  254. package/dist-web/assets/vennDiagram-4TSXK5OY-CiWHjSVc.js +34 -0
  255. package/dist-web/assets/verilog-CjI9Y6RI.js +1 -0
  256. package/dist-web/assets/vhdl-kS471soi.js +1 -0
  257. package/dist-web/assets/wardley-WFR3VGLG-FOCO1NlU.js +1 -0
  258. package/dist-web/assets/wardleyDiagram-VM6X3IG4-Da3kkvxV.js +78 -0
  259. package/dist-web/assets/webidl-D5jiJvOU.js +1 -0
  260. package/dist-web/assets/xquery-BKJx4mf9.js +1 -0
  261. package/dist-web/assets/xychartDiagram-S5SC5T6Z-DPxie1fH.js +7 -0
  262. package/dist-web/assets/yacas-CXXgtw0p.js +1 -0
  263. package/dist-web/assets/z80-Co3PbHdE.js +1 -0
  264. package/dist-web/index.html +6 -18
  265. package/dist-web/theme-guard.js +21 -0
  266. package/package.json +29 -24
  267. package/templates/strikethroo/config/config.yaml +2 -2
  268. package/dist-web/assets/apl-B4CMkyY2.js +0 -1
  269. package/dist-web/assets/arc-DA6tr0lU.js +0 -1
  270. package/dist-web/assets/architectureDiagram-3BPJPVTR-BEH2YihV.js +0 -36
  271. package/dist-web/assets/asciiarmor-Df11BRmG.js +0 -1
  272. package/dist-web/assets/asn1-EdZsLKOL.js +0 -1
  273. package/dist-web/assets/asterisk-B-8jnY81.js +0 -1
  274. package/dist-web/assets/blockDiagram-GPEHLZMM-jgUyFGxx.js +0 -132
  275. package/dist-web/assets/brainfuck-C4LP7Hcl.js +0 -1
  276. package/dist-web/assets/c4Diagram-AAUBKEIU-Do-n7I5O.js +0 -10
  277. package/dist-web/assets/channel-DJ33z8Wx.js +0 -1
  278. package/dist-web/assets/chunk-2J33WTMH-CgMvCn22.js +0 -1
  279. package/dist-web/assets/chunk-4BX2VUAB-FO8RQkkL.js +0 -1
  280. package/dist-web/assets/chunk-55IACEB6-DL_6pZjw.js +0 -1
  281. package/dist-web/assets/chunk-727SXJPM-DW7J3hiD.js +0 -206
  282. package/dist-web/assets/chunk-AQP2D5EJ-TPWnvFSC.js +0 -231
  283. package/dist-web/assets/chunk-ND2GUHAM-D0Nmkz3P.js +0 -1
  284. package/dist-web/assets/chunk-QZHKN3VN-BxgxRNWB.js +0 -1
  285. package/dist-web/assets/classDiagram-4FO5ZUOK--tqQjy0s.js +0 -1
  286. package/dist-web/assets/classDiagram-v2-Q7XG4LA2--tqQjy0s.js +0 -1
  287. package/dist-web/assets/clike-B9uivgTg.js +0 -1
  288. package/dist-web/assets/clojure-BMjYHr_A.js +0 -1
  289. package/dist-web/assets/cmake-BQqOBYOt.js +0 -1
  290. package/dist-web/assets/cobol-CWcv1MsR.js +0 -1
  291. package/dist-web/assets/coffeescript-S37ZYGWr.js +0 -1
  292. package/dist-web/assets/commonlisp-DBKNyK5s.js +0 -1
  293. package/dist-web/assets/cose-bilkent-S5V4N54A-ysHXC5GT.js +0 -1
  294. package/dist-web/assets/crystal-SjHAIU92.js +0 -1
  295. package/dist-web/assets/css-BnMrqG3P.js +0 -1
  296. package/dist-web/assets/cypher-C_CwsFkJ.js +0 -1
  297. package/dist-web/assets/cytoscape.esm-BHYC38rz.js +0 -331
  298. package/dist-web/assets/d-pRatUO7H.js +0 -1
  299. package/dist-web/assets/dagre-BM42HDAG-G_XIk8Dj.js +0 -4
  300. package/dist-web/assets/defaultLocale-CrowFXzY.js +0 -1
  301. package/dist-web/assets/diagram-2AECGRRQ-7HG2PLhr.js +0 -43
  302. package/dist-web/assets/diagram-5GNKFQAL-BdS1bF_R.js +0 -10
  303. package/dist-web/assets/diagram-KO2AKTUF-AFaiXGZQ.js +0 -3
  304. package/dist-web/assets/diagram-LMA3HP47-CTWrauj7.js +0 -24
  305. package/dist-web/assets/diagram-OG6HWLK6-BmBckGLa.js +0 -24
  306. package/dist-web/assets/diff-DbItnlRl.js +0 -1
  307. package/dist-web/assets/dockerfile-BKs6k2Af.js +0 -1
  308. package/dist-web/assets/dtd-DF_7sFjM.js +0 -1
  309. package/dist-web/assets/dylan-DwRh75JA.js +0 -1
  310. package/dist-web/assets/ebnf-CDyGwa7X.js +0 -1
  311. package/dist-web/assets/ecl-Cabwm37j.js +0 -1
  312. package/dist-web/assets/eiffel-CnydiIhH.js +0 -1
  313. package/dist-web/assets/elm-vLlmbW-K.js +0 -1
  314. package/dist-web/assets/erDiagram-TEJ5UH35-C0B2cXE-.js +0 -85
  315. package/dist-web/assets/erlang-BNw1qcRV.js +0 -1
  316. package/dist-web/assets/factor-kuTfRLto.js +0 -1
  317. package/dist-web/assets/fcl-Kvtd6kyn.js +0 -1
  318. package/dist-web/assets/flowDiagram-I6XJVG4X-CZ70tn_Q.js +0 -162
  319. package/dist-web/assets/forth-Ffai-XNe.js +0 -1
  320. package/dist-web/assets/fortran-DYz_wnZ1.js +0 -1
  321. package/dist-web/assets/ganttDiagram-6RSMTGT7-h7O-Xh-D.js +0 -292
  322. package/dist-web/assets/gas-Bneqetm1.js +0 -1
  323. package/dist-web/assets/gherkin-heZmZLOM.js +0 -1
  324. package/dist-web/assets/gitGraphDiagram-PVQCEYII-BDZixURw.js +0 -106
  325. package/dist-web/assets/graph-Dqkl27Ch.js +0 -1
  326. package/dist-web/assets/groovy-D9Dt4D0W.js +0 -1
  327. package/dist-web/assets/haskell-BWDZoCOh.js +0 -1
  328. package/dist-web/assets/haxe-H-WmDvRZ.js +0 -1
  329. package/dist-web/assets/http-DBlCnlav.js +0 -1
  330. package/dist-web/assets/idl-BEugSyMb.js +0 -1
  331. package/dist-web/assets/index-B-KlYMEI.js +0 -1
  332. package/dist-web/assets/index-B0a4C4Lb.js +0 -1
  333. package/dist-web/assets/index-B90tvIxG.js +0 -3
  334. package/dist-web/assets/index-BLXIwDvb.js +0 -1
  335. package/dist-web/assets/index-BjZYUODU.js +0 -1
  336. package/dist-web/assets/index-BmsczLPZ.js +0 -1
  337. package/dist-web/assets/index-BpU7RpGz.js +0 -1
  338. package/dist-web/assets/index-BwFIiA6J.js +0 -2
  339. package/dist-web/assets/index-C53NKwQ5.js +0 -1
  340. package/dist-web/assets/index-C73riuQN.js +0 -1
  341. package/dist-web/assets/index-C9RcHSPW.js +0 -1
  342. package/dist-web/assets/index-CEBV-m_B.js +0 -1
  343. package/dist-web/assets/index-CG1O2Vjg.js +0 -1
  344. package/dist-web/assets/index-CRL66wiY.js +0 -169
  345. package/dist-web/assets/index-CddJufqj.js +0 -1
  346. package/dist-web/assets/index-CrzBaw1K.css +0 -1
  347. package/dist-web/assets/index-CuBsNWzH.js +0 -13
  348. package/dist-web/assets/index-CuCAyRTw.js +0 -7
  349. package/dist-web/assets/index-CuUh3dvS.js +0 -1
  350. package/dist-web/assets/index-CwPWc9jQ.js +0 -1
  351. package/dist-web/assets/index-DHBbud_j.js +0 -1
  352. package/dist-web/assets/index-LLaxWDbg.js +0 -1
  353. package/dist-web/assets/index-XOpAvr0E.js +0 -13
  354. package/dist-web/assets/index-aX67gnlS.js +0 -2
  355. package/dist-web/assets/index-lkaAPBmM.js +0 -6
  356. package/dist-web/assets/index-pUkuW0EP.js +0 -1
  357. package/dist-web/assets/index-sbfqG9cy.js +0 -1
  358. package/dist-web/assets/index-udFbjSlZ.js +0 -2
  359. package/dist-web/assets/index-yjEPVwyN.js +0 -1
  360. package/dist-web/assets/infoDiagram-5YYISTIA-CKXHxMh_.js +0 -2
  361. package/dist-web/assets/init-Gi6I4Gst.js +0 -1
  362. package/dist-web/assets/ishikawaDiagram-YF4QCWOH-DGancylI.js +0 -70
  363. package/dist-web/assets/javascript-qCveANmP.js +0 -1
  364. package/dist-web/assets/journeyDiagram-JHISSGLW-DifvKy-w.js +0 -139
  365. package/dist-web/assets/julia-DuME0IfC.js +0 -1
  366. package/dist-web/assets/kanban-definition-UN3LZRKU-ByC-4YyY.js +0 -89
  367. package/dist-web/assets/katex-C5jXJg4s.js +0 -257
  368. package/dist-web/assets/layout-DO9UvE1P.js +0 -1
  369. package/dist-web/assets/linear-Cm0Y2OWD.js +0 -1
  370. package/dist-web/assets/livescript-BwQOo05w.js +0 -1
  371. package/dist-web/assets/lua-VAEuO923.js +0 -1
  372. package/dist-web/assets/mathematica-DTrFuWx2.js +0 -1
  373. package/dist-web/assets/mbox-CNhZ1qSd.js +0 -1
  374. package/dist-web/assets/mermaid.core-DBlLt9sa.js +0 -307
  375. package/dist-web/assets/mindmap-definition-RKZ34NQL-tkThiQWd.js +0 -96
  376. package/dist-web/assets/mllike-CXdrOF99.js +0 -1
  377. package/dist-web/assets/modelica-Dc1JOy9r.js +0 -1
  378. package/dist-web/assets/mscgen-BA5vi2Kp.js +0 -1
  379. package/dist-web/assets/mumps-BT43cFF4.js +0 -1
  380. package/dist-web/assets/nsis-LdVXkNf5.js +0 -1
  381. package/dist-web/assets/ntriples-BfvgReVJ.js +0 -1
  382. package/dist-web/assets/octave-Ck1zUtKM.js +0 -1
  383. package/dist-web/assets/ordinal-Cboi1Yqb.js +0 -1
  384. package/dist-web/assets/oz-BzwKVEFT.js +0 -1
  385. package/dist-web/assets/pascal--L3eBynH.js +0 -1
  386. package/dist-web/assets/perl-CdXCOZ3F.js +0 -1
  387. package/dist-web/assets/pieDiagram-4H26LBE5-BXGBVjcj.js +0 -30
  388. package/dist-web/assets/pig-CevX1Tat.js +0 -1
  389. package/dist-web/assets/powershell-CFHJl5sT.js +0 -1
  390. package/dist-web/assets/properties-C78fOPTZ.js +0 -1
  391. package/dist-web/assets/protobuf-ChK-085T.js +0 -1
  392. package/dist-web/assets/pug-DukmZTjD.js +0 -1
  393. package/dist-web/assets/puppet-DMA9R1ak.js +0 -1
  394. package/dist-web/assets/python-BuPzkPfP.js +0 -1
  395. package/dist-web/assets/q-pXgVlZs6.js +0 -1
  396. package/dist-web/assets/quadrantDiagram-W4KKPZXB-DnF0iEBo.js +0 -7
  397. package/dist-web/assets/r-DUYO_cvP.js +0 -1
  398. package/dist-web/assets/requirementDiagram-4Y6WPE33-BooGjmPb.js +0 -84
  399. package/dist-web/assets/rpm-CTu-6PCP.js +0 -1
  400. package/dist-web/assets/ruby-B2Rjki9n.js +0 -1
  401. package/dist-web/assets/sankeyDiagram-5OEKKPKP-7le5uaC7.js +0 -40
  402. package/dist-web/assets/scheme-C41bIUwD.js +0 -1
  403. package/dist-web/assets/sequenceDiagram-3UESZ5HK-B9GCKMDd.js +0 -162
  404. package/dist-web/assets/shell-CjFT_Tl9.js +0 -1
  405. package/dist-web/assets/sieve-C3Gn_uJK.js +0 -1
  406. package/dist-web/assets/simple-mode-GW_nhZxv.js +0 -1
  407. package/dist-web/assets/smalltalk-CnHTOXQT.js +0 -1
  408. package/dist-web/assets/solr-DehyRSwq.js +0 -1
  409. package/dist-web/assets/sparql-DkYu6x3z.js +0 -1
  410. package/dist-web/assets/spreadsheet-BCZA_wO0.js +0 -1
  411. package/dist-web/assets/sql-D0XecflT.js +0 -1
  412. package/dist-web/assets/stateDiagram-AJRCARHV-CO2qL8R6.js +0 -1
  413. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-DUkgqBTd.js +0 -1
  414. package/dist-web/assets/stex-C3f8Ysf7.js +0 -1
  415. package/dist-web/assets/stylus-B533Al4x.js +0 -1
  416. package/dist-web/assets/swift-BzpIVaGY.js +0 -1
  417. package/dist-web/assets/tcl-DVfN8rqt.js +0 -1
  418. package/dist-web/assets/textile-CnDTJFAw.js +0 -1
  419. package/dist-web/assets/tiddlywiki-DO-Gjzrf.js +0 -1
  420. package/dist-web/assets/tiki-DGYXhP31.js +0 -1
  421. package/dist-web/assets/timeline-definition-PNZ67QCA-FLzWM85F.js +0 -120
  422. package/dist-web/assets/toml-Bm5Em-hy.js +0 -1
  423. package/dist-web/assets/troff-wAsdV37c.js +0 -1
  424. package/dist-web/assets/ttcn-CfJYG6tj.js +0 -1
  425. package/dist-web/assets/ttcn-cfg-B9xdYoR4.js +0 -1
  426. package/dist-web/assets/turtle-B1tBg_DP.js +0 -1
  427. package/dist-web/assets/vb-CmGdzxic.js +0 -1
  428. package/dist-web/assets/vbscript-BuJXcnF6.js +0 -1
  429. package/dist-web/assets/velocity-D8B20fx6.js +0 -1
  430. package/dist-web/assets/vennDiagram-CIIHVFJN-Dt6p6Ib1.js +0 -34
  431. package/dist-web/assets/verilog-C6RDOZhf.js +0 -1
  432. package/dist-web/assets/vhdl-lSbBsy5d.js +0 -1
  433. package/dist-web/assets/wardley-L42UT6IY-D6k_B5It.js +0 -173
  434. package/dist-web/assets/wardleyDiagram-YWT4CUSO-jT3ItNLi.js +0 -78
  435. package/dist-web/assets/webidl-ZXfAyPTL.js +0 -1
  436. package/dist-web/assets/xquery-CQfU5ijd.js +0 -1
  437. package/dist-web/assets/xychartDiagram-2RQKCTM6-CpM6UhUO.js +0 -7
  438. package/dist-web/assets/yacas-BJ4BC0dw.js +0 -1
  439. package/dist-web/assets/z80-Hz9HOZM7.js +0 -1
@@ -15,9 +15,12 @@
15
15
  * to the workspace's structured configuration file `config/config.yaml` (the
16
16
  * file behind the Customize section's Config form). In every case the target
17
17
  * file must ALREADY exist (this never creates a new file). When the guards
18
- * pass it overwrites the file content verbatim. It never deletes or renames.
19
- * Expected guard failures are returned as a typed result, not thrown; only an
20
- * unexpected filesystem error surfaces as `fs-error`. Node built-ins only.
18
+ * pass it overwrites the file content verbatim through the shared containment
19
+ * helper, so a symlinked file or directory anywhere below the workspace root
20
+ * (or a non-regular file at the target) is refused as `not-found` rather than
21
+ * followed. It never deletes or renames the target itself. Expected guard
22
+ * failures are returned as a typed result, not thrown; only an unexpected
23
+ * filesystem error surfaces as `fs-error`. Node built-ins only.
21
24
  */
22
25
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
26
  if (k2 === undefined) k2 = k;
@@ -54,8 +57,8 @@ var __importStar = (this && this.__importStar) || (function () {
54
57
  })();
55
58
  Object.defineProperty(exports, "__esModule", { value: true });
56
59
  exports.writeConfigFile = void 0;
57
- const fs = __importStar(require("fs"));
58
60
  const path = __importStar(require("path"));
61
+ const safe_fs_1 = require("../skill-scripts/shared/safe-fs");
59
62
  /** The directory-backed config kinds that may be written. */
60
63
  const KINDS = new Set(['hooks', 'templates']);
61
64
  /**
@@ -66,14 +69,15 @@ const KINDS = new Set(['hooks', 'templates']);
66
69
  * performs zero filesystem changes on any guard failure.
67
70
  */
68
71
  const writeConfigFile = async (root, kind, id, content) => {
69
- let target;
72
+ /** Target path relative to `root`; the helper does the on-disk containment. */
73
+ let relTarget;
70
74
  if (kind === 'workspace') {
71
75
  // The workspace's single structured config file. No id namespace exists
72
76
  // here — `config` is the only valid id, fixed to config/config.yaml.
73
77
  if (id !== 'config') {
74
78
  return { ok: false, reason: 'invalid-id', message: 'Invalid config file id.' };
75
79
  }
76
- target = path.resolve(root, 'config', 'config.yaml');
80
+ relTarget = path.join('config', 'config.yaml');
77
81
  }
78
82
  else {
79
83
  if (!KINDS.has(kind)) {
@@ -84,30 +88,25 @@ const writeConfigFile = async (root, kind, id, content) => {
84
88
  return { ok: false, reason: 'invalid-id', message: 'Invalid config file id.' };
85
89
  }
86
90
  const dir = path.resolve(root, 'config', kind);
87
- target = path.resolve(dir, `${id}.md`);
88
- // Containment: the resolved target must be a direct, flat child of `dir`.
91
+ const target = path.resolve(dir, `${id}.md`);
92
+ // Lexical containment: the resolved target must be a direct, flat child of
93
+ // `dir`. The on-disk walk below is what rejects links and special files.
89
94
  const withinDir = target.startsWith(dir + path.sep);
90
95
  const isFlatChild = path.dirname(target) === dir;
91
96
  if (!withinDir || !isFlatChild) {
92
97
  return { ok: false, reason: 'invalid-id', message: 'Invalid config file id.' };
93
98
  }
99
+ relTarget = path.join('config', kind, `${id}.md`);
94
100
  }
95
- try {
96
- const stat = await fs.promises.stat(target);
97
- if (!stat.isFile()) {
98
- return { ok: false, reason: 'not-found', message: 'Config file not found.' };
99
- }
100
- }
101
- catch {
102
- return { ok: false, reason: 'not-found', message: 'Config file not found.' };
103
- }
104
- try {
105
- await fs.promises.writeFile(target, content, 'utf8');
101
+ const written = await (0, safe_fs_1.writeFileAtomic)(root, relTarget, content, { mustExist: true });
102
+ if (!('error' in written))
106
103
  return { ok: true };
107
- }
108
- catch {
104
+ // Anything the helper refused to resolve (missing, linked, special, escaped)
105
+ // is reported as absent; only a genuine I/O failure is an fs-error.
106
+ if (written.error === 'fs-error' || written.error === 'too-large') {
109
107
  return { ok: false, reason: 'fs-error', message: 'Failed to write config file.' };
110
108
  }
109
+ return { ok: false, reason: 'not-found', message: 'Config file not found.' };
111
110
  };
112
111
  exports.writeConfigFile = writeConfigFile;
113
112
  //# sourceMappingURL=config-write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-write.js","sourceRoot":"","sources":["../../src/serve/config-write.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-write.js","sourceRoot":"","sources":["../../src/serve/config-write.ts"],"names":[],"mappings":"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"}
@@ -3,15 +3,30 @@
3
3
  *
4
4
  * Provides `GET /api/events`: a `text/event-stream` that broadcasts a single
5
5
  * coalesced `changed` ping whenever the workspace mutates on disk. The event
6
- * carries no diff payload — clients refetch the affected API data (the browser
7
- * consumer is a later plan).
6
+ * carries no diff payload — clients refetch the affected API data.
8
7
  *
9
8
  * Exposes an {@link EventsHub} that owns the connected-client set and the
10
9
  * workspace watcher, plus an `ApiHandler` the server registers so this module
11
- * stays decoupled from routing. Connections are cleaned up on disconnect so no
12
- * listeners or sockets leak. Node built-ins only.
10
+ * stays decoupled from routing. Delivery is bounded per session: at most
11
+ * {@link MAX_SSE_CLIENTS} streams are admitted, a client whose socket stops
12
+ * accepting data is written to only once more (one coalesced `changed` on
13
+ * `drain`), and one still blocked after {@link BLOCKED_TIMEOUT_MS} is ended and
14
+ * removed. Disconnect and {@link EventsHub.close} release every per-client
15
+ * timer and listener so nothing leaks. Node built-ins only.
13
16
  */
14
17
  import * as http from 'http';
18
+ /** Keep-alive comment interval (ms) to hold idle proxies/streams open. */
19
+ export declare const KEEP_ALIVE_MS = 15000;
20
+ /** Upper bound on concurrently connected SSE clients per hub. */
21
+ export declare const MAX_SSE_CLIENTS = 16;
22
+ /** How long (ms) a client may stay blocked on backpressure before it is dropped. */
23
+ export declare const BLOCKED_TIMEOUT_MS = 30000;
24
+ /** The compiled bounds; tests shorten them through the constructor. */
25
+ export interface EventsHubLimits {
26
+ maxClients: number;
27
+ blockedTimeoutMs: number;
28
+ keepAliveMs: number;
29
+ }
15
30
  /**
16
31
  * Owns the SSE client set and the workspace watcher. One hub per server. Start
17
32
  * the watcher with {@link start} after the server is listening; release it with
@@ -22,16 +37,30 @@ export declare class EventsHub {
22
37
  private readonly debounceMs?;
23
38
  private readonly clients;
24
39
  private watcher;
25
- constructor(workspaceDir: string, debounceMs?: number | undefined);
40
+ private readonly limits;
41
+ constructor(workspaceDir: string, debounceMs?: number | undefined, limits?: Partial<EventsHubLimits>);
26
42
  /** Begins watching the workspace; coalesced changes broadcast to all clients. */
27
43
  start(): void;
28
44
  /** Stops the watcher and ends every open client connection. */
29
45
  close(): void;
30
46
  /** Number of currently connected SSE clients (used by tests). */
31
47
  get clientCount(): number;
32
- /** Sends a single coalesced `changed` event to every connected client. */
33
- private broadcast;
34
- /** Attaches an SSE response: writes headers, registers cleanup on close. */
48
+ /** Number of connected clients currently held back by backpressure. */
49
+ get blockedClientCount(): number;
50
+ /**
51
+ * Sends a single coalesced `changed` event to every connected client. A
52
+ * blocked client is owed exactly one `changed` on `drain`, however many
53
+ * broadcasts it misses. Called by the watcher; public so tests can drive the
54
+ * stream without touching disk.
55
+ */
56
+ broadcast(): void;
57
+ /**
58
+ * Writes one chunk, honoring backpressure: when `write()` returns `false` the
59
+ * client is marked blocked, further writes are skipped, a `drain` listener is
60
+ * armed to resume, and the slow timer starts.
61
+ */
62
+ private send;
63
+ /** Attaches an SSE response, or refuses it with `503` when at capacity. */
35
64
  handleConnection(req: http.IncomingMessage, res: http.ServerResponse): void;
36
65
  /** An {@link ApiHandler} for `GET /api/events`; returns false otherwise. */
37
66
  apiHandler: (req: http.IncomingMessage, res: http.ServerResponse, ctx: {
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAM7B;;;;GAIG;AACH,qBAAa,SAAS;IAKlB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAL9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAC1D,OAAO,CAAC,OAAO,CAAiC;gBAG7B,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,YAAA;IAGtC,iFAAiF;IACjF,KAAK,IAAI,IAAI;IASb,+DAA+D;IAC/D,KAAK,IAAI,IAAI;IAWb,iEAAiE;IACjE,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,0EAA0E;IAC1E,OAAO,CAAC,SAAS;IAMjB,4EAA4E;IAC5E,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI;IAyB3E,4EAA4E;IAC5E,UAAU,GACR,KAAK,IAAI,CAAC,eAAe,EACzB,KAAK,IAAI,CAAC,cAAc,EACxB,KAAK;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,KACxB,OAAO,CAMR;CACH"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,0EAA0E;AAC1E,eAAO,MAAM,aAAa,QAAQ,CAAC;AAEnC,iEAAiE;AACjE,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAQxC,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAeD;;;;GAIG;AACH,qBAAa,SAAS;IAMlB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAN9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+C;IACvE,OAAO,CAAC,OAAO,CAAiC;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAGtB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,YAAA,EACpC,MAAM,GAAE,OAAO,CAAC,eAAe,CAAM;IASvC,iFAAiF;IACjF,KAAK,IAAI,IAAI;IASb,+DAA+D;IAC/D,KAAK,IAAI,IAAI;IAab,iEAAiE;IACjE,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,uEAAuE;IACvE,IAAI,kBAAkB,IAAI,MAAM,CAI/B;IAED;;;;;OAKG;IACH,SAAS,IAAI,IAAI;IAOjB;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAYZ,2EAA2E;IAC3E,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI;IAyD3E,4EAA4E;IAC5E,UAAU,GACR,KAAK,IAAI,CAAC,eAAe,EACzB,KAAK,IAAI,CAAC,cAAc,EACxB,KAAK;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,KACxB,OAAO,CAMR;CACH"}
@@ -4,29 +4,40 @@
4
4
  *
5
5
  * Provides `GET /api/events`: a `text/event-stream` that broadcasts a single
6
6
  * coalesced `changed` ping whenever the workspace mutates on disk. The event
7
- * carries no diff payload — clients refetch the affected API data (the browser
8
- * consumer is a later plan).
7
+ * carries no diff payload — clients refetch the affected API data.
9
8
  *
10
9
  * Exposes an {@link EventsHub} that owns the connected-client set and the
11
10
  * workspace watcher, plus an `ApiHandler` the server registers so this module
12
- * stays decoupled from routing. Connections are cleaned up on disconnect so no
13
- * listeners or sockets leak. Node built-ins only.
11
+ * stays decoupled from routing. Delivery is bounded per session: at most
12
+ * {@link MAX_SSE_CLIENTS} streams are admitted, a client whose socket stops
13
+ * accepting data is written to only once more (one coalesced `changed` on
14
+ * `drain`), and one still blocked after {@link BLOCKED_TIMEOUT_MS} is ended and
15
+ * removed. Disconnect and {@link EventsHub.close} release every per-client
16
+ * timer and listener so nothing leaks. Node built-ins only.
14
17
  */
15
18
  Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.EventsHub = void 0;
19
+ exports.EventsHub = exports.BLOCKED_TIMEOUT_MS = exports.MAX_SSE_CLIENTS = exports.KEEP_ALIVE_MS = void 0;
17
20
  const watcher_1 = require("./watcher");
18
21
  /** Keep-alive comment interval (ms) to hold idle proxies/streams open. */
19
- const KEEP_ALIVE_MS = 15000;
22
+ exports.KEEP_ALIVE_MS = 15000;
23
+ /** Upper bound on concurrently connected SSE clients per hub. */
24
+ exports.MAX_SSE_CLIENTS = 16;
25
+ /** How long (ms) a client may stay blocked on backpressure before it is dropped. */
26
+ exports.BLOCKED_TIMEOUT_MS = 30000;
27
+ /** `Retry-After` (seconds) sent with the `503` for a refused connection. */
28
+ const RETRY_AFTER_SECONDS = 5;
29
+ const CHANGED_EVENT = 'event: changed\ndata: {}\n\n';
30
+ const KEEP_ALIVE_COMMENT = ': keep-alive\n\n';
20
31
  /**
21
32
  * Owns the SSE client set and the workspace watcher. One hub per server. Start
22
33
  * the watcher with {@link start} after the server is listening; release it with
23
34
  * {@link close} when the server closes.
24
35
  */
25
36
  class EventsHub {
26
- constructor(workspaceDir, debounceMs) {
37
+ constructor(workspaceDir, debounceMs, limits = {}) {
27
38
  this.workspaceDir = workspaceDir;
28
39
  this.debounceMs = debounceMs;
29
- this.clients = new Set();
40
+ this.clients = new Map();
30
41
  this.watcher = null;
31
42
  /** An {@link ApiHandler} for `GET /api/events`; returns false otherwise. */
32
43
  this.apiHandler = (req, res, ctx) => {
@@ -36,6 +47,11 @@ class EventsHub {
36
47
  }
37
48
  return false;
38
49
  };
50
+ this.limits = {
51
+ maxClients: limits.maxClients ?? exports.MAX_SSE_CLIENTS,
52
+ blockedTimeoutMs: limits.blockedTimeoutMs ?? exports.BLOCKED_TIMEOUT_MS,
53
+ keepAliveMs: limits.keepAliveMs ?? exports.KEEP_ALIVE_MS,
54
+ };
39
55
  }
40
56
  /** Begins watching the workspace; coalesced changes broadcast to all clients. */
41
57
  start() {
@@ -49,42 +65,112 @@ class EventsHub {
49
65
  this.watcher.close();
50
66
  this.watcher = null;
51
67
  }
52
- for (const res of this.clients) {
53
- res.end();
68
+ for (const [res, state] of [...this.clients]) {
69
+ state.cleanup();
70
+ // A blocked socket cannot flush an `end()`; drop it instead.
71
+ if (state.blocked)
72
+ res.destroy();
73
+ else
74
+ res.end();
54
75
  }
55
- this.clients.clear();
56
76
  }
57
77
  /** Number of currently connected SSE clients (used by tests). */
58
78
  get clientCount() {
59
79
  return this.clients.size;
60
80
  }
61
- /** Sends a single coalesced `changed` event to every connected client. */
81
+ /** Number of connected clients currently held back by backpressure. */
82
+ get blockedClientCount() {
83
+ let count = 0;
84
+ for (const state of this.clients.values())
85
+ if (state.blocked)
86
+ count += 1;
87
+ return count;
88
+ }
89
+ /**
90
+ * Sends a single coalesced `changed` event to every connected client. A
91
+ * blocked client is owed exactly one `changed` on `drain`, however many
92
+ * broadcasts it misses. Called by the watcher; public so tests can drive the
93
+ * stream without touching disk.
94
+ */
62
95
  broadcast() {
63
- for (const res of this.clients) {
64
- res.write('event: changed\ndata: {}\n\n');
96
+ for (const [res, state] of this.clients) {
97
+ if (state.blocked)
98
+ state.pending = true;
99
+ else
100
+ this.send(res, state, CHANGED_EVENT);
65
101
  }
66
102
  }
67
- /** Attaches an SSE response: writes headers, registers cleanup on close. */
103
+ /**
104
+ * Writes one chunk, honoring backpressure: when `write()` returns `false` the
105
+ * client is marked blocked, further writes are skipped, a `drain` listener is
106
+ * armed to resume, and the slow timer starts.
107
+ */
108
+ send(res, state, chunk) {
109
+ if (state.blocked)
110
+ return;
111
+ if (res.write(chunk))
112
+ return;
113
+ state.blocked = true;
114
+ res.once('drain', state.onDrain);
115
+ state.slowTimer = setTimeout(() => {
116
+ state.cleanup();
117
+ res.destroy();
118
+ }, this.limits.blockedTimeoutMs);
119
+ state.slowTimer.unref?.();
120
+ }
121
+ /** Attaches an SSE response, or refuses it with `503` when at capacity. */
68
122
  handleConnection(req, res) {
123
+ if (this.clients.size >= this.limits.maxClients) {
124
+ const body = JSON.stringify({ error: 'Too many event-stream clients.' });
125
+ res.writeHead(503, {
126
+ 'Content-Type': 'application/json; charset=utf-8',
127
+ 'Content-Length': Buffer.byteLength(body),
128
+ 'Retry-After': String(RETRY_AFTER_SECONDS),
129
+ });
130
+ res.end(body);
131
+ return;
132
+ }
69
133
  res.writeHead(200, {
70
134
  'Content-Type': 'text/event-stream',
71
135
  'Cache-Control': 'no-cache',
72
136
  Connection: 'keep-alive',
73
137
  });
74
- // Initial comment opens the stream and flushes headers to the client.
75
- res.write(': connected\n\n');
76
- this.clients.add(res);
77
- const keepAlive = setInterval(() => {
78
- res.write(': keep-alive\n\n');
79
- }, KEEP_ALIVE_MS);
80
- // Don't let the keep-alive timer hold the event loop / process open.
81
- keepAlive.unref?.();
82
- const cleanup = () => {
83
- clearInterval(keepAlive);
84
- this.clients.delete(res);
138
+ const state = {
139
+ blocked: false,
140
+ pending: false,
141
+ keepAlive: setInterval(() => this.send(res, state, KEEP_ALIVE_COMMENT), this.limits.keepAliveMs),
142
+ slowTimer: null,
143
+ onDrain: () => {
144
+ if (!this.clients.has(res))
145
+ return;
146
+ state.blocked = false;
147
+ if (state.slowTimer) {
148
+ clearTimeout(state.slowTimer);
149
+ state.slowTimer = null;
150
+ }
151
+ if (state.pending) {
152
+ state.pending = false;
153
+ this.send(res, state, CHANGED_EVENT);
154
+ }
155
+ },
156
+ cleanup: () => {
157
+ if (!this.clients.delete(res))
158
+ return;
159
+ clearInterval(state.keepAlive);
160
+ if (state.slowTimer)
161
+ clearTimeout(state.slowTimer);
162
+ res.removeListener('drain', state.onDrain);
163
+ req.removeListener('close', state.cleanup);
164
+ res.removeListener('close', state.cleanup);
165
+ },
85
166
  };
86
- req.on('close', cleanup);
87
- res.on('close', cleanup);
167
+ // Don't let the keep-alive timer hold the event loop / process open.
168
+ state.keepAlive.unref?.();
169
+ this.clients.set(res, state);
170
+ req.on('close', state.cleanup);
171
+ res.on('close', state.cleanup);
172
+ // Initial comment opens the stream and flushes headers to the client.
173
+ this.send(res, state, ': connected\n\n');
88
174
  }
89
175
  }
90
176
  exports.EventsHub = EventsHub;
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAGH,uCAAqE;AAErE,0EAA0E;AAC1E,MAAM,aAAa,GAAG,KAAK,CAAC;AAE5B;;;;GAIG;AACH,MAAa,SAAS;IAIpB,YACmB,YAAoB,EACpB,UAAmB;QADnB,iBAAY,GAAZ,YAAY,CAAQ;QACpB,eAAU,GAAV,UAAU,CAAS;QALrB,YAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;QAClD,YAAO,GAA4B,IAAI,CAAC;QAmEhD,4EAA4E;QAC5E,eAAU,GAAG,CACX,GAAyB,EACzB,GAAwB,EACxB,GAAyB,EAChB,EAAE;YACX,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,GAAG,CAAC,QAAQ,KAAK,cAAc,EAAE,CAAC;gBACtE,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAChC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;IAzEC,CAAC;IAEJ,iFAAiF;IACjF,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAA,gCAAsB,EACnC,IAAI,CAAC,YAAY,EACjB,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,EACtB,IAAI,CAAC,UAAU,CAChB,CAAC;IACJ,CAAC;IAED,+DAA+D;IAC/D,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,iEAAiE;IACjE,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAClE,SAAS;QACf,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,gBAAgB,CAAC,GAAyB,EAAE,GAAwB;QAClE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QACH,sEAAsE;QACtE,GAAG,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAE7B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEtB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChC,CAAC,EAAE,aAAa,CAAC,CAAC;QAClB,qEAAqE;QACrE,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAEpB,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC;QACF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3B,CAAC;CAcF;AAjFD,8BAiFC"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":"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"}
@@ -14,9 +14,17 @@
14
14
  * Untrusted input (the path string) is never passed to the shell: `spawn` is
15
15
  * invoked with an argv array, and the path is rejected before spawning unless it
16
16
  * resolves to an existing file under `plans/` or `archive/`. Node built-ins only.
17
+ *
18
+ * Launches are bounded: a {@link LaunchRegistry} tracks the plans whose child is
19
+ * still running, refusing a duplicate for the same plan and anything past
20
+ * {@link MAX_CONCURRENT_SELF_REVIEWS}. The registry is in-memory and per server
21
+ * instance: a restart resets the accounting, and the detached children — which
22
+ * the viewer never waits on — can outlive it. It is not a job manager.
17
23
  */
18
24
  /** The binary name looked up on PATH and spawned. */
19
25
  export declare const SELF_REVIEW_BINARY = "self-review";
26
+ /** Upper bound on self-review children running at once per server instance. */
27
+ export declare const MAX_CONCURRENT_SELF_REVIEWS = 2;
20
28
  /** Where to obtain self-review; surfaced by the SPA when it is not installed. */
21
29
  export declare const SELF_REVIEW_URL = "https://github.com/e0ipso/self-review";
22
30
  /**
@@ -40,11 +48,26 @@ export interface LaunchResult {
40
48
  ok: false;
41
49
  error: string;
42
50
  };
51
+ /** Extra response headers (e.g. `Retry-After` on a busy refusal). */
52
+ headers?: Record<string, string>;
53
+ }
54
+ /**
55
+ * The plans (by canonical absolute path) whose self-review child is running.
56
+ * One per server instance; see the module comment for what it is not.
57
+ */
58
+ export type LaunchRegistry = Set<string>;
59
+ /** Creates an empty {@link LaunchRegistry}. */
60
+ export declare const createLaunchRegistry: () => LaunchRegistry;
61
+ /** The slice of `ChildProcess` the launcher relies on; fakes implement it. */
62
+ export interface SpawnedChild {
63
+ once(event: string, listener: (...args: never[]) => void): unknown;
64
+ unref(): void;
43
65
  }
44
- /** Seams for testing: availability probe and the detached spawn. */
66
+ /** Seams for testing: availability probe, the spawn, and the registry. */
45
67
  export interface LaunchDeps {
46
68
  available?: () => boolean;
47
- spawnDetached?: (command: string, args: string[]) => void;
69
+ spawn?: (command: string, args: string[]) => SpawnedChild;
70
+ registry?: LaunchRegistry;
48
71
  }
49
72
  /**
50
73
  * Resolves a client-supplied plan path to an absolute path, requiring it to be
@@ -54,7 +77,10 @@ export interface LaunchDeps {
54
77
  * `root` is the absolute `.ai/strikethroo` directory; client paths are the
55
78
  * workspace-relative form the SPA shows (e.g. `.ai/strikethroo/plans/NN--s/…`),
56
79
  * so they are resolved against the project root (`root/../..`). Absolute client
57
- * paths are accepted too — the containment check is what enforces safety.
80
+ * paths are accepted too — the containment check is what enforces safety: the
81
+ * lexical check below picks the subtree, and the shared helper walks the real
82
+ * components so a symlinked plan file or directory is refused rather than
83
+ * followed out of the workspace.
58
84
  */
59
85
  export declare const resolveReviewPath: (root: string, clientPath: string) => {
60
86
  absPath: string;
@@ -63,9 +89,13 @@ export declare const resolveReviewPath: (root: string, clientPath: string) => {
63
89
  status: number;
64
90
  };
65
91
  /**
66
- * Validates `clientPath` and, if the binary is available, launches
67
- * `self-review <absolutePath>` detached. Pure of HTTP concerns: returns the
68
- * status/body the endpoint should send so it stays unit-testable.
92
+ * Validates `clientPath` and, if the binary is available and a slot is free,
93
+ * launches `self-review <absolutePath>` detached. Resolves `200` only after the
94
+ * child's `spawn` event; a launch `error` (e.g. `ENOENT`) is a fixed `500`. The
95
+ * plan's slot is taken synchronously before the spawn, so two simultaneous
96
+ * requests for one plan cannot both launch, and is released — idempotently —
97
+ * when the child exits, errors, or fails to launch. Pure of HTTP concerns:
98
+ * returns the status/body the endpoint should send so it stays unit-testable.
69
99
  */
70
- export declare const launchSelfReview: (root: string, clientPath: string, deps?: LaunchDeps) => LaunchResult;
100
+ export declare const launchSelfReview: (root: string, clientPath: string, deps?: LaunchDeps) => Promise<LaunchResult>;
71
101
  //# sourceMappingURL=self-review.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"self-review.d.ts","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,iFAAiF;AACjF,eAAO,MAAM,eAAe,0CAA0C,CAAC;AAmCvE;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,MAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,KACpD,OAQF,CAAC;AAEF,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACnD;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3D;AAWD;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,YAAY,MAAM,KACjB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CA4BvD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAM,UAAe,KACpB,YAwBF,CAAC"}
1
+ {"version":3,"file":"self-review.d.ts","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAK7C,iFAAiF;AACjF,eAAO,MAAM,eAAe,0CAA0C,CAAC;AAmCvE;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAChC,MAAK,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,KACpD,OAQF,CAAC;AAEF,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;AAEzC,+CAA+C;AAC/C,eAAO,MAAM,oBAAoB,QAAO,cAAmC,CAAC;AAK5E,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC;IACnE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,0EAA0E;AAC1E,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,YAAY,CAAC;IAC1D,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC3B;AAkBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,YAAY,MAAM,KACjB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAqCvD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,OAAM,UAAe,KACpB,OAAO,CAAC,YAAY,CAmDtB,CAAC"}